项目开发的时候,页面发送的数据结构和数据库表的结构很多时候并不一致,我们通常会写 DTO 对象
那么 DTO 和 DAO 相互转换的时候,需要我们手动调用 set 方法,请注意下面用了 lombok 来生成代码
import lombok.Data;
@Data
public class StudentDto {
private String userName;
private String userId;
private String address;
private String school;
private int age;
private String email;
}
//==============================================================
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Student {
private String userName;
private String userId;
private String address;
private String school;
private int age;
private String emailAddress;
public Student(){}
public Student(String userName, String userId, String address, String school, int age, String emailAddress) {
this.userName = userName;
this.userId = userId;
this.address = address;
this.school = school;
this.age = age;
this.emailAddress = emailAddress;
}
}
我们手动调用 set 方法来传递数据
Student vo = new Student();
vo.setUserId("A123");
vo.setUserName("Jack");
StudentDto dto = new StudentDto();
dto.setUserId( vo.getUserId() );
dto.setUserName( vo.getUserName() );
.....
这种代码低效,我们就想者能不能写个工具,帮助我们复制数据,于是就有了 MapStruct
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
<version>1.4.2.Finalversion>
dependency>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstructartifactId>
<version>1.4.2.Finalversion>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombok-mapstruct-bindingartifactId>
<version>0.2.0version>
dependency>
import org.mapstruct.Mapper;
import org.merlin.project.cloudhospital.bean.Student;
import org.merlin.project.cloudhospital.dto.StudentDto;
@Mapper
public interface StudentConvert {
StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
Student convertStudent(StudentDto studentDto);
StudentDto convertStudentDTO(Student student);
}
下面这段代码测试时请注意,2个类都有使用 lombok 生成方法,默认和 MapStruct 是有冲突的,所以POM一定要引入 lombok-mapstruct-binding。这样测试就是正常的
@Test
void testSimpleMap() {
StudentVo studentVo = StudentVo.builder()
.school("郑州大学")
.userId("A369")
.userName("张三")
.age(99)
.address("郑州")
.build();
StudentDto studentDto = mainMapper.studentVo2Dto(studentVo);
System.out.println(studentDto);
}
studenVo和studenDto 有email 和emailAddress 字段不一致,可以通过 @Mapping 解决
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.merlin.project.cloudhospital.bean.Student;
import org.merlin.project.cloudhospital.dto.StudentDto;
@Mapper
public interface StudentConvert {
StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
@Mapping(source = "email" , target = "emailAddress")
Student convertStudent(StudentDto studentDto);
@Mapping(source = "emailAddress" , target = "email")
StudentDto convertStudentDTO(Student student);
}
Student student = Student.builder().userId("123").userName("Jack").emailAddress("[email protected]").build();
Student student2 = Student.builder().userId("222").userName("张三").emailAddress("[email protected]").build();
List<Student> list = List.of(student, student2);
List<StudentDto> studentDtos = StudentConvert.INSTANCE.convertStudentDTOList(list);
studentDtos.forEach( studentDto -> System.out.println(studentDto));
新增类 Grade
@Data
public class Grade {
private Integer gradeId;
private String gradeName;
}
修改 Student
@Data
@Builder
public class Student {
private String userName;
private String userId;
private String address;
private String school;
private int age;
private String emailAddress;
private Grade grade;
private List<Grade> grades = new ArrayList<>();
public Student(){}
public Student(String userName, String userId, String address, String school, int age, String emailAddress, Grade grade, List<Grade> grades) {
this.userName = userName;
this.userId = userId;
this.address = address;
this.school = school;
this.age = age;
this.emailAddress = emailAddress;
this.grade = grade;
this.grades = grades;
}
}
修改 StudentDTO
@Data
public class StudentDto {
private String userName;
private String userId;
private String address;
private String school;
private int age;
private String email;
private Grade grade;
private List<Grade> grades = new ArrayList<>();
}
修改 StudentConvert
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import org.merlin.project.cloudhospital.bean.Grade;
import org.merlin.project.cloudhospital.bean.Student;
import org.merlin.project.cloudhospital.dto.StudentDto;
import java.util.List;
@Mapper
public interface StudentConvert {
StudentConvert INSTANCE = Mappers.getMapper(StudentConvert.class);
@Mapping(source = "email" , target = "emailAddress")
Student convertStudent(StudentDto studentDto);
/**
* 当出现多个相同参数和返回值的方法,我们需要为方法提供标识,以供 MapStruct 能够明白调用那个方法
* @param student
* @return
*/
@Named("one")
@Mapping(source = "emailAddress" , target = "email")
StudentDto convertStudentDTO(Student student);
List<StudentDto> convertStudentListDTO(List<Student> students);
@Named("two")
@Mapping(source = "emailAddress" , target = "email")
default StudentDto convertStudentExtDTO(Student student) {
if( student == null) {
return null;
}
StudentDto studentDto = convertStudentDTO(student);
studentDto.setGrade( student.getGrade() );
List<Grade> grades = student.getGrades();
studentDto.setGrades( grades );
return studentDto;
}
}
测试
@Test
void contextLoads() {
Student student = Student.builder().userId("123").userName("Jack").emailAddress("[email protected]").build();
Grade g1 = new Grade();
g1.setGradeId(1);
g1.setGradeName("一年级");
Grade g2 = new Grade();
g2.setGradeId(2);
g2.setGradeName("2年级");
List<Grade> gradeList = List.of(g1, g2);
student.setGrades( gradeList );
student.setGrade(g1);
StudentDto studentDto =
StudentConvert.INSTANCE.convertStudentExtDTO(student);
System.out.println(studentDto);
}