优雅的实现前端回显字典枚举值

引言

Hello 大家好,这里是Anyin。

在我们日常的开发工作当中,肯定会遇到类似状态、类型等字段需要以中文的形式返回给前端。例如,在数据库中性别是存储man、woman,而在前端界面显示要求是显示成男、女。

在实现以上需求会有以下几种方式

1.业务代码或者get方法中转义,即在业务代码通过判断然后转换成对应的中文或者在返回的实体类中get方法中判断返回对应的中文

2.所有的字典值入库,通过数据库left join 实现中文意思查询,返回的时候添加一个中文的字段

3.在spring mvc 返回的时候通过序列化转换,但是需要在返回的实体类添加对应的注解元数据信息

4.前端拉取所有的字典类型和对应的值,在页面渲染的时候自行处理,会在前端缓存暴露所有的字典数据

在以上4个方法中,第3种方式会比较合适,因为它会统一处理所有的字典值,并且屏蔽对业务代码的影响,同时在安全性也有一定的保证。

思路

在实现代码之前,我们梳理下思路。

1.在spring mvc 把实体类序列化的时候我们进行一顿操作

2.以对象的形式返回对应的字典信息,并且字段名不变,例如:status字段,实体类是一个String类型,返回前端的时候变为一个对象: status : { code: "enable", text: "启用" }

3.通过自定义注解来指定是某个类型的字典值

4.通过@JsonSerialize注解指定自定义序列化器

实现

根据以上思路,我们可以在@JsonSerialize 注解上看到一个using的属性,它指定了一个Class<? extends JsonSerializer的类型。

优雅的实现前端回显字典枚举值

所以,我们可以自己定义一个序列化器继承JsonSerializer类。

@Slf4j
public class StringAsDictSerializer extends JsonSerializer{


    public StringAsDictSerializer(){}


    @SneakyThrows
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
    }
}

serialize方法的value参数,就是我们需要转为字典对象的code值。但是我们还缺少一样信息,这个code值是属于那个类型的字典,是属于sex还是status类型的字典?

所以,这个类还要实现ContextualSerializer接口,从BeanProperty属性中获取对应的注解。

完整的StringAsDictSerializer类的代码如下:

@Slf4j
public class StringAsDictSerializer extends JsonSerializer implements ContextualSerializer {
    // 当前字段的字典自定义注解
    private DictAnnotation annotation;


    public StringAsDictSerializer(DictAnnotation annotation) {
        this.annotation = annotation;
    }


    public StringAsDictSerializer(){}


    @SneakyThrows
    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if(annotation == null){
            log.error("dict annotation not found");
            return;
        }
        Class<? extends Enum> typeClazz = annotation.type();
        // 转为基础枚举类
        BaseEnum type = Arrays.stream(typeClazz.getEnumConstants()).map(t -> (BaseEnum) t)
                .filter(t -> Objects.equals(t.getCode(), value))
                .findAny().orElse(null);
        if(type == null){
            log.error("annotation type not found");
            return;
        }
        // 转为对象然后返回
        Dict dict = new Dict();
        dict.setCode(type.getCode());
        dict.setText(type.getText());
        gen.writeObject(dict);
    }


    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        // 获取当前字段的注解信息
        DictAnnotation annotation = Optional.ofNullable(property).map(item -> item.getAnnotation(DictAnnotation.class)).orElse(null);
        return new StringAsDictSerializer(annotation);
    }
}

接着再新增一个自定义注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DictAnnotation {
    Class<? extends Enum> type();
}

这个自定义注解的type字段即表示字典的类型,一般情况下数据库的字典字段在代码都会有一个对应的枚举类。

最后我们定义下需要返回给前端的字典对象

@Data
public class Dict {
    private String code;
    private String text;
}

测试

接下来,我们来测试下我们的代码。在controller返回的实体类中,我们添加上对应的注解配置,如下:

@Data
public static class TestDTO{
    @JsonSerialize(using = StringAsDictSerializer.class)
    @DictAnnotation(type = SexEnum.class)
    private String sex;


    @JsonSerialize(using = StringAsDictSerializer.class)
    @DictAnnotation(type = StatusEnum.class)
    private String status;
}

使用postman返回结果:

优雅的实现前端回显字典枚举值

最后

以上,我们实现了字典枚举值的前端字典回显,你学废了吗?

相关源码地址Anyin Cloud[1]

References

[1] Anyin Cloud: https://gitee.com/anyin/anyin-cloud

展开阅读全文

页面更新:2024-05-01

标签:字典   注解   字段   中文   思路   优雅   对象   类型   代码   数据库   业务

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top