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

相关推荐
豌豆花下猫13 分钟前
Python 潮流周刊#118:Python 异步为何不够流行?(摘要)
后端·python·ai
尚学教辅学习资料35 分钟前
Ruoyi-vue-plus-5.x第五篇Spring框架核心技术:5.1 Spring Boot自动配置
vue.js·spring boot·spring
晚安里1 小时前
Spring 框架(IoC、AOP、Spring Boot) 的必会知识点汇总
java·spring boot·spring
秋难降1 小时前
SQL 索引突然 “罢工”?快来看看为什么
数据库·后端·sql
上官浩仁2 小时前
springboot ioc 控制反转入门与实战
java·spring boot·spring
Access开发易登软件2 小时前
Access开发导出PDF的N种姿势,你get了吗?
后端·低代码·pdf·excel·vba·access·access开发
叫我阿柒啊2 小时前
从Java全栈到前端框架:一位程序员的实战之路
java·spring boot·微服务·消息队列·vue3·前端开发·后端开发
中国胖子风清扬3 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust
bobz9653 小时前
分析 docker.service 和 docker.socket 这两个服务各自的作用
后端
野犬寒鸦3 小时前
力扣hot100:旋转图像(48)(详细图解以及核心思路剖析)
java·数据结构·后端·算法·leetcode