逻辑删除

使用 mybatis-plus-global-logic-field 来实现逻辑删除功能。

前后端通信时忽略的字段

通过 @JsonIgnore 注解来指定前后端通信时需要忽略的字段。

自动填充机制

  1. 字段填充设置
    利用 @TableField(fill=FieldFill.Update) 来标注需要自动填充的字段,指明填充时机(此处为更新时)。
  2. 填充值规则设置
    实现 MetaObjectHandler 接口,并重写 insertFill()updateFill() 两个方法,以此来定义具体的填充值规则。

枚举类型和数字之间的对应关系设置

  1. 默认情况
    枚举 ItemType 有两个常量值:APARTMENT(1,"公寓")ROOM(2,"房间")。在Java端,若有 ItemTypeAPARTMENT,往数据库中保存时,默认是将它的字符串形式 "APARTMENT" 保存到对应的列中。但数据库中该列对应的类型是 tinyint,我们希望将 1(也就是 ItemType 这个枚举中的 code 属性值)保存到这一列中,所以需要使用 @EnumValuecode 属性上标注。
  2. 前端到后端请求体转换
    在前端,用户选择 "公寓""房间" 时,向后端发送的是 "1" 或者 "2"。而后端的 entity 中的属性类型不是 int,而是 ItemType。因此,需要将前端发送过来的 "1" 或者 "2" 转化成 ItemType 这个类型,此时需要说明请求体中的 "1" 或者 "2" 到底和 ItemType 中的哪个属性对应,请求体中的 1ItemType 中的 code 属性对应,需要使用 @JsonValue
  3. 后端到前端响应体转换
    服务器端从数据库中查询出了 "1",服务器端实体中的属性类型是 ItemType,这个 1 依据 @EnumValueItemType 中的属性赋值,然后服务器端查询到的数据需要通过响应体响应给前端,ItemType 这个枚举如果直接响应给前端,则是 "APARTMENT",但我们需要将 1 或者 2 响应给前端,因此,需要使用 @JsonValuecode 属性上标注。
  4. 请求参数相关情况及解决方法
    如果不是请求体,而是请求参数中包含 1 或者 2springmvc 有一个组件 WebDataBinder,它其中一个作用是参数绑定。

    • WebDataBinder默认处理情况

    WebDataBinder 默认情况下直接处理 String 类型的参数,获取前端的数据一定是字符串类型,例如 "1" ,如果Java端对应的属性是 String 类型,则直接赋值;如果类型不一致,例如获取到参数 "1" ,Java端对应的是 IntegerspringMVC 内置了常规类型的数据类型转换器(Converter),可以将 String 转换成 Integer。在常规转换规则下,字符串和枚举也可以自动转换(如 1 -> 某一个枚举值),不过实际情况是 "APARTMENT"ItemType 这个枚举之间自动对应,而不是 "1" 对应,所以需要自己去实现字符串和枚举之间的转换关系。

    • 解决方法一(针对单个枚举类)

    自定义类实现 Converter,重写其中的 convert 方法,示例代码如下:

    public class StringToItemTypeConverter implements Converter<String, ItemType> {
     @Override
     public ItemType convert(String source) {
         return Arrays.stream(ItemType.values())
                .filter(itemType -> source.equals(itemType.getCode()))
                .findFirst().orElseThrow(RuntimeException::new);
     }
    }

    然后通过 WebMvcConfigurer 注册这个转换器,示例代码如下:

    public class WebMvcConfiguration implements WebMvcConfigurer {
     public void addFormatter(registry){
         registry.addConverter(stringToItemTypeConverter);
     }
    }

    按照这种解决方式,当前项目中存在很多的枚举类(如 ItemTypeAppointmentStatusReleaseStatus 等),每个枚举类都要对应一个 Converter,然后分别去注册它们。

    • 解决方法二(通用方案)

    使用 ConverterFactory,示例代码如下:

    public class StringToBaseEnumConverterFactory implements ConverterFactory<String, BaseEnum> {
     public <T extends BaseEnum> Converter<String, T> getConverter(Class<T> targetType) {
         return new Converter<String, T>() {
             @Override
             public T convert(String source) {
                 return Arrays.stream(targetType.getEnumConstants()).filter(t -> source.equals(t.getCode()+""))
                        .findFirst().orElseThrow(RuntimeException::new);
             }
         };
     }
    }