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

相关推荐
全栈派森36 分钟前
云存储最佳实践
后端·python·程序人生·flask
电商数据girl41 分钟前
酒店旅游类数据采集API接口之携程数据获取地方美食品列表 获取地方美餐馆列表 景点评论
java·大数据·开发语言·python·json·旅游
CircleMouse41 分钟前
基于 RedisTemplate 的分页缓存设计
java·开发语言·后端·spring·缓存
獨枭2 小时前
使用 163 邮箱实现 Spring Boot 邮箱验证码登录
java·spring boot·后端
维基框架2 小时前
Spring Boot 封装 MinIO 工具
java·spring boot·后端
秋野酱2 小时前
基于javaweb的SpringBoot酒店管理系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
☞无能盖世♛逞何英雄☜2 小时前
Flask框架搭建
后端·python·flask
Q_Q19632884752 小时前
python的家教课程管理系统
开发语言·spring boot·python·django·flask·node.js·php
进击的雷神2 小时前
Perl语言深度考查:从文本处理到正则表达式的全面掌握
开发语言·后端·scala
进击的雷神3 小时前
Perl测试起步:从零到精通的完整指南
开发语言·后端·scala