Easy Trans
1、适用场景
1 我有一个id,但是我需要给客户展示他的title/name 但是我又不想自己手动做表关联查询
2 我有一个字典码 sex 和 一个字典值0 我希望能翻译成 男 给客户展示。
3 我有一组user id 比如 1,2,3 我希望能展示成 张三,李四,王五 给客户
4 我有一个枚举,枚举里有一个title字段,我想给前端展示title的值 给客户
5 我有一个唯一键(比如手机号,身份证号码,但是非其他表id字段),但是我需要给客户展示他的title/name 但是我又不想自己手动做表关联查询
2、easy trans 支持的五种类型
字典翻译(TransType.DICTIONARY)
需要使用者把字典信息刷新到DictionaryTransService 中进行缓存,使用字典翻译的时候取缓存数据源
简单翻译(TransType.SIMPLE)
比如有userId需要userName或者userPo给前端,原理是组件使用MybatisPlus/JPA的API自动进行查询,把结果放到TransMap中。
跨微服务翻译(TransType.RPC)
比如订单和用户是2个微服务,但是我要在订单详情里展示订单的创建人的用户名,需要用到RPC翻译,原理是订单微服务使用restTemplate调用用户服务的一个统一的接口,把需要翻译的id传过去,然后用户微服务使用MybatisPlus/JPA的API自动进行查询把结果给订单微服务,然后订单微服务拿到数据后进行翻译,当然使用者只是需要一个注解,这些事情都是由组件自动完成的。
自动翻译(TransType.AUTO)
还是id翻译name场景,但是使用者如果想组件调用自己写的方法而不通过Mybatis Plus/JPA 的API进行数据查询,就可以使用AutoTrans
枚举翻译(TransType.ENUM)
比如我要把SEX.BOY 翻译为男,可以用枚举翻译。
3、环境搭建
引入maven依赖
注意,阿里云Maven仓库因为阿里本身软件升级所以暂时无法同步中央仓库的新发布版本依赖,所以要用新版本请使用中央仓库maven
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-spring-bootstarter</artifactId>
<version>2.0.12</version>
</dependency>
使用Mybatis plus,请引入Mybatis plus 扩展:
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-mybatis-plusextend</artifactId>
<version>2.0.12</version>
</dependency>
使用JPA,请引入JPA 扩展:
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-jpa-extend</artifactId>
<version>2.0.12</version>
</dependency>
使用Redis,请添加redis的引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-dataredis</artifactId>
</dependency>
4、简单翻译(TransType.SIMPLE)
4.1 使用步骤
TransType.SIMPLE 简单翻译,无需自己实现数据源(推荐),适用于根据id翻译name/title等 。此数据源需要配合easy_trans_mybatis_plus_extend或者easy_trans_jpa_extend一起使用。
在需要翻译的字段上添加下面一行注解即可:
@Trans(type = TransType.SIMPLE,target = Users.class,fields = "userName")
type表示翻译类型 -- 简单翻译
target表示要翻译出来的结果字段在哪个表中(对应的实体类)
fields表示对应翻译的是哪个字段
除了此这几个属性必须添加外,还可以添加ref/refs,fileds,alias,后面会详细介绍他们的用法。
我们准备一张设备表device和一张用户表users,其中device表中的device_id 字段关联了users表中的id字段。
Device.java
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.util.List;
@Data
//实现TransPojo 接口,代表这个类需要被翻译或者被当作翻译的数据源
public class Device extends BaseEntity implements TransPojo {
private Long id;
private String deviceCode;
private String deviceName;
private String devicePlace;
private String deviceImage;
//SIMPLE 翻译,用于关联其他的表进行翻译 userName和phone为Users 的字段
@Trans(type = TransType.SIMPLE,target = Users.class,fields = {"userName", "phone"})
private Long userId;
}
Users.java
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.time.LocalDate;
import java.util.Date;
@Data
//实现TransPojo 接口,代表这个类需要被翻译或者被当作翻译的数据源
public class Users extends BaseEntity implements TransPojo {
private Long id;
private String userName;
private LocalDate hireDate; //入职时间
private Integer gender; //用户性别,1--男,0--女
private String phone;
}
DeviceController.java
@Autowired
private DeviceService deviceService;
@GetMapping
//TransMethodResult用于将翻译的结果映射到trnasMap中展示
@TransMethodResult
public R<List<Device>> getDeviceList() {
//list()是Mybais plus提供的方法
List<Device> deviceList = deviceService.list();
}
查询结果如下:
我们发现userId已经成功地被翻译成了userName和phone,并将翻译的结果封装在了transMap中。
如果我们想让userName、phone在json中和userId同级展示,可以使用平铺模式:
在application.xml中开局平铺模式
easy-trans:
is-enable-tile: true #启用平铺模式
此时再看结果,我们发现 userName、phone和userId是同级
ref/refs,fileds,alias的使用
ref----将翻译出来的数据映射到本实体类的某个属性上
refs----将翻译出来的数据映射到本实体类的某个属性上--多个
alias----别名,解决翻译结果字段名重名问题
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.util.List;
@Data
public class Device extends BaseEntity implements TransPojo {
private Long id;
private String deviceCode;
private String deviceName;
private String devicePlace;
private String deviceImage;
@Trans(type = TransType.SIMPLE,target = Users.class,fields = {"userName", "phone"},refs = {"userName","phone"},alias="english")
private Long userId;
@TableField(exist = false)
private String englishUserName;
@TableField(exist = false)
private String englishPhone;
}
4.3 SIMPLE 翻译缓存
官方提供了@TransDefaultSett注解 来开启SIMPLE的缓存功能,只需要给数据源实体类上加@TransDefaultSett(isUseCache = true) 即可。可选参数:
1. isUseCache 是否开启 缓存 默认为false 需要开启设置为true即可
2. cacheSeconds 缓存失效时间 单位秒 默认5
3. maxCache 最大缓存数量 默认为1000
4. isAccess 默认false 设置为true的话会按照最后一次访问时间 进行缓存过期计时 false按照添加时间计时
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.time.LocalDate;
import java.util.Date;
@Data
@TransDefaultSett(isUseCache = true,cacheSeconds = 1000,maxCache = 1000,isAccess = false)
public class Users extends BaseEntity implements TransPojo {
private Long id;
private String userName;
private LocalDate hireDate; //入职时间
private Integer gender; //用户性别,1--男,0--女
private String phone;
}
没配置缓存时,后台查询了两个表
配置缓存后第二次查询,发现只查询了主表,说明我们配置缓存成功了
5、字典翻译(TransType.DICTIONARY)
5.1 使用步骤
如果我们要将users表中的性别gender字段进行翻译,gender为0时翻译成男,gender为1时翻译成女。这个时候我们可以使用字典翻译:
在需要翻译的字段上添加下面一行注解即可:
@Trans(type = TransType.DICTIONARY,key = "gender")
type表示翻译类型 -- 字典翻译
key:指定具体数据源(type为TransType.DICTIONARY 的时候,DictionaryTransService 我们注入了很多字典分组的数据,有订单状态,有性别,有爱好,那么这里要指 定字典分组的名字,比如你要翻译的是性别那么就指定sex,你想翻译订单状态就指定orderStatus)
初始化字典数据:
package com.example.config;
import com.fhs.trans.service.impl.DictionaryTransService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DictionaryConfig implements InitializingBean {
//注入字典翻译服务
@Autowired
private DictionaryTransService dictionaryTransService;
@Override
public void afterPropertiesSet() throws Exception {
//将字典缓存刷新到翻译服务中
Map<String,String> transMap = new HashMap<>();
transMap.put("0","男");
transMap.put("1","女");
dictionaryTransService.refreshCache("gender",transMap);
}
}
Users.java
package com.example.pojo;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.time.LocalDate;
@Data
public class Users extends BaseEntity implements TransPojo {
private Long id;
private String userName;
private LocalDate hireDate; //入职时间
@Trans(type = TransType.DICTIONARY,key = "gender")
private Integer gender; //用户性别,1--男,0--女
private String phone;
}
接下来我们来看翻译结果:
5.2 配置redis缓存
字典默认使用hashmap来存放缓存,也支持使用redis 来组二级缓存,这样内存中没有的时候会自动去redis里面找,然后放到内存中,解决了多微服务字典问题,也保证了性能。
开启方式:
easy-trans:
is-enable-redis: true
dict-use-redis: true
5.3 枚举翻译
直接看代码:
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.time.LocalDate;
@Data
public class Users extends BaseEntity implements TransPojo {
private Long id;
private String userName;
private LocalDate hireDate; //入职时间
private Integer gender; //用户性别,1--男,0--女
@Trans(type = TransType.ENUM, key = "desc")
@TableField(exist = false)
private UserSexEnum sexEnum;
public UserSexEnum getSexEnum() {
if(gender != null) {
return UserSexEnum.getEnum(gender);
}
return sexEnum;
}
private String phone;
}
package com.example.pojo;
public enum UserSexEnum {
男(1,"男"),
女(0,"女");
private Integer type;
private String desc;
public String getDesc() {
return desc;
}
UserSexEnum(Integer type, String desc) {
this.type = type;
this.desc = desc;
}
public static UserSexEnum getEnum(Integer type) {
UserSexEnum value = null;
for(UserSexEnum temp : UserSexEnum.values()) {
if(type.equals(temp.type)) {
value = temp;
break;
}
}
return value;
}
@Override
public String toString() {
return this.getDesc();
}
}
接下来我们来看翻译结果:
6、跨微服务翻译(TransType.RPC)
6.1 使用步骤
首先准备一张 tb_order表和一张 tb_user表,分别存放订单服务的数据和用户服务的数据
然后在idea中创建微服务项目,分别创建 order-service服务、user-service服务、eureka-service服务。
cloud-demo:父工程,管理依赖
- order-service:订单微服务,负责订单相关业务
- user-service:用户微服务,负责用户相关业务
- eureak-service:注册中心
接下来,分别在order-service和user-service中引入easy-trans依赖:
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-spring-bootstarter</artifactId>
<version>2.0.12</version>
</dependency>
<dependency>
<groupId>com.fhs-opensource</groupId>
<artifactId>easy-trans-mybatis-plusextend</artifactId>
<version>2.0.12</version>
</dependency>
需求:在查询订单的同时,根据订单中包含的userId查询出用户信息,一起返回。所以这里需要使用远程翻译 TransType.RPC,使用注解如下:
@Trans(type = TransType.RPC,targetClassName = "cn.itcast.user.pojo.User",fields = "userName",serviceName = "user-service")
serviceName:对方微服务的服务名称 (TransType.RPC的时候组件自动调用其他微服务的接口获取数据,所以要指定服务名称,easyTrans会自动去注册中心获取对应的服务实例URL进行调用)
targetClassName:对方的实体类全名
fields:用来指定我需要对方类的要哪个字段
Order.java (order-service)
package cn.itcast.order.pojo;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
@Data
public class Order implements TransPojo {
private Long id;
private Long price;
private String name;
private Integer num;
@Trans(type = TransType.RPC,targetClassName = "cn.itcast.user.pojo.User",fields = "userName",serviceName = "user-service")
private Long userId;
}
OrderController.java
@GetMapping()
@TransMethodResult
public List<Order> getOrderList() {
// 根据查询所有订单并返回
return orderService.list();
}
然后我们将user-service和order-service以及eureak-service全部启动,调用对应的api,结果如下:
userId已经成功地在微服务环境下翻译成了userName
7、自定义数据源翻译(TransType.AUTO_Trance)
7.1 使用步骤
TransType.AUTO_TRANS 表示自动自定义数据源翻译,如果想组件调用自己写的方法而不通过Mybatis Plus/JPA 的API进行数据查询,就可以使用AutoTrans
如果用了Mybatis Plus或者springDataJPA,官方强烈建议使用SIMPLE Trans来代替AutoTrans,如果非要使用,那么继续往下看:
1、先在application.yam文件配置你的数据源类所在的包:
easy-trans:
autotrans:
package: com.example.service.**;
2、然后在需要翻译的实体类中添加@Trans注解
package com.example.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fhs.core.trans.anno.Trans;
import com.fhs.core.trans.anno.TransDefaultSett;
import com.fhs.core.trans.constant.TransType;
import com.fhs.core.trans.vo.TransPojo;
import lombok.Data;
import java.util.List;
@Data
public class Device extends BaseEntity implements TransPojo {
private Long id;
private String deviceCode;
private String deviceName;
private String devicePlace;
private String deviceImage;
@Trans(type = TransType.AUTO_TRANS, key = "user")
private Long userId;
@TableField(exist = false)
private Users users;
}
3、在所在类里实现AutoTransAble接口和添加@AutoTrans注解
package com.example.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mapper.UserMapper;
import com.example.pojo.Users;
import com.example.service.UserService;
import com.fhs.core.trans.anno.AutoTrans;
import com.fhs.core.trans.vo.VO;
import com.fhs.trans.service.AutoTransable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.net.ssl.SSLSession;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Service
// namespace 别名,和@Trans注解的key对应上 fields别的类需要我的什么字段,这里就写什么
@AutoTrans(namespace = "user",fields = {"userName","phone"})
public class UserServiceImpl extends ServiceImpl<UserMapper,Users> implements UserService, AutoTransable<Users> {
@Override
public List<Users> selectByIds(List<?> ids) {
System.out.println(ids);
List<Users> usersList = new ArrayList<>();
for (Object id : ids) {
Users user = this.getById((Long) id);
usersList.add(user);
}
return usersList;
}
@Override
public List<Users> select() {
return null;
}
@Override
public Users selectById(Object primaryValue) {
return null;
}
}
为了查询方便,我这里仍然使用了Mybatis plus作为查询,但因为这里是自定义数据源,可以自己写sql执行查询。接下来我们来看结果:
需要更详细说明请参考官方文档!!