前言
当你做业务内容开发时,数据库数据转化为人类数据,例如:机构id=》机构名称,用户Id=>用户名称。你是否受够了,不同业务的相同转化要写多次,写的抓狂。下面可以看看,我自己写的自动翻译工具,是否符合你的要求。
什么是自动翻译工具
自动翻译工具就是用来解决上述痛点,同时实现一次定义多处使用。通过AOP思想对接口进行拦截,自动触发数据转换和数据组装。只需要定义好翻译者,添加一些注解,剩下的就可以交给自动翻译工具了,电梯:使用场景-简单翻译。
主要思想
自动翻译工具,就是利用Spring AOP思想,对接口进行拦截,针对指定的对象,自动获取数据库数据,再主动调用用户定义的翻译者,获取人类数据,最后在自动填充。
代码结构
说明:
- 用户自定义各种Translator,然后系统自动加载到TranslatorFactory,通过TranslateFactory提供翻译者。
- TranslateAspect是核心内容,通过自定义切面,拦截所有@TransAnnotation的方法。
使用场景
简单翻译
简单翻译:根据Dto中的id直接翻译成名字。
- 定义翻译者,指定能解决的翻译格式。
/**
* @author jiakunfeng
* 根据用户id,返回相对应的用户名称
*/
@Component
public class UserTranslator implements Translator<Long,String> {
@Override
public String name() {
return "userTranslator";
}
@Override
public Map<Long, String> translate(List<Long> idList) {
//模拟查询数据库获取数据
return findUserName(idList);
}
private Map<Long,String> findUserName(List<Long> idList){
Map<Long,String> userNameMap = new HashMap<>();
for (Long id : idList) {
userNameMap.put(id,"酷我音乐盒"+id);
}
return userNameMap;
}
}
- 定义被翻译对象,添加@TransObject、@TransSource、@TransTarget
@Data
@NoArgsConstructor
@AllArgsConstructor
/**声明被翻译对象
这是简单根据id翻译名称。
*/
@TransObject
public class KuWoUser implements Serializable {
/**声明被翻译对象的id来源*/
@TransSource(name="userTranslator")
private Long id;
/**声明被翻译对象的翻译结果填充*/
@TransTarget(name="userTranslator")
private String name;
}.
- 方法调用,添加TransAnnotation
@Service
@Slf4j
public class KuWoUserReadServiceImpl implements KuWoUserReadService{
@Override
@TransAnnotation(translators = {
"userTranslator"})
public List<KuWoUser> list() {
return null;
}
@Override
@TransAnnotation(translators = {
"userTranslator"})
public KuWoUser findById() {
return null;
}
}
说明:
- 自定义Translator时,name至关重要,必须保证不重复,重复会有异常提示,同时后续使用该翻译者的所有注解(@TransSource,@TransTarget)都必须相同。
批次翻译
批次翻译:Dto中用多个相同的变量,但是用的都是一个翻译器。例如:User中的创建人和更新人的名字。只需要修改步骤1。
/**Music对象中的创建人名字和更新人名字都是查询User库就可以翻译,这种现象就是批量翻译,即一个Dto存在多个字段需要用同一个翻译者进行翻译,因此通过group进行区分,请注意group的唯一性(同一个translator必须唯一)*/
@Data
@TransObject
public class Music implements Serializable {
private Long id;
@TransSource(name = "userTranslator",group = "creator")
private Long creatorId;
@TransTarget(name = "userTranslator",group = "creator")
private String creatorName;
@TransSource(name = "userTranslator",group = "operator")
private Long operatorId;
@TransTarget(name = "userTranslator",group = "operator")
private String operatorName;
public Music(Long id,Long creatorId,Long operatorId){
this.id = id;
this.creatorId = creatorId;
this.operatorId = operatorId;
}
}
剩余的步骤跟简单调用相同。主要是Dto的注解需要特殊处理。
继承翻译
父类声明了相关的翻译,那么子类继承后,不需要再次声明。
@Data
@TransObject
public class BaseUser implements Serializable {
@TransSource(name="userTranslator")
private Long id;
@TransTarget(name="userTranslator")
private String name;
public BaseUser(Long id){
this.id = id;
}
}
@Data
public class QQUser extends BaseUser {
public QQUser(Long id) {
super(id);
}
}
QQUser不需要相关的声明,使用的时候按照上述补步骤即可。
多内容翻译
Dto中存在多个需要翻译的字段,例如:存在机构名称、操作人名称需要翻译。只需要修改第2、3步骤即可。
- 不同字段添加不同的翻译者
@Data
@NoArgsConstructor
@AllArgsConstructor
/**声明被翻译对象*/
@TransObject
public class KuWoUser implements Serializable {
/**声明被翻译对象的id来源*/
@TransSource(name="userTranslator")
private Long id;
/**声明被翻译对象的翻译结果填充*/
@TransTarget(name="userTranslator")
private String name;
@TransSource(name="orgTranslator")
private Long orgId;
@TransTarget(name="orgTranslator")
private String orgName;
}
- 修改方法调用中翻译者,添加多个翻译者。
@Override
@TransAnnotation(translators = {
"userTranslator","orgTranslator"})
public List<KuWoUser> listByName() {
KuWoUser user1 = new KuWoUser(1L,1111L);
KuWoUser user2 = new KuWoUser(2L,2222L);
return Lists.newArrayList(user1,user2);
}
自定义返回格式翻译
自定义格式翻译:现在的返回值格式,只支持:List、Map(Key)、Map(Value)、Set、Array、单一Object(直接有@TransObject注解),如果想添加更多格式,例如:Response(包装返回值)、Paging(分页)等。只需要添加格式转化者和修改步骤3。
添加转换者
/**
* 接口的返回值是Paging包装,进行拆包转List
*/
@Component
public class PagingReturnConverter extends AbstractReturnConverter {
@Override
public String name() {
return "paging";
}
@Override
public List<Object> covertReturn(Object ret) {
Paging<Object> retPage = (Paging<Object>) ret;
if (retPage.empty()) {
return Lists.newArrayList();
}
return retPage.getData();
}
}
添加retType
修改接口调用,@TransAnnotation的retType=“paging”
@Override
@TransAnnotation(translators = {
"userTranslator"},retType = "paging")
public Paging<KuGoUser> paging() {
KuGoUser user1 = new KuGoUser(1L, 30,"浙江");
KuGoUser user2 = new KuGoUser(2L, 31,"杭州");
return new Paging<>(Lists.newArrayList(user1,user2),2L);
}
注意事项
- AOP拦截的方法的返回值中的集合元素的Class文件必须相同,例如List的所有元素都是同一个Class,严禁:List:List.add(String),List.add(Integer)这种形式的集合。
- @TransAnnoation(translators={“XXX”})、@TransTarget(name=“XXX”)、@TransSource(name=“XXX”)、Translator的name()的字符串必须相同。
代码
代码还没有整理完成,后续会放在git上,尽情关注。
说明
后续会补充自动翻译工具的由来和Spring AOP的相关内容。