字典表自动翻译
创建自定义字典注解
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 dicCode();
String dicText() default "";
String dictTable() default "";
}
创建字典AOP类
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hudie.module.base.common.CommonConstant;
import com.hudie.module.base.common.api.CommonApi;
import com.hudie.module.base.common.aspect.annotation.Dict;
import com.hudie.module.base.common.util.ConvertUtils;
import com.hudie.module.base.common.util.RedisUtil;
import com.hudie.module.base.common.vo.DictModel;
import com.hudie.module.base.common.vo.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@Aspect
@Component
@Slf4j
public class DictAspect {
@Autowired
private RedisUtil redisUtil;
@Autowired
private CommonApi commonApi;
@Pointcut("execution(public * com.hudie.module..*.*Controller.*(..))")
public void logPointCut() {
}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
Object result = point.proceed();
this.parseDictText(result);
return result;
}
private void parseDictText(Object result) {
if (result instanceof Result) {
if (((Result) result).getResult() instanceof IPage) {
List<JSONObject> items = new ArrayList<>();
List<Field> dictFieldList = new ArrayList<>();
Map<String, List<String>> dataListMap = new HashMap<>();
for (Object record : ((IPage) ((Result) result).getResult()).getRecords()) {
ObjectMapper mapper = new ObjectMapper();
String json="{}";
try {
json = mapper.writeValueAsString(record);
} catch (JsonProcessingException e) {
log.error("json解析失败"+e.getMessage(),e);
}
JSONObject item = JSONObject.parseObject(json);
for (Field field : ConvertUtils.getAllFields(record)) {
String value = item.getString(field.getName());
if (StringUtils.isEmpty(value)) {
continue;
}
if (field.getAnnotation(Dict.class) != null) {
if (!dictFieldList.contains(field)) {
dictFieldList.add(field);
}
String code = field.getAnnotation(Dict.class).dicCode();
String text = field.getAnnotation(Dict.class).dicText();
String table = field.getAnnotation(Dict.class).dictTable();
List<String> dataList;
String dictCode = code;
if (!StringUtils.isEmpty(table)) {
dictCode = String.format("%s,%s,%s", table, text, code);
}
dataList = dataListMap.computeIfAbsent(dictCode, k -> new ArrayList<>());
this.listAddAllDeduplicate(dataList, Arrays.asList(value.split(",")));
}
if (field.getType().getName().equals("java.util.Date")&&field.getAnnotation(JsonFormat.class)==null&&item.get(field.getName())!=null){
SimpleDateFormat aDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
}
}
items.add(item);
}
Map<String, List<DictModel>> translText = this.translateAllDict(dataListMap);
for (JSONObject record : items) {
for (Field field : dictFieldList) {
String code = field.getAnnotation(Dict.class).dicCode();
String text = field.getAnnotation(Dict.class).dicText();
String table = field.getAnnotation(Dict.class).dictTable();
String fieldDictCode = code;
if (!StringUtils.isEmpty(table)) {
fieldDictCode = String.format("%s,%s,%s", table, text, code);
}
String value = record.getString(field.getName());
if (org.apache.commons.lang3.StringUtils.isNotEmpty(value)) {
List<DictModel> dictModels = translText.get(fieldDictCode);
if(dictModels==null || dictModels.size()==0){
continue;
}
String textValue = this.translDictText(dictModels, value);
record.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);
}
}
}
((IPage) ((Result) result).getResult()).setRecords(items);
}
}
}
private String translDictText(List<DictModel> dictModels, String values) {
List<String> result = new ArrayList<>();
String[] splitVal = values.split(",");
for (String val : splitVal) {
String dictText = val;
for (DictModel dict : dictModels) {
if (val.equals(dict.getValue())) {
dictText = dict.getText();
break;
}
}
result.add(dictText);
}
return String.join(",", result);
}
private Map<String, List<DictModel>> translateAllDict(Map<String, List<String>> dataListMap) {
Map<String, List<DictModel>> translText = new HashMap<>();
List<String> needTranslData = new ArrayList<>();
for (String dictCode : dataListMap.keySet()) {
List<String> dataList = dataListMap.get(dictCode);
if (dataList.size() == 0) {
continue;
}
List<String> needTranslDataTable = new ArrayList<>();
for (String s : dataList) {
String data = s.trim();
if (data.length() == 0) {
continue;
}
if (dictCode.contains(",")) {
String keyString = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, data);
if (redisUtil.hasKey(keyString)) {
try {
String text = ConvertUtils.getString(redisUtil.get(keyString));
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
list.add(new DictModel(data, text));
} catch (Exception e) {
log.warn(e.getMessage());
}
} else if (!needTranslDataTable.contains(data)) {
needTranslDataTable.add(data);
}
} else {
String keyString = String.format("sys:cache:dict::%s:%s", dictCode, data);
if (redisUtil.hasKey(keyString)) {
try {
String text = ConvertUtils.getString(redisUtil.get(keyString));
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
list.add(new DictModel(data, text));
} catch (Exception e) {
log.warn(e.getMessage());
}
} else if (!needTranslData.contains(data)) {
needTranslData.add(data);
}
}
}
}
if (needTranslData.size() > 0) {
List<String> dictCodeList = Arrays.asList(dataListMap.keySet().toArray(new String[]{}));
List<String> filterDictCodes = dictCodeList.stream().filter(key -> !key.contains(",")).collect(Collectors.toList());
String dictCodes = String.join(",", filterDictCodes);
String values = String.join(",", needTranslData);
Map<String, List<DictModel>> manyDict = commonApi.translateManyDict(dictCodes, values);
for (String dictCode : manyDict.keySet()) {
List<DictModel> list = translText.computeIfAbsent(dictCode, k -> new ArrayList<>());
List<DictModel> newList = manyDict.get(dictCode);
list.addAll(newList);
for (DictModel dict : newList) {
String redisKey = String.format("sys:cache:dict::%s:%s", dictCode, dict.getValue());
try {
redisUtil.set(redisKey, dict.getText());
} catch (Exception e) {
log.warn(e.getMessage(), e);
}
}
}
}
return translText;
}
private void listAddAllDeduplicate(List<String> dataList, List<String> addList) {
List<String> filterList = addList.stream().filter(i -> !dataList.contains(i)).collect(Collectors.toList());
dataList.addAll(filterList);
}
}
创建数据库字典表与字典分类表
CREATE TABLE `sys_dict_data` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自然主键',
`item_value` int(11) DEFAULT NULL COMMENT '字典项值',
`description` longtext COMMENT '描述',
`enabled_mark` int(11) DEFAULT NULL COMMENT '有效标志',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_by` int(11) DEFAULT NULL COMMENT '创建用户',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`update_by` int(11) DEFAULT NULL COMMENT '修改用户',
`del_flag` tinyint(1) DEFAULT '0' COMMENT '删除状态(0-正常,1-已删除)',
`dictionary_type_id` varchar(50) DEFAULT NULL COMMENT '类别主键',
`item_text` varchar(255) DEFAULT NULL COMMENT '字典项文本',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='字典数据';
CREATE TABLE `sys_dict_type` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自然主键',
`full_name` varchar(50) DEFAULT NULL COMMENT '名称',
`dict_code` varchar(50) DEFAULT NULL COMMENT '编号',
`description` longtext COMMENT '描述',
`enabled_mark` int(11) DEFAULT NULL COMMENT '有效标志',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`create_by` int(11) DEFAULT NULL COMMENT '创建用户',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`update_by` int(11) DEFAULT NULL COMMENT '修改用户',
`del_flag` tinyint(1) DEFAULT '0' COMMENT '删除状态(0-正常,1-已删除)',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='字典分类';
创建字典表实体类
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("sys_dictionarydata")
@ApiModel(value="SysDictionarydata对象", description="字典数据")
public class SysDictionarydata implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "自然主键")
@TableId(type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "字典项文本")
private String itemText;
@ApiModelProperty(value = "字典项值")
private Integer itemValue;
@ApiModelProperty(value = "描述")
private String description;
@ApiModelProperty(value = "有效标志")
private Integer enabledMark;
@ApiModelProperty(value = "创建时间")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;
@ApiModelProperty(value = "创建用户")
private String createBy;
@ApiModelProperty(value = "修改时间")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date updateTime;
@ApiModelProperty(value = "修改用户")
private String updateBy;
@ApiModelProperty(value = "类别主键")
private String dictionaryTypeId;
}
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("sys_dictionarytype")
@ApiModel(value="SysDictionarytype对象", description="字典分类")
public class SysDictionarytype implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "自然主键")
@TableId(type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "名称")
private String fullName;
@ApiModelProperty(value = "编号")
private String dictCode;
@ApiModelProperty(value = "描述")
private String description;
@ApiModelProperty(value = "有效标志")
private Integer enabledMark;
@ApiModelProperty(value = "创建时间")
@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date createTime;
@ApiModelProperty(value = "创建用户")
private String createBy;
@ApiModelProperty(value = "修改用户")
private String updateBy;
@ApiModelProperty(value = "删除状态(0-正常,1-已删除)")
private Boolean delFlag;
}
其他 (实现字典翻译的代码)
@Component
public class CommonApi {
private final SysDictDataService dictDataService;
@Autowired
public CommonApi(SysDictDataService dictDataService) {
this.dictDataService = dictDataService;
}
public Map<String, List<DictModel>> translateManyDict(String dictCodes, String keys) {
List<String> dictCodeList = Arrays.asList(dictCodes.split(","));
List<String> values = Arrays.asList(keys.split(","));
return dictDataService.queryManyDictByKeys(dictCodeList, values);
}
}
public interface SysDictDataService extends IService<SysDictData> {
Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> values);
}
@Service
public class SysDictDataServiceImpl extends ServiceImpl<SysDictDataMapper, SysDictData> implements SysDictDataService {
@Override
public Map<String, List<DictModel>> queryManyDictByKeys(List<String> dictCodeList, List<String> values) {
List<DictModelMany> list = baseMapper.queryManyDictByKeys(dictCodeList, values);
Map<String, List<DictModel>> dictMap = new HashMap<>(16);
for (DictModelMany dict : list) {
List<DictModel> dictItemList = dictMap.computeIfAbsent(dict.getDictCode(), i -> new ArrayList<>());
dictItemList.add(new DictModel(dict.getValue(), dict.getText()));
}
return dictMap;
}
}
@Mapper
public interface SysDictDataMapper extends BaseMapper<SysDictData> {
List<DictModelMany> queryManyDictByKeys(@Param("dictCodeList") List<String> dictCodeList, @Param("keys") List<String> keys);
}
<mapper namespace="com.hudie.module.system.mapper.SysDictDataMapper">
<select id="queryManyDictByKeys" resultType="com.hudie.module.system.dto.DictModelMany">
SELECT
t2.dict_code,
t1.item_text AS "text",
t1.item_value AS "value"
from
sys_dict_data t1
INNER JOIN sys_dict_type t2 on t2.id = t1.dictionary_type_id
where t2.dict_code in (
<foreach item="dictCode" collection="dictCodeList" separator=",">
#{dictCode}
</foreach>
)
and t1.item_value IN (
<foreach item="key" collection="keys" separator=",">
#{key}
</foreach>
)
</select>
</mapper>
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@JsonIgnoreProperties(ignoreUnknown = true)
public class DictModel implements Serializable {
private static final long serialVersionUID = 1L;
public DictModel() {
}
public DictModel(String value, String text) {
this.value = value;
this.text = text;
}
private String value;
private String text;
public String getTitle() {
return this.text;
}
}
@Data
@EqualsAndHashCode(callSuper = true)
public class DictModelMany extends DictModel {
private String dictCode;
}