[新增功能](dev): 常规更新
1. 增加工具类 TranslatorUtil (有时候不方便写 @Translator 注解) 2. 缓存触发翻译的字段(数组翻译时不用每次都去解析,算提升点速度吧) 3. 自定义翻译注解的 conditionField 字段支持写固定值。格式:V:<值>
This commit is contained in:
parent
8f75fa8108
commit
bb59361d5e
@ -60,6 +60,13 @@ public @interface Translate {
|
||||
|
||||
/**
|
||||
* 判断条件字段(仅自定义 dictionary 时有效)
|
||||
* <p>
|
||||
* 该参数有两种形式,定义如下:
|
||||
*
|
||||
* <ul>
|
||||
* <li>1. 【值形式】 填写格式为 “V:{具体值}” 如 “V:123” ,这样会直接将 “123” 传到翻译实现接口。</li>
|
||||
* <li>2. 【字段形式】 填写的是对象中的其他字段,翻译前会先获取该字段的结果,并将结果值传到翻译实现接口。</li>
|
||||
* </ul>
|
||||
*/
|
||||
String conditionField() default "";
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.aizuda.trans.aspect;
|
||||
|
||||
import com.aizuda.trans.handler.TranslatorHandle;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Pointcut;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -19,10 +19,10 @@ import org.springframework.stereotype.Component;
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TranslateAspect {
|
||||
|
||||
@Autowired
|
||||
private GenericConversionService genericConversionService;
|
||||
private final GenericConversionService genericConversionService;
|
||||
|
||||
@Pointcut("@annotation(com.aizuda.trans.annotation.Translator)")
|
||||
public void pointCut() {
|
||||
|
@ -5,10 +5,12 @@ import com.aizuda.trans.service.SummaryExtractService;
|
||||
import com.aizuda.trans.service.impl.DefaultDictTranslateServiceImpl;
|
||||
import com.aizuda.trans.service.impl.DefaultSummaryExtractServiceImpl;
|
||||
import com.aizuda.trans.service.impl.wrapper.IPageUnWrapper;
|
||||
import com.aizuda.trans.util.TranslatorUtil;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
|
||||
/**
|
||||
* 翻译配置
|
||||
@ -56,4 +58,16 @@ public class TranslatorConfig {
|
||||
return new IPageUnWrapper<Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译工具类
|
||||
*
|
||||
* @param conversionService 转换服务
|
||||
* @return {@link TranslatorUtil }
|
||||
* @author nn200433
|
||||
*/
|
||||
@Bean
|
||||
public TranslatorUtil translatorUtil(GenericConversionService conversionService) {
|
||||
return new TranslatorUtil(conversionService);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package com.aizuda.trans.handler;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
@ -22,6 +24,7 @@ import com.aizuda.trans.summary.ISummaryExtract;
|
||||
import com.aizuda.trans.util.NameUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
import sun.reflect.annotation.AnnotationType;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@ -44,7 +47,12 @@ import static com.aizuda.trans.util.LambdaUtil.uncheck;
|
||||
*/
|
||||
@Slf4j
|
||||
public class TranslatorHandle {
|
||||
|
||||
|
||||
/** 条件字段是否为常量值的前缀 */
|
||||
private static String CONDITION_FIELD_IS_VALUE_PREFIX = "V:";
|
||||
/** 循环遍历缓存 */
|
||||
private static Cache<String, List<Field>> LOOP_FIELD_CACHE = CacheUtil.newLFUCache(100);
|
||||
|
||||
/**
|
||||
* 翻译Map或Entity或Page
|
||||
*
|
||||
@ -84,7 +92,7 @@ public class TranslatorHandle {
|
||||
* @param <T> 支持Entity或者Map
|
||||
* @return List
|
||||
*/
|
||||
public static <T> Collection<T> parse(Collection<T> originList) {
|
||||
private static <T> Collection<T> parse(Collection<T> originList) {
|
||||
if (CollUtil.isEmpty(originList)) {
|
||||
return originList;
|
||||
}
|
||||
@ -93,18 +101,24 @@ public class TranslatorHandle {
|
||||
final FormatType fieldFormatType = getFieldType(originList);
|
||||
|
||||
// 翻译数据
|
||||
originList.forEach(bean -> {
|
||||
originList.parallelStream().forEach(bean -> {
|
||||
final Class<?> beanClass = bean.getClass();
|
||||
/*
|
||||
final Field[] declaredFields = ReflectUtil.getFields(beanClass);
|
||||
// 循环处理需要转换的字段,字段上的注解链上需要有@Transform,且字段类型必须为String
|
||||
Arrays.stream(declaredFields)
|
||||
// 只转换简单值类型的属性(会把值转为String类型处理),其他类型的属性代表是嵌套情况需要过滤掉,后面处理
|
||||
.filter(field -> ClassUtil.isSimpleValueType(field.getType()) && AnnotationUtil.hasAnnotation(field, Translate.class))
|
||||
.filter(field -> field.isAnnotationPresent(Translate.class) && ClassUtil.isSimpleValueType(field.getType()))
|
||||
.forEach(field -> transformField(bean, fieldFormatType, field));
|
||||
// 转换嵌套字段,字段上需要标注@Transform且字段类型不为String(递归转换)
|
||||
Arrays.stream(declaredFields)
|
||||
.filter(field -> field.getType() != String.class && field.isAnnotationPresent(Translator.class))
|
||||
.filter(field -> field.isAnnotationPresent(Translator.class) && !ClassUtil.isSimpleValueType(field.getType()))
|
||||
.forEach(field -> transform(ReflectUtil.invoke(bean, ReflectUtil.getMethodByName(beanClass, "get" + StrUtil.upperFirst(field.getName())))));
|
||||
*/
|
||||
// 只转换简单值类型的属性(会把值转为String类型处理),其他类型的属性代表是嵌套情况需要过滤掉,后面处理
|
||||
getLoopFields(beanClass, Translate.class).forEach(field -> transformField(bean, fieldFormatType, field));
|
||||
// 转换嵌套字段,字段上需要标注@Transform且字段类型不为String(递归转换)
|
||||
getLoopFields(beanClass, Translator.class).forEach(field -> transform(ReflectUtil.invoke(bean, ReflectUtil.getMethodByName(beanClass, "get" + StrUtil.upperFirst(field.getName())))));
|
||||
});
|
||||
|
||||
return originList;
|
||||
@ -119,10 +133,7 @@ public class TranslatorHandle {
|
||||
* @return {@link List }<{@link Object }>
|
||||
* @author nn200433
|
||||
*/
|
||||
public static List<Object> parse(String originValue, Dictionary dictionaryConfig, ExtendParam extendParam) {
|
||||
if (originValue == null) {
|
||||
return null;
|
||||
}
|
||||
private static List<Object> parse(String originValue, Dictionary dictionaryConfig, ExtendParam extendParam) {
|
||||
final Translatable translator = getTranslatable(extendParam.getDictClass(), dictionaryConfig.translator());
|
||||
return CollUtil.defaultIfEmpty(translator.translate(originValue, dictionaryConfig, extendParam), Collections.emptyList());
|
||||
}
|
||||
@ -157,10 +168,9 @@ public class TranslatorHandle {
|
||||
}
|
||||
|
||||
// 获取条件字段值
|
||||
String conditionFieldValue = null;
|
||||
if (StrUtil.isNotBlank(conditionField)) {
|
||||
conditionFieldValue = Convert.toStr(getProperty(origin, conditionField));
|
||||
}
|
||||
String conditionFieldValue = Opt.ofBlankAble(conditionField)
|
||||
.map(c -> StrUtil.startWith(c, CONDITION_FIELD_IS_VALUE_PREFIX) ? StrUtil.removePrefix(c, CONDITION_FIELD_IS_VALUE_PREFIX) : Convert.toStr(getProperty(origin, c)))
|
||||
.get();
|
||||
|
||||
// 获取翻译结果并脱敏处理
|
||||
final ExtendParam extendParam = new ExtendParam(groupValue, conditionFieldValue, dictClass, maxLen);
|
||||
@ -367,9 +377,9 @@ public class TranslatorHandle {
|
||||
*/
|
||||
private static Method getMethod(Class<?> clazz, String fieldName, String prefix) {
|
||||
final String methodName = prefix + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
|
||||
return Stream.of(ReflectUtil.getMethods(clazz, m -> m.getName().equals(methodName))).findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException(
|
||||
clazz.getSimpleName() + ".class中未添加翻译属性" + fieldName + "或其对应get/set方法"));
|
||||
return Stream.of(ReflectUtil.getMethods(clazz, m -> m.getName().equals(methodName)))
|
||||
.findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException(clazz.getSimpleName() + ".class中未添加翻译属性" + fieldName + "或其对应get/set方法"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,8 +398,7 @@ public class TranslatorHandle {
|
||||
}
|
||||
|
||||
// 否则进行脱敏操作
|
||||
final DesensitizedUtil.DesensitizedType desensitizedType = EnumUtil.fromString(
|
||||
DesensitizedUtil.DesensitizedType.class, desensitizedModel, null);
|
||||
final DesensitizedUtil.DesensitizedType desensitizedType = EnumUtil.fromString(DesensitizedUtil.DesensitizedType.class, desensitizedModel, null);
|
||||
if (null == desensitizedType && StrUtil.isWrap(desensitizedModel, StrUtil.DELIM_START, StrUtil.DELIM_END)) {
|
||||
// 找不到匹配脱敏模型时,用hide解析
|
||||
final String model = StrUtil.unWrap(desensitizedModel, StrUtil.DELIM_START, StrUtil.DELIM_END);
|
||||
@ -441,8 +450,40 @@ public class TranslatorHandle {
|
||||
}
|
||||
|
||||
// Translatable 实现类上配置了 @Component 则使用 Spring 容器获取 否者 new 一个实现类
|
||||
return translatorClass.isAnnotationPresent(Component.class) ? SpringUtil.getBean(translatorClass) : uncheck(translatorClass::newInstance);
|
||||
return translatorClass.isAnnotationPresent(Service.class) || translatorClass.isAnnotationPresent(Component.class) ? SpringUtil.getBean(translatorClass) : uncheck(translatorClass::newInstance);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取循环字段
|
||||
*
|
||||
* @param beanClass bean类
|
||||
* @param annotationClass 注释类
|
||||
* @return {@link List }<{@link Field }>
|
||||
* @author nn200433
|
||||
*/
|
||||
private static List<Field> getLoopFields(Class<?> beanClass, Class<? extends Annotation> annotationClass) {
|
||||
final String key = beanClass.getName() + StrUtil.UNDERLINE + annotationClass.getName();
|
||||
List<Field> resultFieldList = LOOP_FIELD_CACHE.get(key);
|
||||
if (ObjUtil.isNull(resultFieldList)) {
|
||||
final Field[] declaredFields = ReflectUtil.getFields(beanClass);
|
||||
if (ClassUtil.isAssignable(Translate.class, annotationClass)) {
|
||||
log.debug("---> {} 初始化要翻译的字段缓存", key);
|
||||
// 字段翻译
|
||||
resultFieldList = Arrays.stream(declaredFields)
|
||||
// 过滤出简单类型、简单数组类型、Collection实现类
|
||||
.filter(f -> f.isAnnotationPresent(Translate.class) && (ClassUtil.isSimpleValueType(f.getType()) || ClassUtil.isSimpleTypeOrArray(f.getType()) || ClassUtil.isAssignable(Collection.class, f.getType())))
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
log.debug("---> {} 初始化要嵌套翻译的字段缓存", key);
|
||||
// 嵌套翻译
|
||||
resultFieldList = Arrays.stream(declaredFields)
|
||||
.filter(f -> f.isAnnotationPresent(Translator.class) && !ClassUtil.isSimpleValueType(f.getType()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
LOOP_FIELD_CACHE.put(key, resultFieldList);
|
||||
}
|
||||
return resultFieldList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ import com.aizuda.trans.enums.FormatType;
|
||||
import com.aizuda.trans.service.Translatable;
|
||||
import com.aizuda.trans.util.NameUtil;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@ -35,13 +35,13 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DataBaseTranslator implements Translatable {
|
||||
|
||||
/**
|
||||
* 获取数据源
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
private DataSource dataSource;
|
||||
private final DataSource dataSource;
|
||||
|
||||
@Override
|
||||
public List<Object> translate(String origin, Dictionary dictConfig, ExtendParam extendParam) {
|
||||
|
@ -4,8 +4,8 @@ import com.aizuda.trans.annotation.Dictionary;
|
||||
import com.aizuda.trans.entity.ExtendParam;
|
||||
import com.aizuda.trans.service.DictTranslateService;
|
||||
import com.aizuda.trans.service.Translatable;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -19,10 +19,10 @@ import java.util.List;
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DictCacheTranslator implements Translatable {
|
||||
|
||||
@Autowired
|
||||
private DictTranslateService dictTranslateService;
|
||||
private final DictTranslateService dictTranslateService;
|
||||
|
||||
@Override
|
||||
public List<Object> translate(String origin, Dictionary dictConfig, ExtendParam extendParam) {
|
||||
|
@ -4,7 +4,7 @@ import com.aizuda.trans.annotation.Dictionary;
|
||||
import com.aizuda.trans.entity.ExtendParam;
|
||||
import com.aizuda.trans.service.SummaryExtractService;
|
||||
import com.aizuda.trans.service.Translatable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -17,10 +17,10 @@ import java.util.List;
|
||||
* @date 2023-06-07 09:32:49
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SummaryExtractTranslator implements Translatable {
|
||||
|
||||
@Autowired
|
||||
private SummaryExtractService summaryExtractService;
|
||||
private final SummaryExtractService summaryExtractService;
|
||||
|
||||
@Override
|
||||
public List<Object> translate(String origin, Dictionary dictConfig, ExtendParam extendParam) {
|
||||
|
@ -0,0 +1,32 @@
|
||||
package com.aizuda.trans.util;
|
||||
|
||||
import com.aizuda.trans.handler.TranslatorHandle;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
|
||||
/**
|
||||
* 翻译工具类
|
||||
*
|
||||
* @author nn200433
|
||||
* @date 2023-08-01 001 16:28:54
|
||||
*/
|
||||
public class TranslatorUtil {
|
||||
|
||||
private static GenericConversionService genericConversionService;
|
||||
|
||||
public TranslatorUtil(GenericConversionService conversionService) {
|
||||
genericConversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 翻译
|
||||
* <p>
|
||||
* 会先进行解对象(比如 Ipage 对象只会提取 Records 进行翻译)
|
||||
*
|
||||
* @param origin 源对象
|
||||
* @author nn200433
|
||||
*/
|
||||
public static void transform(Object origin) {
|
||||
TranslatorHandle.transform(genericConversionService.convert(origin, Object.class));
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user