Spring Boot2.0之十 使用自定义注解、Json序列化器实现自动转换字典类型字段

前言

项目中经常需要后端将字典类型字段值的中文名称返回给前端。通过sql中关联字典表或者自定义函数不仅影响性能还不能使用mybatisplus自带的查询方法,所以推荐使用自定义注解、Json序列化器,Spring的缓存功能实现自动转换字典类型字段。以下实现SpringBoot版本为2.6.13。

一、自定义字典注解

复制代码
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.common.utils.DictSerializer;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
 /**
 定义一个自定义注解,用于标识需要进行字典自动翻译的字段。
 **/
@Target({ElementType.FIELD}) //表示它只能应用在类的字段上。
@Retention(RetentionPolicy.RUNTIME) //确保注解在运行时可用。
@JacksonAnnotationsInside 
@JsonSerialize(using = DictSerializer.class)//指定使用DictSerializer来处理被注解字段的序列化,不加@Dict注解的字段不会被DictSerializer处理。
public @interface Dict {
 
    /**
	 * 字典代码
	 */
	String type() default "";

	/**
	 * 字段后缀
	 */
	String suffix() default "Name";
}

二、自定义Json序列化器

复制代码
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lombok.SneakyThrows;
import java.io.IOException;
import java.util.Objects;
 /**
 @Dict注解中引入了JsonSerializer,加了@Dict注解的字段的序列化会被DictSerializer处理。不能在DictSerializer 类上加@JsonComponent注解或者自定义配置类 JacksonConfig来注册Json序列化器,使用注解或配置类注册序列化器会使其全局生效,任何字段的序列化会被DictSerializer处理。
 **/
public class DictSerializer extends JsonSerializer<Object> {

    @SneakyThrows
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
        // 写入原字段的值
        gen.writeObject(value);
        if (Objects.nonNull(value)) {
            // 获取数据字典项服务实例
            // 不使用全局变量和在构造函数中获取Bean,延迟加载Bean,避免构造函数初始化空指针问题
            DictService dictService = SpringContextHolder.getBean(SysDictItemService.class);
            // 序列化字段名称
            String fieldName = gen.getOutputContext().getCurrentName();
            // 字典项注解对象
            Dict dictAnno = gen.getCurrentValue().getClass()
                    .getDeclaredField(fieldName)
                    .getAnnotation(Dict.class);
            String dictItemName = dictService.getDictItemName(dictAnno.type(), value);
            // 写入新字段名称
            gen.writeFieldName(fieldName + dictAnno.suffix());
            // 写入新字段的值
            gen.writeString(dictItemName);
        }
    }
}

三、Spring上下文工具类

复制代码
@Component
public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    public static <T> T getBean(Class<T> clazz) {
        return context.getBean(clazz);
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) {
        context = ctx;
    }
}

三、字典服务层(含缓存)

1.SpringBoot启动类上加@EnableCaching注解开启缓存功能

2.根据字典代码和字典项代码查询字典项名称

复制代码
	/**
     * @Cacheable为SpringBoot自带的缓存注解,使用字典代码+字典项代码作为缓存的key,使用该注解会自动		   
     * 缓存getDictItemName方法的返回值。
     */
    @Cacheable(value = "dictCache", key = "#dictCode+':'+#code")
    @Override
    public String getDictItemName(String dictCode, Object code) {
        List<SysDictItem> itemList = ......;
        String value = null;
        if(CollectionUtils.isNotEmpty(itemList)){
            value = itemList.get(0).getItemName();
        }
        return Optional.ofNullable(value).orElse(code.toString());
    }

3.新增或修改字典项

复制代码
 	 /**
     * @CachePut注解是SpringBoot自带的缓存注解,使用该注解在更新字典时会自动更新字典缓存,注意此处	
     * 的key要与getDictItemName方法@Cacheable注解中的key一致,saveOrUpdateDictItem方法必须要返回要
     * 缓存的内容,即字典项名称。
     */
    @CachePut(value = "dictCache", key = "#dictItem.dictCode+':'+#dictItem.itemCode")
    @Override
    public String saveOrUpdateDictItem(SysDictItem dictItem) {
        String itemName = null;
        int con;
        if(StringUtils.isBlank(dictItem.getItemId())){
            //新增
            con = baseMapper.insert(dictItem);
        } else {
            //修改
            con = baseMapper.updateById(dictItem);
        }
        if(con > 0){
            itemName = dictItem.getItemName();
        }
        return itemName;
    }

参考资料:

1.百度DeepSeek-R1满血版搜索结果

2.csdn收藏(Springboot)中的https://blog.csdn.net/hangbingbihai/article/details/145452376?spm=1001.2014.3001.5506

https://blog.csdn.net/demo_yo/article/details/129157902?spm=1001.2014.3001.5506

相关推荐
程序员小假7 分钟前
我们来说一下无锁队列 Disruptor 的原理
java·后端
ProgramHan25 分钟前
Spring Boot 3.2 新特性:虚拟线程的落地实践
java·jvm·spring boot
武子康1 小时前
大数据-209 深度理解逻辑回归(Logistic Regression)与梯度下降优化算法
大数据·后端·机器学习
maozexijr1 小时前
Rabbit MQ中@Exchange(durable = “true“) 和 @Queue(durable = “true“) 有什么区别
开发语言·后端·ruby
源码获取_wx:Fegn08952 小时前
基于 vue智慧养老院系统
开发语言·前端·javascript·vue.js·spring boot·后端·课程设计
独断万古他化2 小时前
【Spring 核心: IoC&DI】从原理到注解使用、注入方式全攻略
java·后端·spring·java-ee
毕设源码_郑学姐2 小时前
计算机毕业设计springboot基于HTML5的酒店预订管理系统 基于Spring Boot框架的HTML5酒店预订管理平台设计与实现 HTML5与Spring Boot技术驱动的酒店预订管理系统开
spring boot·后端·课程设计
不吃香菜学java2 小时前
spring-依赖注入
java·spring boot·后端·spring·ssm
ja哇2 小时前
Spring AOP 详细讲解
java·后端·spring
南部余额2 小时前
Spring Boot 整合 MinIO:封装常用工具类简化文件上传、启动项目初始化桶
java·spring boot·后端·文件上传·工具类·minio·minioutils