• Java高性能实体类转换工具MapStruct


    MapStruct官网介绍

    它是什么?
    MapStruct 是一个代码生成器,它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现。

    生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。

    为什么?
    多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射。编写这样的映射代码是一项乏味且容易出错的任务。MapStruct 旨在通过尽可能地自动化来简化这项工作。

    与其他映射框架相比,MapStruct 在编译时生成 bean 映射,这确保了高性能,允许快速的开发人员反馈和彻底的错误检查。

    如何?
    MapStruct 是一个注解处理器,它插入到 Java 编译器中,可用于命令行构建(Maven、Gradle 等)以及您首选的 IDE。

    MapStruct 使用合理的默认值,但在配置或实现特殊行为时会采取措施。

    使用场景:

    1、数据库中的字段和你对接的A部门、B部门的入参字段不一致的情况。

    2、涉及到一些入参和出参值的转换 比如:性别、日期等。

    使用教程

    1、引入pom.xml

    1. <dependency>
    2. <groupId>org.mapstructgroupId>
    3. <artifactId>mapstructartifactId>
    4. <version>1.3.1.Finalversion>
    5. dependency>
    6. <dependency>
    7. <groupId>org.mapstructgroupId>
    8. <artifactId>mapstruct-processorartifactId>
    9. <version>1.3.1.Finalversion>
    10. <scope>providedscope>
    11. dependency>

    2、入参(每个部门的入参可能不太一样)

    1. package com.lezu.springboot.common.dto.param;
    2. import io.swagger.annotations.ApiModelProperty;
    3. import lombok.Data;
    4. /**
    5. * @author LianJiaYu
    6. * @date 2022/9/1 14:09
    7. */
    8. @Data
    9. public class UserInfoParam {
    10. @ApiModelProperty(value = "用户账号")
    11. private String account;
    12. @ApiModelProperty(value = "性别")
    13. private String gender;
    14. @ApiModelProperty(value = "密码")
    15. private String password;
    16. @ApiModelProperty(value = "出生日期")
    17. private Long birthday;
    18. @ApiModelProperty(value = "验证码captchaId")
    19. private String captchaId;
    20. @ApiModelProperty(value = "昵称")
    21. private String name;
    22. @ApiModelProperty(value = "验证码")
    23. private String code;
    24. }

     3、对应数据库中的字段

    1. package com.lezu.springboot.common.dto.in;
    2. import com.lezu.springboot.common.Page;
    3. import io.swagger.annotations.ApiModelProperty;
    4. import lombok.AllArgsConstructor;
    5. import lombok.Data;
    6. import lombok.NoArgsConstructor;
    7. import javax.validation.constraints.NotNull;
    8. import java.io.Serializable;
    9. import java.util.Date;
    10. /**
    11. * @Author LianJiaYu
    12. * @Date 2021/4/4 22:06
    13. * @Version 1.0
    14. */
    15. @Data
    16. @AllArgsConstructor
    17. @NoArgsConstructor
    18. public class InUserInfoDto extends Page implements Serializable {
    19. private static final long serialVersionUID = 5755742614532104337L;
    20. @ApiModelProperty(value = "用户账号")
    21. @NotNull(message = "用户名不能为空")
    22. private String username;
    23. @ApiModelProperty(value = "性别")
    24. private Integer gender;
    25. @ApiModelProperty(value = "密码")
    26. @NotNull(message = "密码不能为空")
    27. private String password;
    28. @ApiModelProperty(value = "出生日期")
    29. private Date birthday;
    30. @ApiModelProperty(value = "验证码captchaId")
    31. private String captchaId;
    32. @ApiModelProperty(value = "昵称")
    33. private String name;
    34. @ApiModelProperty(value = "验证码")
    35. private String code;
    36. @ApiModelProperty(value = "默认状态")
    37. private String defaultStatus;
    38. }

    3、定义工厂

    1. package com.lezu.springboot.common.dto.Interface;
    2. import com.lezu.springboot.common.ListResult;
    3. import com.lezu.springboot.common.conversion.DataConversionWorker;
    4. import com.lezu.springboot.common.conversion.EnumConversionWorker;
    5. import com.lezu.springboot.common.dto.in.InUserInfoDto;
    6. import com.lezu.springboot.common.dto.out.OutUserInfoDto;
    7. import com.lezu.springboot.common.dto.param.UserInfoParam;
    8. import com.lezu.springboot.common.dto.result.UserInfoResult;
    9. import org.mapstruct.Mapper;
    10. import org.mapstruct.Mapping;
    11. import org.mapstruct.Mappings;
    12. import org.mapstruct.factory.Mappers;
    13. /**
    14. * @author LianJiaYu
    15. * @date 2022/9/1 14:04
    16. */
    17. @Mapper(uses = {DataConversionWorker.class, EnumConversionWorker.class})
    18. public interface UserConvert {
    19. UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
    20. //入参转换
    21. @Mappings({
    22. @Mapping(source = "account", target = "username"),
    23. @Mapping(source = "gender", target = "gender", qualifiedByName = "setGenderToInteger"),
    24. @Mapping(source = "birthday", target = "birthday", qualifiedByName = "getBirthdayToDate"),
    25. @Mapping(target = "defaultStatus", defaultValue = "success"),
    26. })
    27. InUserInfoDto userInfoConvert(UserInfoParam param);
    28. //出参转换
    29. @Mappings({
    30. @Mapping(source = "username", target = "account"),
    31. @Mapping(source = "gender", target = "gender", qualifiedByName = "setGenderToString"),
    32. @Mapping(source = "birthday", target = "birthday", qualifiedByName = "getBirthdayToLong"),
    33. })
    34. UserInfoResult userInfoResultConvert(OutUserInfoDto dto);
    35. ListResult listUserInfoResultConvert(ListResult list);
    36. }

    定义时间戳转换日期和日期转时间戳方法

    1. package com.lezu.springboot.common.conversion;
    2. import cn.hutool.core.date.DateUtil;
    3. import org.mapstruct.Named;
    4. import java.util.Date;
    5. /**
    6. * @author LianJiaYu
    7. * @date 2022/9/2 15:08
    8. */
    9. //@Component
    10. public class DataConversionWorker {
    11. @Named("getBirthdayToDate")
    12. public Date getBirthdayToDate(Long birthday) {
    13. if (birthday == null) {
    14. return null;
    15. }
    16. return DateUtil.date(birthday);
    17. }
    18. @Named("getBirthdayToLong")
    19. public Long getBirthdayToLong(Date birthday) {
    20. if (birthday == null) {
    21. return null;
    22. }
    23. return birthday.getTime();
    24. }
    25. }

    定义性别转换方法

    1. package com.lezu.springboot.common.conversion;
    2. import com.lezu.springboot.enums.UserGenderEnum;
    3. import org.mapstruct.Named;
    4. import org.springframework.stereotype.Component;
    5. /**
    6. * @author LianJiaYu
    7. * @date 2022/9/2 15:08
    8. */
    9. //@Component
    10. public class EnumConversionWorker {
    11. @Named("setGenderToInteger")
    12. public Integer setGenderToInteger(String type) {
    13. return UserGenderEnum.getByType(type).getCode();
    14. }
    15. @Named("setGenderToString")
    16. public Integer setGenderToString(Integer code) {
    17. return UserGenderEnum.getByCode(code).getCode();
    18. }
    19. }

    性别转换枚举

    1. package com.lezu.springboot.enums;
    2. /**
    3. * @author LianJiaYu
    4. * @date 2022/9/16 10:10
    5. */
    6. public enum UserGenderEnum {
    7. FEMALE(0, "female"),
    8. MALE(1, "male"),
    9. UNKNOWN(2, "unknown"),
    10. ;
    11. private Integer code;
    12. private String type;
    13. UserGenderEnum(Integer code, String type) {
    14. this.code = code;
    15. this.type = type;
    16. }
    17. public Integer getCode() {
    18. return code;
    19. }
    20. public String getType() {
    21. return type;
    22. }
    23. public static UserGenderEnum getByCode(Integer code) {
    24. for (UserGenderEnum v : UserGenderEnum.values()) {
    25. if (v.getCode() == code) {
    26. return v;
    27. }
    28. }
    29. return UNKNOWN;
    30. }
    31. public static UserGenderEnum getByType(String type) {
    32. for (UserGenderEnum v : UserGenderEnum.values()) {
    33. if (v.getType().equals(type)) {
    34. return v;
    35. }
    36. }
    37. return UNKNOWN;
    38. }
    39. }

    编写Controller代码进行测试

    1. package com.lezu.springboot.controller;
    2. import com.alibaba.fastjson.JSON;
    3. import com.lezu.springboot.common.ListResult;
    4. import com.lezu.springboot.common.dto.Interface.UserConvert;
    5. import com.lezu.springboot.common.dto.in.InUserInfoDto;
    6. import com.lezu.springboot.common.dto.param.UserInfoParam;
    7. import com.lezu.springboot.common.dto.result.UserInfoResult;
    8. import com.lezu.springboot.enums.ResultEnum;
    9. import com.lezu.springboot.service.UserInfoHandleService;
    10. import io.swagger.annotations.ApiOperation;
    11. import lombok.extern.slf4j.Slf4j;
    12. import org.springframework.beans.factory.annotation.Autowired;
    13. import org.springframework.web.bind.annotation.PostMapping;
    14. import org.springframework.web.bind.annotation.RequestMapping;
    15. import org.springframework.web.bind.annotation.RestController;
    16. import java.util.Objects;
    17. /**
    18. * 高性能实体类转换工具MapStruct
    19. * 类型转换工具
    20. * @author LianJiaYu
    21. * @date 2022/9/1 13:57
    22. */
    23. @RestController
    24. @RequestMapping("/mapstruct")
    25. @Slf4j
    26. public class MapstructController {
    27. @Autowired
    28. private UserInfoHandleService userInfoHandleService;
    29. @ApiOperation("类型转换")
    30. @PostMapping("/login")
    31. public ListResult login(UserInfoParam params) {
    32. ListResult listResult = new ListResult();
    33. if (Objects.isNull(params)) {
    34. return listResult.build(ResultEnum.PARAM_ERROR.getCode(), ResultEnum.PARAM_ERROR.getMsg());
    35. }
    36. //入参-日志
    37. log.info("params:" + JSON.toJSONString(params));
    38. //入参-参数转换
    39. InUserInfoDto inDto = UserConvert.INSTANCE.userInfoConvert(params);
    40. log.info("inDto:" + JSON.toJSONString(inDto));
    41. //出参-参数转换
    42. listResult = UserConvert.INSTANCE.outDtoToResult(userInfoHandleService.listByPage(inDto));
    43. log.info("listResult:" + JSON.toJSONString(listResult));
    44. return listResult;
    45. }
    46. }

    Service层

    1. @Override
    2. public ListResult listByPage(InUserInfoDto inDto) {
    3. ListResult listResult = new ListResult();
    4. LambdaQueryWrapper wrapper = Wrappers.lambdaQuery();
    5. if (StrUtil.isNotBlank(inDto.getUsername())) {
    6. wrapper.like(UserInfo::getUsername, inDto.getUsername());
    7. }
    8. int pageNum = inDto.getPageNum();
    9. int pageSize = inDto.getPageSize() == 0 ? 10 : inDto.getPageSize();
    10. IPage page = new Page<>(pageNum, pageSize);
    11. userInfoService.page(page, wrapper);
    12. List list = page.getRecords().stream().map(v -> {
    13. OutUserInfoDto dto = new OutUserInfoDto();
    14. BeanUtils.copyProperties(v, dto);
    15. return dto;
    16. }).collect(Collectors.toList());
    17. return listResult.ok(list, page.getTotal());
    18. }

    OutUserInfo实体类

    1. package com.lezu.springboot.common.dto.out;
    2. import com.baomidou.mybatisplus.annotation.IdType;
    3. import com.baomidou.mybatisplus.annotation.TableId;
    4. import com.baomidou.mybatisplus.annotation.TableLogic;
    5. import io.swagger.annotations.ApiModelProperty;
    6. import lombok.AllArgsConstructor;
    7. import lombok.Data;
    8. import lombok.NoArgsConstructor;
    9. import java.io.Serializable;
    10. /**
    11. * @Author LianJiaYu
    12. * @Date 2021/4/4 22:06
    13. * @Version 1.0
    14. */
    15. @Data
    16. @AllArgsConstructor
    17. @NoArgsConstructor
    18. public class OutUserInfoDto implements Serializable {
    19. private static final long serialVersionUID = 6248490570574329534L;
    20. @ApiModelProperty(value = "主键id")
    21. @TableId(value = "id", type = IdType.AUTO)
    22. private Integer id;
    23. @ApiModelProperty(value = "用户账号")
    24. private String username;
    25. @ApiModelProperty(value = "性别")
    26. private String gender;
    27. @ApiModelProperty(value = "密码")
    28. private String password;
    29. @ApiModelProperty(value = "权限")
    30. private Integer power;
    31. @ApiModelProperty(value = "昵称")
    32. private String name;
    33. }

  • 相关阅读:
    使用Langchain+GPT+向量数据库chromadb 来创建文档对话机器人
    复杂数据统计与R语言程序设计实验一
    Python爬虫(8)
    RPC 接口测试技术 —— websocket 自动化测试实践!
    页表缓存(TLB)和巨型页的实现
    Playcanvas后处理-辉光bloom
    R语言计算累积异常收益率的统计显著性
    为什么标准AR HUD的FOV必须在10°×3°以上|技术科普
    我想问问DevEco的预览问题
    【高并发】从源码角度深度解析线程池是如何实现优雅退出的
  • 原文地址:https://blog.csdn.net/weixin_42169734/article/details/126870797