目录
目的
简化 BeanUtils.copyProperties 属性对拷代码,自动生成空判断,结合策略模式自定义转换
集合对拷:一行代码就能完成以前 先new,再 for循环,再add的多行代码,而且也不用判空
准备
这里我将开发中经常用到的全部依赖都列举出来 (若下载不下来依赖,将settings.xml替换成我博客存档的那一份),此处为了不影响观看,放在文章末尾处。
注意
写好转换之后,maven 记得 clean install,查看一下生成的实现类有没有问题
实现类在 target 里面,若target没有,执行下列操作
相同类型-属性名不同
将 下面 Doctor 中的 i1 s1 分别转给 DoctorDto 中的 i2 s2
实体类
java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Doctor {
private int id;
private String name;
String s1;
int i1;
}
java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DoctorDto {
private int id;
private String name;
private String s2;
private int i2;
}
映射
java
@Mapper(componentModel = "spring")
public interface BeanConvert {
BeanConvert INSTANCE = Mappers.getMapper(BeanConvert.class);
/**
* 不一致的属性映射
*/
@Mappings({
@Mapping(target = "i2", source = "i1"),
@Mapping(target = "s2", source = "s1")
})
DoctorDto toDto(Doctor doctor);
}
使用
java
@GetMapping("/test")
public DoctorDto get() {
Doctor doctor = new Doctor();
doctor.setId(1);
doctor.setName("张三");
doctor.setI1(1);
doctor.setS1("1");
return BeanConvert.INSTANCE.toDto(doctor);
}
验证-查看实现类
clean install 重启
测试
可以看到 i1,s1中的值已经过来了
不同类型(策略模式)
实体类
将下面 Sku2 中的 Long date Integer code 分别转给 SkuDTO2 中的 Date date String value
一个是时间戳转换,一个是枚举转换
java
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Sku2 {
Long skuId;
String skuCode;
String skuPrice;
List<String> nameList;
Long date;
Integer code;
}
java
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class SkuDTO2 {
Long skuId;
String skuCode;
String skuPrice;
List<String> nameList;
Date date;
String value;
}
映射
uses 定义了两个策略,一个负责转换时间戳,一个负责转换枚举
java
@Mapper(componentModel = "spring", uses = {TimeConvertStrategy.class, EnumConvertStrategy.class})
public interface BeanConvert {
/**
* 策略模式测试
*/
@Mapping(target = "value", source = "code")
SkuDTO2 domain2Dto(Sku2 sku2);
}
java
@Component
public class EnumConvertStrategy {
public String convert(Integer code) {
return MyEnum.getByCode(code);
}
}
java
@Component
public class TimeConvertStrategy {
public Date date2TimeStamp(Long timeStamp) {
if (timeStamp == null) {
return null;
}
return new Date(timeStamp);
}
}
java
public enum MyEnum {
A(1,"哈哈"),B(2,"呵呵");
private final Integer code;
private final String msg;
MyEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
public static String getByCode(Integer code) {
if (code == null) {
return null;
}
for (MyEnum value : MyEnum.values()) {
if (value.getCode().equals(code)) {
return value.getMsg();
}
}
return null;
}
}
工具类
这里使用工具类,主要是辅助容器中的bean初始化的,包括我们定义的策略的初始化
java
/**
* ApplicationContextAware 接口可以让 Bean 获取到 ApplicationContext 对象
* 通过这个对象,可以获取 Spring 容器中的其他 Bean实例 或一些组件
*/
@Component
public class ConvertSupport implements ApplicationContextAware {
private static BeanConvert beanConvert;
/**
* 启动的时候,直接获取到 beanConvert 的实例
*/
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
// 这里如果没有执行,说明没有注入容器,但是我有了@Component注解,说明其未生效,主启动类@ComponentScan指定一下
if (beanConvert == null) {
beanConvert = context.getBean(BeanConvert.class);
System.out.println("执行过这里");
}
}
/**
* 列表转换
*/
public static <I, O> List<O> copyList(List<I> inputList, BiFunction<BeanConvert, I, O> function) {
if (CollectionUtils.isEmpty(inputList)) {
return Collections.emptyList();
}
List<O> resultList = new ArrayList<>(inputList.size());
for (I input : inputList) {
resultList.add(function.apply(beanConvert, input));
}
return resultList;
}
/**
* bean to bean
*/
public static <I, O> O castBean(I input, BiFunction<BeanConvert, I, O> function) {
return function.apply(beanConvert, input);
}
}
使用:对象拷贝
java
@GetMapping("/test2")
public SkuDTO2 get2() {
Sku2 sku2 = new Sku2();
sku2.setSkuId(1L);
sku2.setSkuCode("2");
sku2.setNameList(Lists.newArrayList("测", "试"));
sku2.setDate(new Date().getTime());
sku2.setCode(1);
return ConvertSupport.castBean(sku2, BeanConvert::domain2Dto);
}
验证-查看实现类
clean install 重启
测试
使用:集合拷贝
java
@GetMapping("/test3")
public List<DoctorDto> get3() {
List<Doctor> list = Lists.newArrayList(
new Doctor(1, "张三", "1", 1),
new Doctor(2, "李四", "2", 2),
new Doctor(3, "王五", "3", 3));
return ConvertSupport.copyList(list, BeanConvert::toDto);
}
此后,一行代码就能完成以前 先new,再 for循环,再add的多行代码,而且也不用判空
测试
策略模式说明
上面使用的是用来处理不同类型,平常去除 if else 的使用方式:
先定义两个 策略,和上面类似,spring管理后,通过策略内部判断决定怎么走,方法再抽象出一层
java
/**
* 策略1
*/
@Component
public class Situation1 implements Situation {
private static final String value = "用户传过来的值为1";
/**
* 判断进入哪个策略(if)
*/
@Override
public Boolean judge(String val) {
return value.equals(val);
}
/**
* 逻辑处理
*/
@Override
public int logic(int a, int b) {
return a + b;
}
}
java
/**
* 策略2
*/
@Component
public class Situation2 implements Situation {
private static final String value = "用户传过来的值为2";
/**
* 判断进入哪个策略(if)
*/
@Override
public Boolean judge(String val) {
return value.equals(val);
}
/**
* 逻辑处理
*/
@Override
public int logic(int a, int b) {
return a - b;
}
}
java
public interface Situation {
/**
* 判断进入哪个策略(if)
*/
Boolean judge(String val);
/**
* 逻辑处理
*/
int logic(int a, int b);
}
java
@RestController
public class StrategyTest {
@Autowired
private ApplicationContext applicationContext;
@GetMapping("/test/st")
public void test() {
String value = "用户传过来的值为2";
Map<String, Situation> beans = applicationContext.getBeansOfType(Situation.class);
beans.forEach((k, Strategy) -> {
// 判断用户传过来的值,从而决定进入哪个策略
if (Strategy.judge(value)) {
int num = Strategy.logic(8, 2);
System.out.println(num);
}
});
}
}
准备-依赖
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mytest</groupId>
<artifactId>springboot-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-demo</name>
<description>springboot-demo</description>
<properties>
<org.mapstruct.version>1.5.0.RC1</org.mapstruct.version>
<org.projectlombok.version>1.18.22</org.projectlombok.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--HuTool为我们提供的一些便捷工具。-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.1.14</version>
</dependency>
<!--Valid-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.3.2.RELEASE</version>
</dependency>
<!--自定义注解-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<!-- 定时任务 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<exclusions>
<exclusion>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.21</version>
</dependency>
<!-- pagehelper 分页插件 注意 pagehelper 和 spring-boot-starter-parent 版本,容易出现循环依赖 一般通过加@Lazy解决,这里通过版本号解决-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
<!--HttpUtils需要的所有依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--mybatisplus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--DateTime 需要的依赖,由于没有版本号管理,如果不写version,上面有一处会爆红-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.4</version>
</dependency>
<!--代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!--velocity模板引擎-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<!-- easyexcel依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<!--Lists.partition 需要的依赖-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- <!–jedis,redis客户端–>-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- <!–使用redisson作为所有分布式锁,分布式对象等功能框架,也可以使用springboot的方式,就不用自己@Configuration了–>-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.3</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- 特别注意 mapstruct 和 lombok 的顺序,顺序出问题,实现类就不映射了 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.10</version>
</dependency>
<!--CollectionUtils依赖-->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>com.google.code.google-collections</groupId>
<artifactId>google-collect</artifactId>
<version>snapshot-20080530</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<!-- <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.11.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<!--注意:3.0.0 版本 http://localhost:8081/swagger-ui.html 页面可能登陆不上去-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
<!-- 特别注意 mapstruct 和 lombok 的顺序,顺序出问题,实现类就不映射了 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${org.projectlombok.version}</version>
</path>
<!-- This is needed when using Lombok 1.18.16 and above -->
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
<!-- Mapstruct should follow the lombok path(s) -->
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>