# spring-boot-exp **Repository Path**: Xy_Gitee/spring-boot-exp ## Basic Information - **Project Name**: spring-boot-exp - **Description**: spring-boot集成实验 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-06-23 - **Last Updated**: 2025-12-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Spring Boot Experiment ## List - Spring MVC - Mybatis-Plus - Redis - Elasticsearch - Quartz - xxl-job - RocketMQ 或 Kafka - Activiti 流程引擎 - Tika 文件内容提取 - EasyExcel ## Spring Boot - [x] 统一接口返回数据结构 - [x] 全局异常处理 - [x] logback slf4j - [x] 自定义配置 - [ ] 配置加密(mysql、redis等密码加密) - [x] 拦截器 - [x] 接口认证、RequestId、接口日志、 - [x] 过滤器 - [x] MapStruct - [x] 热部署 热加HotSwap - [ ] 单元测试 - [ ] 国际化 - [ ] XSS注入、SQL注入 - [ ] 监听器 - [x] mybatis plus - [x] redis - [ ] elasticsearch - [ ] 条件注入 - [ ] AOP - [ ] EasyExcel - [ ] FastJson - [ ] protobuf - [ ] Spring boot stater HandlerInterceptor ## slf4j log4j logback log4j2 > - [log框架介绍](https://pdai.tech/md/develop/package/dev-package-x-log.html#common-logging-vs-slf4j) > - [Slf4j+Logback入门实践](https://juejin.cn/post/7317169269430239284?searchId=202406241951131151E2667360DD5336D9) > - [Logback配置详解](https://blog.csdn.net/wo541075754/article/details/109193354) - 日志门面slf4j, 日志实现:log4j、logback、log4j2 **[优选slf4j+logback 或 slf4j+log4j2]** 1. slf4j + log4j: slf4j-log4j12-1.7.21.jar -> slf4j-api-1.7.21.jar 和 log4j-1.2.17.jar 2. slf4j + logback: logback-classic-1.0.13.jar -> slf4j-api-1.7.21.jar 和 logback-core-1.0.13.jar 3. slf4j + log4j2: [log4j2 绑定 SLF4J](https://logging.apache.org/log4j/2.x/log4j-slf4j-impl.html) - log4j-slf4j2-impl:SLF4J 1.7.x版本及以下 - log4j-slf4j-impl:SLF4J 2.0.x版本及以上 ## 入参校验 1. 引入依赖 ```xml org.springframework.boot spring-boot-starter-validation ``` 2. 入参变量校验注解 - @NotBlank - @NotNull - @Max - @Min ```java @Data public class UserVo { private int id; @NotNull(message="用户名不能为空") private String name; @Min(value = 0, message = "年龄不能小于0") @Max(value = 100, message = "年龄不能大于100") private int age; @NotNull(message="账号不能为空") private String account; @NotNull(message="email不能为空") private String email; @NotNull(message="密码不能为空") private String password; } ``` 3. @Valid ```java @RequestMapping("/save/user") @ResponseBody public BaseResponse saveUser(@Valid UserVo u) { } ``` ## 全局异常捕获 - @RestControllerAdvice - @ExceptionHandler(ExpBizException.class) ```java /** * 全局异常捕获 * @author yyh */ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ExpBizException.class) public BaseResponse handleExpBizException(ExpBizException e) { log.error("ExpBizException:{}", e.getMessage()); return new BaseResponse(e.getCode(), e.getSubCode(), e.getMessage()); } } ``` ## 拦截器 1. 自定义拦截器,实现HandlerInterceptor接口 ```java @Component @Slf4j public class ExpHandlerInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } } ``` 2. 自定配置类,实现WebMvcConfigurer接口,注册自定义拦截器 ```java @Configuration public class ExpMvcConfig implements WebMvcConfigurer { @Resource private ExpHandlerInterceptor expHandlerInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(expHandlerInterceptor) .addPathPatterns("/**") .excludePathPatterns("/static/**"); } } ``` ## 过滤器 1. 启动类添加注解 **@ServletComponentScan** 2. 自定义过滤器实现 javax.servlet.Filter接口 3. 自定义过滤器,添加注解 @WebFilter(filterName = "expFilter", urlPatterns = "/*") 4. 当存在多个过滤器时,需要配置过滤器执行顺序,使用注解@Order(1) ***[Lower values have higher priority.]*** ```java @WebFilter(urlPatterns = "/*") @Slf4j public class ExpFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("ExpFilter"); filterChain.doFilter(servletRequest,servletResponse); } } ``` ## 自定义配置 1. resources目录下创建exp.properties文件, 添加配置值:exp.name=exp ```properties exp.name=xxx ``` 2. 自定义配置类ExpProperties,存储自定义配置值,如下,将配置exp.properties文件中的exp.name配置值存储到ExpProperties的name属性 - @PropertySource(value = {"classpath:exp.properties"}) 指定配置文件路径 配置文件近支持properties或xml格式 - @ConfigurationProperties(prefix = "exp") 指定配置前缀 ```java @Data @ToString @Component @PropertySource(value = {"classpath:exp.properties"}) @ConfigurationProperties(prefix = "exp") public class ExpProperties { String name; } ``` 3. @EnableConfigurationProperties(ExpProperties.class)激活配置类 ```java @Configuration @EnableConfigurationProperties(ExpProperties.class) public class ExpConfig { } ``` ## 配置环境变量 1. pom.xml 增加 profiles 和resources ```xml local local dev dev src/main/resources true ``` 2. application.yml 引用pom.xml中启用的profile.active变量,logging.config配置logback-@profile.active@.xml配置文件 ```yaml spring: profiles: active: @profile.active@ logging: config: classpath:log/logback-@profile.active@.xml ``` 3. 创建application-@profile.active@.yml 配置文件,其中配置生效 - application-dev.yml - application-local.yml 4. resouces/log目录下,创建logback-@profile.active@.xml配置文件 - logback-dev.xml - logback-local.xml ## 配置自定义加解密 ## Mybatis Plus > - [Mybatis](https://mybatis.org/mybatis-3/zh_CN/index.html) > - [Mybatis Plus](https://baomidou.com/getting-started/) 1. 引入mybatis-plus-boot-starters依赖 ```xml com.baomidou mybatis-plus-boot-starter ${mybatis-plus.version} ``` 2. 引入mysql连接依赖 ```xml mysql mysql-connector-java ${mysql.version} ``` 3. 配置数据库连接和数据库连接池hikari(spring boot默认连接池) ```yaml spring: datasource: url: jdbc:mysql://localhost:3307/exp?useSSL=false&autoReconnect=true&characterEncoding=utf8&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driver username: root password: EsafeNet. # 指定为HikariDataSource type: com.zaxxer.hikari.HikariDataSource # hikari连接池配置 hikari: #连接池名 pool-name: HikariCP #最小空闲连接数 minimum-idle: 5 # 空闲连接存活最大时间,默认10分钟 idle-timeout: 600000 # 连接池最大连接数,默认是10 maximum-pool-size: 10 # 此属性控制从池返回的连接的默认自动提交行为,默认值:true auto-commit: true # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 max-lifetime: 1800000 # 数据库连接超时时间,默认30秒 connection-timeout: 30000 # 连接测试query connection-test-query: SELECT 1 sql: init: schema-locations: classpath:database/exp-table.sql data-locations: classpath:database/exp-init-data.sql ``` 4. 根据数据库表结构,创建实体类,使用注解@TableName("user")指定表明,@TableId("id")指定主键字段,@TableField("account")指定字段 ```java @Data @ToString @TableName("user") public class User implements java.io.Serializable{ @TableId("id") private int id; @TableField("account") private String account; private String name; private int age; private String email; private String password; } ``` 5. 定义实体类操作接口Mapper,继承BaseMapper<实体类> ```java @Mapper public interface UserMapper extends BaseMapper { } ``` 6. 启动类添加注解@MapperScan("com.example.mapper"),扫描Mapper接口 - 注意问题:Mapper接口不能放在@MapperScan扫描包下,否则会报错:No qualifying bean of type 'com.example.mapper.UserMapper' available ### Hikari连接池 - https://github.com/brettwooldridge/HikariCP/wiki todo: - [ ] Hikari连接池 JMX监控 ## MapStruct > - [MapStruct Spring](https://mapstruct.org/news/2024-01-04-mapstruct-spring-extensions-1-1-1-released/) > - [MapStruct](https://mapstruct.org/) 1. 引入依赖mapstruct ```xml org.mapstruct mapstruct ${mapstruct.version} provided ``` 2. 常用操作 ## 国际化 ## Redis > - [Spring Data Redis 中文](https://springdoc.cn/spring-data-redis/) > - [Spring Data Redis](https://docs.spring.io/spring-data/redis/docs/3.1.12/reference/html/#pubsub) ### redis客户端选择 #### Lettuce ```xml ``` #### Jedis ```xml ``` ### redis连接 #### redis连接 ```yaml ``` #### sentinel连接 ```yaml ``` #### redis cluster 连接 ```yaml ``` ### 配置连接池 #### Lettuce 连接池 ```yaml ``` #### Jedis 连接池 ```yaml ``` ### RedisTemplate #### String #### List #### Set #### ZSet #### Hash #### 事务 #### Pub/Sub ##### 发布消息 ##### 订阅消息 #### 集群 #### sentinel #### db #### 脚本 ### 缓存注解 #### @Cacheable ### CachingConfigurerSupport ### 序列化 #### Java序列化 #### json序列化 ### Redis Repository ## Elasticsearch ## Quartz ## Activti流程引擎 ## Tika ## 安全 ### 限流 ### 接口幂等 ### XSS漏洞 ### sql注入漏洞 ## 问题记录 1. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.ihang.exp.xxx.service.ExpUserService.saveUser - 问题原因:mybaitis @MapperScan注解扫描到使用MapStruct注解@Mapper的类型 - 解决方案:限定@MapperScan("com.ihang.exp.*.mapper")扫描范围,避免扫描到使用MapStruct注解@Mapper的类型 2. @WebFilter(urlPatterns = "/*")自定义过滤器失效 - 解决方案:启动类增加注解@ServletComponentScan 3. MapStruct @Mapper(componentModel = "spring") 注入ioc失败 - 解决方案: 4. MapStruct 部分字段映射转换错误 - 解决方案: mvn clean 5. AVA.SQL.SQLNONTRANSIENTCONNECTIONEXCEPTION: COULD NOT CREATE CONNECTION TO DATABASE SERVER. ATTEMPTED RECONNECT 3 TIMES. GIVING UP. - 问题原因:mysql时区错误 - 解决方案:mysql连接设置时区serverTimezone=GMT与mysql时区一致 6. application.yml或application.properties,引用pom.xml变量 - pom.xml 增加resource ```xml src/main/resources true ``` - application.yml @变量名@ - application.properties ${变量名} 7. Web server failed to start. Port 8080 was already in use. - [IDEA 端口占用,启动失败,提示Web server failed to start. Port 8080 was already in use.](https://www.cnblogs.com/mayhot/p/15156426.html) 1. 查看端口是否占用,若存在占用,则关闭进程 ```shell netstat -ano | findstr 8080 ``` 2. 若查找不到占用端口进程,则查看是否为系统保留端口 ```shell netsh interface ipv4 show excludedportrange protocol=tcp ``` 3. 修改server.port值不在保留端口范围内