本人的环境配置:
idea 2019
java(jdk8)
apache-maven 3.6.1
tomcat 8.5.5
mysql 8.0.12
navicat 16
一、SpringBoot快速上手——创建一个springboot项目
进去之后报红
在设置里面修改maven的配置,改成自己下载的maven的地址
还因为依赖项的版本和springboot版本不兼容,于是将pom.xml文件里的版本号改一下,改完之后加载一下就好了
接着创建一个controller
,实现在浏览器上显示“hello,world”
最后,运行可启动项HelloworldApplication
,在浏览器url栏中输入“http://localhost:8080/hello
”,就可以成功看到:
在实际的项目开发调试过程中会频繁地修改后台类文件,导致需要重新编译、启动,整个过程很麻烦,所以要使用到开发环境热部署
springboot提供了spring-boot-devtools组件,使得无需手动重启项目即可重新编译、启动项目
devtools会监听classpath下的文件变动,触发Restart类加载器重新加载该类,从而实现类文件和属性文件的热部署
1.在pom.xml配置文件中添加dev-tools依赖
使用optional=true表示依赖不会传递,即该项目依赖devtools,其他项目引入此项目生成的jar包,则不会包含devtools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
2.在application.properties中配置devtools
#热部署生效
spring.devtools.restart.enabled=true
#设置重启目录
spring.devtools.restart.additional-paths=src/main/java
#设置classpath目录下的WEB-INF文件夹内容修改不重启
spring.devtools.restart.exclude=static/**
3.打开idea里的settings,勾选如图
然后按住ctrl+shift+alt+/快捷键调出maintenance页面,单击registry,勾选如图
做完这两步配置后,在idea中修改代码保存后,项目会自动重启
二、Web入门
Springboot将传统web开发的mvc、json、tomcat等框架整合,提供了spring-boot-starter-web组件,简化了web应用配置
spring-boot-starter-web启动器主要包括web、webmvc、json、tomcat等基础依赖组件,作用是提供web开发场景所需的所有底层依赖
Springboot提供了@Controller和@RestController两种注解来标识此类负责接收和处理HTTP请求
如果是页面和数据请求,使用@Controller注解即可。如果只是数据请求,则可以使用@RestController注解(以文本形式交给前端)
- MVC设计模式
- 路由映射
@RequestMapping
注解主要负责URL的路由映射。可以添加在Controller类或具体的方法上。如果添加在Controller类上,则这个Controller中的所有路由映射都将会加上此映射规则。@RequestMapping
注解支持使用通配符匹配URL,用于统一映射某些URL规则类似的请求,如@RequestMapping("/getJson/*.json)
。 “*”匹配任意字符,“**”匹配任意路径(多级),“?”匹配单个字符。
@RequestMapping(value = "/hello",method = RequestMethod.GET)
等价于@GetMapping("/hello")
- 参数传递
@RequestParam
将请求参数绑定在控制器的方法参数上,接收的参数来自HTTP请求体或请求url的QueryString。当请求的参数名称与Controller的业务方法参数名称一致时,@RequestParam
可以省略
@PathVaraible
用来处理动态的url,url的值可以作为控制器中处理方法的参数
@RequestBody
接收的参数是来自requestBody中,即请求体。
例如:
当要传的参数变多了,就需要把参数封装到一个对象里去。例如:创建一个User类,属性为username和password。然后测试在浏览器url中输入参数值检验是否能成功绑定。localhost:8080/postTest3?username=zzy&password=123
@RequestMapping(value = "/postTest3",method = RequestMethod.POST)
public String test3(User user){
System.out.println(user);
System.out.println(user.password+user.username);
return "post请求";
}
三、Springboot文件上传+拦截器
在application.properties中直接定义过滤规则和静态资源位置
spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/
过滤规则为/static/**,静态资源位置为classpath:/static/
SpringBoot工程嵌入的tomcat限制了请求的文件大小,每个文件的配置最大为1MB,单次请求的文件的总数不能大于10MB
要更改这个默认值需要在配置文件中加入两个配置:
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request.size=10MB
表单的enctype属性规定在发送到服务器之前应该如何对表单数据进行编码。
当表单的enctype="multipart/form-data"
时,可以使用MultipartFile获取上传的文件数据,再通过transferTo
方法将其写入到磁盘中
报错异常,500一般是后端出问题了,404是url路径输错了
创建一个文件上传的Controller,此处因为还没有做前端的设计,所以用apipost工具进行测试
@RestController
public class FileUpLoadController {
@PostMapping("/upload")
public String up(String nickname, MultipartFile photo, HttpServletRequest request)throws IOException {
System.out.println(nickname);
System.out.println(photo.getOriginalFilename());
System.out.println(photo.getContentType());//文件类型
String path=request.getServletContext().getRealPath("/upload/");//获取web服务器的运行目录,也就是tomcat的运行路径
System.out.println(path);
saveFile(photo,path);
return "上传成功";
}
public void saveFile(MultipartFile photo,String path)throws IOException{
//判断存储的目录是否存在,不存在则创建
File dir=new File(path);
if(!dir.exists()){
//创建目录
dir.mkdir();
}
File file=new File(path+photo.getOriginalFilename());
//将网络上传输过来的文件存储到以上目录当中
photo.transferTo(file);
}
}
在apipost当中上传文件
发送后,在控制台显示以下结果。分别是图片的名称,图片的原始名称,图片的类型,上传成功后存储的路径(在tomcat所运行的路径下,这是个动态路径)
但是我们在浏览器上并不能访问到这张图片,如果用户上传了这张图片后想通过浏览器浏览此图片呢,就需要在配置文件(application.properties)中添加此代码spring.web.resources.static-locations=/upload/
。然后在浏览器url栏中直接输入http://localhost:8080/mebeforeu.jpg
就可以访问了。
Springboot定义了HandlerInterceptor接口来实现自定义拦截器的功能
HandlerInterceptor接口定义了preHandle、postHandle、afterCompletion三种方法,通过重写这三种方法实现请求前、请求后等操作。
这里创建一个interceptor拦截器,LoginInterceptor类实现SpringBoot中的HandlerInterceptor接口。
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return false;
}
}
再新建一个WebConfig类,实现WebMvcConfigurer接口,拦截请求。运行之后控制台打印preHandle,浏览器什么都不显示说明拦截成功,如果要放行就把上面的return false改成true。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
}
}
四、RESTful服务+Swagger
RESTful是目前流行的互联网软件服务架构设计风格
REST并不是一个标准,它更像一组客户端和服务端交互时的架构理念和设计原则,基于这种架构理念和设计原则的Web API更加简洁,更有层次。
SpringBoot提供的spring-boot-starter-web组件完全支持开发RESTful API,提供了与REST操作方式(GET,POST,PUT,DELETE)对应的注解。
@GetMapping
:处理GET请求,获取资源
@PostMapping
:处理POST请求,新增资源
@PutMapping
:处理PUT请求,更新资源
@DeleteMapping
:处理DELETE请求,删除资源
@PatchMapping
:处理PATCH请求,用于部分更新资源
SpringBoot实现RESTful API代码如下
@RestController
public class UserController {
@GetMapping("/user/{id}")
public String getUserById(@PathVariable int id) {
System.out.println(id);
return "根据id获取用户信息";
}
@PostMapping("/user")
public String save(User user) {
return "添加用户";
}
@PutMapping("/user")
public String update(User user){
return "更新用户";
}
@DeleteMapping("/user/{id}")
public String deleteById(@PathVariable int id) {
System.out.println(id);
return "根据id删除用户";
}
}
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,是非常流行的API表达工具。
Swagger能够自动生成完善的RESTful API文档,同时并根据后台代码的修改同步更新,同时提供完整的测试页面来调试API。
在SpringBoot项目中集成Swagger,引入以下依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
然后配置Swagger。在config包里面创建一个SwaggerConfig配置类
@Configuration //告诉Spring容器,这是个配置类
@EnableSwagger2 //启用Swagger2功能
public class SwaggerConfig {
//配置Swagger2相关的bean
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com"))//com包下所有api都交给swagger2管理
.paths(PathSelectors.any()).build();
}
//此处是api文档页面显示信息
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("演示项目API") //标题
.description("演示项目") //描述
.version("1.0") //版本
.build();
}
}
然后在appication.properties配置文件里加一行代码spring.mvc.pathmatch.matching-strategy=ant_path_matcher
最后输入在浏览器中输入http://localhost:8080/swagger-ui.html
即可成功访问以下页面
Swagger还提供了一系列注解来描述接口信息,包括接口说明、请求方法、请求参数、返回信息等。如
@ApiOperation("添加用户")
起到一个注释的效果。
五、MyBatisPlus快速上手
ORM(Object Relational Mapping,对象关系映射)是为了解决面向对象与关系数据库存在的互不匹配现象的一种技术。
ORM通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系数据库中。
ORM框架的本质是简化编程中操作数据库的编码。
MyBatis是一款优秀的数据持久层ORM框架,被广泛应用于系统中。MyBatis能够非常灵活地实现动态SQL,可以使用XML或注解来配置和映射原生信息,能够轻松地将Java的Pojo(Plain Ordinary Java Object,普通的Java对象)与数据库中的表和字段进行映射关联。
MyBatis-Plus是一个MyBatis的增强工具,在MyBatis的基础上做了增强,简化了开发。
添加依赖
<!-- MybatisPlus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!-- mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- 数据库连接池druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
在application.properties里添加数据库配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
这里注意要用数据库软件创建一个叫mydb的数据库,库里创一个user表,属性为username,password,添加几条记录。对应的在实体类里创建User类。
再创一个mapper包,里面创一个UserMapper接口。
@Mapper
public interface UserMapper {
//查询所有记录
@Select("select * from user")
public List<User> find();
@Insert("insert into user values(#{username},#{password})")
//这里的返回值代表插入了几条记录
public int insert(User user);
@Update("update user set username=#{username} where password=#{password}")
public int update(User user);
}
在controller包里创一个UserTestController,测试是否能查询修改数据库里的数据。
@RestController
public class UserTestController {
//自动注入
@Autowired
private UserMapper userMapper;
@GetMapping("/userQuery")
public List query(){
List<User> userList= userMapper.find();
System.out.println(userList);
return userList;
}
@PostMapping("/userInsert")
public String save(User user){
//前端传过来的用户对象传到数据库里去
int i=userMapper.insert(user);
if(i>0){
return "success";
}else {
return "fail";
}
}
@PostMapping("userUpdate")
public String update(User user){
int i=userMapper.update(user);
if(i>0){
return "更新了"+i+"条数据";
}else {
return "更新失败";
}
}
}
最后记得在启动类里加一个包扫描@MapperScan("com.example.test3.mapper")
以上是mybatis的用法,接下来直接用mybatis-plus进行操作。上面的作为了解,可以删掉了(不是)
mysql里表的id设为自增,并且在实体类id上加上此注解@TableId(type = IdType.AUTO)
(主键且自增),如果不加这个注解,数据库里的id会自增,但是代码里拿不到id值
如果实体类和数据库的表名对不上,就在User实体类里加个注解@TableName("t_user")
,表明映射到数据库表tb_user
如果表里面叫name,数据库里叫username,就可以使用@TableField("username")
注解。
直接public interface UserMapper extends BaseMapper<User>
UserMapper继承BaseMapper,使用自带的方法进行增删改查。
例如查询,用List<User> userList= userMapper.selectList(null);
获取查询到的数据列表。
六、MyBatisPlus多表查询及分页查询
实现复杂关系映射,可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置
注意:MySQL数据库里的表的字段名要和Java类中的属性名一一对应,不然会报错。我数据库里id是后加进去的,这里重写的toString就报错了。于是我就把数据库里的id移到最上去就好了。
问题:根据user表的id查询所有用户及其订单记录(两表关联)
得出以下结果:
首先创建数据库,一张tb_user表 { id(主键),username,password }
,一张tb_order表{ id(主键),order_time,total,uid(外键,关联tb_user.id) }
然后添加几条记录,方便查询。
再在idea里创建对应的User类和Order类,注意数据类型要一一对应。
部分User类代码(这里的toString重写和构造函数就不用加orderList了,我就是因为加了然后一直报错500,索引越界。)
public class User {
@TableId(type = IdType.AUTO)
private int id;
private String username;
private String password;
//描述用户所有的订单
// @TableField(exist = false)//是说明orderList在user表里是不存在的。
//相当于select id,username,password,orderList from tb_user。
//需要自己映射,但是这是mp的用法,我们mapper里是自己写的sql语句,所以这个注解可不要
private List<Order> orderList;
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
部分Order类代码
public class Order {
@TableId(type = IdType.AUTO)
private int id;
@TableField("order_time")//数据库里叫order_time
private String orderTime;
private String total;
private int uid;
@Override
public String toString() {
return "Order{" +
"id=" + id +
", order_time='" + orderTime + '\'' +
", total='" + total + '\'' +
", uid=" + uid +
'}';
}
为什么没有加 @TableField(“order_time”) 也能查询出来?
MyBatis-Plus 有自动映射规则,它支持 驼峰命名法 和 下划线命名法 的自动转换。例如:
数据库字段名 order_time 会被自动映射为 Java 类中的 orderTime(假设你用了驼峰命名)。
反之,orderTime 会自动映射为 order_time。
然后创建UserMapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
//查询用户及其所有订单
@Select("select * from tb_user")
@Results(
{
@Result(column = "id",property = "id"),
@Result(column = "username",property = "username"),
@Result(column = "password",property = "password"),
// 映射订单列表的关联查询
@Result(column = "id",property = "orderList",javaType = List.class,
many=@Many(select = "com.example.test3.mapper.OrderMapper.selectByUid"))
//因为一个用户有多个订单,所以是一对多的关系,用注解@Many表示
}
)
List<User> selectAllUserAndOrders();
}
OrderMapper接口
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
//根据用户的id查询所有的订单
@Select("select * from tb_order where uid=#{uid}")
List<Order> selectByUid(int uid);
}
最后创建一个UserTestController进行测试。输入http://localhost:8080/user/findAll
就可以成功看到查询结果了。注意:①确保列顺序和字段名在 @Results 中正确映射,还有类的属性名是否填对。②检查 @One 和 @Many 注解的查询方法返回类型。
@RestController
public class UserTestController {
//自动注入
@Autowired
private UserMapper userMapper;
@GetMapping("/user/findAll")
public List<User> findAll(){
return userMapper.selectAllUserAndOrders();
}
}
问题:根据订单id查询用户,跟上面那个不同的是,一个订单里只有一个用户,但一个用户可以有多个订单
在Order类里面增加private User user;
注意这里还要增加user的get和set方法,不然等会浏览器里不会显示user这个字段的内容。
为什么我没写orderTime的get和set方法,仍然可以出来order_time的结果?
在没有显式 getOrderTime 和 setOrderTime 方法的情况下,MyBatis 通过反射机制可以自动处理字段的映射,只要字段是私有的且能够通过反射访问。只要数据库中的列(如 order_time)和 Java 类的字段名(如 orderTime)通过配置或命名约定保持一致,MyBatis 就能正确地将数据从数据库映射到 Java 对象中。
在orderMapper里增加几行代码
// 查询所有的订单,同时查询订单的用户
@Select("select * from tb_order")
@Results(
{
@Result(column = "id",property = "id"),//列名(字段名),属性名
@Result(column = "order_time",property = "orderTime"),
@Result(column = "total",property = "total"),
@Result(column = "uid",property = "user",javaType = User.class,
one = @One(select = "com.example.test3.mapper.UserMapper.selectById"))
}
)
List<Order> findAllOrdersAndUser();
在UserMapper里增加几行代码
//根据id查询信息
@Select("select * from tb_user where id=#{id}")
User selectById(int id);
最后创建一个OrderTestController,输入http://localhost:8080/order/findOrder
即可成功运行。
@RestController
public class OrderTestController {
@Autowired
private OrderMapper orderMapper;
@GetMapping("/order/findOrder")
public List findOrder(){
return orderMapper.findAllOrdersAndUser();
}
}
问题:根据所选条件进行查询(用mybatis-plus自带的功能)
在UserTestController里增加以下代码,查询姓名为zzy的user信息
//条件查询
@GetMapping("/user/findBy")
public List<User> findBy(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username","zzy");
return userMapper.selectList(queryWrapper);
}
运行之后报错显示查询不到mydb.user表,因为User类上没有加注解@TableName("tb_user")
。然后再运行报错说orderList不在user表里,因为@TableField(exist = false)
这个注解在前面被注释掉了,这里给它解注释即可。
为什么会之前能查询到数据,但是用mybatis-plus的方法就查询失败
①自己写的 SQL 语句能查询数据: 你自己写的 SQL 语句不依赖 MyBatis-Plus 的自动映射机制,所以它直接使用的是你在 SQL 中明确指定的表名(tb_user)。因此,你能够查询到数据。
②MyBatis-Plus 自带的 SQL 语句查找不到表: MyBatis-Plus 在生成 SQL 时会自动根据实体类的名称推测表名,如果没有加 @TableName(“tb_user”) 注解,MyBatis-Plus 会默认将 User 类映射到 user 表(类名 User 转为小写的 user)。但是你的数据库表名是 tb_user,所以 MyBatis-Plus 就会报错找不到 user 表。
修改代码后进行运行即可出现zzy的user信息。
mybatis-plus实现分页查询
在config包里创建一个MybatisPlusConfig类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//创建了一个mybatis-plus的分页拦截器
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
}
在UserTestController里测试
//分页查询
@GetMapping("/user/findByPage")
public IPage findByPage() {
//设置起始值及每页条数。每页显示三条
Page<User> page = new Page<>(0, 3);
IPage iPage = userMapper.selectPage(page, null);
return iPage;
}
七、Vue框架快速上手
Vue是一套用于构建用户界面的渐进式框架。Vue.js提供了MVVM数据绑定和一个可组合的组件系统,具有简单、灵活的API。其目标是通过尽可能简单的API实现响应式的数据绑定和可组合的视图组件。
MVVM是Model-View-ViewModel的缩写,它是一种基于前端开发的架构模式,其核心是提供对View和ViewModel的双向数据绑定。
Vue提供了MVVM风格的双向数据绑定,核心是MVVM中的VM,也就是ViewModel,ViewModel负责连接View和Model,保证视图和数据的一致性。