简化java代码:mapstruct + 策略模式

目录

目的

准备

注意

相同类型-属性名不同

实体类

映射

使用

验证-查看实现类

测试

不同类型(策略模式)

实体类

映射

工具类

使用:对象拷贝

验证-查看实现类

测试

使用:集合拷贝

测试

策略模式说明

准备-依赖


目的

简化 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>
        <!--        &lt;!&ndash;jedis,redis客户端&ndash;&gt;-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <!--        &lt;!&ndash;使用redisson作为所有分布式锁,分布式对象等功能框架,也可以使用springboot的方式,就不用自己@Configuration了&ndash;&gt;-->
        <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>
相关推荐
徐*红14 分钟前
java 线程池
java·开发语言
尚学教辅学习资料14 分钟前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
2401_8576363914 分钟前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端
1 9 J16 分钟前
Java 上机实践4(类与对象)
java·开发语言·算法
Code apprenticeship17 分钟前
Java面试题(2)
java·开发语言
憨子周1 小时前
2M的带宽怎么怎么设置tcp滑动窗口以及连接池
java·网络·网络协议·tcp/ip
霖雨3 小时前
使用Visual Studio Code 快速新建Net项目
java·ide·windows·vscode·编辑器
SRY122404193 小时前
javaSE面试题
java·开发语言·面试
Fiercezm3 小时前
JUC学习
java
无尽的大道3 小时前
Java 泛型详解:参数化类型的强大之处
java·开发语言