SpringBoot 系列教程(一百零八):SpringBoot整合Orika实体映射工具

简介: SpringBoot 系列教程(一百零八):SpringBoot整合Orika实体映射工具

一、背景

在开发过程中,经常涉及到对象之间的拷贝,我记得以前用得最多的Spring框架中自带的一个API方法是:

BeanUtils.copyProperties(Object source, Object target)

BeanUtils.copyProperties(Object source, Object target)的含义是将source的属性值复制到target,属性为null时也会进行复制。但是据测试,发现BeanUtils.copyProperties效率还是比较低的,在大数据量情况下会占用大量资源(性能对比)。因此,给大家介绍一款Java Bean之间对象拷贝的工具Orika,来提高效率,接下来给大家介绍下Orika相关特性。

二、Orika简介

Orika是一个简单、快速的JavaBean拷贝框架,它能够递归地将数据从一个JavaBean复制到另一个JavaBean,这在多层应用开发中涉及到数据的传输、转换是非常有用的。

  • 示例:
Order order = mapper.map(OrderDTO, Order.class);

解释: 将OrderDTO对象拷贝至Order对象中。

三、SpringBoot整合Orika

1. 在SpringBoot项目中,添加Orika依赖

<dependency>
   <groupId>ma.glasnost.orika</groupId>
   <artifactId>orika-core</artifactId>
   <version>1.4.2</version><!-- or latest version -->
</dependency>

2. OrikaConfig配置

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @Description: orkia配置
* @author: thinkingcao
* @Date: 2021/04/23 22:56:26
*
*/
@Configuration
public class OrikaConfig {

    @Bean
    public MapperFactory mapperFactory(){
        return new DefaultMapperFactory.Builder().build();
    }

    @Bean
    public MapperFacade mapperFacade(){
        return mapperFactory().getMapperFacade();
    }
}

3. 完整pom.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.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.thinkingcao</groupId>
    <artifactId>springboot-orika</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-orika</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>ma.glasnost.orika</groupId>
            <artifactId>orika-core</artifactId>
            <version>1.4.2</version><!-- or latest version -->
        </dependency>

        <!-- swagger2依赖 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!-- swagger-ui依赖 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

四、如何使用Orika

1. 首先创建两个Bean对象,用于复制使用

  • OrderDTO
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

@Data
public class OrderDTO {

    @ApiModelProperty(value = "订单ID")
    private String orderId;

    @ApiModelProperty(value = "订单名称")
    private String orderName;

    @ApiModelProperty(value = "订单金额")
    private BigDecimal orderMoney;

    @ApiModelProperty(value = "订单时间")
    private Date orderTime;

    @ApiModelProperty(value = "订单地址")
    private String orderAddress;
}
  • OrderResp
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.Date;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OrderResp {

    private String orderId;

    private String orderName;

    private BigDecimal orderMoney;

    private Date orderTime;

    private String orderAddress;
}

2. OrderController

import com.thinkingcao.springboot.orika.dto.OrderDTO;
import com.thinkingcao.springboot.orika.entity.OrderResp;
import com.thinkingcao.springboot.orika.result.RestResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;

/**
 * @desc: 查询订单列表
 * @author: cao_wencao
 * @date: 2021-04-23 22:59
 */
@Api(value = "查询订单列表API接口",tags="查询订单列表API接口实现")
@Slf4j
@RestController
@RequestMapping(value = "/api/order", produces = "application/json;charset=UTF-8")
public class OrderController {

    @Resource
    private MapperFacade mapperFacade;

    @ApiOperation("查询订单列表")
    @GetMapping("queryOrder/{orderId}")
    public RestResponse queryOrder(@PathVariable("orderId") String orderId){
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setOrderId("20210424231016");
        orderDTO.setOrderName("点一杯杨枝甘露");
        orderDTO.setOrderTime(new Date());
        orderDTO.setOrderMoney(new BigDecimal(10));
        orderDTO.setOrderAddress("上海市徐汇区");
        //假设上面的orderDTO是通过这一步查询出来的OrderDTO orderDTO = orderService.getOrder(orderId);
        OrderResp orderResp = mapperFacade.map(orderDTO,OrderResp.class);
        return RestResponse.success("订单列表查询成功",orderResp);
    }
}

五、测试接口

在这里插入图片描述

在这里插入图片描述

六、项目其他相关类

1. application.yml

spring:
  profiles:
    active: pro

2. SwaggerConfig

package com.thinkingcao.springboot.orika.config;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;


/**
 * @desc: swagger自动配置类
 * @author: cao_wencao
 * @date: 2021-03-24 15:54
 */
@Slf4j
@EnableSwagger2
@AllArgsConstructor
@Configuration
@Profile({"dev","test","uat","pro"})  //通过spring.active激活某个环境
public class SwaggerConfig implements WebMvcConfigurer {

    @Bean
    public Docket apiConfig() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(true)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.thinkingcao.springboot.orika.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    //构建api文档的详细信息
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("SpringBoot 系列教程(一百零八):SpringBoot整合Orika实体映射工具")      //页面标题
                .description("restful风格的API接口")  //描述
                .termsOfServiceUrl("https://thinkingcao.blog.csdn.net/") //url
                .version("1.0") //版本号
                .build();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(new String[]{"/static/**"}).addResourceLocations(new String[]{"classpath:/static/"});
        registry.addResourceHandler(new String[]{"swagger-ui.html"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/"});
        registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"});
    }
}

3. RestResponse

package com.thinkingcao.springboot.orika.result;

import java.io.Serializable;

/**
 * REST接口统一返回数据工具类封装RestResponse
 * @param <T>
 */
public class RestResponse<T> implements Serializable {

    private static final long serialVersionUID = 3728877563912075885L;

    private int code;
    private String msg;
    private T data;

    public RestResponse(){

    }

    public RestResponse(int code, String message, T data) {
        this.code = code;
        this.setMsg(message);
        this.data = data;
    }

    public RestResponse(int code, T data) {
        this.code = code;
        this.data = data;
    }

    public RestResponse(int code, String message) {
        this.code = code;
        this.setMsg(message);
    }
 
    /**
     * 成功时-返回data
     * @param <T>
     * @return
     */
    public static <T> RestResponse<T> success(T data){
        return new RestResponse<T>(200, null, data);
    }

    /**
     * 成功-不返回data
     * @param <T>
     * @return
     */
    public static <T> RestResponse<T> success(String msg){
        return new RestResponse<T>(200, msg);
    }

    /**
     * 成功-返回data+msg
     * @param <T>
     * @return
     */
    public static <T> RestResponse<T> success(String msg, T data){
        return new RestResponse<T>(200, msg, data);
    }
 
    /**
     * 失败
     * @param <T>
     * @return
     */
    public static <T> RestResponse<T> fail(String msg){
        return new RestResponse<T>(500, msg,null);
    }

    /**
     * 失败-code
     * @param <T>
     * @return
     */
    public static <T> RestResponse<T> fail(int code, String msg){
        return new RestResponse<T>(code, msg,null);
    }

 
    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }
 
 
    public T getData() {
        return data;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "RestResponse{" + "code=" + code + ", msg='" + msg + '\'' +", data=" + data +'}';
    }
}

七、扩展Orika工具类封装

  • OrikaUtil
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
 
import java.util.List;
 
/**
 *
 * Orika是一个简单、快速的JavaBean拷贝框架,Orika使用字节代码生成来创建具有最小开销的快速映射器。
 *
 */
public class OrikaUtil {
 
    private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
 
    public static <A, B> ClassMapBuilder<A, B> classMap(Class<A> source, Class<B> target) {
        return mapperFactory.classMap(source, target);
    }
 
    public static <T> T convert(Object source, Class<T> target) {
        return mapperFactory.getMapperFacade().map(source, target);
    }
 
    public static <S, D> List<D> convertList(Iterable<S> source, Class<D> target) {
        return mapperFactory.getMapperFacade().mapAsList(source, target);
    }
 
}

八、源码

GitHub: https://github.com/Thinkingcao/SpringBootLearning/tree/master/springboot-orika

相关文章
|
11天前
|
存储 前端开发 Java
Springboot静态资源映射及文件映射
在Spring Boot项目中,为了解决前端访问后端存储的图片问题,起初尝试通过静态资源映射实现,但发现这种方式仅能访问打包时已存在的文件。对于动态上传的图片(如头像),需采用资源映射配置,将特定路径映射到服务器上的文件夹,确保新上传的图片能即时访问。例如,通过`addResourceHandler(&quot;/img/**&quot;).addResourceLocations(&quot;file:E:\\myProject\\forum_server\\&quot;)`配置,使前端可通过URL直接访问图片。
Springboot静态资源映射及文件映射
|
2月前
|
XML 安全 Java
Spring Boot中使用MapStruct进行对象映射
本文介绍如何在Spring Boot项目中使用MapStruct进行对象映射,探讨其性能高效、类型安全及易于集成等优势,并详细说明添加MapStruct依赖的步骤。
|
2月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
103 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
3月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
152 1
SpringBoot入门(7)- 配置热部署devtools工具
|
3月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
66 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
3月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
80 8
|
3月前
|
JSON Java 数据格式
springboot中表字段映射中设置JSON格式字段映射
springboot中表字段映射中设置JSON格式字段映射
179 1
|
3月前
|
JavaScript 前端开发 Java
SpringBoot_web开发-webjars&静态资源映射规则
https://www.91chuli.com/ 举例:jquery前端框架
34 0
|
3月前
|
关系型数据库 MySQL Java
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
76 0
|
4月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
908 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具