Loading... # 1. springboot起步 ## 1.1 pom文件 pring Boot项目配置主要包括两个部分:pom.xml和application.yml。pom.xml是项目的Maven配置文件,主要用于定义项目的依赖和插件。application.yml是项目的配置文件,主要用于定义项目的各种配置信息,如数据库连接信息、服务器端口等。 下面是一个基本的Spring Boot项目的pom.xml文件示例: ```java <project> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.3.12.RELEASE</version><!-- 根据您的需求选择适当的版本 --> </parent> <dependencies> <!-- Spring Boot 起步依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- Spring Boot Web依赖(包含spring-boot-starter,任选其一) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Boot Test依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- Spring Boot Maven插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> ``` 如果要自定义打包名字和限定jdk版本可以这样设置 ```xml <build> <finalName>${artifactId}-${version}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> ``` ## 1.2 统一返回处理类 ```java package com.emmmua.warehousectrl.common; import lombok.Data; /** * 响应结果通用类 * * @param <T> */ @Data public class ResponseResult<T> { private Integer code; private String message; private T data; public ResponseResult() { } public ResponseResult(Integer code, String message) { this.code = code; this.message = message; } public ResponseResult(Integer code, String message, T data) { this.code = code; this.message = message; this.data = data; } public static <T> ResponseResult<T> success() { return new ResponseResult<>(200, "success"); } public static <T> ResponseResult<T> success(T data) { return new ResponseResult<>(200, "success", data); } public static <T> ResponseResult<T> success(T data, String message) { return new ResponseResult<>(200, message, data); } public static <T> ResponseResult<T> failure(Integer code, String message) { return new ResponseResult<>(code, message); } public static <T> ResponseResult<T> failure(String message) { return new ResponseResult<>(500, message); } } ``` 该类为泛型类,支持任意类型的数据。它包含三个属性:`code`,`message`和 `data`。其中,`code`表示响应状态码,`message`表示响应消息,`data`表示响应数据。该类还提供了多个静态方法,用于快速构建响应结果。比如: - `success()`方法用于构建不带数据的成功响应结果; - `success(T data)`方法用于构建带数据的成功响应结果; - `failure(Integer code, String message)`方法用于构建自定义的失败响应结果; - `failure(String message)`方法用于构建默认的失败响应结果。 使用该类时,可以根据业务需要,选择合适的静态方法来构建响应结果,并将其作为方法的返回值。例如: ```java @GetMapping("/user") public ResponseResult<User> getUser() { User user = userService.getUser(); return ResponseResult.success(user); } @DeleteMapping("/user") public ResponseResult<Void> deleteUser() { userService.deleteUser(); return ResponseResult.success(); } @ExceptionHandler(RuntimeException.class) public ResponseResult<Void> handleException(RuntimeException e) { log.error("An exception occurred: {}", e.getMessage()); return ResponseResult.failure(e.getMessage()); } ``` 在以上示例中,`getUser()`方法通过 `ResponseResult.success(User data)`方法构建成功响应结果,并将 `User`对象作为响应数据返回。`deleteUser()`方法通过 `ResponseResult.success()`方法构建不带数据的成功响应结果。`handleException()`方法在异常处理时,通过 `ResponseResult.failure(String message)`方法构建失败响应结果,并将异常消息作为响应消息返回。 ## 1.3 统一异常处理类 下面是一个简单的SpringBoot统一异常处理类,使用ResponseResult作为异常返回类型。 ### 异常类 ```java /** * 自定义业务异常类 */ @Data public class BusinessException extends RuntimeException { private ResponseResult responseResult; public BusinessException(String message) { super(message); this.responseResult = ResponseResult.failure(message); } public BusinessException(ResponseResult responseResult) { super(responseResult.getMessage()); this.responseResult = responseResult; } } ``` ### 异常处理器 ```java /** * 自定义统一异常处理 * 1、通过注解,声明异常处理类 * 2、编写方法,在方法内部处理异常,构造响应数据 * 3、方法上编写注解,指定此方法可以处理的异常类型 */ @RestControllerAdvice public class ExceptionAdvice { /** * 处理自定义异常 * @param be 自定义异常 * @return 响应结果 */ @ExceptionHandler(BusinessException.class) public ResponseResult handlerBusinessException(BusinessException be) { be.printStackTrace(); ResponseResult responseResult = be.getResponseResult(); return responseResult; } /** * 处理不可预知的异常 * @param be 不可预知的异常 * @return 响应结果 */ @ExceptionHandler(Exception.class) public ResponseResult handlerException(Exception be) { // 如果需要过滤自定义异常MyException if (e instanceof MyException) { // 如果是 MyException 异常,不处理该异常 return null; } // 对于其他异常,继续处理 be.printStackTrace(); ResponseResult responseResult = new ResponseResult(500, "未知异常"); return responseResult; } } ``` 上面的代码中,使用@RestControllerAdvice注解标识这是一个统一异常处理类。其中handleBusinessException方法用于处理自定义的业务异常BusinessException,将异常信息转换为ResponseResult返回;handleException方法用于处理所有未知的异常。 需要注意的是,在使用@RestControllerAdvice注解的类中,还可以添加@ExceptionHandler注解来处理其他特定的异常类型。 ## 1.4 单元测试 <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.fivk.cn/archives/3467.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.fivk.cn/usr/themes/handsome/assets/img/sj/3.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">【知识总结】Spring Boot Starter Test的使用方法详解</p> <div class="inster-summary text-muted"> 引言在现代软件开发中,单元测试是一个至关重要的环节。Spring Boot为我们提供了一个方便而强大的测试模块——... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> ## 1.5 日志处理 <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.fivk.cn/archives/6520.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.fivk.cn/usr/themes/handsome/assets/img/sj/3.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">【知识总结】使用log4j 2记录Spring Boot应用程序日志</p> <div class="inster-summary text-muted"> 一、log4j 2的优势更新和维护:log4j已经停止更新,而log4j 2是其最新版本,持续得到维护和更新,可以... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> # 2.MySql 1. 配置依赖 在 Maven 项目的 pom.xml 文件中,需要引入 MySQL 数据库的驱动依赖,如下所示: ```xml <dependencies> <!-- 引入 Spring Boot 数据库依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 引入 MySQL 驱动依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.25</version> </dependency> </dependencies> ``` 2. 配置数据源 在 Spring Boot 中,可以使用 application.yml 或 application.properties 文件进行数据源的配置。以下是一个使用 YAML 格式配置的示例: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver hikari: connection-timeout: 60000 maximum-pool-size: 10 minimum-idle: 5 idle-timeout: 180000 ``` YAML 配置说明: - url:数据库连接地址,其中 useUnicode、characterEncoding 和 serverTimezone 分别用于设置数据库字符集和时区。 - username 和 password:数据库用户名和密码。 - driver-class-name:数据库驱动类名,此处指定为 com.mysql.cj.jdbc.Driver。 - hikari:用于配置 Hikari 数据库连接池的属性,包括连接超时时间(connection-timeout)、最大连接数(maximum-pool-size)、最小空闲连接数(minimum-idle)和空闲连接超时时间(idle-timeout)等。 3. 配置 JPA 在 Spring Boot 中使用 JPA 进行数据库操作,需要在 application.yml 或 application.properties 文件中配置 JPA 的相关属性。以下是一个使用 YAML 格式配置的示例: ```yaml spring: jpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: dialect: org.hibernate.dialect.MySQL8Dialect ``` YAML 配置说明: - hibernate.ddl-auto:设置数据库表的生成方式,可选值包括 none、validate、update、create 和 create-drop。 - show-sql:设置是否打印 SQL 语句。 - hibernate.dialect:设置 Hibernate 方言,此处指定为 MySQL 8 的方言。 注意:以上示例中的配置仅供参考,具体的配置需要根据实际情况进行调整。 # 3. Mybatis 下面是关于 Spring Boot 中使用 MyBatis 和 Druid 数据库连接池的配置和包常用模板,以及相应的 YAML 配置说明: 1. 配置依赖 在 Maven 项目的 pom.xml 文件中,需要引入 MyBatis 和 Druid 数据库连接池的依赖,如下所示: ```xml <dependencies> <!-- 引入 Spring Boot 数据库依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- 引入 MyBatis 相关依赖 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency> <!-- 引入 Druid 数据库连接池依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.8</version> </dependency> </dependencies> ``` 2. 配置数据源 在 Spring Boot 中,可以使用 application.yml 或 application.properties 文件进行数据源的配置。以下是一个使用 YAML 格式配置的示例: ```xml spring: datasource: url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource druid: initial-size: 5 min-idle: 5 max-active: 20 test-on-borrow: true test-on-return: false test-while-idle: true validation-query: SELECT 1 FROM DUAL time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 filters: stat,wall,log4j2 ``` AML 配置说明: - url:数据库连接地址,其中 useUnicode、characterEncoding 和 serverTimezone 分别用于设置数据库字符集和时区。 - username 和 password:数据库用户名和密码。 - driver-class-name:数据库驱动类名,此处指定为 com.mysql.cj.jdbc.Driver。 - type:指定使用 Druid 数据库连接池。 - druid:用于配置 Druid 数据库连接池的属性,包括初始连接数(initial-size)、最小空闲连接数(min-idle)、最大活动连接数(max-active)、连接池是否在创建时就会预热(test-on-borrow)、是否在归还连接时进行校验(test-on-return)、是否在空闲时进行校验(test-while-idle)、连接校验语句(validation-query)、连接回收周期(time-between-eviction-runs-millis)、最小空闲时间(min-evictable-idle-time-millis)和连接池过滤器(filters)等。 3. 配置 MyBatis 在 Spring Boot 中使用 MyBatis 进行数据库操作,需要在 application.yml 或 application.properties 文件中配置 MyBatis 的相关属性。以下是一个使用 YAML 格式配置的示例: ```xml mybatis: mapper-locations: classpath:mapper/*.xml configuration: map-underscore-to-camel-case: true ``` YAML 配置说明: - mapper-locations:指定 MyBatis Mapper 文件的路径,此处指定为 classpath:mapper/*.xml,表示 Mapper 文件存放在项目的 classpath:mapper 目录下。 - configuration:用于配置 MyBatis 的属性,包括是否开启驼峰命名法(map-underscore-to-camel-case)等。 4. 配置日志 在 MyBatis 中,可以通过配置日志,来帮助开发者了解 SQL 语句的执行情况。Spring Boot 中使用 MyBatis,可以选择使用 SLF4J 或 Log4j2 来进行日志的配置。以下是一个使用 Log4j2 配置日志的示例: ```xml logging: level: com.example.demo.mapper: debug file: name: logs/mybatis.log appenders: console: type: console mybatis: type: File fileName: ${logging.file.name} layout: type: PatternLayout pattern: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{1}:%L - %m%n" loggers: com.example.demo.mapper: additivity: false level: debug appender-ref: - ref: mybatis ``` YAML 配置说明: - logging.level.com.example.demo.mapper:指定 MyBatis Mapper 接口的日志级别为 debug。 - logging.file.name:指定日志文件的路径和名称,此处指定为 logs/mybatis.log。 - logging.appenders.console:配置控制台输出日志。 - logging.appenders.mybatis:配置日志文件输出日志,其中 fileName 属性使用了 logging.file.name 属性。 - logging.appenders.mybatis.layout:指定日志的格式。 - logging.loggers.com.example.demo.mapper:指定 MyBatis Mapper 接口的日志配置,包括是否继承 RootLogger(additivity)、日志级别和日志输出方式(appender-ref)。此处指定了日志输出方式为 mybatis,即上一步中配置的日志文件输出方式。 5.Mapper.xml模板 ```xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.emmmmua.mapper.UserMapper"> </mapper> ``` ## mybatis批量插入 <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.fivk.cn/archives/6340.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.fivk.cn/usr/themes/handsome/assets/img/sj/3.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">【开发技巧】Mybatis官方推荐的批量插入方法</p> <div class="inster-summary text-muted"> 1.背景介绍在写crud时使用mybatis写批量插入用的foreach标签,报错 Packet for quer... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> # 4.MyBatisPlus 内容主要包括了 MyBatis-Plus 的常用配置,包括了: 1. 配置 MyBatis-Plus 的分页插件; 2. 配置 MyBatis-Plus 的逻辑删除插件; 3. 配置 MyBatis-Plus 的性能分析插件; 4. 配置 MyBatis-Plus 的防止全表更新与删除插件; 5. 配置 MyBatis-Plus 的多租户插件; 6. 配置 MyBatis-Plus 的主键自动生成策略; 7. 配置 MyBatis-Plus 的全局通用查询映射器; 8. 配置 MyBatis-Plus 的动态表名插件; 9. 配置 MyBatis-Plus 的多租户数据源插件; 10. 配置 MyBatis-Plus 的乐观锁插件; 11. 配置 MyBatis-Plus 的自动填充插件。 ## 4.1 起步配置 MyBatis-Plus 的常用配置。需要注意的是,MyBatis-Plus 是在 MyBatis 的基础上进行的二次封装,所以它的配置方式与 MyBatis 类似。 1. 引入 MyBatis-Plus 依赖 在项目的 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.x.x</version> </dependency> ``` 其中,`3.x.x` 是 MyBatis-Plus 的版本号,可以根据实际情况进行修改。 ### 4.2 配置数据源和连接池 MyBatis-Plus 的数据源和连接池配置与 MyBatis 类似,这里我们以使用 Druid 连接池为例进行说明。在 `application.yml` 文件中添加以下配置: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/mybatis_plus_test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: map-underscore-to-camel-case: true ``` 以上配置中,`mybatis-plus.configuration.map-underscore-to-camel-case` 属性用来配置下划线自动转驼峰,默认值为 `false`,表示不进行自动转换。 ### 4.3 配置实体类与数据库表的映射关系 MyBatis-Plus 提供了一个 `@TableName` 注解来标识实体类对应的表名,使用方式与 MyBatis 相同。此外,MyBatis-Plus 还提供了一些注解来简化实体类与数据库表的映射,如 `@TableId`、`@TableField` 等。以下是一个示例: ```java @Data @TableName("t_user") public class User { @TableId(value = "id", type = IdType.AUTO) private Long id; @TableField("user_name") private String userName; private String password; private String email; private String phone; } ``` 在上面的示例中,`@TableId` 注解用来标识主键属性,`value` 属性用来指定数据库中的列名,`type` 属性用来指定主键生成策略,此处为自动递增。`@TableField` 注解用来标识非主键属性,`value` 属性用来指定数据库中的列名。 ## 4.2 MyBatis-Plus使用案例 这里提供一个基于MyBatis-Plus的增删改查的案例,包含了Controller、Service、ServiceImpl和Mapper: 先创建一个 `User`实体类: ```java public class User { @TableId(type = IdType.AUTO) private Long id; private String username; private String password; private Integer age; private String email; private LocalDateTime createTime; private LocalDateTime updateTime; @TableLogic private Integer deleted; // 省略getter/setter } ``` 这里使用了 `@TableId`指定主键策略为自增长,使用了 `@TableLogic`指定逻辑删除字段。 接下来创建一个 `UserController`,实现增删改查的接口: ```java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @GetMapping("") public List<User> getAllUsers() { return userService.getAllUsers(); } @GetMapping("/{id}") public User getUserById(@PathVariable Long id) { return userService.getUserById(id); } @PostMapping("") public String createUser(@RequestBody User user) { userService.createUser(user); return "create user success"; } @PutMapping("/{id}") public String updateUser(@PathVariable Long id, @RequestBody User user) { user.setId(id); userService.updateUser(user); return "update user success"; } @DeleteMapping("/{id}") public String deleteUser(@PathVariable Long id) { userService.deleteUser(id); return "delete user success"; } } ``` 其中,`UserController`依赖于 `UserService`,使用 `@Autowired`注解进行注入。接下来是 `UserService`接口和 `UserServiceImpl`实现类: ```java public interface UserService extends IService<User> { List<User> getAllUsers(); User getUserById(Long id); void createUser(User user); void updateUser(User user); void deleteUser(Long id); } @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Override public List<User> getAllUsers() { return list(); } @Override public User getUserById(Long id) { return getById(id); } @Override public void createUser(User user) { save(user); } @Override public void updateUser(User user) { updateById(user); } @Override public void deleteUser(Long id) { removeById(id); } } ``` `UserServiceImpl`继承了 `ServiceImpl`,自动获得了MyBatis-Plus提供的大量通用方法,如 `list()`、`getById()`、`save()`、`updateById()`和 `removeById()`等。最后是 `UserMapper`: ```java @Mapper public interface UserMapper extends BaseMapper<User> { } ``` `UserMapper`继承了 `BaseMapper`,也可以直接使用MyBatis-Plus提供的通用方法,如 `selectById()`、`selectList()`、`insert()`、`updateById()`和 `deleteById()`等。 至此,基于MyBatis-Plus的增删改查案例完成。 ## 4.3 MyBatis-Plus工具 还可以参考Mybatis的PageHelper分页。 <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.fivk.cn/archives/3499.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.fivk.cn/usr/themes/handsome/assets/img/sj/3.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">【MyBatis】PageHelper分页插件</p> <div class="inster-summary text-muted"> 之前都是用Mybatis Plus分页插件,没用过PageHelper分页。在项目中遇到了,今天来记录一下。Pag... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> ### 4.3.1 分页插件 MyBatis-Plus是一个基于MyBatis的增强工具包,提供了许多MyBatis没有提供的便捷功能,其中包括分页插件。在SpringBoot中使用MyBatis-Plus的分页插件,可以轻松地实现分页查询功能。 以下是一个使用MyBatis-Plus分页插件的示例: 1. 添加依赖 在Maven项目中,需要在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3.1</version> </dependency> ``` 2. 配置分页插件 在SpringBoot的配置文件application.yml或application.properties中添加以下配置: ```yaml mybatis-plus: configuration: # 开启驼峰命名自动转换为下划线命名 map-underscore-to-camel-case: true global-config: # 开启分页插件 db-config: page-size: 10 # 默认分页大小 page-current: 1 # 默认当前页码 # 开启 count sql 解析 count-sql-parser: true # 是否开启默认分页 default-page: true # 是否开启排序 order-by-field: true ``` ```java @Configuration //扫描mapper接口所在的包 @MapperScan("com.emmmua.mapper") public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //添加分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` 4. 使用分页插件 在DAO接口中,使用MyBatis-Plus的Page对象作为参数,即可实现分页查询功能。例如: ```java import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import java.util.List; public interface UserMapper extends BaseMapper<User> { List<User> selectAll(); IPage<User> selectPageVo(Page<?> page); } ``` 在Service中调用DAO接口的selectPageVo方法,即可实现分页查询功能。例如: ```java import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> selectAll() { return userMapper.selectAll(); } @Override public Page<User> selectPageVo(Integer pageNum, Integer pageSize) { // 设置分页信息 Page<User> page = new Page<>(pageNum, pageSize); // 执行分页查询 return userMapper.selectPageVo(page); } } ``` 在Controller中调用Service接口的selectPageVo方法,即可返回分页结果。例如: ```java import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class UserController { @Autowired private UserService userService; @GetMapping("/users") public Page<User> getUsers(@RequestParam Integer pageNum, @RequestParam Integer pageSize) { return userService.selectPageVo(pageNum, pageSize); } } ``` 以上就是使用MyBatis-Plus分页插件的一个简单示例。需要注意的是,在Mapper接口中,使用MyBatis-Plus的BaseMapper接口,并在实现类中继承它。BaseMapper中已经封装好了常用的CRUD操作,同时也包括分页查询操作。因此,不需要再手动编写SQL语句,直接使用BaseMapper提供的方法即可。 另外,分页插件还支持自定义分页SQL语句,可以在配置文件中设置自定义SQL语句和正则表达式。 ### 4.3.2 逻辑删除插件 当我们使用 MyBatis-Plus 进行数据库操作时,有时候需要使用逻辑删除,即将数据库中的数据标记为删除状态,而不是直接从数据库中删除数据。MyBatis-Plus 为我们提供了逻辑删除插件来方便地实现逻辑删除功能。 使用 MyBatis-Plus 的逻辑删除插件,我们需要进行以下几个步骤: 1. 在实体类中添加逻辑删除字段和注解 在实体类中添加一个字段用于标记是否被删除,同时使用 `@TableLogic` 注解标注该字段。 ```java public class User { private Long id; private String name; private Integer age; @TableLogic // 标记为逻辑删除字段 private Integer deleted; // 0 表示未删除,1 表示已删除 // 省略 getter 和 setter 方法 } ``` 2. 配置 MyBatis-Plus 的逻辑删除插件 在 Spring Boot 的配置文件中添加以下配置: ```yaml mybatis-plus: global-config: db-config: logic-delete-value: 1 # 删除时设置逻辑删除值为 1 logic-not-delete-value: 0 # 恢复时设置逻辑删除值为 0 ``` 这里设置了逻辑删除值为 1,恢复时设置逻辑删除值为 0。如果需要自定义逻辑删除字段名,可以在 `db-config` 中添加 `logic-delete-field` 属性,如: ```yaml mybatis-plus: global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0 logic-delete-field: is_deleted # 自定义逻辑删除字段名 ``` 3. 在 Mapper 中使用逻辑删除方法 MyBatis-Plus 的逻辑删除插件为我们提供了 `deleteByIdWithFill` 方法来实现逻辑删除。在 Mapper 中使用该方法即可实现逻辑删除功能。 ```java public interface UserMapper extends BaseMapper<User> { // 使用逻辑删除方法 int deleteByIdWithFill(User user); } ``` 使用方法如下: ```java @Autowired private UserMapper userMapper; // 删除用户 User user = new User(); user.setId(1L); int rows = userMapper.deleteByIdWithFill(user); ``` 以上就是使用 MyBatis-Plus 的逻辑删除插件的方法。使用逻辑删除可以避免误删数据,同时也可以保留删除记录,方便查询和恢复。 ### 4.3.3 性能分析插件 MyBatis-Plus 的性能分析插件可以帮助我们快速地定位和解决 SQL 语句执行效率低下的问题,提高系统的性能。 使用 MyBatis-Plus 的性能分析插件,我们需要进行以下几个步骤: 1. 在配置文件中启用性能分析插件 在 Spring Boot 的配置文件中添加以下配置: ```yaml mybatis-plus: configuration: # 开启性能分析插件 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL 执行最大时长,超过该值会输出警告日志,默认值:0(不限制) max-time: 1000 # SQL 是否格式化输出 format: true # SQL 是否开启全局缓存 cache: true ``` 2. 使用分页插件的 `Interceptor` 接口实现类 MyBatis-Plus 的性能分析插件是一个实现了 `Interceptor` 接口的类,我们需要在配置文件中添加分页插件的 `Interceptor` 接口实现类,如下所示: ```yaml mybatis-plus: configuration: # 配置分页插件的 Interceptor 接口实现类 interceptor: - com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor ``` 3. 在 Mapper 中使用分页方法 在 Mapper 中使用 MyBatis-Plus 提供的分页方法,即可启用性能分析插件。例如,使用 `selectPage` 方法进行分页查询: ```java public interface UserMapper extends BaseMapper<User> { // 分页查询用户列表 IPage<User> selectUserPage(Page<User> page, @Param("query") UserQuery query); } ``` 以上就是使用 MyBatis-Plus 的性能分析插件的方法。使用性能分析插件可以帮助我们及时发现 SQL 语句执行效率低下的问题,方便及时优化提高系统的性能。 ### 4.3.4 防止全表更新与删除插件 MyBatis-Plus 提供了防止全表更新和删除的插件,可以避免误操作导致数据的大量删除和更新,保障系统的数据安全。 使用 MyBatis-Plus 的防止全表更新和删除插件,我们需要进行以下几个步骤: 1. 在配置文件中启用防止全表更新和删除插件 在 Spring Boot 的配置文件中添加以下配置: ```yaml mybatis-plus: configuration: # 开启防止全表更新和删除插件 sql-parser-cache: true # SQL 是否格式化输出 format: true # 配置全局的 SQL 解析处理器,可以自定义 SQL 解析规则 sql-parser: limit: com.baomidou.mybatisplus.extension.plugins.inner.limit.InnerLimitHandler ``` 2. 在 Mapper 中使用 `@SqlParser` 注解 在 Mapper 中使用 `@SqlParser` 注解,指定是否启用全表更新和删除的防护功能。例如: ```yaml public interface UserMapper extends BaseMapper<User> { // 根据 ID 删除用户 @SqlParser(filter = true) // 启用防止全表删除插件 int deleteById(Long id); } ``` 在以上示例中,我们使用 `@SqlParser(filter = true)` 注解启用了全表删除插件,即在执行删除操作时,如果 SQL 语句中不带有 `where` 条件,将无法执行删除操作,避免误操作导致数据的大量删除。 3. 在 Service 层中使用 `@SqlParser` 注解 在 Service 层中使用 `@SqlParser` 注解,同样可以启用全表更新和删除的防护功能。 ```java @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Override @Transactional @SqlParser(filter = true) // 启用防止全表更新插件 public boolean updateById(User user) { return super.updateById(user); } } ``` 以上就是使用 MyBatis-Plus 的防止全表更新和删除插件的方法。使用该插件可以避免误操作导致数据的大量删除和更新,保障系统的数据安全。 ### 4.3.5 多租户插件 MyBatis-Plus 提供了多租户插件,可以方便地实现基于多租户的数据隔离和访问控制。 使用 MyBatis-Plus 的多租户插件,我们需要进行以下几个步骤: 1. 在配置文件中启用多租户插件 在 Spring Boot 的配置文件中添加以下配置: ```yaml mybatis-plus: global-config: # 配置多租户插件 db-config: logic-not-delete-value: 0 logic-delete-value: 1 tenant-handler: com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParserHandler tenant-line: # 多租户字段名 field: tenant_id # 多租户 SQL 表达式 expression: 'tenant_id = {0}' ``` 在以上示例中,我们配置了多租户插件,包括多租户字段名和多租户 SQL 表达式等信息。 2. 实现多租户 SQL 解析器 在使用多租户插件时,需要实现多租户 SQL 解析器,该解析器需要继承 `TenantHandler` 接口,实现其中的 `getTenantIdColumn()` 和 `getTenantId()` 方法,分别用于获取多租户字段名和多租户 ID。 ```java public class MyTenantHandler implements TenantHandler { @Override public Expression getTenantId(boolean select) { // 根据实际业务需求返回多租户 ID return new LongValue(1); } @Override public String getTenantIdColumn() { return "tenant_id"; } @Override public boolean doTableFilter(String tableName) { // 根据实际业务需求过滤表名 return false; } } ``` 在以上示例中,我们实现了 `getTenantIdColumn()` 方法获取多租户字段名,并实现了 `getTenantId()` 方法获取多租户 ID,可以根据实际业务需求返回相应的值。 3. 在 Mapper 中使用多租户插件 在 Mapper 中使用多租户插件,我们需要使用 `@SqlParser` 注解指定要进行多租户解析的 SQL 语句。 ```java public interface UserMapper extends BaseMapper<User> { // 根据 ID 查询用户 @SqlParser(filter = true) // 启用多租户插件 User selectById(Long id); } ``` 在以上示例中,我们使用 `@SqlParser(filter = true)` 注解启用了多租户插件,即在执行查询操作时,插件会自动解析 SQL 语句中的多租户条件,并进行数据隔离和访问控制。 以上就是使用 MyBatis-Plus 的多租户插件的方法。使用该插件可以方便地实现基于多租户的数据隔离和访问控制,提高系统的安全性和可维护性。 ### 4.3.6 主键自动生成策略 MyBatis-Plus 提供了多种主键自动生成策略,可以方便地实现主键自动生成,避免手动维护主键的麻烦。 以下是 MyBatis-Plus 常用的主键自动生成策略: 1. 自增 ID:使用数据库的自增功能来生成主键。需要在实体类中使用 @TableId(type = IdType.AUTO) 来指定 ID 生成类型为自增。 2. 全局唯一 ID:使用雪花算法等生成全局唯一 ID 来作为主键。需要在实体类中使用 @TableId(type = IdType.ASSIGN_ID) 来指定 ID 生成类型为全局唯一 ID。 3. UUID:使用 Java 的 UUID 来生成主键。需要在实体类中使用 @TableId(type = IdType.UUID) 来指定 ID 生成类型为 UUID。 4. ID_WORKER:使用 MyBatis-Plus 自带的 ID 生成器来生成主键。需要在实体类中使用 @TableId(type = IdType.ID_WORKER) 来指定 ID 生成类型为 ID_WORKER。 5. ID_WORKER_STR:使用 MyBatis-Plus 自带的 ID 生成器来生成字符串类型的主键。需要在实体类中使用 @TableId(type = IdType.ID_WORKER_STR) 来指定 ID 生成类型为 ID_WORKER_STR。 以上是 MyBatis-Plus 常用的主键自动生成策略,通过使用不同的主键自动生成策略可以方便地实现主键的自动生成。 ### 4.3.7 全局通用查询映射器 MyBatis-Plus 的全局通用查询映射器(GlobalConfiguration)是 MyBatis-Plus 提供的一种自定义配置方式,可以全局配置一些通用的查询条件和映射规则,方便统一管理和使用。 通过配置全局通用查询映射器,可以自动对查询条件进行解析,并根据解析结果拼接对应的 SQL 语句,从而实现一些通用的查询功能。全局通用查询映射器可以全局生效,对所有的 Mapper 接口有效。 下面是一个 MyBatis-Plus 全局通用查询映射器的示例配置: ```java @Configuration public class MybatisPlusConfig { @Bean public GlobalConfiguration globalConfiguration() { GlobalConfiguration globalConfig = new GlobalConfiguration(); // 设置查询条件拦截器 globalConfig.setSqlInjector(new BlockAttackSqlInjector()); // 设置表名下划线转驼峰命名规则 globalConfig.setDbConfig(new GlobalConfig.DbConfig().setTableUnderline(true).setColumnUnderline(true)); // 设置主键策略 globalConfig.setDbConfig(new GlobalConfig.DbConfig().setIdType(IdType.AUTO)); return globalConfig; } } ``` 上述代码中,我们通过 GlobalConfiguration 对象设置了三个通用的映射规则: 1. 设置了一个查询条件拦截器,可以在查询时对条件进行拦截和处理,避免 SQL 注入等问题。 2. 设置了一个表名下划线转驼峰命名规则,可以自动将数据库中的下划线命名方式转为驼峰命名方式,方便 Java 编码。 3. 设置了一个主键策略,可以指定生成主键的方式,例如使用数据库自增 ID、全局唯一 ID 等。 通过配置全局通用查询映射器,可以方便地实现一些通用的查询功能和规则,提高代码的复用性和可维护性。 ### 4.3.8 动态表名插件 MyBatis-Plus 的动态表名插件(DynamicTableName)是一种自定义插件,可以根据不同的条件动态改变 SQL 语句中的表名,从而实现对不同表的操作。动态表名插件可以在 MyBatis-Plus 的基础上进行扩展,支持更多的动态表名方式。 下面是一个 MyBatis-Plus 动态表名插件的示例配置: ```java @Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 添加动态表名插件 interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor(new TableNameHandler() { @Override public String dynamicTableName(String sql, String tableName) { // 根据条件动态改变表名,这里以用户 ID 为例 Long userId = UserContextHolder.getUser().getId(); if (userId != null) { return tableName + "_" + userId; } return tableName; } })); return interceptor; } } ``` 上述代码中,我们通过 MybatisPlusInterceptor 对象添加了一个动态表名插件。动态表名插件需要使用 DynamicTableNameInnerInterceptor 对象,并传入一个 TableNameHandler 对象,用于实现动态表名的逻辑。 在 TableNameHandler 接口中,我们实现了一个 dynamicTableName 方法,该方法根据不同的条件动态改变表名。在上述示例中,我们以用户 ID 为条件,如果当前用户 ID 不为空,则将表名改为原表名加上下划线和用户 ID,否则返回原表名。 通过配置动态表名插件,我们可以实现对不同表的动态操作,提高代码的灵活性和可扩展性。 ### 4.3.9 乐观锁插件 MyBatis-Plus的乐观锁插件是用来解决在高并发情况下,数据更新可能会出现的数据冲突问题。它的实现原理是在每一次更新操作时,会对原始数据进行比对,如果发现数据被其他线程修改过,则会更新失败,这时需要重新读取最新的数据,再次进行更新。MyBatis-Plus的乐观锁插件提供了两种实现方式: 1. 基于版本号的乐观锁:这种方式需要在表结构中增加一个版本号字段,每次更新时将版本号加一,更新时将版本号与原始版本号比较,如果相等则进行更新,否则更新失败。 2. 基于CAS算法的乐观锁:这种方式是通过比较更新前后的记录是否相同来判断是否被其他线程修改过。MyBatis-Plus的乐观锁插件使用了Java的Atomic包实现CAS算法,提高了乐观锁的效率。 下面是MyBatis-Plus乐观锁插件的配置方法: 1. 在实体类中定义一个版本号字段,并使用@Version注解进行标记。 2. 在MyBatis-Plus的配置文件中开启乐观锁插件。 ```yaml mybatis-plus: global-config: db-config: id-type: auto logic-delete-value: 1 logic-not-delete-value: 0 # 开启乐观锁插件 logic-delete-mapper: com.baomidou.mybatisplus.mapper.LogicSqlInjector sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector meta-object-handler: com.baomidou.mybatisplus.handler.MybatisMapWrapperFactory db-type: mysql # 开启乐观锁插件 optimistic-locking: true ``` 在以上配置中,需要注意的是: - 需要使用@Version注解标记版本号字段。 - 在MyBatis-Plus的全局配置文件中开启乐观锁插件。 - 开启乐观锁插件需要配置MyBatis-Plus的乐观锁插件类。 ### 4.3.10 自动填充插件 MyBatis-Plus 的自动填充插件可以自动为实体类中的特定字段进行赋值,例如在创建或修改操作时自动填充创建时间、修改时间等字段。这个插件的使用需要结合实体类注解和数据库表字段注解完成,下面介绍一下具体的使用步骤: 1. 引入依赖 在 pom.xml 中加入 MyBatis-Plus 的自动填充插件依赖: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-extension</artifactId> <version>${mybatis-plus.version}</version> </dependency> ``` 2. 创建实体类 在实体类中需要填充的字段上加上 `@TableField` 注解,同时在字段对应的 set 方法上添加 `@TableField(fill = FieldFill.INSERT)` 或 `@TableField(fill = FieldFill.UPDATE)` 注解,表示该字段在插入或更新时自动填充: ```java @Data public class User { @TableId(type = IdType.AUTO) private Long id; private String name; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.UPDATE) private Date updateTime; } ``` 3. 创建自动填充处理器 自动填充处理器需要实现 `MetaObjectHandler` 接口,可以在其中实现自动填充逻辑: ```java @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime", new Date(), metaObject); } } ``` 这样配置之后,在执行插入或更新操作时,就会自动填充对应的字段,大大简化了开发过程中的代码编写。 ### 4. 3.11日志信息 Mybatis-Plus 默认使用的是 Mybatis 的日志实现,可以通过 Mybatis 的配置文件进行配置。具体配置方式如下: 1. 在 application.yaml 文件中添加以下配置: ```yaml mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制台输出日志 ``` 2. 如果要使用 Log4j2 进行日志输出,则需要添加 Log4j2 的依赖,例如: ```xml <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j2.version}</version> </dependency> ``` 3. 在 application.yaml 文件中添加以下配置: ```yaml mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl # 使用 Log4j2 进行日志输出 ``` 需要注意的是,如果使用 Log4j2 进行日志输出,则需要在 Log4j2 的配置文件中添加相应的 Appender 和 Logger 配置,例如: ```xml <?xml version="1.0" encoding="UTF-8"?> <Configuration status="INFO"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="org.apache.ibatis.logging" level="WARN"/> <Root level="INFO"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration> ``` 其中,Loggers 中的 org.apache.ibatis.logging 配置是 Mybatis-Plus 的日志输出配置,Root 中的 AppenderRef 是指向 Console Appender 的引用。 ### 4.3.12 批量插入 - Mapper ```java @Mapper public interface StudentMapper extends BaseMapper<StudentRecord> { /** * 批量插入 仅适用于mysql * @param entityList 实体列表 * @return 影响行数 */ Integer insertBatchSomeColumn(Collection<StudentRecord> entityList); } ``` - 配置类 ```java @Configuration @EnableTransactionManagement //开启mybatis事物管理 public class MPConfiguration { @Bean @Primary//批量插入配置 public EasySqlInjector easySqlInjector() { return new EasySqlInjector(); } } ``` - EasySqlInjector方法 ```java public class EasySqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) { List<AbstractMethod> methodList=super.getMethodList(mapperClass, tableInfo); methodList.add(new InsertBatchSomeColumn());//添加批量插入方法 return methodList; } } ``` 注意:改批量查询只支持mysql,且在连接时,需添加批量写入参数,完整mysql连接如下 ```yaml jdbc:mysql://127.0.0.1:3306/you_mysql_datebase?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&rewriteBatchedStatements=true ``` # 5 Redis ## 5.1 Redis起步配置 Redis是一种高性能的键值存储数据库,它常用于缓存、会话管理、排行榜、消息队列等应用场景。下面我将介绍在Spring Boot项目中使用Redis的相关配置。 首先,需要在pom.xml文件中添加依赖: ```xml <!-- Redis依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- FastJson序列化依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.75</version> </dependency> ``` 接下来,在application.yaml文件中添加Redis的配置: ```yaml # Redis配置 spring: redis: host: localhost # Redis服务器地址 port: 6379 # Redis服务器端口号 database: 0 # Redis数据库编号 password: # Redis密码,若没有设置则为空 lettuce: pool: max-active: 8 # 连接池最大连接数(负数表示无限制) max-idle: 8 # 连接池中最大空闲连接数 min-idle: 0 # 连接池中最小空闲连接数 ``` 上面的配置中,我们使用了lettuce作为Redis的客户端,同时设置了连接池的相关参数。如果使用Jedis作为Redis客户端,可以将lettuce改为jedis即可。 接下来,我们可以编写一个Redis的配置类,使用FastJson作为Redis的序列化器: ```java import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import com.alibaba.fastjson.parser.ParserConfig; import org.springframework.util.Assert; import java.nio.charset.Charset; /** * Redis使用FastJson序列化 * * @author sg */ public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class<T> clazz; static { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); } public FastJsonRedisSerializer(Class<T> clazz) { super(); this.clazz = clazz; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return JSON.parseObject(str, clazz); } protected JavaType getJavaType(Class<?> clazz) { return TypeFactory.defaultInstance().constructType(clazz); } } ``` ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean @SuppressWarnings(value = { "unchecked", "rawtypes" }) public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class); // 使用StringRedisSerializer来序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(serializer); // Hash的key也采用StringRedisSerializer的序列化方式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(serializer); template.afterPropertiesSet(); return template; } } ``` 上面的配置类中,我们使用了RedisTemplate作为Redis的客户端,并且设置了FastJsonRedisSerializer作为序列化器。 ## 5.2 Redis使用案例 我们可以通过访问/set、/get、/delete接口来设置、获取、删除键值对。具体的案例代码如下: **Controller** ```java @RestController public class RedisController { @Autowired private RedisService redisService; @PostMapping("/set") public void set(@RequestParam("key") String key, @RequestParam("value") String value) { redisService.set(key, value); } @GetMapping("/get") public String get(@RequestParam("key") String key) { return redisService.get(key); } @DeleteMapping("/delete") public void delete(@RequestParam("key") String key) { redisService.delete(key); } } ``` **Service** ```java @Service public class RedisServiceImpl implements RedisService { @Autowired private StringRedisTemplate stringRedisTemplate; @Override public void set(String key, String value) { ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); ops.set(key, value); } @Override public String get(String key) { ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); return ops.get(key); } @Override public void delete(String key) { stringRedisTemplate.delete(key); } } ``` # 6.MongoDB MongoDB是一个开源的NoSQL文档数据库,支持快速的数据处理和存储,非常适合用于处理大规模的非结构化数据。 下面是使用Spring Boot集成MongoDB时需要注意的配置和相关知识点: ## 6.1 添加Maven依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> ``` ## 6.2 配置MongoDB连接信息 在application.yml文件中添加MongoDB的连接信息,例如: ```yaml spring: data: mongodb: uri: mongodb://username:password@localhost:27017/myDatabase ``` ## 6.3 MongoDB使用案例 实体类 ```java @Document(value="person") public class Person { private ObjectId id; private String name; private int age; private String address; // get和set以及构造方法省略 } ``` 完成CRUD ```java public class MongoTest { /** * 1. 注入MongoTemplate对象 * 2. 调用其他方法完成数据的CRUD */ @Autowired private MongoTemplate mongoTemplate; // 保存 @Test public void testSave() { Person person = new Person(); person.setName("李四"); person.setAge(18); person.setAddress("北京东城"); mongoTemplate.save(person); } // 查询 @Test public void testFindAll() { List<Person> persons = mongoTemplate.findAll(Person.class); for (Person person : persons) { System.out.println(person); } } // 条件查询 @Test public void testFind() { // 1. 创建Criteria对象,并设置查询条件 Criteria criteria = Criteria.where("myname").is("李四") .and("age").is(18); // is相当于sql中的= // 2. 根据Criteria对象创建Query对象 Query query = Query.query(criteria); // 3. 使用MongoTemplate进行查询 List<Person> persons = mongoTemplate.find(query, Person.class); // Query实体类对象 for (Person person : persons) { System.out.println(person); } } // 分页查询 @Test public void testFindPage() { int page = 1; int size = 2; // 1. 创建Criteria对象,并设置查询条件 Criteria criteria = Criteria.where("age").lt(50); // 2. 根据Criteria对象创建Query对象,在Query中设置分页参数 Query query = Query.query(criteria) .skip((page - 1) * size) // 从第几条开始查询 .limit(size) // 每页查询条数 .with(Sort.by(Sort.Order.desc("age"))); // 降序排序 // 3. 使用MongoTemplate进行查询 List<Person> persons = mongoTemplate.find(query, Person.class); // Query实体类对象 for (Person person : persons) { System.out.println(person); } } // 更新 @Test public void testUpdate() { // 1. 创建Criteria对象,并设置查询条件 Criteria criteria = Criteria.where("id").is("633ac0a9a4140a30e6836053"); // 2. 构建Query对象 Query query = Query.query(criteria); // 3. 设置需要更新的内容 Update update = new Update(); update.set("age", 10); update.set("myname", "赵六"); // 4. 执行操作 mongoTemplate.updateFirst(query, update, Person.class); } // 删除 @Test public void testRemove() { // 1. 创建Criteria对象,并设置查询条件 Criteria criteria = Criteria.where("id").is("633ac0a9a4140a30e6836053"); // 2. 构建Query对象 Query query = Query.query(criteria); // 2. 删除 mongoTemplate.remove(query, Person.class); } } ``` # 7.JWT ## 7.1 简介 JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据。此特性便于可伸缩性, 同时保证应用程序的安全 ## 7.2 格式 * JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C * A由JWT头部信息header加密得到 * B由JWT用到的身份验证信息json数据加密得到 * C由A和B加密得到,是校验部分 ![](https://blog.fivk.cn/usr/uploads/2023/09/1670172383.png) ## 7.3 流程 ![](https://blog.fivk.cn/usr/uploads/2023/09/2136252074.png) ## 7.4 示例 导入依赖: ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 编写测试用例: ```java @Test public void testCreateToken() { //生成token //1、准备数据 Map map = new HashMap(); map.put("id",1); map.put("mobile","13800138000"); //2、使用JWT的工具类生成token long now = System.currentTimeMillis(); String token = Jwts.builder() .signWith(SignatureAlgorithm.HS512, "itcast") //指定加密算法 .setClaims(map) //写入数据 .setExpiration(new Date(now + 30000)) //失效时间 .compact(); System.out.println(token); } //解析token /** * SignatureException : token不合法 * ExpiredJwtException:token已过期 */ @Test public void testParseToken() { String token = "eyJhbGciOiJIUzUxMiJ9.eyJtb2JpbGUiOiIxMzgwMDEzODAwMCIsImlkIjoxLCJleHAiOjE2MTgzOTcxOTV9.2lQiovogL5tJa0px4NC-DW7zwHFqZuwhnL0HPAZunieGphqnMPduMZ5TtH_mxDrgfiskyAP63d8wzfwAj-MIVw"; try { Claims claims = Jwts.parser() .setSigningKey("itcast") .parseClaimsJws(token) .getBody(); Object id = claims.get("id"); Object mobile = claims.get("mobile"); System.out.println(id + "--" + mobile); }catch (ExpiredJwtException e) { System.out.println("token已过期"); }catch (SignatureException e) { System.out.println("token不合法"); } } ``` 通过解析Token得知,如果抛出SignatureException异常表示token不合法,如果抛出ExpiredJwtException异常表示token已过期 ## 7.5 JWT工具类 ```java public class JwtUtils { // TOKEN的有效期1小时(S) private static final int TOKEN_TIME_OUT = 1 * 3600; // 加密KEY private static final String TOKEN_SECRET = "blog.fivk.cn"; // 生成Token public static String getToken(Map params){ long currentTime = System.currentTimeMillis(); return Jwts.builder() .signWith(SignatureAlgorithm.HS512, TOKEN_SECRET) //加密方式 .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳 .addClaims(params) .compact(); } /** * 获取Token中的claims信息 */ public static Claims getClaims(String token) { return Jwts.parser() .setSigningKey(TOKEN_SECRET) .parseClaimsJws(token).getBody(); } /** * 是否有效 true-有效,false-失效 */ public static boolean verifyToken(String token) { if(StringUtils.isEmpty(token)) { return false; } try { Claims claims = Jwts.parser() .setSigningKey("wufan") .parseClaimsJws(token) .getBody(); }catch (Exception e) { return false; } return true; } } ``` # 8. 数据校验validation 在 Spring Boot 开发中,**数据校验(Validation)** 是一个常见且重要的功能,能够帮助我们对输入数据进行约束检查,确保系统的安全性和数据完整性。本文将介绍如何在 Spring Boot 中快速使用 Validation,并实现一个完整的示例。 --- ## 8.1.什么是 Validation? Validation 是 Java 提供的一种标准化数据校验机制。通过使用 **Java Bean Validation API(如 Jakarta Validation 或 Hibernate Validator)**,我们可以使用注解直接声明字段的约束规则,例如: - `@NotNull`: 不允许为 `null`。 - `@Size`: 指定字符串或集合的长度范围。 - `@Min` / `@Max`: 指定数值的最小值和最大值。 - `@Pattern`: 校验字符串是否匹配特定的正则表达式。 Spring Boot 对 Validation 的集成非常友好,只需几步简单配置即可使用。 --- ## 8.2.引入 Maven 依赖 详细文档:https://springdoc.cn/spring-boot-bean-validation/ 官方文档:https://beanvalidation.org/2.0/ 在 Spring Boot 项目的 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> ``` Spring Boot 的 `spring-boot-starter-validation` 已包含 `Hibernate Validator`,它是 Jakarta Validation 的参考实现。 --- ## 8.3.创建实体类并添加校验注解 下面我们以一个用户注册接口为例,展示如何定义校验规则。 ```java import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; public class UserDTO { @NotBlank(message = "用户名不能为空") @Size(min = 3, max = 20, message = "用户名长度必须在3到20个字符之间") private String username; @NotBlank(message = "密码不能为空") @Size(min = 6, max = 50, message = "密码长度必须在6到50个字符之间") private String password; @NotNull(message = "年龄不能为空") @Size(min = 18, max = 100, message = "年龄必须在18到100之间") private Integer age; @NotBlank(message = "邮箱不能为空") @Email(message = "邮箱格式不正确") private String email; // Getters 和 Setters } ``` 在上述代码中: - `@NotBlank`: 用于校验字符串,必须非空且长度大于 0。 - `@Size`: 指定字符串长度范围。 - `@Email`: 用于校验邮箱格式。 - `@NotNull`: 确保字段不为 `null`。 --- ## 8.4.在 Controller 中使用校验 我们通过 Spring 的 `@Valid` 注解触发校验逻辑,并结合 `@RestControllerAdvice` 处理校验失败的异常。 ##### 创建 Controllerapp-translate-content #####app-translate-config-button ```java import jakarta.validation.Valid; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/users") public class UserController { @PostMapping("/register") public String register(@Valid @RequestBody UserDTO userDTO) { // 如果校验通过,处理业务逻辑 return "用户注册成功: " + userDTO.getUsername(); } } ``` ## 8.5. 处理校验异常 当目标参数未能通过验证时,Spring Boot 会抛出一个 [`MethodArgumentNotValidException`](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/MethodArgumentNotValidException.html) 异常。 ```java import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class ValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); for (FieldError error : ex.getBindingResult().getFieldErrors()) { errors.put(error.getField(), error.getDefaultMessage()); } return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); } } ``` 为了呼应我们前面设置的全局异常处理,我们可以设置为这样(前提是你已经添加了1.3的统一异常处理类)。 ```java /** * 处理参数校验异常 * @param ex 参数校验异常 * @return 响应结果 */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseResult<String> handleValidationExceptions(MethodArgumentNotValidException ex) { StringBuilder message = new StringBuilder(); for (FieldError error : ex.getBindingResult().getFieldErrors()) { message.append(error.getDefaultMessage()).append(";"); } return ResponseResult.failure(message.toString()); } ``` ## 8.6.测试接口app-translate-content **请求 Body:** ```json { "username": "us", "password": "123", "age": 17, "email": "invalid-email" } ``` **返回结果:** ```json app-translate-content jsonapp-translate-config-button{ "username": "用户名长度必须在3到20个字符之间", "password": "密码长度必须在6到50个字符之间", "age": "年龄必须在18到100之间", "email": "邮箱格式不正确" } ``` # 9.SpringBoot事务 <div class="preview"> <div class="post-inser post box-shadow-wrap-normal"> <a href="https://blog.fivk.cn/archives/6551.html" target="_blank" class="post_inser_a no-external-link no-underline-link"> <div class="inner-image bg" style="background-image: url(https://blog.fivk.cn/usr/themes/handsome/assets/img/sj/3.jpg);background-size: cover;"></div> <div class="inner-content" > <p class="inser-title">Spring Boot 中同时开启并配置 MongoDB、MySQL 和 Redis 的事务支持</p> <div class="inster-summary text-muted"> 在现代应用开发中,事务管理是保证数据一致性的重要手段。当我们同时使用多种数据库(如 MySQL、MongoDB 和... </div> </div> </a> <!-- .inner-content #####--> </div> <!-- .post-inser ####--> </div> 最后修改:2025 年 01 月 10 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏