为了账号安全,请及时绑定邮箱和手机立即绑定

自定义注解自动化翻译项目中的字典值

标签:
Java

背景:

项目中经常会遇到需要把某些字典值翻译给前端,我们所有的字典值往往存在一个单独的表里,在业务表中只存储对应的code码,需要使用时则根据code码去查找对应字典项的名称。例如:我们的字典表为dict,表结构如下:

https://img1.sycdn.imooc.com//60b47f420001703605590143.jpg

其中code就是字典项code码,name是字典项对应的名称,type是该字典值类型。

我们在业务表person中有个字段sex,代表性别,我们在该表中只存储其code值,需要用时才会根据code 值和type值查询其对应的名称,如下所示:

person表

https://img1.sycdn.imooc.com//60b4802c0001a76b03910115.jpg

dict表:

https://img1.sycdn.imooc.com//60b4812a0001f8ad02280222.jpg

如果每次都手动查询dict表返回给前端太麻烦,有时项目中会缓存全量的字典值,需要用时从缓存中取值,这样做一方面会损耗系统性能,另一方面也不具有实时性。所以,我们需要对其进行改造,实现以下效果:

1、每次返回给前端code值时会自动去数据库查询对应的name值,而不需要手动处理。

2、支持通过注解设置返回给前端的字段名。

3、可以指定配置生效的controller,而对于未配置的controller不会生效。

解决方案:

1、创建自定义注解@DictField,

@JacksonAnnotationsInside
@JsonSerialize(using = DictSerializer.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface DictField {
    //返回字段的字段名
    String name() default "";
    //字段在字典表中的类型
    String value();
}

2、编写序列化处理逻辑

public class DictSerializer extends JsonSerializer<String> implements ContextualSerializer {
    private DictField dictField;
    private BeanProperty beanProperty;
    public DictSerializer(DictField dictField, BeanProperty beanProperty) {
        this.dictField = dictField;
        this.beanProperty = beanProperty;
    }
    public DictSerializer() {
    }
    public static String getDictName(String code,String type) {
        TransitSupportDictService transitSupportDictService = ApplicationContextUtil.getBean(TransitSupportDictService.class);
        return transitSupportDictService.getTypeName(code,type);
    }

    @Override
    //数据序列化时,会执行此方法,value是标注@DictField注解的字段值,即code码,通过getDictName(value,dictField.value())方法
    //根据字段类型dictField.value()和code码查询出该字段名称,设置到字段名dictField.name()上。
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        jsonGenerator.writeString(value);
        String dictName = getDictName(value,dictField.value());
        if (StringUtils.isNotEmpty(dictName)) {
            String name = dictField.name();
            if (name.length() == 0) {
                name = beanProperty.getName() + "_mc";
            }
            jsonGenerator.writeStringField(name, dictName);
        }
    }
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            DictField dictField = beanProperty.getAnnotation(DictField.class);
            if (dictField != null) {
                return new DictSerializer(dictField, beanProperty);
            } else {
                return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
            }
        }
        return serializerProvider.findNullValueSerializer(null);
    }
}

3、使用自定义注解

https://img1.sycdn.imooc.com//60b48cb6000105c806410409.jpg

4.指定生效controller

       由于我们项目中底层做了重写,默认使用fastjson,所以需要重新做拦截,针对指定的controller 改用jackjson我们之前的配置才会生效。

@ControllerAdvice
public class TransitSupportDictResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    private final MappingJackson2HttpMessageConverter converter;

    public TransitSupportDictResponseBodyAdvice() {
        converter = buildConverter();
    }

    private MappingJackson2HttpMessageConverter buildConverter() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        ObjectMapper objectMapper = builder
                .indentOutput(true)
                .simpleDateFormat("yyyy-MM-dd HH:mm:ss")
                .timeZone(TimeZone.getTimeZone("GMT+08:00"))
                .mixIn(ResponseMessage.class, ResponseMessageIgnore.class)
                .build();
        return new MappingJackson2HttpMessageConverter(objectMapper);
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
      //只有配置了的controller 才会生效
      return (returnType.getDeclaringClass().getPackage().getName().startsWith(transitSupportCommonProperties.getBasePackages())
        && returnType.getMethod().getReturnType() == ResponseMessage.class)
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body == null) {
            return null;
        }
        try {
            converter.write(body, returnType.getGenericParameterType(), MediaType.APPLICATION_JSON_UTF8, response);
        } catch (IOException ignore) {
        }
        return null;
    }

5、最终效果

https://img1.sycdn.imooc.com//60b48ea00001ecca08100507.jpg

至此,即可实现自动化翻译项目中的字典值。









点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消