# 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值不在保留端口范围内