它是什么?
MapStruct 是一个代码生成器,它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现。
生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。
为什么?
多层应用程序通常需要在不同的对象模型(例如实体和 DTO)之间进行映射。编写这样的映射代码是一项乏味且容易出错的任务。MapStruct 旨在通过尽可能地自动化来简化这项工作。
与其他映射框架相比,MapStruct 在编译时生成 bean 映射,这确保了高性能,允许快速的开发人员反馈和彻底的错误检查。
如何?
MapStruct 是一个注解处理器,它插入到 Java 编译器中,可用于命令行构建(Maven、Gradle 等)以及您首选的 IDE。
MapStruct 使用合理的默认值,但在配置或实现特殊行为时会采取措施。
使用场景:
1、数据库中的字段和你对接的A部门、B部门的入参字段不一致的情况。
2、涉及到一些入参和出参值的转换 比如:性别、日期等。
使用教程
1、引入pom.xml
<!--mapStruct依赖-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.1.Final</version>
<scope>provided</scope>
</dependency>
2、入参(每个部门的入参可能不太一样)
package com.lezu.springboot.common.dto.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author LianJiaYu
* @date 2022/9/1 14:09
*/
@Data
public class UserInfoParam {
@ApiModelProperty(value = "用户账号")
private String account;
@ApiModelProperty(value = "性别")
private String gender;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "出生日期")
private Long birthday;
@ApiModelProperty(value = "验证码captchaId")
private String captchaId;
@ApiModelProperty(value = "昵称")
private String name;
@ApiModelProperty(value = "验证码")
private String code;
}
3、对应数据库中的字段
package com.lezu.springboot.common.dto.in;
import com.lezu.springboot.common.Page;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Date;
/**
* @Author LianJiaYu
* @Date 2021/4/4 22:06
* @Version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InUserInfoDto extends Page implements Serializable {
private static final long serialVersionUID = 5755742614532104337L;
@ApiModelProperty(value = "用户账号")
@NotNull(message = "用户名不能为空")
private String username;
@ApiModelProperty(value = "性别")
private Integer gender;
@ApiModelProperty(value = "密码")
@NotNull(message = "密码不能为空")
private String password;
@ApiModelProperty(value = "出生日期")
private Date birthday;
@ApiModelProperty(value = "验证码captchaId")
private String captchaId;
@ApiModelProperty(value = "昵称")
private String name;
@ApiModelProperty(value = "验证码")
private String code;
@ApiModelProperty(value = "默认状态")
private String defaultStatus;
}
3、定义工厂
package com.lezu.springboot.common.dto.Interface;
import com.lezu.springboot.common.ListResult;
import com.lezu.springboot.common.conversion.DataConversionWorker;
import com.lezu.springboot.common.conversion.EnumConversionWorker;
import com.lezu.springboot.common.dto.in.InUserInfoDto;
import com.lezu.springboot.common.dto.out.OutUserInfoDto;
import com.lezu.springboot.common.dto.param.UserInfoParam;
import com.lezu.springboot.common.dto.result.UserInfoResult;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* @author LianJiaYu
* @date 2022/9/1 14:04
*/
@Mapper(uses = {DataConversionWorker.class, EnumConversionWorker.class})
public interface UserConvert {
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
//入参转换
@Mappings({
@Mapping(source = "account", target = "username"),
@Mapping(source = "gender", target = "gender", qualifiedByName = "setGenderToInteger"),
@Mapping(source = "birthday", target = "birthday", qualifiedByName = "getBirthdayToDate"),
@Mapping(target = "defaultStatus", defaultValue = "success"),
})
InUserInfoDto userInfoConvert(UserInfoParam param);
//出参转换
@Mappings({
@Mapping(source = "username", target = "account"),
@Mapping(source = "gender", target = "gender", qualifiedByName = "setGenderToString"),
@Mapping(source = "birthday", target = "birthday", qualifiedByName = "getBirthdayToLong"),
})
UserInfoResult userInfoResultConvert(OutUserInfoDto dto);
ListResult<UserInfoResult> listUserInfoResultConvert(ListResult<OutUserInfoDto> list);
}
定义时间戳转换日期和日期转时间戳方法
package com.lezu.springboot.common.conversion;
import cn.hutool.core.date.DateUtil;
import org.mapstruct.Named;
import java.util.Date;
/**
* @author LianJiaYu
* @date 2022/9/2 15:08
*/
//@Component
public class DataConversionWorker {
@Named("getBirthdayToDate")
public Date getBirthdayToDate(Long birthday) {
if (birthday == null) {
return null;
}
return DateUtil.date(birthday);
}
@Named("getBirthdayToLong")
public Long getBirthdayToLong(Date birthday) {
if (birthday == null) {
return null;
}
return birthday.getTime();
}
}
定义性别转换方法
package com.lezu.springboot.common.conversion;
import com.lezu.springboot.enums.UserGenderEnum;
import org.mapstruct.Named;
import org.springframework.stereotype.Component;
/**
* @author LianJiaYu
* @date 2022/9/2 15:08
*/
//@Component
public class EnumConversionWorker {
@Named("setGenderToInteger")
public Integer setGenderToInteger(String type) {
return UserGenderEnum.getByType(type).getCode();
}
@Named("setGenderToString")
public Integer setGenderToString(Integer code) {
return UserGenderEnum.getByCode(code).getCode();
}
}
性别转换枚举
package com.lezu.springboot.enums;
/**
* @author LianJiaYu
* @date 2022/9/16 10:10
*/
public enum UserGenderEnum {
FEMALE(0, "female"),
MALE(1, "male"),
UNKNOWN(2, "unknown"),
;
private Integer code;
private String type;
UserGenderEnum(Integer code, String type) {
this.code = code;
this.type = type;
}
public Integer getCode() {
return code;
}
public String getType() {
return type;
}
public static UserGenderEnum getByCode(Integer code) {
for (UserGenderEnum v : UserGenderEnum.values()) {
if (v.getCode() == code) {
return v;
}
}
return UNKNOWN;
}
public static UserGenderEnum getByType(String type) {
for (UserGenderEnum v : UserGenderEnum.values()) {
if (v.getType().equals(type)) {
return v;
}
}
return UNKNOWN;
}
}
编写Controller代码进行测试
package com.lezu.springboot.controller;
import com.alibaba.fastjson.JSON;
import com.lezu.springboot.common.ListResult;
import com.lezu.springboot.common.dto.Interface.UserConvert;
import com.lezu.springboot.common.dto.in.InUserInfoDto;
import com.lezu.springboot.common.dto.param.UserInfoParam;
import com.lezu.springboot.common.dto.result.UserInfoResult;
import com.lezu.springboot.enums.ResultEnum;
import com.lezu.springboot.service.UserInfoHandleService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;
/**
* 高性能实体类转换工具MapStruct
* 类型转换工具
* @author LianJiaYu
* @date 2022/9/1 13:57
*/
@RestController
@RequestMapping("/mapstruct")
@Slf4j
public class MapstructController {
@Autowired
private UserInfoHandleService userInfoHandleService;
@ApiOperation("类型转换")
@PostMapping("/login")
public ListResult<UserInfoResult> login(UserInfoParam params) {
ListResult listResult = new ListResult();
if (Objects.isNull(params)) {
return listResult.build(ResultEnum.PARAM_ERROR.getCode(), ResultEnum.PARAM_ERROR.getMsg());
}
//入参-日志
log.info("params:" + JSON.toJSONString(params));
//入参-参数转换
InUserInfoDto inDto = UserConvert.INSTANCE.userInfoConvert(params);
log.info("inDto:" + JSON.toJSONString(inDto));
//出参-参数转换
listResult = UserConvert.INSTANCE.outDtoToResult(userInfoHandleService.listByPage(inDto));
log.info("listResult:" + JSON.toJSONString(listResult));
return listResult;
}
}
Service层
@Override
public ListResult listByPage(InUserInfoDto inDto) {
ListResult listResult = new ListResult();
LambdaQueryWrapper<UserInfo> wrapper = Wrappers.lambdaQuery();
if (StrUtil.isNotBlank(inDto.getUsername())) {
wrapper.like(UserInfo::getUsername, inDto.getUsername());
}
int pageNum = inDto.getPageNum();
int pageSize = inDto.getPageSize() == 0 ? 10 : inDto.getPageSize();
IPage<UserInfo> page = new Page<>(pageNum, pageSize);
userInfoService.page(page, wrapper);
List<OutUserInfoDto> list = page.getRecords().stream().map(v -> {
OutUserInfoDto dto = new OutUserInfoDto();
BeanUtils.copyProperties(v, dto);
return dto;
}).collect(Collectors.toList());
return listResult.ok(list, page.getTotal());
}
OutUserInfo实体类
package com.lezu.springboot.common.dto.out;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Author LianJiaYu
* @Date 2021/4/4 22:06
* @Version 1.0
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OutUserInfoDto implements Serializable {
private static final long serialVersionUID = 6248490570574329534L;
@ApiModelProperty(value = "主键id")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "用户账号")
private String username;
@ApiModelProperty(value = "性别")
private String gender;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "权限")
private Integer power;
@ApiModelProperty(value = "昵称")
private String name;
}