使用mapstruct_使用MapStruct自动化代码,告别手动书写DTO,VO和PO

本文介绍了如何使用MapStruct这个Java注释处理器在Spring Boot应用中自动化转换Java Bean,减少手动编写DTO、VO和PO的工作。通过示例展示了MapStruct的配置、实体和DTO的创建、映射器接口的定义以及测试,揭示了MapStruct如何简化对象映射并提高代码质量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通常,我们需要将域模型转换为DTO(数据传输对象),反之亦然。将数据传输到前端或远程接口时,这是必需的。手动处理复杂的映射变得很麻烦,并可能导致错误。

3b69f9369beecde0c77adadea1c31b6f.png

在本文中,我想介绍MapStruct,这是一个Java注释处理器,可以在编译时为Java bean生成映射器实现。它使用简单的Java方法调用来映射对象,并且不涉及任何反射或运行时处理。

我将引导您完成将MapStruct集成到Spring Boot应用程序中的步骤。

Maven依赖

让我们创建一个示例Spring Boot应用程序,并在pom.xml中添加MapStruct及其处理器依赖性。

所述mapstruct处理器用于在编译期间产生映射器实现。

org.mapstruct

mapstruct-jdk8

1.3.0.Final

org.mapstruct

mapstruct-processor

1.3.0.Final

provided

创建JPA实体和DTO

让我们创建两个实体Library和Book。

所述mapstruct处理器用于在编译期间产生映射器实现。

package

com.swathisprasad.mapstruct.dao.entity;

import lombok.Data;

import lombok.EqualsAndHashCode;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import javax.validation.constraints.NotNull;

import java.io.Serializable;

import java.util.ArrayList;

import java.util.List;

import java.util.UUID;

@Data

@EqualsAndHashCode

@Entitypublic

class Library implements Serializable {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue (generator = "uuid")

@GenericGenerator (name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")

@Column (name = "id", updatable = false, nullable = false)

private UUID id;

@NotNull

@Column (name = "name", nullable = false)

private String name;

@EqualsAndHashCode.Exclude

@OneToMany(mappedBy = "library", cascade = CascadeType.ALL, fetch = FetchType.LAZY)

private List books = new ArrayList<>();}

package com.swathisprasad.mapstruct.dao.entity;

import lombok.Data;

import lombok.EqualsAndHashCode;

import lombok.ToString;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

import javax.validation.constraints.NotNull;

import java.io.Serializable;

import java.time.LocalDateTime;

import java.util.UUID;

@Data

@EqualsAndHashCode

@Entitypublic

class Book implements Serializable {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue (generator="uuid")

@GenericGenerator (name="uuid", strategy="org.hibernate.id.UUIDGenerator")

@Column (name="id", updatable=false, nullable=false)

private UUID id;

@NotNull

@Column (name="name", nullable=false)

private String name;

@NotNull

@Column (name="author", nullable=false)

private String author;

@NotNull

@Column (name="published_date", nullable=false)

private LocalDateTime publishedDate;

@EqualsAndHashCode.Exclude

@ToString.Exclude

@ManyToOne(optional=false)

@JoinColumn (name="library_id", nullable=false)

private Library library;

}

在这里,我们在Library和Book之间存在一对多的双向关系。另外,我在项目中添加了Lombok,以避免在实体类中编写样板代码,例如getter,setter,hashCode()和Equals()。

让我们创建相应的DTO类。

package com.swathisprasad.mapstruct.dto;

import lombok.Data;

import javax.validation.constraints.NotNull;

import java.io.Serializable;

import java.util.ArrayList;

import java.util.List;

import java.util.UUID;

@Datapublic class LibraryDTO implements Serializable {

private UUID id;

@NotNull

private String name;

@NotNull

private List bookDTOs = new ArrayList<>();

}

package com.swathisprasad.mapstruct.dto;

import lombok.Data;

import javax.validation.constraints.NotNull;

import java.io.Serializable;

import java.time.LocalDateTime;

import java.util.UUID;

@Datapublic

class BookDTO implements Serializable{

private UUID id;

@NotNull

private String name;

@NotNull

private String author;

@NotNull

private LocalDateTime publishedDate;

private UUID libraryId;

}

Bean Mappers

现在,我们将创建使用MapStruct的映射器接口。

package com.swathisprasad.mapstruct.dto.mapper;

import com.swathisprasad.mapstruct.dao.entity.Library;

import com.swathisprasad.mapstruct.dto.LibraryDTO;

import org.mapstruct.Mapper;import org.mapstruct.Mapping;

import java.util.UUID;

@Mapper(componentModel = "spring", uses = {BookMapper.class})

public interface LibraryMapper extends IEntityMapper {

@Mapping(source = "books", target = "bookDTOs")

LibraryDTO toDto(final Library library);

Library toEntity(final LibraryDTO libraryDTO);

default Library fromId(final UUID id) {

if (id == null) {

return null;

}

final Library library=new Library();

library.setId(id);

return library;

}

正如您在此处注意到的那样,由于MapStruct为我们生成了代码,因此我们没有编写任何实现。映射器接口必须使用@Mapper注释进行注释。在这里,componentModel属性生成了一个单例作用域的Spring bean映射器,可以在需要时直接注入它。由于我们已经定义了Library和Book之间的一对多关系,因此我们需要映射子对象(即Book对象的列表),因此可以通过uses属性注入其他BookMapper。

我们告诉Mapstruct映射一对多关系中的子对象,即在本例中通过@Mapping注释进行预订。

package com.swathisprasad.mapstruct.dto.mapper;

import com.swathisprasad.mapstruct.dao.entity.Book;

import com.swathisprasad.mapstruct.dto.BookDTO;

import org.mapstruct.Mapper;

import org.mapstruct.Mapping;

import java.util.List;import java.util.UUID;

@Mapper(componentModel = "spring", uses = {LibraryMapper.class})

public interface BookMapper extends IEntityMapper {

@Mapping(source="library.id", target="libraryId")

BookDTO toDto(final Book book);

List toDto(final List book);

@Mapping(source="libraryId", target="library")

Book toEntity(final BookDTO bookDTO);

List toEntity(final List bookDTOs);

default Book fromId(final UUID id) {

if (id == null) {

return null;

}

final Book book=new Book();

book.setId(id);

return book;

}}

我们可以执行mvn clean install或mvn clean verify来触发MapStruct处理,这将在/ target / generate-sources / annotations /下生成实现类。

测试映射器接口

让我们为Library和Book创建JPA存储库。

package com.swathisprasad.mapstruct.dao.repository;

import com.swathisprasad.mapstruct.dao.entity.Library;

import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repositorypublic

interface ILibraryRepository extends JpaRepository {}

package com.swathisprasad.mapstruct.dao.repository;

import com.swathisprasad.mapstruct.dao.entity.Book;

import org.springframework.data.jpa.repository.JpaRepository;

import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repositorypublic interface IBookRepository extends JpaRepository {}

创建一个LibraryService以将Library和Book实体保存在数据库中。

package com.swathisprasad.mapstruct.service;

import com.swathisprasad.mapstruct.dao.entity.Book;

import com.swathisprasad.mapstruct.dao.entity.Library;

import com.swathisprasad.mapstruct.dao.repository.IBookRepository;

import com.swathisprasad.mapstruct.dao.repository.ILibraryRepository;

import com.swathisprasad.mapstruct.dto.LibraryDTO;

import com.swathisprasad.mapstruct.dto.mapper.BookMapper;

import com.swathisprasad.mapstruct.dto.mapper.LibraryMapper;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;

import java.util.List;

@Service

@Transactionalpublic

class LibraryService {

private final ILibraryRepository libraryRepository;

private final IBookRepository bookRepository;

private final LibraryMapper libraryMapper;

private final BookMapper bookMapper;

public LibraryService(final ILibraryRepository libraryRepository, final IBookRepository bookRepository,final LibraryMapper libraryMapper, final BookMapper bookMapper) {

this.libraryRepository = libraryRepository;this.bookRepository = bookRepository;this.libraryMapper = libraryMapper;

this.bookMapper = bookMapper;

}

public LibraryDTO save(final LibraryDTO libraryDTO) {

final Library library = libraryMapper.toEntity(libraryDTO);

final Library createdLibrary = libraryRepository.save(library);

final List books = new ArrayList<>();

libraryDTO.getBookDTOs().forEach(bookDTO -> {

final Book book = bookMapper.toEntity(bookDTO);

book.setLibrary(createdLibrary);

books.add(book);

});

createdLibrary.setBooks(books);

bookRepository.saveAll(books);

return libraryMapper.toDto(createdLibrary);

}}

这是测试用例:

package com.swathisprasad.mapstruct.service;

import com.swathisprasad.mapstruct.Application;

import com.swathisprasad.mapstruct.dto.BookDTO;

import com.swathisprasad.mapstruct.dto.LibraryDTO;

import org.junit.jupiter.api.Test;

import org.junit.jupiter.api.extension.ExtendWith;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.time.LocalDateTime;

import java.util.ArrayList;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith (SpringExtension.class)

@SpringBootTest (classes = Application.class)public class LibraryServiceTest{

@Autowiredprivate LibraryService libraryService;

@Testpublic void saveLibrary()

{

final LibraryDTO libraryDTO=new LibraryDTO();

libraryDTO.setName("Library");

final List books=new ArrayList<>();

final BookDTO book1=new BookDTO();

book1.setName("Book1");

book1.setAuthor("Author1");

book1.setPublishedDate(LocalDateTime.now());

books.add(book1);

final BookDTO book2=new BookDTO();

book2.setName("Book2");

book2.setAuthor("Author2");

book2.setPublishedDate(LocalDateTime.now().minusDays(10));

books.add(book2);

libraryDTO.setBookDTOs(books);

final LibraryDTO createdLibraryDTO = libraryService.save(libraryDTO);

final List createdBooks=createdLibraryDTO.getBookDTOs();

assertThat(createdBooks).hasSize(2);

createdBooks.forEach(bookDTO -> assertThat(bookDTO.getLibraryId()).isEqualTo(createdLibraryDTO.getId()));

}}

结论

旨在通过使其尽可能自动化来简化工作。本文只是介绍了MapStruct的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值