知识点一:逻辑删除
数据库添加字段 ,
实体类添加属性 ,
配置逻辑删除生效
知识点二:@JsonIgnore
: 忽略实体类的某个属性不转成也不接收JSON数据
@JsonIgnore
@TableLogic
@Schema(description = “逻辑删除”)
@TableField(“is_deleted”)
private Byte isDeleted;
知识点三:自动填充
- 指定填充字段和策略
属性上-> @TableFiled(fill = FieldFill.Insert | Update )
- 定义填充值实现类 MetaObjectHandler(common模块下 / mybatis-plus…)
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, “属性名”, 属性类型.class, 填充的值);
}
1
2
3
4
5
|
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充...");
this.strictUpdateFill(metaObject, "属性名", 属性类型.class, 填充的值);
}
|
}
知识点四:自定义转化器
基础转化器:
1.1 定义个转化器类 实现 Converter<String,目标类型>接口
1.2 重写转化方法 目标类型 converter方法(String 原数据值)
1.3 方法中实现类型转化 if || 枚举.values() + for || 超出值范围抛异常
1.4 springmvc的配置类中添加自定义转化器 addFormatter()
转化器工厂:
1.1 定义工厂类 实现 ConverterFactory<String,枚举的接口>
1.2 重写创建转化器的方法getConverter
1.3 getConverter方法new Converter对象完成转化逻辑编写(class)
class.getEnumContents() == 枚举类型.values()
1.4 注册转化器工厂
registry.addConverterFactory(stringToBaseEnumConverterFactory);
2. json类型的转化器jackson
@JsonValue即可完成json和枚举值的处理
3. 数据库存储和获取转化器mybatis(typeHandler)
https://www.baomidou.com/guides/auto-convert-enum/ @EnumValue //mybatis-plus 向数据库存储数据的时候,获取code属性进行存储 || 读取数据库数据的时候,将值赋值给code
转换器工厂:实现implements ConverterFactory<String, BaseEnum>接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Component
public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
@Override
public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
return new Converter<String, T>() {
@Override
public T convert(String source) {
for (T enumConstant : targetType.getEnumConstants()) {
if (enumConstant.getCode() == Integer.parseInt(source)) {
return enumConstant;
}
}
throw new RuntimeException("类型错误");
}
};
}
}
|
知识点五:多表查询注意点:
- 多表查询,需要自定义查询 方法和结果集映射(外连接 | resultMap)
- 自定义查询需要处理逻辑删除条件问题 is_deleted = 0
- 外连接条件 where和on条件的区别
一旦使用外连接, where后面不能放子表的查询条件。
情况: 主表有数据 子表没数据 条件都不为nul都出现问题
- 解决: on后面可以添加子表的条件,on在合并之前进行赛选。 on后面的条件不会破坏外连接的特性, 一定保证主表的数据会被查询到。
知识点六:
知识点七:全局异常处理
①在common模块写一个类 加注解@RestControllerAdvice
②在这个类的方法上面加注解 @ExceptionHandler
1
2
3
4
5
6
|
全局异常处理实现(common | springmvc)
common中导入web-starter (springmvc jackson)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
|
知识点八:文件上传-minio
- 注意事项:
文件上传默认的大小是1MB
修改文件:
spring:
servlet:
multipart:
max-file-size: 20MB #单个文件大小
max-request-size: 60MB # 一次请求的大小
①@ConfigurationProperties(prefix=“minio”)
必须加入到ioc容器
方式一 :@Component
方式二:EnableConfigurationProperties(xxx.class)
1
2
3
4
5
6
7
8
9
|
@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {
//@Value("${minio.endpoint}") 单独读取
private String endpoint;
private String accessKey;
private String secretKey;
private String bucketName;
}
|
②web / web-admin /application配置文件声明参数
声明四个参数
1
2
3
4
5
|
minio:
endpoint: \http://47.94.86.115:9000 #注意: 不要加 /
secret-key: minioadmin
access-key: minioadmin
bucket-name: lease0923
|
③编写minioClient的配置类 (MinioClient加入ioc容器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@EnableConfigurationProperties(MinioProperties.class)
@Configuration
public class MinioConfiguration {
@Autowired
private MinioProperties minioProperties;
@Bean
public MinioClient minioClient(){
MinioClient minioClient = MinioClient.builder().endpoint(minioProperties.getEndpoint()).
credentials(minioProperties.getAccessKey(), minioProperties.getSecretKey()).build();
return minioClient;
}
}
|
④编写文件上传的具体业务 FileController | FileService…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
String url = fileService.uploadFile(file);
return Result.ok(url);
@Override
public String uploadFile(MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
//步骤1: 判断桶是否存在
boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minioProperties.getBucketName()).build());
//步骤2: 不存在,创建桶以及设置访问权限
if (!bucketExists) {
//创建桶
minioClient.makeBucket(MakeBucketArgs.builder().bucket(minioProperties.getBucketName()).build());
//设置权限
//设置hello-minio桶的访问权限
String policy = """
{
"Statement" : [ {
"Action" : "s3:GetObject",
"Effect" : "Allow",
"Principal" : "*",
"Resource" : "arn:aws:s3:::%s/*"
} ],
"Version" : "2012-10-17"
}""".formatted(minioProperties.getBucketName());
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().
bucket(minioProperties.getBucketName())
.config(policy).build());
}
//步骤3: 向桶中传递文件
//todo: 文件重名的问题 uuid + file.getOriginalFilename()
//todo: 文件直接放在桶中太乱的问题
// 20241210/uuid_对象名.png
String objectName = new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + UUID.randomUUID().toString().replaceAll("-","") + "_" + file.getOriginalFilename();
//minioClient.uploadObject() 传递本地存在的文件 c d f ... filename = 文件的地址
//minioClient.putObject() 传递内存中存在文件数据 流 | 字节数组
minioClient.putObject(PutObjectArgs.builder()
.bucket(minioProperties.getBucketName())
.object(objectName)
.stream(file.getInputStream(),file.getSize(),-1) //-1 不切割原有文件大小
.contentType(file.getContentType())
.build());
return String.join("/",minioProperties.getEndpoint(),minioProperties.getBucketName(),objectName);
}
|
知识点九:mybatis-plus分页插件
1
2
3
4
5
6
|
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
|
知识点十:controller中方法的参数有多个(Integer current,Integer size,QueryVO queryVO),有实体类,knife4j解析参数时,会误解析成json,这时候要在application.yml里面添加配置:springdoc.default-flat-param-object: true
知识点十一:异常处理流派
抛异常:1.快速终止调用
2.快速的捕捉结果,避免多层返回
核心:
1.springmvc全局异常处理
2.自定义异常

知识点十二:mybatis-plus字段更新策略
Mybatis-Plus update strategy
使用Mybatis-Plus提供的更新方法时,若实体中的字段为null
,默认情况下,最终生成的update语句中,不会包含该字段。若想改变默认行为,可做以下配置。
-
全局配置
在application.yml
中配置如下参数
mybatis-plus:
global-config:
db-config:
update-strategy: <\strategy>
注:上述<strategy>
可选值有:ignore
、not_null
、not_empty
、never
,默认值为not_null
ignore
:忽略空值判断,不管字段是否为空,都会进行更新
not_null
:进行非空判断,字段非空才会进行判断
not_empty
:进行非空判断,并进行非空串("")判断,主要针对字符串类型
never
:从不进行更新,不管该字段为何值,都不更新
-
局部配置
在实体类中的具体字段通过@TableField
注解进行配置,如下:
1
2
3
|
@Schema(description = "密码")
@TableField(value = "password", updateStrategy = FieldStrategy.NOT_EMPTY)
private String password;
|
知识点十三:mybatis-plus映射
full
auto-mapping-behavior: full
- 列名不能重复
- 设置嵌套模式为full,不用全部编写result标签
- 自定义查询语句都需要思考逻辑删除问题
知识点十四:表查询的on和where
on是在两张表left join之前过滤一遍子表
where是在两张表left join 之后对整张表进行过滤
知识点十五:定时任务
周期性的工作和安排。
springboot自带定时任务。
步骤一:开启定时任务–@Scheduling【启动类】
步骤二:定义一个方法,编写定时任务逻辑
步骤三:设置方法的执行周期(cron表达式) @Scheduled(crons = “* * * * * *”)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
@Component
public class MyTask {
@Autowired
private LeaseAgreementService leaseAgreementService;
//定期检查租约状态
@Scheduled(cron = "0 0 1 * * *")
public void leaseAgreementCheckStatus() {
LambdaUpdateWrapper<LeaseAgreement> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.lt(LeaseAgreement::getLeaseEndDate,new Date());
updateWrapper.in(LeaseAgreement::getStatus, LeaseStatus.SIGNED,LeaseStatus.WITHDRAWING,LeaseStatus.RENEWING);
updateWrapper.set(LeaseAgreement::getStatus,LeaseStatus.EXPIRED);
leaseAgreementService.update(updateWrapper);
}
}
|
知识点十六:jackson注解
- @JsonIgnore–>某个属性要忽略不生成json。
- @JsonFormat–>时间格式和时区设置。【也可以在yml文件全局配置:spring,jackson.date-format】
- @JsonProperty–>后台实体类的名称和接口文档不一致时候。
修改属性生成json的key:
User id name
name—>@JsonProperty(“username”)
{id:1,username:‘xxx’}
知识点十七:base64
base64是一种转码和解码的工具,可以将任何内容转成字符串。
如:<\img src=“base64字符串”> 前端自动解码
知识点十八:登录流程
1.获取验证码 —-> 后台请求
1、生成验证码图片和正确的验证码
2、生成uuid
3、uuid + 验证码 + 有效时间 –> 存储到redis
4、将图片和key(uuid)返回给前端
2.登录实现
前端–>账号 密码 输入的验证码 uuid
后台–>
1.校验验证码
2.校验账号
3.校验密码(加密)
4.校验用户是否可用
5.生成token
6.返回token
3.获取用户信息
前端 -> token ->后台 -> 解析token -> 用户 ->查询用户数据 -> 返回
知识点十九:拦截器
1.定义拦截器 ———–>实现HandlerInterceptor接口,重写方法
2.编写拦截逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1.获取request中请求头的token [access_token]
String accessToken = request.getHeader("access_token");
//2.检查token是否为null
if (ObjectUtils.isEmpty(accessToken)){
//没有token 没有登录
throw new LeaseException(ResultCodeEnum.ADMIN_LOGIN_AUTH);
}
//3.检查token是否过期和有效
//内部自动抛异常
JwtUtil.parseToken(accessToken);
//true放行 | false拦截 [if(! preHandler()) return ;]
return true;
}
}
|
3.注册拦截器 ————>配置类 实现WebMvcConfigure,addInterceptor
4.设置拦截器,以及指定拦截和放行地址(mvc)
1
2
3
4
5
6
|
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
//匿名资源: 登录 获取验证码
.addPathPatterns("/admin/**").excludePathPatterns("/admin/login/**");
}
|
知识点二十:application.yml配置文件可以提取
配置文件,提取出来到其他模块
知识点二十一:排除
自动化加载排除:
@SpringbootApplication(exclude={MinioConfiguration.class})
componentScan扫描排除:
@ComponentScan(excludeFilters = @ComponentScan.Filter(…….))
知识点二十二:项目部署-虚拟机
