如果你还在为国际化的问题苦恼的话, 不妨往下看看 ↓↓↓

本文采取数据库存储国际化字典,再对响应内容做全局处理

1.数据库设计

CREATE TABLE `i18n_dictionary` (
  `key` varchar(255) DEFAULT NULL COMMENT '中文内容',
  `system` varchar(255) DEFAULT NULL COMMENT '自定义程序标识,用来区分程序',
  `lang_en` varchar(255) DEFAULT NULL COMMENT '英语',
  `lang_thai` varchar(255) DEFAULT NULL COMMENT '泰文',
  `type` varchar(255) DEFAULT NULL COMMENT '类型 content表示json内容 key表示json的key'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在这里插入图片描述

2.依赖

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.83</version>
</dependency>
<dependency>
  <groupId>cn.hutool</groupId>
  <artifactId>hutool-all</artifactId>
  <version>5.8.4</version>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.4.2</version>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>org.junit.vintage</groupId>
      <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
  </exclusions>
</dependency>

3.目录展示

e&taskId=ucc21a2d4-bd13-4476-8d0b-d9951770607&title=&width=459)

4.查询sql

1.查询出国际化字典的列
2.根据类型查询响应的词典

    /**
     * 获取表头
     * @return
     */
    @Select("SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE table_name = 'i18n_dictionary'")
    List<String> getI18nDictionary();

    /**
     * 根据类型获取国际化数据
     * @param type
     * @return
     */
    @Select("select * from i18n_dictionary where type=#{type}")
    List<Map<String,String>> getI18nListMap(@Param("type")String type);

5.初始化缓存加载和全局处理

缓存类

初始加载字典缓存, 以及对字典定时刷新

import com.zsx.i18ndemo.mapper.I18nMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
public class I18nDictionaryCache {

    // 语言, 中文 对应content内容
    private static Map<String, Map<String, String>> i18nContentDictionary = new HashMap<>();
    // 语言, 中文, 对应json返回map的key
    private static Map<String, Map<String, String>> i18nKeyDictionary = new HashMap<>();
    //其他, 支持自定义呗
    private static Map<String, Map<String, String>> i18nHeaderDictionary = new HashMap<>();
    // 外国语言转成中文用于批量导入
    private static Map<String, Map<String, String>> i18nTransChineseDict = new HashMap<>();
    @Autowired
    private I18nMapper i18nMapper;

    /**
     * 初始化加载字典
     */
    @PostConstruct
    public void init() {
        long time = System.currentTimeMillis();
        initDictionary("content", i18nContentDictionary, TranTypeEnum.CN_TO_OTHER);
        initDictionary("key", i18nKeyDictionary, TranTypeEnum.CN_TO_OTHER);
        initDictionary("header", i18nHeaderDictionary, TranTypeEnum.CN_TO_OTHER);
        initDictionary("title", i18nTransChineseDict, TranTypeEnum.OTHER_TO_CN);
        log.info("初始化国际化字典信息完成,耗时:" + (System.currentTimeMillis() - time));
    }
      
   /**
     * 初始化加载字典
     */
    @Scheduled(fixedRate = 30000)
    public void refreshDictionary() {
        long time = System.currentTimeMillis();
        initDictionary("content", i18nContentDictionary, TranTypeEnum.CN_TO_OTHER);
        initDictionary("key", i18nKeyDictionary, TranTypeEnum.CN_TO_OTHER);
        initDictionary("header", i18nHeaderDictionary, TranTypeEnum.CN_TO_OTHER);
        initDictionary("title", i18nTransChineseDict, TranTypeEnum.OTHER_TO_CN);
        log.info("刷新化国际化字典信息完成,耗时:" + (System.currentTimeMillis() - time));
    }

    /**
     * 添加字典
     */
    public static void addDictionary(String locale, String key, String value, Map<String, Map<String, String>> i18nContentDictionary) {
        Map<String, String> stringStringMap = i18nContentDictionary.computeIfAbsent(locale, k -> new LinkedHashMap<>());
        stringStringMap.put(key, value);
    }
          
    /**
     * 将国际化字典添加到map,(批量导入的,其他语言转成中文)
     *
     * @param type
     * @param i18nDictionaryType
     */
    public void initDictionary(String type, Map<String, Map<String, String>> i18nDictionaryType, TranTypeEnum tranType) {
        List<String> columns = i18nMapper.getI18nDictionary();
        List<Map<String, String>> i18nListMap = i18nMapper.getI18nListMap(type);
        //这里进行一下排序,防止转换不全:  例如   添加成功   先匹配成功 ,就成了 添加success
        List<Map<String, String>> i18nListMapSorted = i18nListMap.stream().sorted((i, j) -> j.get("key").length() - i.get("key").length()).collect(Collectors.toList());
        if (i18nListMapSorted.size() > 0 && i18nDictionaryType.size() > 0) {
            i18nDictionaryType.clear();
        }
        for (Map<String, String> map : i18nListMapSorted) {
                      for (String column : columns) {
                if (column.contains("lang")) {
                    if (tranType.getValue() == 0) {
                        //其他语言做key
                        addDictionary(column, map.get("key"), map.get(column), i18nDictionaryType);
                    } else {
                        //中文做key
                        addDictionary(column, map.get(column), map.get("key"), i18nDictionaryType);
                    }
                }
            }
        }
    }

    public static Map<String, String> getContentDictionary(String locale) {return i18nContentDictionary.get(locale);}
    public static Map<String, String> getKeyDictionary(String locale) {return i18nKeyDictionary.get(locale);}
    public static Map<String, String> getHeaderDictionary(String locale) {return i18nHeaderDictionary.get(locale);}
    public static Map<String,String> getTransChineseDict(String locale){return i18nTransChineseDict.get(locale);}
转换类型枚举
public enum TranTypeEnum {
    CN_TO_OTHER(0,"中文作key"),
    OTHER_TO_CN(1,"英文做key")
    ;


    private  Integer value;
    private  String remark;

    TranTypeEnum(int value, String remark) {
        this.value=value;
        this.remark=remark;
    }

    public Integer getValue() {
        return value;
    }

    public String getRemark() {
        return remark;
    }
}
通用返回实体
@Data
public class RetObj<T> {

    int code;
    /**
     * 结果描述信息
     */
    String msg;
    /**
     * 结果对象
     */
    T obj;
    /**
     * 扩展数据
     */
    Map<String, Object> extend;

    public RetObj(){
        code = 200;
    }

    public RetObj(int code, String msg, T obj, Map<String, Object> extend) {
        super();
        this.code = code;
        this.msg = msg;
        this.obj = obj;
        this.extend = extend;
    }

    /***
     * 设置为错误
     * @param msg
     */
    public void fail(String msg){
        code = 500;
        this.msg = msg;
    }
}
测试用户实体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;

    private Integer age;

    private String address;

    private String sex;
}
全局处理
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zsx.i18ndemo.cache.I18nDictionaryCache;
import com.zsx.i18ndemo.util.ResponseI18nUtil;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.Map;
@ControllerAdvice(basePackages = "com.zsx.i18ndemo.controller")
public class ResponseBodyI18nAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    
@Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //响应国际化内容
        HttpHeaders headers = request.getHeaders();
        //需要响应的语言
        String locale = headers.getFirst("locale");
        if(locale!=null && body!=null){
            Map<String, String> contentDictionary = I18nDictionaryCache.getContentDictionary(locale);
            if(contentDictionary!=null){
                JSONObject jsonObject = (JSONObject) JSON.toJSON(body);
                ResponseI18nUtil.jsonObjectI18n(jsonObject,contentDictionary);
                Map<String, String> keyDictionary = I18nDictionaryCache.getKeyDictionary(locale);
                //转换中文key
                if(keyDictionary!=null){
                    return ResponseI18nUtil.changeJsonObj(jsonObject,keyDictionary);
                }
                return jsonObject;
            }
        }
        return body;
    }
}

6.响应帮助类

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zsx.i18ndemo.cache.I18nDictionaryCache;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.util.*;

public class ResponseI18nUtil {
    /**
* jsonObject国际化
*
* @param jsonObject
* @param keyMap
*/
    public static void jsonObjectI18n(JSONObject jsonObject, Map<String, String> keyMap) {
        Set<String> keySet = jsonObject.keySet();
        for (String key : keySet) {
            Object obj = jsonObject.get(key);
            if (obj instanceof String) {
                replaceValue(jsonObject, key, keyMap);
            } else {
                if (obj instanceof JSONObject) {
                    jsonObjectI18n(jsonObject.getJSONObject(key), keyMap);
                }
                if (obj instanceof JSONArray) {
                    jsonArrayI18n(jsonObject.getJSONArray(key), keyMap);
                }
            }
        }
    }

    /**
* jsonArray国际化
*
* @param jsonArray
* @param keyMap
*/
    public static void jsonArrayI18n(JSONArray jsonArray, Map<String, String> keyMap) {
        for (int i = 0; i < jsonArray.size(); i++) {
            Object obj = jsonArray.get(i);
            if (obj instanceof JSONObject) {
                jsonObjectI18n(jsonArray.getJSONObject(i), keyMap);
            }
            if (obj instanceof JSONArray) {
                jsonArrayI18n(jsonArray.getJSONArray(i), keyMap);
            }
        }
    }

    /**
* 替换value值
*
* @param jsonObject
* @param key
* @param keyMap
*/
    public static void replaceValue(JSONObject jsonObject, String key, Map<String, String> keyMap) {
        String value = jsonObject.getString(key);
        for (Map.Entry<String, String> entry : keyMap.entrySet()) {
            if (StrUtil.isNotBlank(key)) {
                if (value.contains(entry.getKey())&&entry.getValue()!=null) {
                    value = value.replace(entry.getKey(), entry.getValue());
                }
            }
        }
        jsonObject.put(key, value);
    }
    /**
* 国际化集合中对象的String字段
*
* @param data
* @throws Exception
*/
    private static <T> void changeStringField(List<T> data, Map<String, String> keyMap) throws Exception {
        for (T obj : data) {
            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (field.getType() == String.class) {
                    field.setAccessible(true);
                    String oldValue = (String) field.get(obj);
                    for (Map.Entry<String, String> entry : keyMap.entrySet()) {
                        if (StrUtil.isNotBlank(oldValue)) {

                            if (oldValue.contains(entry.getKey())&&entry.getValue()!=null) {
        oldValue = oldValue.replace(entry.getKey(), entry.getValue());
    }
                        }
                    }
                    field.set(obj, oldValue);
                }
            }
        }
    }

    /**
* 国际化对象集合中的String字段
*
* @param data
* @throws Exception
*/
    public static <T> void i18nFormatExportData(List<T> data) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String locale = request.getHeader("locale");
        if (StrUtil.isNotBlank(locale)) {
            Map<String, String> keyMap = I18nDictionaryCache.getContentDictionary(locale);
            if(keyMap==null){
                return;
            }
            changeStringField(data, keyMap);
        }
    }

    /**
* 国际化对象集合中的String字段
*
* @param titleHeaders
* @throws Exception
*/
    private static void i18nFormatExportHeader(Map<String, String> titleHeaders)   {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String locale = request.getHeader("locale");
        if (StrUtil.isNotBlank(locale)) {
            Map<String, String> keyMap = I18nDictionaryCache.getHeaderDictionary(locale);
            if(keyMap==null){
                return;
            }
            for (Map.Entry<String, String> entry : titleHeaders.entrySet()) {
                String oldValue = entry.getValue();
                for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                    if (oldValue.contains(dictEntry.getKey())&&dictEntry.getValue()!=null) {
                        oldValue = oldValue.replace(dictEntry.getKey(), dictEntry.getValue());
                    }
                }
                titleHeaders.put(entry.getKey(),oldValue);
            }
        }
    }

    public static String[] i18nFormatExportHeader(String[] titleHeaders)   {
    HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    String locale = request.getHeader("locale");
    if (StrUtil.isNotBlank(locale)) {
            List<String> titleHeaderList = new ArrayList<>();
            Map<String, String> keyMap = I18nDictionaryCache.getHeaderDictionary(locale);
            for (String oldValue : titleHeaders) {
                for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                    if (oldValue.contains(dictEntry.getKey())&&dictEntry.getValue()!=null) {
                        oldValue = oldValue.replace(dictEntry.getKey(), dictEntry.getValue());
                    }
                }
                titleHeaderList.add(oldValue);
            }
            return titleHeaderList.toArray(new String[titleHeaderList.size()]);
        }
    return titleHeaders;
}

    public static String[] i18nFormatExportHeader(String[] titleHeaders,String locale)   {
    if (StrUtil.isNotBlank(locale)) {
            List<String> titleHeaderList = new ArrayList<>();
            Map<String, String> keyMap = I18nDictionaryCache.getHeaderDictionary(locale);
            for (String oldValue : titleHeaders) {
                for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                    if (oldValue.contains(dictEntry.getKey())&&dictEntry.getValue()!=null) {
                        oldValue = oldValue.replace(dictEntry.getKey(), dictEntry.getValue());
                    }
                }
                titleHeaderList.add(oldValue);
            }
            return titleHeaderList.toArray(new String[titleHeaderList.size()]);
        }
    return titleHeaders;
}

    public static String i18nFormatExportFileName(String fileName){
    HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    String locale = request.getHeader("locale");
    if (StrUtil.isNotBlank(locale) && null != fileName) {
            Map<String, String> keyMap = I18nDictionaryCache.getHeaderDictionary(locale);
            for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                if (null != dictEntry.getKey() && dictEntry.getKey().equals(fileName)) {
                    return dictEntry.getValue().replaceAll(" ", "");
                }
            }
        }
    return fileName;
}

    /**
* key的国际化
*
* @param jsonObj
* @param keyMap
* @return
*/
    public static JSONObject changeJsonObj(JSONObject jsonObj, Map<String, String> keyMap) {
        JSONObject resJson = new JSONObject();
        Set<String> keySet = jsonObj.keySet();
        for (String key : keySet) {
            String resKey = keyMap.get(key) == null ? key : keyMap.get(key);
            try {
                Object obj=  jsonObj.get(key);
                if(obj instanceof String){
                  resJson.put(resKey, jsonObj.get(key));
              } else {
                  JSONObject jsonobj1 = jsonObj.getJSONObject(key);
                  resJson.put(resKey, changeJsonObj(jsonobj1, keyMap));
              }
            } catch (Exception e) {
                try {
                    JSONArray jsonArr = jsonObj.getJSONArray(key);
                    resJson.put(resKey, changeJsonArr(jsonArr, keyMap));
                } catch (Exception x) {
                    resJson.put(resKey, jsonObj.get(key));
                }
            }
        }
        return resJson;
    }

    /**
* key的国际化
*
* @param jsonArr
* @param keyMap
* @return
*/
    public static JSONArray changeJsonArr(JSONArray jsonArr, Map<String, String> keyMap) {
        JSONArray resJson = new JSONArray();
        for (int i = 0; i < jsonArr.size(); i++) {
            JSONObject jsonObj = jsonArr.getJSONObject(i);
            resJson.add(changeJsonObj(jsonObj, keyMap));
        }
        return resJson;
    }
    public static void i18nFormatContentData(List<Map<String, Object>> list) {
    HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
    String locale = request.getHeader("locale");
    if (StrUtil.isNotBlank(locale)) {
            Map<String, String> keyMap = I18nDictionaryCache.getContentDictionary(locale);
            if (keyMap != null) {
                list.forEach(x -> {
                    for (Map.Entry<String, Object> valueEntry : x.entrySet()) {
                        if (null != valueEntry.getValue()) {
                            for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                                String value = valueEntry.getValue().toString();
                                if (value.contains(dictEntry.getKey()) && dictEntry.getValue() != null) {
                                      value = value.replace(dictEntry.getKey(), dictEntry.getValue());
                                      x.put(valueEntry.getKey(), value);
                                  }
                            }
                        }
                    }
                });
            }
        }
}        

    public static String i18nFormatStringValue(String value) {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String locale = request.getHeader("locale");
        if (StrUtil.isNotBlank(locale)) {
            Map<String, String> keyMap = I18nDictionaryCache.getContentDictionary(locale);
            for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                if (value.contains(dictEntry.getKey())&&dictEntry.getValue()!=null) {
                    value = value.replaceAll(dictEntry.getKey(), dictEntry.getValue());
                }
            }
        }
        return value;
    }

    /**
* 其他语言 转换中文
* @return
*/
    public static String i18nTransChinese(String value){
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String locale = request.getHeader("locale");
        if (StrUtil.isNotBlank(locale)) {
            Map<String, String> keyMap = I18nDictionaryCache.getTransChineseDict(locale);
            for (Map.Entry<String, String> dictEntry : keyMap.entrySet()) {
                if (value.equals(dictEntry.getKey())&&dictEntry.getValue()!=null) {
                    value = dictEntry.getValue();
                }
            }
        }
        return value;
    }

7.测试代码

@RestController
@RequestMapping("/user")
public class I18nController {

    @RequestMapping("/getInfo")
    public RetObj<User> getUserInfo(){
        RetObj<User> ret=new RetObj<>();
        User user = new User("汤姆", 23, "中国", "男");
        ret.setMsg("成功");
        ret.setObj(user);
        return ret;
    }
}

未设置国际化标识

未设置header

设置国际化标识之后

设置header

至此结束!!!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐