Umwandlung von Entität in DTO für eine Spring-REST-API

Entity To DTO-Konvertierung für eine Spring REST-API

1. Überblick

In diesem Lernprogramm werden die Konvertierungen behandelt, diebetween the internal entities of a Spring application and the external DTOs (Datenübertragungsobjekte) ausführen müssen, die wieder auf dem Client veröffentlicht werden.

Weitere Lektüre:

Eine Anleitung zum Mappen mit Dozer

Dozer ist ein Java Bean to Java Bean-Mapper, der Daten von einem Objekt in ein anderes kopiert, Attribut für Attribut, die Zuordnung zwischen Attributnamen, die Typkonvertierung und viele andere Dinge unterstützt.

Read more

Kurzanleitung zu MapStruct

Eine schnelle und praktische Anleitung zur Verwendung von MapStruct

Read more

2. Model Mapper

Beginnen wir mit der Einführung der Hauptbibliothek, die wir für diese Entity-DTO-Konvertierung verwenden werden -ModelMapper.

Wir benötigen diese Abhängigkeit inpom.xml:


    org.modelmapper
    modelmapper
    2.3.2

go here, um zu überprüfen, ob es eine neuere Version dieser Bibliothek gibt.

Anschließend definieren wir dieModelMapper-Bean in unserer Spring-Konfiguration:

@Bean
public ModelMapper modelMapper() {
    return new ModelMapper();
}

3. Der DTO

Als nächstes stellen wir die DTO-Seite dieses zweiseitigen Problems vor -Post DTO:

public class PostDto {
    private static final SimpleDateFormat dateFormat
      = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    private Long id;

    private String title;

    private String url;

    private String date;

    private UserDto user;

    public Date getSubmissionDateConverted(String timezone) throws ParseException {
        dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
        return dateFormat.parse(this.date);
    }

    public void setSubmissionDate(Date date, String timezone) {
        dateFormat.setTimeZone(TimeZone.getTimeZone(timezone));
        this.date = dateFormat.format(date);
    }

    // standard getters and setters
}

Beachten Sie, dass die 2 benutzerdefinierten datumsbezogenen Methoden die Datumskonvertierung zwischen dem Client und dem Server durchführen:

  • Die Methode vongetSubmissionDateConverted()konvertiert die Datumszeichenfolge in ein Datum in der Zeitzone des Servers, um sie in der persistierenden Post-Entität zu verwenden

  • Die Methode vonsetSubmissionDate()besteht darin, das DTO-Datum in der aktuellen Benutzerzeitzone auf das Datum des Beitrags zu setzen.

4. Die Serviceschicht

Betrachten wir nun eine Service Level-Operation, die offensichtlich mit der Entität (nicht mit dem DTO) funktioniert:

public List getPostsList(
  int page, int size, String sortDir, String sort) {

    PageRequest pageReq
     = PageRequest.of(page, size, Sort.Direction.fromString(sortDir), sort);

    Page posts = postRepository
      .findByUser(userService.getCurrentUser(), pageReq);
    return posts.getContent();
}

Wir werden uns als nächstes die Ebene über dem Dienst ansehen - die Controller-Ebene. Hier wird die Konvertierung auch tatsächlich stattfinden.

5. Die Controller-Schicht

Schauen wir uns nun eine Standard-Controller-Implementierung an, die die einfache REST-API für die RessourcePostverfügbar macht.

Wir werden hier einige einfache CRUD-Operationen zeigen: Erstellen, Aktualisieren, Abrufen einer und Abrufen aller. Und da die Operationen ziemlich einfach sind,we are especially interested in the Entity-DTO conversion aspects:

@Controller
class PostRestController {

    @Autowired
    private IPostService postService;

    @Autowired
    private IUserService userService;

    @Autowired
    private ModelMapper modelMapper;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List getPosts(...) {
        //...
        List posts = postService.getPostsList(page, size, sortDir, sort);
        return posts.stream()
          .map(post -> convertToDto(post))
          .collect(Collectors.toList());
    }

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    public PostDto createPost(@RequestBody PostDto postDto) {
        Post post = convertToEntity(postDto);
        Post postCreated = postService.createPost(post));
        return convertToDto(postCreated);
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public PostDto getPost(@PathVariable("id") Long id) {
        return convertToDto(postService.getPostById(id));
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.OK)
    public void updatePost(@RequestBody PostDto postDto) {
        Post post = convertToEntity(postDto);
        postService.updatePost(post);
    }
}

Und hier istour conversion from Post entity to PostDto:

private PostDto convertToDto(Post post) {
    PostDto postDto = modelMapper.map(post, PostDto.class);
    postDto.setSubmissionDate(post.getSubmissionDate(),
        userService.getCurrentUser().getPreference().getTimezone());
    return postDto;
}

Und hier ist die Umrechnungfrom DTO to an entity:

private Post convertToEntity(PostDto postDto) throws ParseException {
    Post post = modelMapper.map(postDto, Post.class);
    post.setSubmissionDate(postDto.getSubmissionDateConverted(
      userService.getCurrentUser().getPreference().getTimezone()));

    if (postDto.getId() != null) {
        Post oldPost = postService.getPostById(postDto.getId());
        post.setRedditID(oldPost.getRedditID());
        post.setSent(oldPost.isSent());
    }
    return post;
}

Wie Sie sehen können, verwenden wir mit Hilfe des Modell-Mappersthe conversion logic is quick and simple - wir verwenden diemap-API des Mappers und konvertieren die Daten, ohne eine einzige Zeile Konvertierungslogik zu schreiben.

6. Unit Testing

Lassen Sie uns abschließend einen sehr einfachen Test durchführen, um sicherzustellen, dass die Konvertierungen zwischen der Entität und dem DTO gut funktionieren:

public class PostDtoUnitTest {

    private ModelMapper modelMapper = new ModelMapper();

    @Test
    public void whenConvertPostEntityToPostDto_thenCorrect() {
        Post post = new Post();
        post.setId(Long.valueOf(1));
        post.setTitle(randomAlphabetic(6));
        post.setUrl("www.test.com");

        PostDto postDto = modelMapper.map(post, PostDto.class);
        assertEquals(post.getId(), postDto.getId());
        assertEquals(post.getTitle(), postDto.getTitle());
        assertEquals(post.getUrl(), postDto.getUrl());
    }

    @Test
    public void whenConvertPostDtoToPostEntity_thenCorrect() {
        PostDto postDto = new PostDto();
        postDto.setId(Long.valueOf(1));
        postDto.setTitle(randomAlphabetic(6));
        postDto.setUrl("www.test.com");

        Post post = modelMapper.map(postDto, Post.class);
        assertEquals(postDto.getId(), post.getId());
        assertEquals(postDto.getTitle(), post.getTitle());
        assertEquals(postDto.getUrl(), post.getUrl());
    }
}

7. Fazit

Dies war ein Artikel übersimplifying the conversion from Entity to DTO and from DTO to Entity in a Spring REST API, in dem die Modell-Mapper-Bibliothek verwendet wurde, anstatt diese Konvertierungen von Hand zu schreiben.

Der vollständige Quellcode für die Beispiele ist inGitHub project verfügbar.