豪门足球风云vivo账号登录版
972.64MB · 2025-12-03
平时我经常使用Hutool中的BeanUtil类来实现对象转换,用多了之后就发现有些缺点:
对于这些不足,MapStruct都能解决,不愧为一款功能强大的对象映射工具!
MapStruct是一款基于Java注解的对象属性映射工具,在Github上已经有7.5k+star。使用的时候我们只要在接口中定义好对象属性映射规则,它就能自动生成映射实现类,不使用反射,性能优秀,能实现各种复杂映射。
<dependency>
<!--MapStruct相关依赖-->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
Member;/**
* @auther macrozheng
* @description 购物会员
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Member {
private Long id;
private String username;
private String password;
private String nickname;
private Date birthday;
private String phone;
private String icon;
private Integer gender;
}
MemberDto,我们需要将Member对象转换为MemberDto对象;/**
* @auther macrozheng
* @description 购物会员Dto
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class MemberDto {
private Long id;
private String username;
private String password;
private String nickname;
//与PO类型不同的属性
private String birthday;
//与PO名称不同的属性
private String phoneNumber;
private String icon;
private Integer gender;
}
MemberMapper,实现同名同类型属性、不同名称属性、不同类型属性的映射;/**
* @auther macrozheng
* @description 会员对象映射
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper
public interface MemberMapper {
MemberMapper INSTANCE = Mappers.getMapper(MemberMapper.class);
@Mapping(source = "phone",target = "phoneNumber")
@Mapping(source = "birthday",target = "birthday",dateFormat = "yyyy-MM-dd")
MemberDto toDto(Member member);
}
INSTANCE实例调用转换方法toDto;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "基本映射")
@GetMapping("/baseMapping")
public CommonResult baseTest() {
List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
MemberDto memberDto = MemberMapper.INSTANCE.toDto(memberList.get(0));
return CommonResult.success(memberDto);
}
}
@Mapper和@Mapping等注解,在运行时生成接口的实现类,我们可以打开项目的target目录看下,可以和手写Getter、Setter说再见了!MemberMapper接口中添加toDtoList方法用于列表转换;/**
* @auther macrozheng
* @description 会员对象映射
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper
public interface MemberMapper {
@Mapping(source = "phone",target = "phoneNumber")
@Mapping(source = "birthday",target = "birthday",dateFormat = "yyyy-MM-dd")
List<MemberDto> toDtoList(List<Member> list);
}
INSTANCE实例调用转换方法toDtoList;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "集合映射")
@GetMapping("/collectionMapping")
public CommonResult collectionMapping() {
List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
List<MemberDto> memberDtoList = MemberMapper.INSTANCE.toDtoList(memberList);
return CommonResult.success(memberDtoList);
}
}
Order,嵌套有Member和Product对象;/**
* @auther macrozheng
* @description 订单
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Order {
private Long id;
private String orderSn;
private Date createTime;
private String receiverAddress;
private Member member;
private List<Product> productList;
}
OrderDto对象,OrderDto中包含MemberDto和ProductDto两个子对象同样需要转换;/**
* @auther macrozheng
* @description 订单Dto
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class OrderDto {
private Long id;
private String orderSn;
private Date createTime;
private String receiverAddress;
//子对象映射Dto
private MemberDto memberDto;
//子对象数组映射Dto
private List<ProductDto> productDtoList;
}
uses将子对象的转换Mapper注入进来,然后通过@Mapping设置好属性映射规则即可;/**
* @auther macrozheng
* @description 订单对象映射
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper(uses = {MemberMapper.class,ProductMapper.class})
public interface OrderMapper {
OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class);
@Mapping(source = "member",target = "memberDto")
@Mapping(source = "productList",target = "productDtoList")
OrderDto toDto(Order order);
}
INSTANCE实例调用转换方法toDto;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "子对象映射")
@GetMapping("/subMapping")
public CommonResult subMapping() {
List<Order> orderList = getOrderList();
OrderDto orderDto = OrderMapper.INSTANCE.toDto(orderList.get(0));
return CommonResult.success(orderDto);
}
}
Member和Order的部分属性映射到MemberOrderDto中去;/**
* @auther macrozheng
* @description 会员商品信息组合Dto
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class MemberOrderDto extends MemberDto{
private String orderSn;
private String receiverAddress;
}
toMemberOrderDto方法,这里需要注意的是由于参数中具有两个属性,需要通过参数名称.属性的名称来指定source来防止冲突(这两个参数中都有id属性);/**
* @auther macrozheng
* @description 会员对象映射
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper
public interface MemberMapper {
@Mapping(source = "member.phone",target = "phoneNumber")
@Mapping(source = "member.birthday",target = "birthday",dateFormat = "yyyy-MM-dd")
@Mapping(source = "member.id",target = "id")
@Mapping(source = "order.orderSn", target = "orderSn")
@Mapping(source = "order.receiverAddress", target = "receiverAddress")
MemberOrderDto toMemberOrderDto(Member member, Order order);
}
INSTANCE实例调用转换方法toMemberOrderDto;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "组合映射")
@GetMapping("/compositeMapping")
public CommonResult compositeMapping() {
List<Order> orderList = LocalJsonUtil.getListFromJson("json/orders.json", Order.class);
List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
Member member = memberList.get(0);
Order order = orderList.get(0);
MemberOrderDto memberOrderDto = MemberMapper.INSTANCE.toMemberOrderDto(member,order);
return CommonResult.success(memberOrderDto);
}
}
@Mapper注解的componentModel参数设置为spring即可,这样在生成接口实现类时,MapperStruct会为其添加@Component注解;/**
* @auther macrozheng
* @description 会员对象映射(依赖注入)
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper(componentModel = "spring")
public interface MemberSpringMapper {
@Mapping(source = "phone",target = "phoneNumber")
@Mapping(source = "birthday",target = "birthday",dateFormat = "yyyy-MM-dd")
MemberDto toDto(Member member);
}
@Autowired注解注入即可使用;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Autowired
private MemberSpringMapper memberSpringMapper;
@Operation(summary = "使用依赖注入")
@GetMapping("/springMapping")
public CommonResult springMapping() {
List<Member> memberList = LocalJsonUtil.getListFromJson("json/members.json", Member.class);
MemberDto memberDto = memberSpringMapper.toDto(memberList.get(0));
return CommonResult.success(memberDto);
}
}
/**
* @auther macrozheng
* @description 商品
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Product {
private Long id;
private String productSn;
private String name;
private String subTitle;
private String brandName;
private BigDecimal price;
private Integer count;
private Date createTime;
}
id属性设置为常量,count设置默认值为1,productSn设置为UUID生成;/**
* @auther macrozheng
* @description 商品Dto
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProductDto {
//使用常量
private Long id;
//使用表达式生成属性
private String productSn;
private String name;
private String subTitle;
private String brandName;
private BigDecimal price;
//使用默认值
private Integer count;
private Date createTime;
}
ProductMapper接口,通过@Mapping注解中的constant、defaultValue、expression设置好映射规则;/**
* @auther macrozheng
* @description 商品对象映射
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper(imports = {UUID.class})
public interface ProductMapper {
ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);
@Mapping(target = "id",constant = "-1L")
@Mapping(source = "count",target = "count",defaultValue = "1")
@Mapping(target = "productSn",expression = "java(UUID.randomUUID().toString())")
ProductDto toDto(Product product);
}
INSTANCE实例调用转换方法toDto;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Api(tags = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "使用常量、默认值和表达式")
@GetMapping("/defaultMapping")
public CommonResult defaultMapping() {
List<Product> productList = LocalJsonUtil.getListFromJson("json/products.json", Product.class);
Product product = productList.get(0);
product.setId(100L);
product.setCount(null);
ProductDto productDto = ProductMapper.INSTANCE.toDto(product);
return CommonResult.success(productDto);
}
}
ProductRoundMapper,通过@BeforeMapping注解自定义映射前操作,通过@AfterMapping注解自定义映射后操作;/**
* @auther macrozheng
* @description 商品对象映射(自定义处理)
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper(imports = {UUID.class})
public abstract class ProductRoundMapper {
public static ProductRoundMapper INSTANCE = Mappers.getMapper(ProductRoundMapper.class);
@Mapping(target = "id",constant = "-1L")
@Mapping(source = "count",target = "count",defaultValue = "1")
@Mapping(target = "productSn",expression = "java(UUID.randomUUID().toString())")
public abstract ProductDto toDto(Product product);
@BeforeMapping
public void beforeMapping(Product product){
//映射前当price<0时设置为0
if(product.getPrice().compareTo(BigDecimal.ZERO)<0){
product.setPrice(BigDecimal.ZERO);
}
}
@AfterMapping
public void afterMapping(@MappingTarget ProductDto productDto){
//映射后设置当前时间为createTime
productDto.setCreateTime(new Date());
}
}
INSTANCE实例调用转换方法toDto;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "在映射前后进行自定义处理")
@GetMapping("/customRoundMapping")
public CommonResult customRoundMapping() {
List<Product> productList = LocalJsonUtil.getListFromJson("json/products.json", Product.class);
Product product = productList.get(0);
product.setPrice(new BigDecimal(-1));
ProductDto productDto = ProductRoundMapper.INSTANCE.toDto(product);
return CommonResult.success(productDto);
}
}
/**
* @auther macrozheng
* @description 商品验证异常类
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
public class ProductValidatorException extends Exception{
public ProductValidatorException(String message) {
super(message);
}
}
price设置小于0时抛出我们自定义的异常;/**
* @auther macrozheng
* @description 商品验证异常处理器
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
public class ProductValidator {
public BigDecimal validatePrice(BigDecimal price) throws ProductValidatorException {
if(price.compareTo(BigDecimal.ZERO)<0){
throw new ProductValidatorException("价格不能小于0!");
}
return price;
}
}
@Mapper注解的uses属性运用验证类;/**
* @auther macrozheng
* @description 商品对象映射(处理映射异常)
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@Mapper(uses = {ProductValidator.class},imports = {UUID.class})
public interface ProductExceptionMapper {
ProductExceptionMapper INSTANCE = Mappers.getMapper(ProductExceptionMapper.class);
@Mapping(target = "id",constant = "-1L")
@Mapping(source = "count",target = "count",defaultValue = "1")
@Mapping(target = "productSn",expression = "java(UUID.randomUUID().toString())")
ProductDto toDto(Product product) throws ProductValidatorException;
}
price为-1,此时在进行映射时会抛出异常;/**
* @auther macrozheng
* @description MapStruct对象转换测试Controller
* @date 2025/8/22
* @github https://*g*i*thub.com/macrozheng
*/
@RestController
@Tag(name = "MapStructController", description = "MapStruct对象转换测试")
@RequestMapping("/mapStruct")
public class MapStructController {
@Operation(summary = "处理映射异常")
@GetMapping("/exceptionMapping")
public CommonResult exceptionMapping() {
List<Product> productList = LocalJsonUtil.getListFromJson("json/products.json", Product.class);
Product product = productList.get(0);
product.setPrice(new BigDecimal(-1));
ProductDto productDto = null;
try {
productDto = ProductExceptionMapper.INSTANCE.toDto(product);
} catch (ProductValidatorException e) {
e.printStackTrace();
}
return CommonResult.success(productDto);
}
}
通过上面对MapStruct的使用体验,我们可以发现MapStruct远比BeanUtils要强大。当我们想实现比较复杂的对象映射时,通过它可以省去写Getter、Setter方法的过程。 当然上面只是介绍了MapStruct的一些常用功能,它的功能远不止于此,感兴趣的朋友可以研究下。
github.com/mapstruct/m…
github.com/macrozheng/…