
前言场景正文
一 添加配置二 添加项目内省器三 自定义序列化规则四 字典缓存工具五 测试对象六 测试接口七 测试结果 总结
前言在前后端分离的项目中,存在很多字段是下拉框选项的情况。
比如:性别字段
在数据库中,存的是代码值,前端显示的时候,需要显示值。这时候,在返回的时候,就需要做一次代码转换。
(为什么不是前端自己转换?为了统一管理和方便变更。)
字典字段为空,则不转换。一个对象中的多个字段是字典字段。对象中的子对象也有字典字段。对象的子对象是集合,也存在字典字段。 正文
因为在业务开发过程中,存在非常多的这种实体,所以需要制定一个统一处理。减少业务开发的工作量。
(最终结果,减少到只需要一行注解)
项目中都有 fasterxml 的依赖吧,没有自己添加。
添加类 JacksonConfig,用于配置自定义内省器。
import com.cah.project.conf.serializer.ProjectJacksonAnnotationIntrospector;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class JacksonConfig {
public JacksonConfig() {}
@Bean
@Primary
@ConditionalOnMissingBean({ObjectMapper.class})
public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
// 定义 不为空,才能进行序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 添加 自定义 项目注解内省器
objectMapper.setAnnotationIntrospector(new ProjectJacksonAnnotationIntrospector());
return objectMapper;
}
}
二 添加项目内省器
import com.cah.project.core.annotation.Dict;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
public class ProjectJacksonAnnotationIntrospector extends JacksonAnnotationIntrospector {
public ProjectJacksonAnnotationIntrospector() {}
@Override
public Object findSerializer(Annotated a) {
// 如果是字典注解
Dict dict = _findAnnotation(a, Dict.class);
if(dict != null) {
return new DictSerializer(dict.type(), dict.separator());
}
// 其他扩展。。。
return super.findSerializer(a);
}
}
其中 Dict 注解类 为自定义注解。内容如下:
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)
public @interface Dict {
String type();
String desc() default "";
String separator() default ",";
}
三 自定义序列化规则
import com.cah.project.core.cache.DictCacheUtil; import com.cah.project.core.domain.bo.DictData; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; public class DictSerializer extends StdSerializer四 字典缓存工具
字典缓存工具,使用的是hutool工具包中的缓存。
至于缓存如何清理与同步,这是另外一个问题。也可以从redis中获取缓存。
缓存是为了加快转换速度。各自发挥就好了。
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import com.cah.project.core.domain.bo.DictData;
import java.util.HashMap;
import java.util.Map;
public class DictCacheUtil {
protected static Cache> dictCache = CacheUtil.newLFUCache(10000);
public static void put(String type, DictData dd) {
Map map = dictCache.get(type);
if(map == null) {
map = new HashMap<>();
dictCache.put(type, map);
}
map.put(dd.getValue(), dd);
}
public static DictData get(String type, String value) {
Map map = dictCache.get(type);
if(map == null) {
return new DictData(type, value, value);
}
return map.getOrDefault(value, new DictData(type, value, value));
}
public static String getLabel(String type, String value) {
Map map = dictCache.get(type);
if(map == null) {
return value;
}
DictData dd = map.get(value);
return dd != null ? dd.getLabel() : value;
}
}
五 测试对象
测试对象为返回的实体对象。其中字段字段都添加了 @Dict 注解
import com.cah.project.core.annotation.Dict;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class TestOutVO implements Serializable {
private String name;
@Dict(type = "STATUS_CD")
private String status;
@Dict(type = "SEX_CD")
private String sex;
private List children;
}
import com.cah.project.core.annotation.Dict;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ChildOutVO {
private String name;
@Dict(type = "TYPE_CD")
private Integer type;
@Dict(type = "SEX_CD")
private String sex;
}
六 测试接口
import cn.hutool.core.collection.ListUtil;
import com.cah.project.core.domain.out.CommonResult;
import com.cah.project.test.out.ChildOutVO;
import com.cah.project.test.out.TestOutVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Api(tags = {"测试 控制层"})
@RestController
@RequestMapping("/test")
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class TestController {
@GetMapping("getById")
@ApiOperation(value="测试获取数据")
public CommonResult getById(@RequestParam("id") String id){
TestOutVO outVO = new TestOutVO();
outVO.setName("名称");
outVO.setStatus("1");
outVO.setSex("0,1");
ChildOutVO c1 = ChildOutVO.builder().name("子1").type(2).sex("0").build();
ChildOutVO c2 = ChildOutVO.builder().name("子2").type(3).sex("1").build();
List list = ListUtil.toList(c1, c2);
outVO.setChildren(list);
return CommonResult.data(outVO);
}
}
七 测试结果
总结
通过以上的方式,可以解放业务开发过程中反复的字典映射 *** 作。但是也存在一些问题。比如复杂的转换,非缓存数据转换等。
对于以上问题,可以使用 @JsonSerialize(using = XxxSerializer.class)
的方式进行处理。
代码地址
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)