闽公网安备 35020302035485号
在项目中,常常会遇到从数据库读取数据后不能直接返回给前端展示的情况,因为还需要对字段进行加工,比如去除时间戳记录、隐藏敏感数据等。传统的处理方式是创建一个新类,然后编写大量的 get/set 方法进行赋值,若字段很多,这无疑是一场噩梦,而且还容易出现遗漏的情况。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<lombok.version>1.18.34</lombok.version>
<mapstruct.version>1.6.2</mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<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>provider</scope>
</dependency>
</dependencies>
org.mapstruct:mapstruct这个依赖是MapStruct的注解处理器(Annotation Processor)。在Java编译过程中,它会查找带有MapStruct注解(来自org.mapstruct:mapstruct库)的接口或抽象类。一旦找到这样的接口或抽象类,它会根据定义的映射关系(通过@Mapper、@Mapping等注解)生成具体的映射实现类。这个生成过程是在编译时进行的,生成的代码会被编译到最终的字节码中。
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private long id;
private String name;
private int age;
private String password;
private Date createTime;
}
import lombok.Data;
@Data
public class UserVO {
private Long id;
private String name;
private Integer age;
private String code;
private String hello;
private String createTime;
}
定义转换的mapperpackage com.zxy.demo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface UserMapper {
public static final UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
// 堆代码 duidaima.com
static String hello(User user) {
return "hello " + user.getName();
}
@Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss")
@Mapping(target = "code", expression="java(\"xx-\" + user.getId())")
@Mapping(target = "hello", expression = "java(UserMapper.hello(user))")
UserVO toUserVO(User user);
}
如果所有的字段都一样,用@Mappings({})。不一样的用target+source,需要特殊处理的可以用expression。在 MapStruct 中,expression是一个强大的功能,用于在对象映射过程中执行自定义的表达式。它允许开发人员在映射规则中使用 Java 表达式来处理复杂的映射逻辑,而不仅仅是简单的属性到属性的映射。
这在源对象和目标对象的属性之间存在复杂关系,或者需要进行额外的计算、逻辑判断等情况时非常有用。
package com.zxy.demo;
import java.util.Date;
import org.junit.Assert;
import org.junit.Test;
public class UserTest {
@Test
public void ok() {
User u = new User();
u.setId(1);
u.setAge(10);
u.setName("zxy");
u.setPassword("123456");
u.setCreateTime(new Date());
Assert.assertEquals(10, u.getAge());
Assert.assertEquals("zxy", u.getName());
System.out.println(new User(1, "zxy", 12, "123456", new Date()));
UserVO vo = UserMapper.INSTANCE.toUserVO(u);
System.out.println("vo: "+vo);
Assert.assertEquals("zxy", vo.getName());
Assert.assertEquals("xx-1", vo.getCode());
Assert.assertEquals("hello zxy", vo.getHello());
}
}
简单看一下生成的代码 // Source code is unavailable, and was generated by the Fernflower decompiler.
package com.zxy.demo;
import java.text.SimpleDateFormat;
// 堆代码 duidaima.com
public class UserMapperImpl implements UserMapper {
public UserVO toUserVO(User user) {
if (user == null) {
return null;
} else {
UserVO userVO = new UserVO();
if (user.getCreateTime() != null) {
userVO.setCreateTime((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(user.getCreateTime()));
}
userVO.setId(user.getId());
userVO.setName(user.getName());
userVO.setAge(user.getAge());
userVO.setCode("xx-" + user.getId());
userVO.setHello(UserMapper.hello(user));
return userVO;
}
}
}