# plugin-transform
**Repository Path**: myqf_site/plugin-transform
## Basic Information
- **Project Name**: plugin-transform
- **Description**: 自动翻译VO层对象里的的属性,让属性自动赋上对应中文值。
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2022-10-20
- **Last Updated**: 2024-09-26
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
> 源代码:[https://gitee.com/myqf_site/plugin-transform.git](https://gitee.com/myqf_site/plugin-transform.git)
## 产生的背景
前后端联调时,后端将会返回VO对象到页面展示,在这个过程中后端经常需要经历对象内的一些属性做手动挡的显式转换,这些操作可能会涉及到跨服务调用(如果说是微服务项目需要通过Dubbo或者FeignClient调用其它服务)、联表关联查询等问题,这会将开发流程复杂化且基础代码写的烦不想写,我们应该期望方式是将这些属性的转换交给框架自动处理,即自动挡的隐式转换。
## 能处理的业务行为
1. 所有实现指定接口的枚举自动翻译:
例如:店铺类型枚举 shopTpeEnum(1:成本型;2:服务型;3:专职型),原来的处理方式是需要手动一个个去设置枚举对应的中文值:xxVO.setShopTypeName(ShopTypeEnum.name())。
2. 翻译静态数据字典表的字典项:
eg:sex(0:女;1:男)
静态数据字典表里存储的往往都是公用的枚举类型,一般都集中在公用服务Service里,当其它服务需要翻译 它时往往需要跨服务调用它的service。
3. 某个ID需要翻译成ID对应的名字:
eg:店铺shop表里关联了一个业务组group_id,表示这个店铺属于这个业务组,那我们在前端页面显示的时候,如果需要将业务组groupId转换成业务组名展示,那我需要再查一次业务组表或者sql里联表查出来。
针对上面的问题有一种可替代方案是让前端自己翻译匹配对应数据,如字典项,枚举,但这种方式还是尽量不要去选择,前端无法即时感知需要翻译对象的变化,应该让前端尽量脱离业务做单纯的展示。
## 对它的定义
Translator将是一款功能全面的数据翻译插件,只需要几个简单的注解配置,就可以实现各种姿势的数据翻译,彻底抛弃联表查询与硬编码翻译逻辑。
## 业务流程
举个栗子,定义一个ShopVO对象,他的属性如下:
```java
@Data
@Accessors(chain = true)
public class ShopVO {
/**
* 店铺的自增主健
*/
private Long id;
/**
* 店铺名
*/
private String name;
/**
* 店铺所属业务组ID
*/
private Long groupId;
/**
* 店铺所属业务组名
*/
@Transform(from = "groupId", transformer = GroupTransformer.class)
private String groupName;
}
```
它除了有自己的ID与名称外,还有一个业务组ID与业务组名, 我们现在需要实现:在返回这个对象时,将业务组名也一起返回。以下是翻译它的时序图:

概要流程:
1. 定义一个切面 Aspect,重写 @AfterReturning 方法,当目标方法执行后,会去调用该方法实现
2. 请求执行完成,将要返回
3. 进入切面
4. 找到被 **Transform **注解标志的Controlelr层方法
5. 从方法里获取该方法的响应对象
6. 根据响应对象类型向工厂中拿对应的处理类型类(TransformTypeConvert )进一步获取后端返回的响应体里的数据
7. 通过反射获取被 **@Transform **注解的字段以及注解里面的属性值
8. 获取注解里的属性值之一:**transformer** 。这个属性值是你要告诉好框架该向哪里去拿目标值
9. 拿到目标值之后,通过反射把值设置到目标属性
10. 切面返回,请求返回前端
## 核心代码设计
1)定义注解:**Transform,**将该注解放在需要翻译的对象的字段上,填入必填的几个属性 :
```java
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface Transform {
/**
* 翻译的字段
*/
Class extends Transformer> transformer() default Transformer.class;
/**
* 数据源,即你要告诉注解它要取得信息在哪里
*/
Class> dataSource() default Void.class;
/**
* 默认是当前字段或”字段+Code“或“字段+Id”
*/
String from() default "";
/**
* 参数
*/
String param() default "";
}
```
2)定义顶层转换接口:**Transformer** **,**它是作为所有转换能力实现的顶层抽象,比如,你需要翻译某个枚举类型、翻译某个ID成Name,那具备着两种能力的类需要实现这个接口。
```java
public interface Transformer {
/**
* 翻译
*
* @param original 原始值
* @param datasource 翻译数据源
* @param param 翻译后取值参数名字
* @return 翻译后的值
*/
String transform(T original, Class> datasource, String param);
}
```
例如,具备翻译枚举的能力类:**EnumTransformer:**
```java
@Component
public class EnumTransformer implements Transformer