实际需求

通过feign获取第三方接口,将结果映射成dto,不过dto里面的对象的属性接收的值命名可能不规范(全是大写等,不是驼峰命令等方式),所以才会用vo来接收dto的值。

如果只是对象copy,可以使用BeanUtils.copyProperties进行对象之间的属性赋值(浅拷贝)

但是如果对象里面还有对象和集合之类的,这样就copy失败了,这里就可以采用Mapstruct工具类进行深拷贝。

Mapstruct实现步骤

1.引入相关依赖(pom.xml)

        <dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-jdk8</artifactId><version>${org.mapstruct.version}</version></dependency><dependency><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>${org.mapstruct.version}</version></dependency>

2.引入plugin(pom.xml)

            <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>1.8</source><target>1.8</target><!--<annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></path><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-jdk8</artifactId><version>${org.mapstruct.version}</version></path></annotationProcessorPaths>--></configuration></plugin>

3.新增mapper接口SourceTargetMapper

package com.frank.hello.mapper;import com.frank.hello.dto.DataResponse;
import com.frank.hello.dto.Teacher;
import com.frank.hello.vo.DataResponseVO;
import com.frank.hello.vo.TeacherVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;/*** @author 小石潭记* @date 2020/7/2 21:39* @Description: ${todo}*/
@Mapper(componentModel = "spring")
public interface SourceTargetMapper {SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class);TeacherVO toTarget(Teacher source);// 如果需要转多个,则再定义一个方法,将源数据和目标数据修改即可// TargetData toTargetData(SourceData sourceData);}

4.调用接口方式,传入源数据,生成目标数据

SoucrceData data = SourceTargetMapper.MAPPER.toTarget(targetData);

集成mapstruct可能遇到的坑

1)查看资料如果引入swagger,在引入mapstruct,需要在swagger依赖下添加<exclusions>如下文所示</exclusions>

<!--  引入swagger包 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.2.2</version><exclusions><exclusion><artifactId>mapstruct</artifactId><groupId>org.mapstruct</groupId></exclusion></exclusions></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.2.2</version><exclusions><exclusion><artifactId>mapstruct</artifactId><groupId>org.mapstruct</groupId></exclusion></exclusions></dependency>

2)mapstruct和lombok同时引入,可能会出现生成不了get、set方法(compile生成接口的实现类),在plugin里面添加<annotationProcessorPaths>如下文所示</annotationProcessorPaths>

注意lombok的版本不要太低,我这里是:

<properties><java.version>1.8</java.version><m2e.apt.activation>jdt_apt</m2e.apt.activation><org.mapstruct.version>1.3.0.Final</org.mapstruct.version><lombok.version>1.18.12</lombok.version>
</properties>
            <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>1.8</source><target>1.8</target><!--<annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></path><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-jdk8</artifactId><version>${org.mapstruct.version}</version></path></annotationProcessorPaths>--></configuration></plugin>

3)最后一点我被坑惨了。

注意DTO和VO里面的属性名称一定要一致,返回的对象可以不一样,但是属性名一定要一致,图中的list里面的对象的属性名也要保持一致,不然compile不会生成对应的get、set这样拷贝的对象就不正确,没有拷贝完所有属性,这个地方我被坑惨了(实际项目中DTO对象嵌套的层数太多了,没有逐一去查看属性是否一致。)

4)如果对象不复杂,可以通过下面的方式进行mapping一一映射

/*** 这个方法就是用于实现对象属性复制的方法** @Mapping 用来定义属性复制规则 source 指定源对象属性 target指定目标对象属性** @param user 这个参数就是源对象,也就是需要被复制的对象* @return 返回的是目标对象,就是最终的结果对象*/@Mappings({@Mapping(source = "id", target = "userId"),@Mapping(source = "username", target = "name"),@Mapping(source = "role.roleName", target = "roleName")})UserRoleDto toUserRoleDto(User user);

目录结构:

application.properties文件暂未配置内容

Swagger2
package com.frank.hello.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;/*** @author 小石潭记* @date 2020/7/2 22:11* @Description: ${todo}*/
@Configuration
@EnableSwagger2
// http://localhost:8080/swagger-ui.html
public class Swagger2 {@Beanpublic Docket createRestApi(){return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.basePackage("com.frank.hello"))//扫描接口的包.build();}public ApiInfo apiInfo(){return new ApiInfoBuilder().title("spring boot利用swagger构建api文档").description("简单优雅的rest风格").termsOfServiceUrl("http://localhost:8080")//文档遵循的开发协议的展现网址.version("1.0")//版本.build();}
}
Animal
package com.frank.hello.dto;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author 小石潭记* @date 2020/7/2 21:11* @Description: ${todo}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Animal {@JsonProperty("NAME")private String name;@JsonProperty("AGE")private int age;}
DataResponse
package com.frank.hello.dto;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author 小石潭记* @date 2020/7/2 21:15* @Description: ${todo}*/
@NoArgsConstructor
@AllArgsConstructor
@Data
public class DataResponse {@JsonProperty("CODE")private int code;@JsonProperty("MESSAGE")private String message;@JsonProperty("DATA")private Teacher data;}
Student
package com.frank.hello.dto;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;/*** @author 小石潭记* @date 2020/7/2 21:10* @Description: ${todo}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {@JsonProperty("ID")private int id;@JsonProperty("NAME")private String name;@JsonProperty("ADDRESS")private String address;@JsonProperty("ANIMALS")private List<Animal> animals;}
Teacher
package com.frank.hello.dto;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;/*** @author 小石潭记* @date 2020/7/2 21:10* @Description: ${todo}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {@JsonProperty("ID")private int id;@JsonProperty("NAME")private String name;@JsonProperty("ADDRESS")private String address;@JsonProperty("STUDENTS")private List<Student> students;}
SourceTargetMapper(核心配置,compile项目之后,会生成该接口的实现类)
package com.frank.hello.mapper;import com.frank.hello.dto.DataResponse;
import com.frank.hello.dto.Teacher;
import com.frank.hello.vo.DataResponseVO;
import com.frank.hello.vo.TeacherVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;/*** @author 小石潭记* @date 2020/7/2 21:39* @Description: ${todo}*/
@Mapper(componentModel = "spring")
public interface SourceTargetMapper {SourceTargetMapper MAPPER = Mappers.getMapper(SourceTargetMapper.class);TeacherVO toTarget(Teacher dataResponse);// 如果需要转多个,则再定义一个方法,将源数据和目标数据修改即可// TargetData toTargetData(SourceData sourceData);}
AnimalVO
package com.frank.hello.vo;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;/*** @author 小石潭记* @date 2020/7/2 21:11* @Description: ${todo}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "AnimalVO", description = "动物类")
public class AnimalVO {@ApiModelProperty(value = "名字",name = "name",example = "小花")private String name;@ApiModelProperty(value = "年级",name = "age",example = "1")private int age;
}
DataResponseVO
package com.frank.hello.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;/*** @author 小石潭记* @date 2020/7/2 21:15* @Description: ${todo}*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Accessors(chain = true) //链式风格,在调用set方法时,返回这个类的实例对象
@ApiModel(value = "DataResponseVO", description = "返回的结果类")
public class DataResponseVO {@ApiModelProperty(value = "返回的code码",name = "code",example = "200")private int code;@ApiModelProperty(value = "返回的信息",name = "message",example = "success")private String message;@ApiModelProperty(value = "返回的数据",name = "data",example = "返回的数据")private TeacherVO data;
}
StudentVO
package com.frank.hello.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;/*** @author 小石潭记* @date 2020/7/2 21:10* @Description: ${todo}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "StudentVO", description = "学生类")
public class StudentVO {@ApiModelProperty(value = "学号",name = "id",example = "1001")private int id;@ApiModelProperty(value = "学生的姓名",name = "name",example = "张三")private String name;@ApiModelProperty(value = "学生地址",name = "address",example = "成都")private String address;@ApiModelProperty(value = "学生所拥有的动物",name = "animals",example = "学生所拥有的动物")private List<AnimalVO> animals;
}
TeacherVO
package com.frank.hello.vo;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;/*** @author 小石潭记* @date 2020/7/2 21:10* @Description: ${todo}*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "TeacherVO", description = "老师类")
public class TeacherVO {@ApiModelProperty(value = "老师的编号",name = "id",example = "1001")private int id;@ApiModelProperty(value = "老师的姓名",name = "name",example = "张老师")private String name;@ApiModelProperty(value = "地址",name = "address",example = "成都")private String address;@ApiModelProperty(value = "老师所教的学生",name = "students",example = "老师所教的学生")private List<StudentVO> students;
}
HelloController
package com.frank.hello.web;import com.frank.hello.dto.Animal;
import com.frank.hello.dto.DataResponse;
import com.frank.hello.dto.Student;
import com.frank.hello.dto.Teacher;
import com.frank.hello.mapper.SourceTargetMapper;
import com.frank.hello.vo.DataResponseVO;
import com.frank.hello.vo.TeacherVO;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.List;/*** @author 小石潭记* @date 2020/7/2 21:12* @Description: ${todo}*/
@RestController
@Api(value = "HelloController", description = "主页")
public class HelloController {@GetMapping("/index")@ApiOperation(value = "获取接口信息",notes = "获取接口信息",tags = "DataResponseVO",httpMethod = "GET")@ApiResponses({//方法返回值的swagger注释@ApiResponse(code = 200,message = "成功",response = DataResponseVO.class),@ApiResponse(code = 400,message = "用户输入错误",response = DataResponseVO.class),@ApiResponse(code = 500,message = "系统内部错误",response = DataResponseVO.class)})public DataResponseVO index(){List<Animal> animals = new ArrayList<>();animals.add(new Animal("小一", 1));animals.add(new Animal("小二", 2));animals.add(new Animal("小三", 3));List<Student> students = new ArrayList<>();students.add(new Student(1, "小明", "成都", animals));Teacher teacher = new Teacher(1, "小梅沙", "四川", students);// 这里模拟从第三方接口获取的数据DataResponse dataResponse = new DataResponse(200, "成功", teacher);// 这里直接将上面的数据拷贝变成DataResponseVO,这里注意一下先compile一下整个项目TeacherVO responseVo = SourceTargetMapper.MAPPER.toTarget(dataResponse.getData());DataResponseVO dataResponseVO = new DataResponseVO();dataResponseVO.setCode(dataResponse.getCode()).setMessage(dataResponse.getMessage()).setData(responseVo);return dataResponseVO;}
}
HelloApplication
package com.frank.hello;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class HelloApplication {public static void main(String[] args) {SpringApplication.run(HelloApplication.class, args);}}

编译项目之后,会自动生成mapper的实现类。

http://localhost:8080/swagger-ui.html   这里可以查看对应接口的请求参数、返回对象等信息。

项目地址

Springboot使用Mapstruct拷贝对象,集成swagger2相关推荐

  1. MapStruct入门及集成springboot

    MapStruct入门及集成springboot MapStruct官网地址: http://mapstruct.org/ 1.引入依赖 maven的pom.xml ... <propertie ...

  2. springboot集成swagger2,构建优雅的Restful API

    springboot集成swagger2,构建优雅的Restful API 转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springboot/2017/07/ ...

  3. SpringBoot集成Swagger2自动生成友好的RestApi测试页面及文档

    springBoot集成swagger2 水煮鱼又失败了 https://www.jianshu.com/p/002ce2f26103 1 背景 springBoot作为微服务首选框架,为其他服务提供 ...

  4. SpringBoot集成Swagger2、Swagger2和Swagger3的区别Swagger的注解学习

    Swagger的介绍 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新. 随着前后端 ...

  5. SpringBoot集成Swagger2

    SpringBoot集成Swagger2 刚开始用2.0.2.RELEASE版本的SpringBoot去继承2.7.0版本的springfox-swagger2一直出现请求下面这种情况,就是在启动Sp ...

  6. SpringBoot集成Swagger2生成API接口文档

    SpringBoot2.3.0集成Swagger2 引入Swagger2相应的依赖 入门示例 SpringBoot2集成Swagger2后启动报错 结语 背景:最近在工作中发现,已经多次发现后台开发人 ...

  7. springboot集成swagger2测试接口

    springboot集成swagger2测试接口 1.需要的依赖 2.开始编写一个swagger2 3.演示效果图片 1.需要的依赖 <dependency><groupId> ...

  8. springboot集成swagger2多模块中文配置详细步骤,解决集成mybatis或mybatis-plus无法正常使用问题

    springboot集成swagger2多模块中文配置详细步骤,解决集成mybatis或mybatis-plus无法正常使用问题 参考文章: (1)springboot集成swagger2多模块中文配 ...

  9. 13.9 SpringBoot集成Swagger2中遇到的问题

    13.9 SpringBoot集成Swagger2中遇到的问题 我们在使用SpringBoot集成Swagger2中,访问:http://127.0.0.1:8188/swagger-ui.html ...

最新文章

  1. Windows和Linux的编译理解
  2. ai皮肤检测分数_智能AI皮肤检测仪三步走话术
  3. 大话中文文本分类之fastText
  4. 法流程图_【对反应过程的笔记整理方法——时间轴法】
  5. 对请求并发数做限制的通用RequestDecorator
  6. 详解vue项目和普通项目如何解决开发环境与生产环境下的跨域问题
  7. 资金时间价值的计算机应用视频讲解,第八章资金时间价值与方案经济比选20161018讲解.ppt...
  8. mysql 主从一致性_mysql 主从一致性保证
  9. CANopen | 拓展知识 - CANopen,CAN总线与OSI模型的关系
  10. 【mysql问题】can't connect to mysql server on 'localhost' (10060)
  11. Ogre 3d 工具集
  12. C#读取文件-古文观止(总结一下)
  13. matlab字体设置
  14. lg-1 x 怎么算_四六级分数怎么算?交白卷都不会得0分|巨微英语
  15. Magrittr包:简化你的R代码
  16. Windows Azure Cloud Service (25) 使用Startup注册COM组件(下)
  17. C++ 读取txt文件方法读取速度比较
  18. 排查DHCP(动态获取IP)服务器故障的经验 (好文推荐)
  19. c# 用SqlParameter实现多字段模糊查询
  20. 抢答网页PHP,GitHub - zhaiwenjun/vie-to-answer: 用于小型多人的线下知识竞赛活动的在线抢答器...

热门文章

  1. 批量更新用户mous余额
  2. ssm在线考试系统设计与实现(论文+程序设计+数据库文件)下载
  3. html data-src和src的区别,img 的data-src 属性实现懒加载
  4. android脚本 附近的人,前天微信上有个附近的人加我,我发现她是个脚本
  5. 【学习笔记】【正则表达式】`A-Za-z`和`A-z`的区别,前者更精准,后者包括部分字符。
  6. 7-5 快乐的尽头 (17 分)
  7. java宠物之王-龙灵传说,《宠物之王-龙灵传说》的流程攻略(上)
  8. XILINX GTX学习笔记
  9. 李开复致中国大学生父母的一封信
  10. android通知栏样式自定义,如何给状态栏上的时钟自定义样式或位置?(位置篇)