笔记:SpringBoot+Vue全栈开发
1. 开发环境热部署
使用spring-boot-devtools组件,pom.xml文件中添加依赖,如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
在application.properties文件中添加如下配置
# 热部署生效
spring.devtools.restart.enabled=true
# 设置重启目录
spring.devtools.restart.additional-paths=src/main/java
# 设置classpath目录下的的web-inf文件夹内容修改不重启
spring.devtools.restart.exclude=static/**
IDEA还需要设置如下:Settings->Compiler->Build project automatically ,把这个选项勾上
之后还需按Ctrl+Shift+Alt+/快捷键调出Maintenance页面,单击Registry,勾选compiler.automake.allow.when.app.running复选框。
之后只需重启项目代码即可。
2. SpringBoot @RestController的使用
package com.liuze.demo.controller;
import com.liuze.demo.entity.User;
import org.springframework.web.bind.annotation.*;
@RestController
public class TestController {
// http://localhost:8080/test1
@GetMapping(value = "/test1")
String test1(){
return "test1";
}
// http://localhost:8080/test2?usr=liuze&pwd=123456
@GetMapping(value = "/test2")
String test2(String usr,String pwd){
return "test2" + usr + "&" +pwd;
}
// http://localhost:8080/test3?username=liuze&password=123456
@GetMapping(value = "/test3")
String test3(@RequestParam(value = "username") String usr, @RequestParam(value = "password") String pwd){
return "test3" + usr + "&" +pwd;
}
// http://localhost:8080/test4 参数在请求体中
@PostMapping(value = "/test4")
String test4(String usr,String pwd){
return "test4" + usr +" &" + pwd;
}
// http://localhost:8080/test5 参数在请求体中
@PostMapping(value = "/test5")
String test5(User user){
return "test5" + user;
}
// http://localhost:8080/test6 参数在json数据中
@PostMapping(value = "/test6")
String test6(@RequestBody User user){
return "test6" + user;
}
}
其中post请求路径为test4,test5,test6。test4,test5,请求如下:
User为封装的User对象,有属性usr、pwd、类型均为String,需要提供get、set方法。
test6请求如下:
3. SpringBoot实现文件上传
Spring Boot限制了请求的文件大小,每个文件的配置最大为1MB,单次请求的文件的总数不能大于10MB。更改这个默认值在配置文件application.properties中添加这两个配置即可。
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB
上传参照代码为:
package com.liuze.demo.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
@RestController
public class FileUpload {
private final String SAVE_DIR = "E:/upolad/";
@PostMapping(path = "/upload")
public String fileUp(MultipartFile mfile) throws IOException {
System.out.println(mfile.getContentType());
// 获取文件类型
System.out.println(mfile.getSize());
// 获取文件大小
saveFile(mfile);
return "上传成功!";
}
private void saveFile(MultipartFile mFile) throws IOException {
String filename = mFile.getOriginalFilename();
// 获取文件原始名称
System.out.println(filename);
String path = SAVE_DIR + filename;
File file = new File(path);
mFile.transferTo(file);
}
}
运行结果:
出现报错,报错信息为The field mfile exceeds its maximum permitted size of 1048576 bytes.
这是因为上传的图片超过1MB导致的,把配置文件添加上述配置之后即可上传成功!
要想访问刚才上传的图片,还需要添加如下配置。
spring.web.resources.static-locations=file:E:/upolad/
4. 配置拦截器
也就是只有满足一定条件后,才能访问某些页面或接口。
package com.liuze.demo.interceptor;
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("测试");
return true;
}
}
为了使这个拦截器生效,需要添加配置
package com.liuze.demo.config;
import com.liuze.demo.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/test/**");
}
}
表示只有访问路径中带有/test的才进入拦截器,访问http://localhost:8080/test1,控制台并没有打印测试字样,当把addPathPatterns去掉,表示拦截所有,此时再访问刚才那个接口,控制台会有打印。
5. Restful服务+Swagger
Restful风格接口比如:http://localhost:8080/user/1,http://localhost:8080/user/2等,请求的数据直接跟在请求接口后,与之前参数查询不同http://localhost:8080/user?useri=1
@GetMapping(path = "/user/{id}")
public String getUser(@PathVariable(value = "id") int id2){
return "用户id:"+id2;
}
另外就是使用了Get、Post、Put、Delete等请求方式,请求接口一样,但请求类型不一样,从而导致结果不一样。
Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化Restful风格和web服务。需要添加的依赖为:
<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-->
添加配置类如下:
package com.liuze.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2 // 启用swagger2功能
public class SwaggerConfig {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com")) // 把com下的所有交给swagger进行管理
.paths(PathSelectors.any())
.build();
}
/**
* api文档页面显示信息
*/
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("api")
.description("演示使用")
.version("1.0")
.build();
}
}
访问页面http://localhost:8080/swagger-ui.html即可
出现的问题,springboot与swagger版本不兼容,当前使用的springboot版本为2.5.6,swagger版本为2.9.2。开始的springboot版本为2.7.12,启动springboot项目报错如下:
报错信息如下:
Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerException
只需要在application.properties配置文件中添加如下配置即可
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
其他解决方法可以参照这位大佬的文章:Failed to start bean ‘documentationPluginsBootstrapper‘; nested exception is java.lang.NullPointerEx
6. 使用MyBatis-Plus进行数据库操作
导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--mybatis-plus依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<!-- druid-->
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/test_1?useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
在启动类上添加@MapperScan,如下:
使用直接在对于的mapper接口,让其继承BaseMapper接口
对应的控制类为:
package com.liuze.demo.controller;
import com.liuze.demo.entity.User;
import com.liuze.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController{
@Autowired
private UserMapper um;
// 查询所有的用户信息
@GetMapping(path = "/users")
public List<User> find(){
List<User> users = um.selectList(null);
System.out.println(users);
return users;
}
@PostMapping(path = "/add")
public int add(User user){
int i = um.insert(user);
System.out.println(user);
return i;
}
}
访问接口:http://localhost:8080/users
添加用户:http://localhost:8080/add
数据库中的数据为:
因为数据库中字段与实体类的字段名不一致,所以在实体类User上添加了如下注解。@TableField
package com.liuze.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.ibatis.type.JdbcType;
import org.mapstruct.BeanMapping;
import org.springframework.context.annotation.Bean;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@TableName("user")
public class User {
@TableId(value = "uid",type = IdType.AUTO)
private Integer uid;
@TableField("username")
private String usr;
@TableField("password")
private String pwd;
}
7. 多表查询、条件查询及分页查询
多表查询就不能用到mybatis-plus,mybatis-plus只是用单表条件查询。现在有一个用户表,一个用户可以有多个订单,为此有一个订单表,现在想查询所有用户数据,当然用户下的订单也需要查询得到。首先需要做的是在User实体类下添加属性List<Order> order,之后在UserMapper 下添加代码如下
package com.liuze.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.liuze.demo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select * from user")
@Results(
{
@Result(column = "uid",property = "uid"),
@Result(column = "username",property = "usr"),
@Result(column = "password",property = "pwd"),
@Result(column = "uid",property = "orders",javaType = List.class,
many = @Many(select="com.liuze.demo.mapper.OrderMapper.findById"))
}
)
List<User> selectAll();
@Select("select * from user where uid = #{uid}")
List<User> selectById2(Integer uid);
}
订单类Order拥有的属性有oid(订单号)、total(订单金额)、uid(用户编号),其对应的OrderMapper如下:
package com.liuze.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.liuze.demo.entity.Order;
import com.liuze.demo.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
@Select("select * from order1 where oid = #{uid}")
List<Order> findById(int oid);
@Select("select * from order1")
@Results({
@Result(column = "oid",property = "oid"),
@Result(column = "total",property = "total"),
@Result(column = "uid",property = "user",javaType = User.class,
one = @One(select = "com.liuze.demo.mapper.UserMapper.selectById"))
})
List<Order> findAll();
}
上述还有一个要求,通过一个订单,查看这个订单所属用户,因此在订单类下添加属性User。
运行结果:
这是所有用户信息,目前只有用户编号为1的用户拥有一条订单数据。
这是查询全部订单的结果,目前只有一条订单数据,数据里边拥有用户的信息(只是测试使用,数据随意造的)
条件查询需要使用QueryWrapper,把查询条件设置到这个对象里边即可
@GetMapping("/userByUsr/{usr}")
public List<User> findByUsr(@PathVariable("usr") String username){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
return um.selectList(wrapper);
}
分页查询需要添加配置类,如下:
package com.liuze.demo.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor pageInteceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
return mybatisPlusInterceptor;
}
}
所对应的控制类为:
@GetMapping("/userByPage/{page}/{limitSize}")
public IPage<User> findByPage(@PathVariable("page") Integer page, @PathVariable Integer limitSize){
System.out.println(page+" "+limitSize);
Page<User> page1 = new Page<User>(page,limitSize);
return um.selectPage(page1,null);
}
运行结果: