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

相关文章
|
3月前
|
Cloud Native Java C++
Springboot3新特性:开发第一个 GraalVM 本机应用程序(完整教程)
文章介绍如何在Spring Boot 3中利用GraalVM将Java应用程序编译成独立的本机二进制文件,从而提高启动速度、减少内存占用,并实现不依赖JVM运行。
403 1
Springboot3新特性:开发第一个 GraalVM 本机应用程序(完整教程)
|
3月前
|
前端开发 Java 数据安全/隐私保护
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
文章通过一个简单的SpringBoot项目,详细介绍了前后端如何实现用户登录功能,包括前端登录页面的创建、后端登录逻辑的处理、使用session验证用户身份以及获取已登录用户信息的方法。
554 2
用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程
|
1月前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
83 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
89 1
SpringBoot入门(7)- 配置热部署devtools工具
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
59 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
1月前
|
XML 安全 Java
Spring Boot中使用MapStruct进行对象映射
本文介绍如何在Spring Boot项目中使用MapStruct进行对象映射,探讨其性能高效、类型安全及易于集成等优势,并详细说明添加MapStruct依赖的步骤。
|
2月前
|
分布式计算 关系型数据库 MySQL
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型
SpringBoot项目中mysql字段映射使用JSONObject和JSONArray类型 图像处理 光通信 分布式计算 算法语言 信息技术 计算机应用
69 8
|
2月前
|
JSON Java 数据格式
springboot中表字段映射中设置JSON格式字段映射
springboot中表字段映射中设置JSON格式字段映射
168 1
|
3月前
|
Java API Apache
Springboot+shiro,完整教程,带你学会shiro
这篇文章提供了一个完整的Apache Shiro与Spring Boot结合使用的教程,包括Shiro的配置、使用以及在非Web和Web环境中进行身份验证和授权的示例。
154 2
Springboot+shiro,完整教程,带你学会shiro
|
3月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
785 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个