两种解决方案

  • 前端查询字典数据然后前端转码
  • 后端查询字典值,然后再转码返回给前段。

本文及时针对方案2 进行的改进

目标:

在需要返回给前段的字段上添加指定的注解例如:@DictDesc 则根据该字段定义的值结合注解配置生成 xxxDesc字段并自动赋值为注解属性值所对应的字典描述;

具体使用的技术涉及到jackson序列化与反序列化,其他JSON工具包也类型的效果;

字典注解定义

/**
 * 字典类型字段自动生成Desc描述字段
 */
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@JsonSerialize(using = DictDescSerializer.class)
@JsonDeserialize(using = DictDescDeserializer.class)
public @interface DictDesc {
    /**
     * 枚举类型的class
     * 取值:getValue, getCode, getStatus, name
     * 描述:getDesc
     *
     * @return 字典类型
     */
    Class<? extends Enum<? extends DictEnum>>[] enumType() default {};
    /**
     * 字典类型分组
     *
     * @return 字典类型
     */
    String[] dictType() default {};
    /**
     * 字典转换失败时默认值
     *
     * @return String 默认值
     */
    String defaultValue() default "";
    /**
     * 是否抛出异常,默认不抛出异常,返回默认值
     *
     * @return true 转换失败则抛出异常,false 异常返回默认值
     */
    boolean throwException() default false;
}

该注解中定义了解析该注解需要序列化器与返序列化器:

@JsonSerialize(using = DictDescSerializer.class)

@JsonDeserialize(using = DictDescDeserializer.class)

字典序列化与返序列化器的实现

import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.aimilin.common.dict.annotation.DictDesc;
import com.aimilin.common.dict.service.impl.DictDescSerializerUtils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Objects;
/**
 * 字典类型返序列化器
 *
 * @author liujunguang1
 * @version V1.0
 * @date 2022/5/20 21:08
 */
@Slf4j
@NoArgsConstructor
public class DictDescDeserializer extends JsonDeserializer<Object> implements ContextualDeserializer {
    /**
     * 生成序列化字段后缀
     */
    private static final String LABEL_SUFFIX = "Desc";
    /**
     * 参数类型
     */
    private Class<?> rawClass;
    /**
     * 默认转换器
     */
    private ConversionService converter;
    /**
     * 设置方法
     */
    private Method writeMethod;
    /**
     * 字典配置信息
     */
    private DictDesc dict;
    public DictDescDeserializer(DictDesc dict, BeanProperty property) {
        this.dict = dict;
        this.rawClass = property.getType().getRawClass();
        this.converter = new DefaultConversionService();
        Class<?> targetClass = property.getMember().getDeclaringClass();
        String writeField = property.getName()   LABEL_SUFFIX;
        PropertyDescriptor propertyDescriptor = BeanUtils.getPropertyDescriptor(targetClass, writeField);
        this.writeMethod = Objects.isNull(propertyDescriptor) ? null : propertyDescriptor.getWriteMethod();
        if (Objects.isNull(this.writeMethod)) {
            log.info("类:{},字典属性:{},没有写入方法:{},不设置值!", targetClass.getName(), property.getName(), writeField);
        }
    }
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        DictDesc dict = property.getAnnotation(DictDesc.class);
        if (dict != null) {
            return new DictDescDeserializer(dict, property);
        }
        return this;
    }
    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
        Object result = this.getValue(p.getText());
        this.setDictDesc(result, p.getCurrentName(), p.getCurrentValue());
        return result;
    }
    /**
     * 将数据类型转换为目标类型
     *
     * @param value 字符串值
     * @return 目标类型值
     * @throws IOException
     */
    public Object getValue(String value) throws IOException {
        return converter.convert(value, this.rawClass);
    }
    /**
     * 设置字典会限制
     *
     * @param result       字典value
     * @param currentName  当前属性名称
     * @param currentValue 当前对象
     */
    private void setDictDesc(Object result, String currentName, Object currentValue) {
        try {
            if (this.writeMethod != null) {
                writeMethod.invoke(currentValue, DictDescSerializerUtils.getDesc(this.dict, currentName, result));
            }
        } catch (Exception e) {
            log.error("类:{},字典属性:{},回显异常:{}", currentValue.getClass(), currentName, e.getMessage(), e);
        }
    }
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.aimilin.common.dict.annotation.DictDesc;
import com.aimilin.common.dict.service.impl.DictDescSerializerUtils;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
/**
 * 字典序列化器
 *
 * @author liujunguang1
 * @version V1.0
 * @date 2022/5/20 20:48
 */
@Slf4j
@NoArgsConstructor
public class DictDescSerializer extends JsonSerializer<Object> implements ContextualSerializer {
    /**
     * 生成序列化字段后缀
     */
    private static final String LABEL_SUFFIX = "Desc";
    /**
     * 字典配置信息
     */
    private DictDesc dict;
    /**
     * 构造方法
     *
     * @param dict 字典描述
     */
    public DictDescSerializer(DictDesc dict) {
        this.dict = dict;
    }
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        DictDesc dict = property.getAnnotation(DictDesc.class);
        if (dict != null) {
            return new DictDescSerializer(dict);
        }
        return this;
    }
    /**
     * Method that can be called to ask implementation to serialize
     * values of type this serializer handles.
     *
     * @param value    Value to serialize; can <b>not</b> be null.
     * @param gen      Generator used to output resulting Json content
     * @param provider Provider that can be used to get serializers for
     *                 serializing Objects value contains, if any.
     */
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        provider.defaultSerializeValue(value, gen);
        if (dict != null) {
            String fieldName = gen.getOutputContext().getCurrentName();
            // 添加转换之后的字段:xxxDesc
            gen.writeStringField(fieldName.concat(LABEL_SUFFIX), DictDescSerializerUtils.getDesc(dict, fieldName, value));
        }
    }
}

字典序列化与反序列工具类

import cn.hutool.extra.spring.SpringUtil;
import com.aimilin.common.core.pojo.system.SysDict;
import com.aimilin.common.dict.annotation.DictDesc;
import com.aimilin.common.dict.annotation.DictEnum;
import com.aimilin.common.dict.exception.DictException;
import com.aimilin.common.dict.exception.enums.DictExceptionEnum;
import com.aimilin.common.dict.service.SysDictService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
 * 字典转换工具类
 *
 * @author liujunguang1
 * @version V1.0
 * @date 2022/5/20 23:19
 */
@Slf4j
public class DictDescSerializerUtils {
    /**
     * 获取字典信息
     *
     * @param dict  字典对象
     * @param value 字典值
     * @return
     */
    public static String getDesc(DictDesc dict, String field, Object value) {
        if (ArrayUtils.isEmpty(dict.dictType()) && ArrayUtils.isEmpty(dict.enumType())) {
            throw new DictException(DictExceptionEnum.REQUEST_DICT_TYPE, field);
        }
        try {
            if (value == null) {
                throw new DictException(DictExceptionEnum.REQUEST_NOT_NULL, field);
            }
            if (ArrayUtils.isNotEmpty(dict.enumType())) {
                return getEnumDesc(dict, field, value);
            }
            return getDictDesc(dict, field, value);
        } catch (Exception e) {
            log.error("字典转换异常, field:{}, enumType:{}, dictType:{}, 值:{}, 异常:{}",
                    field, dict.enumType(), dict.dictType(), value, e.getMessage(), e);
            if (dict.throwException()) {
                throw e instanceof DictException ? (DictException) e : new DictException(DictExceptionEnum.DICT_EXCEPTION, e);
            }
            return dict.defaultValue();
        }
    }
    /**
     * 获取枚举类型的描述信息
     *
     * @param dict  字典
     * @param value 值
     * @return 枚举desc字段
     */
    public static String getEnumDesc(DictDesc dict, String field, Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        for (Class<? extends Enum<? extends DictEnum>> dictEnum : dict.enumType()) {
            Method getCode = dictEnum.getMethod("getCode");
            Method getMessage = dictEnum.getMethod("getMessage");
            for (Enum<? extends DictEnum> e : dictEnum.getEnumConstants()) {
                if (value.equals(getCode.invoke(e))) {
                    return Objects.toString(getMessage.invoke(e));
                }
            }
        }
        throw new DictException(DictExceptionEnum.UNKNOWN_ENUM_DICT_VALUE,
                String.format("Field:%s, EnumType: %s, Value: %s", field, Arrays.toString(dict.enumType()), value));
    }
    /**
     * 获取字典中的值
     *
     * @param dict  字典注解
     * @param value 属性值
     * @return 字典名称
     */
    public static String getDictDesc(DictDesc dict, String field, Object value) {
        if (ArrayUtils.isEmpty(dict.dictType())) {
            throw new DictException(DictExceptionEnum.REQUEST_DICT_TYPE, field);
        }
        List<SysDict> sysDictList = SpringUtil.getBean(SysDictService.class).getDictByDictTypeCode(dict.dictType());
        if (CollectionUtils.isEmpty(sysDictList)) {
            throw new DictException(DictExceptionEnum.NO_DICT_DATA, field, Arrays.toString(dict.dictType()));
        }
        for (SysDict sysDict : sysDictList) {
            if (StringUtils.equals(sysDict.getCode(), Objects.toString(value))) {
                return sysDict.getValue();
            }
        }
        throw new DictException(DictExceptionEnum.UNKNOWN_DICT_VALUE, field, Arrays.toString(dict.dictType()));
    }
}

字典转换服务类

/**
 * 字典服务类
 *
 * @author liujunguang1
 * @version V1.0
 * @date 2022/5/20 16:03
 */
public interface SysDictService {
    /**
     * 根据字典类型code获取字典列表
     *
     * @param dictTypeCodes 字典类型code
     * @return List<SysDict>
     */
    public List<SysDict> getDictByDictTypeCode(String... dictTypeCodes);
}

服务实现类:

/**
 * 系统字典服务实现类
 *
 * @author liujunguang1
 * @version V1.0
 * @date 2022/5/20 16:13
 */
@Service
public class SysDictServiceImpl implements SysDictService {
    @Resource
    private SystemContextServiceApi systemContextServiceApi;
    @Resource
    private SysDictCache sysDictCache;
    /**
     * 根据字典类型编码获取字典数据
     *
     * @param dictTypeCodes 字典类型编码值
     * @return List<SysDict>
     */
    @Override
    public List<SysDict> getDictByDictTypeCode(String... dictTypeCodes) {
        List<SysDict> dictTypeCache = sysDictCache.getDictTypeCache(dictTypeCodes);
        if (CollectionUtils.isNotEmpty(dictTypeCache)) {
            return dictTypeCache;
        }
        return systemContextServiceApi.getDictByDictTypeCode(dictTypeCodes).getData();
    }
}

字典缓存服务

可以修改为使用本地缓存方式

/**
 * 字典缓存服务
 *
 * @version V1.0
 * @date 2022/5/19 12:13
 */
@Slf4j
@Service
public class SysDictCache {
    @Resource
    private RedisService redisService;
    /**
     * 获取字典类型缓存
     *
     * @param dictTypes 字典类型
     * @return 字典列表
     */
    public List<SysDict> getDictTypeCache(String... dictTypes) {
        if (Objects.isNull(redisService)) {
            log.info("redisService 为空,不使用字典缓存");
            return null;
        }
        List<List<SysDict>> dictValues = redisService.getMultiCacheMapValue(CommonConstant.DICT_CACHE_KEY, Arrays.asList(dictTypes));
        if (CollectionUtils.isEmpty(dictValues)) {
            return null;
        }
        List<SysDict> result = new ArrayList<>();
        dictValues.stream().filter(Objects::nonNull).forEach(result::addAll);
        log.debug("查询字典缓存,dictTypes:{}, 结果:{}", dictTypes, result);
        return result;
    }
    /**
     * 清空字典类型缓存
     *
     * @param dictTypes 字典类型
     */
    public void cleanDictTypeCache(String... dictTypes) {
        if (Objects.isNull(redisService)) {
            return;
        }
        redisService.deleteCacheMapValue(CommonConstant.DICT_CACHE_KEY, dictTypes);
        log.info("清除字典缓存,dictTypes:{}", StringUtils.join(dictTypes));
    }
    /**
     * 添加缓存
     *
     * @param sysDictList 系统字典列表
     */
    public void putDictTypeCache(List<SysDict> sysDictList) {
        if (Objects.isNull(redisService) || CollectionUtils.isEmpty(sysDictList)) {
            return;
        }
        Map<String, List<SysDict>> collect = sysDictList.stream().collect(Collectors.groupingBy(SysDict::getTypeCode));
        for (Map.Entry<String, List<SysDict>> entry : collect.entrySet()) {
            redisService.setCacheMapValue(CommonConstant.DICT_CACHE_KEY, entry.getKey(), entry.getValue());
            log.info("设置字典缓存,dictType:{},结果:{}", entry.getKey(), entry.getValue());
        }
    }
}

到此这篇关于Java分析讲解序列化与字典功能的序列化的文章就介绍到这了,更多相关Java序列化内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java分析讲解序列化与字典功能的序列化的更多相关文章

  1. ios – CGPath和UIBezierPath()有什么区别?

    目前,我正在努力制作一个自定义按钮,我有一个图像,并具有坐标,但我发现您可以通过使用CGPath类或UIBezierPath创建一个按钮/对象类.有人可以告诉我两者有什么区别?解决方法CGPath是CoreGraphics库的不透明类型,而UIBezierPath是UIKit中的Obj-C类.UIBezierPath是一个围绕CGPath的包装,具有更加面向对象的界面和一些方便的方法.使用CGPath可能会略微更快,因为它不必经过Obj-C,并且它具有更高级的功能,如CGPathApply.重要的是,UI

  2. swift 快速奔跑的兔几 本节的内容是:序列化与反序列化

    在cocoa中,我们经常需要向磁盘保存数据块,cocoa将这些数据块表示为NSData对象例如,有一个字符串,将其转换为NSData,可以使用如下方法:我们还可以将对象转化为数据。遵守协议NSCoding的对象可以转换为NSData对象,也可以从NSData对象中加载,方法如下:

  3. Swift中一个类中的枚举enum类型的数据该如何实现序列化NSCoder

    简述昨天在开发中遇到了这样一个问题,需要用NSUserDefaults持久化一些数据,其中需要保存一个自己定义的类对象。结束其实枚举本来就是一个Int,因此我们将其声明为Int型就可以根据Int值初始化了,以此实现序列化和反序列化。

  4. swift json的序列化和反序列化

    还有一点东西没写完,权作笔记参考:http://www.hangge.com/blog/cache/detail_983.html

  5. Swift中对象序列化的实现

    Swift中对象序列化的实现在swift中要使某个类可以序列化,只需要类实现NSCoding协议,并实现协议中的一个必要的构造函数和一个方法,分别对应序列化和反序列化的二个过程。

  6. Alamofire 4.0 迁移指南

    原文:Alamofire4.0MigrationGuide作者:cnoon译者:kemchenj译者注:最近打算把公司项目迁移到Swift3.0,顺手把Alamofire4.0的迁移指南翻译了,之前虽然读过一部分源码,但还是看到了很多新东西,新的Adapter和Retrier我都打算用到项目里,希望大家看完也能够有收获.Alamofire4.0是Alamofire最新的一个大版本更新,一个基于Sw

  7. [HandyJSON] 在Swift语言中处理JSON - 转换JSON和Model

    而HandyJSON是其中使用最舒服的一个库,本文将介绍用HandyJSON来进行Model和JSON间的互相转换。而HandyJSON另辟蹊径,采用Swift反射+内存赋值的方式来构造Model实例,规避了上述两个方案遇到的问题。所以我们要定义一个Mapping函数来做这两个支持:就这样,HandyJSON完美地帮我们进行了JSON到Model类的转换。把Model转换为JSON文本HandyJSON还提供了把Model类序列化为JSON文本的能力,简直无情。

  8. 数组 – 在swift中存储对数组的引用

    我错过了一些允许我这样做的Swift构造吗?你必须使用NSArray或NSMutableArray,因为SwiftArrays是值类型,所以任何赋值都会复制.

  9. android – 如何在Realm for Java中将RealmObject序列化为JSON?

    也就是说,使用RealmObject并将其序列化为JSON?它还应该序列化该对象内的任何RealmList.解决方法来自英国的基督徒在这里.RealmforAndroid目前没有任何此类方法,虽然核心数据库实际上支持JSON序列化,所以现在你要么必须手动操作,要么使用像GSON这样的第三方工具然而).

  10. android – GSON反序列化自定义对象数组

    我正在尝试使用GSON在Android中序列化/反序列化JSON.我有两个类看起来像这样:和:我正在使用GSON来序列化/反序列化数据.我像这样序列化:这将生成如下所示的JSON:我这样反序列化:我打电话的时候收到错误.我不知道这个错误意味着什么.我不认为自己做了任何严重的错误.有帮助吗?解决方法将您的代码更改为:使用Interfaces是一个很好的做法,GSON要求.Gson将javascript中的数组“[]”转换为LinkedList对象.在您的代码中,GSON尝试在_users字段中注入一个Lin

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部