Java多语言国际化i18n(ResponseBodyAdvice或JsonSerializer方式处理)

  • 背景

       项目已经上线,因业务需要进行国际化。要求原业务和接口不变,通过注解的方式实现,主要是在返回属性上使用注解的方式实现。

  •  实现方式1 通过实现ResponseBodyAdvice接口进行属性国际化

注解:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReflectI18n {
    String type();
}

数据库配置的多语言信息,项目启动加载到redis,通过xxljob进行redis数据更新(代码略),主要通过反射方法,获取到每个类,属性进行判断zhuanh具体处理注解代码如下:

//@ControllerAdvice
public class I18nResponseBodyAdvice implements ResponseBodyAdvice {

    @Autowired
    private RedisUtil i18nRedisUtil;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //取到header头信息中的多语言参数字段
        String languageCode = RequestHolder.getDataLanguageHeaderValue();
        if (null == languageCode || "".equals(languageCode)) {
            return body;
        }
        if (languageCode.equals("zh")) { // 处理默认语言的问题
            return body;
        }

        if (body != null) {
            // 对message进行处理
            if (body instanceof Result) {
                Result bodyResult = (Result) body;
                if (bodyResult.getMessage() != null) {
                    // 通过返回码处理多语言,根据编码+多语言:得到消息
                    if (bodyResult.getErrorCode() != null) { // 根据errorcode去缓存中获取多语言的字段

                    }else{
                        // 如果errorCode为空,则不转换多语言,默认系统返回的语言。接口中强制返回errorCode字段
                        if (i18nRedisUtil.hasKey(I18nConstants.MESSAGE_PRE + bodyResult.getMessage())) {
                            if (i18nRedisUtil.hasKey(I18nConstants.I18N_PRE + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE + bodyResult.getMessage()) + languageCode)) {
                                // bodyResult.set(bodyResult.getData(), i18nRedisUtil.get(I18nConstants.I18N_PRE + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE + filedValue) + languageCode));  // 给变量赋值
                                bodyResult.setMessage((String)i18nRedisUtil.get(I18nConstants.I18N_PRE + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE + bodyResult.getMessage()) + languageCode));
                            }
                        }
                    }


                }
                if (null != bodyResult.getData()) {
                    Class<?> cls = bodyResult.getData().getClass();
                    if (List.class.isAssignableFrom(cls)) {
                        List lists = (ArrayList) bodyResult.getData();
                        if (null == lists) {
                            return body;
                        }
                        if (lists.size() <= 0) {
                            return body;
                        }
                        // 如果list不为空,就遍历list
                        setMultiLanguageByList(lists, languageCode);
                    } else {// 不是list,则按照对象进行处理
                        setMultiLanguageByObject(cls, bodyResult, languageCode);
                    }
                }
            }
            if (body instanceof ListResult) {
                ListResult bodyResult = (ListResult) body;
                List list = bodyResult.getData().getList();
                if (null == list) {
                    return body;
                }
                if (list.size() <= 0) {
                    return body;
                }
                setMultiLanguageByList(list, languageCode);
            }
        }
        return body;
    }

    /**
     * 处理结果是list的返回数据
     *
     * @param list
     */
    private void setMultiLanguageByList(List<?> list, String languageCode) {
        for (int i = 0; i < list.size(); i++) {
            Class<?> dtoClass = list.get(i).getClass(); // 获取list中的对象
            Field[] fields = dtoClass.getDeclaredFields();// 获取他的字段数组
            for (Field field : fields) {
                field.setAccessible(true);         // 设置字段可访问
                //获取带有 i18n 注解的字段
                ReflectI18n languageAnnotation = field.getDeclaredAnnotation(ReflectI18n.class);
                if (languageAnnotation != null) {
                    try {
                        String type = languageAnnotation.type();
                        // field.set(list.get(i), "哈哈哈哈哈哈--test,后期屏蔽");  // 给变量赋值-test
                        String value = (String) field.get(list.get(i));
                        // 先判断message的key,根据message的key那id的code+language进行替换
                        if (i18nRedisUtil.hasKey(I18nConstants.MESSAGE_PRE +languageAnnotation.type() + value)) {
                            if (i18nRedisUtil.hasKey(I18nConstants.I18N_PRE  +languageAnnotation.type() + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE +languageAnnotation.type() + value) + languageCode)) {
                                field.set(list.get(i), i18nRedisUtil.get(I18nConstants.I18N_PRE +languageAnnotation.type() + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE +languageAnnotation.type() + value) + languageCode));  // 给变量赋值
                            }
                        }
                    } catch (IllegalAccessException e) {
                        log.error("变量赋值出错" + e.getMessage(), e);
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 处理结果是对象的方法
     *
     * @param cls
     * @param bodyResult
     */
    private void setMultiLanguageByObject(Class<?> cls, Result bodyResult, String languageCode) {
        Field[] fields = cls.getDeclaredFields();// 获取他的字段数组
        for (Field field : fields) {
            field.setAccessible(true);         // 设置字段可访问
            //获取带有 i18n 注解的字段
            ReflectI18n languageAnnotation = field.getDeclaredAnnotation(ReflectI18n.class);
            if (languageAnnotation != null) {
                try {
                    String filedValue = (String) field.get(bodyResult.getData());
                    // 先判断message的key,根据message的key那id的code+language进行替换
                    if (i18nRedisUtil.hasKey(I18nConstants.MESSAGE_PRE +languageAnnotation.type()+ filedValue)) {
                        if (i18nRedisUtil.hasKey(I18nConstants.I18N_PRE + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE+languageAnnotation.type() + filedValue) + languageCode)) {
                            field.set(bodyResult.getData(), i18nRedisUtil.get(I18nConstants.I18N_PRE+languageAnnotation.type() + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE +languageAnnotation.type()+ filedValue) + languageCode));  // 给变量赋值
                        }
                    }
                } catch (IllegalAccessException e) {
                    log.error("变量赋值出错" + e.getMessage(), e);
                    e.printStackTrace();
                }

            }
        }
    }
}

使用方式

     @ReflectI18n(type="1")
     private String title;
  •  
  •  
  • 实现方式2:通过序列化方式进行多语言转换

注解代码:

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotationsInside
@JsonSerialize(using = TypeJsonI18nSerializer.class)
public @interface TypeJsonI18n {

    String type() ;
}

业务实现:通过继承 JsonSerializer进行处理,代码如下:

主要逻辑是从redis中获取多语言匹配的值,进行处理。

jsonGenerator.writeString((String) i18nRedisUtil.get(I18nConstants.I18N_PRE + jsonI18nType + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE + jsonI18nType + s) + languageCode));
@Component
public class TypeJsonI18nSerializer extends JsonSerializer<String> implements ContextualSerializer {

    @Resource
    private RedisUtil i18nRedisUtil;

    private String jsonI18nType;

    private boolean flag = false;

    public TypeJsonI18nSerializer() {
        flag = false;
    }

    public TypeJsonI18nSerializer(RedisUtil i18nRedisUtil) {
        flag = false;
        this.i18nRedisUtil = i18nRedisUtil;
    }

    public TypeJsonI18nSerializer(String jsonI18nType, boolean flag,RedisUtil i18nRedisUtil) {
        this.i18nRedisUtil = i18nRedisUtil;
        this.jsonI18nType = jsonI18nType;
        this.flag = flag;

    }


    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if (flag) {
            String languageCode = RequestHolder.getDataLanguageHeaderValue();
            if (i18nRedisUtil.hasKey(I18nConstants.MESSAGE_PRE + jsonI18nType + s)) {
                if (i18nRedisUtil.hasKey(I18nConstants.I18N_PRE + jsonI18nType + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE + jsonI18nType + s) + languageCode)) {
                    jsonGenerator.writeString((String) i18nRedisUtil.get(I18nConstants.I18N_PRE + jsonI18nType + i18nRedisUtil.get(I18nConstants.MESSAGE_PRE + jsonI18nType + s) + languageCode)); 
                } else {
                    jsonGenerator.writeString(s);
                }
            } else {
                jsonGenerator.writeString(s);
            }
        } else {
            jsonGenerator.writeString(s);
        }

    }

   @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        TypeJsonI18n annotation = beanProperty.getAnnotation(TypeJsonI18n.class);
        if (annotation == null) {
            return new TypeJsonI18nSerializer(i18nRedisUtil);
        }

        return new TypeJsonI18nSerializer(annotation.type(),true,i18nRedisUtil);
    }
}

使用方式:

@TypeJsonI18n(type="1")
private String title;

 

 

  • 总结

项目进行国际化的过程中,使用spring的ResponseBodyAdvice,使用序列化方式进行多语言的转换。在此做个记录

 

 

 

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值