Рубрики
Без рубрики

Преобразование сущности в DTO для API Spring REST

Как упростить преобразование сущностей в DTOS и обратно в API Spring REST.

Автор оригинала: baeldung.

1. Обзор

В этом руководстве мы рассмотрим преобразования, которые должны произойти между внутренними сущностями приложения Spring и внешними DTO (объектами передачи данных), которые публикуются обратно клиенту.

Дальнейшее чтение:

Аннотации Spring’s RequestBody и ResponseBody

Краткое руководство по MapStruct

2. Картограф моделей

Давайте начнем с представления основной библиотеки, которую мы собираемся использовать для выполнения этого преобразования entity-DTO, ModelMapper .

Нам понадобится эта зависимость в pom.xml :


    org.modelmapper
    modelmapper
    2.3.5

Чтобы проверить, есть ли какая-либо более новая версия этой библиотеки, перейдите сюда .

Затем мы определим ModelMapper bean в нашей весенней конфигурации:

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

3. DTO

Далее давайте представим ВЕРХНЮЮ сторону этой двусторонней проблемы, Post TO:

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
}

Обратите внимание, что два пользовательских метода, связанных с датой, обрабатывают преобразование данных между клиентом и сервером:

  • get Submission Date Converted() метод преобразует дату Строку в Дату в часовом поясе сервера, чтобы использовать ее в сохраняющейся Post сущности
  • установить дату отправки() метод состоит в том, чтобы установить данные DTO в Post ‘s Date в текущем часовом поясе пользователя

4. Уровень Обслуживания

Теперь давайте рассмотрим операцию уровня обслуживания, которая, очевидно, будет работать с сущностью (а не с):

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();
}

Далее мы рассмотрим слой над сервисом, уровень контроллера. Именно здесь на самом деле произойдет преобразование.

5. Уровень Контроллера

Далее давайте рассмотрим стандартную реализацию контроллера, раскрывающую простой REST API для ресурса Post .

Мы покажем здесь несколько простых операций CRUD: создание, обновление, получение одного и получение всех. Учитывая, что операции довольно просты, нас особенно интересуют аспекты преобразования сущности в DTO :

@Controller
class PostRestController {

    @Autowired
    private IPostService postService;

    @Autowired
    private IUserService userService;

    @Autowired
    private ModelMapper modelMapper;

    @GetMapping
    @ResponseBody
    public List getPosts(...) {
        //...
        List posts = postService.getPostsList(page, size, sortDir, sort);
        return posts.stream()
          .map(this::convertToDto)
          .collect(Collectors.toList());
    }

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

    @GetMapping(value = "/{id}")
    @ResponseBody
    public PostDto getPost(@PathVariable("id") Long id) {
        return convertToDto(postService.getPostById(id));
    }

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

Вот наше преобразование из Post entity в PostDto :

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

Вот преобразование из DTO в сущность :

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;
}

Таким образом, как мы видим, с помощью картографа моделей логика преобразования быстра и проста. Мы используем map API картографа и получаем данные, преобразованные без написания одной строки логики преобразования.

6. Модульное тестирование

Наконец, давайте проведем очень простой тест, чтобы убедиться, что преобразования между сущностью и объектом работают хорошо:

public class PostDtoUnitTest {

    private ModelMapper modelMapper = new ModelMapper();

    @Test
    public void whenConvertPostEntityToPostDto_thenCorrect() {
        Post post = new Post();
        post.setId(1L);
        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(1L);
        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. Заключение

В этой статье мы подробно описали упрощение преобразования из Entity в DTO и из DTO в Entity в API Spring REST , используя библиотеку model mapper вместо написания этих преобразований вручную.

Полный исходный код примеров доступен в проекте GitHub .