xm-知识点

知识点一:逻辑删除

数据库添加字段 , 实体类添加属性 , 配置逻辑删除生效

知识点二:@JsonIgnore

: 忽略实体类的某个属性不转成也不接收JSON数据

@JsonIgnore
@TableLogic
@Schema(description = “逻辑删除”)
@TableField(“is_deleted”)
private Byte isDeleted;

知识点三:自动填充

  1. 指定填充字段和策略 属性上-> @TableFiled(fill = FieldFill.Insert | Update )
  2. 定义填充值实现类 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.自定义异常 |475

知识点十二:mybatis-plus字段更新策略

Mybatis-Plus update strategy 使用Mybatis-Plus提供的更新方法时,若实体中的字段为null,默认情况下,最终生成的update语句中,不会包含该字段。若想改变默认行为,可做以下配置。

  • 全局配置 在application.yml中配置如下参数 mybatis-plus:
    global-config:
      db-config:
        update-strategy: <\strategy>

    :上述<strategy>可选值有:ignorenot_nullnot_emptynever,默认值为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(…….))

知识点二十二:项目部署-虚拟机

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计