Dto java spring это

Java Guides

In the previous tutorial, we created a Spring boot project and build CRUD RESTful Webservices using Spring Boot 3, Spring Data JPA (Hibernate), and MySQL database.

In this tutorial, we will see how to DTO (Data Transfer Object) pattern to transfer the data between the Client and Server in the Spring boot application.

DTO ( Data Transfer Object) Overview

Data Transfer Object Design Pattern is a frequently used design pattern. It is basically used to pass data with multiple attributes in one shot from client to server, to avoid multiple calls to a remote server.

Another advantage of using DTOs on RESTful APIs written in Java (and on Spring Boot), is that they can help to hide implementation details of domain objects (JPA entities). Exposing entities through endpoints can become a security issue if we do not carefully handle what properties can be changed through what operations.

Prerequisites

This tutorial is a continuation of Spring Boot 3 CRUD RESTful WebServices with MySQL Database tutorial so first, you need to create a Spring Boot project with CRUD REST API’s using this tutorial:

Development Steps

1. Create UserDto Class

package net.javaguides.springboot.dto; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Setter @Getter @NoArgsConstructor @AllArgsConstructor public class UserDto

2. Change CRUD REST API’s to Return UserDTO to the Client

package net.javaguides.springboot.controller; import lombok.AllArgsConstructor; import net.javaguides.springboot.dto.UserDto; import net.javaguides.springboot.entity.User; import net.javaguides.springboot.exception.ErrorDetails; import net.javaguides.springboot.exception.ResourceNotFoundException; import net.javaguides.springboot.service.UserService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.WebRequest; import java.time.LocalDateTime; import java.util.List; @RestController @AllArgsConstructor @RequestMapping("api/users") public class UserController < private UserService userService; // build create User REST API @PostMapping public ResponseEntitycreateUser(@RequestBody UserDto user)< UserDto savedUser = userService.createUser(user); return new ResponseEntity<>(savedUser, HttpStatus.CREATED); > // build get user by id REST API // http://localhost:8080/api/users/1 @GetMapping("") public ResponseEntity getUserById(@PathVariable("id") Long userId)< UserDto user = userService.getUserById(userId); return new ResponseEntity<>(user, HttpStatus.OK); > // Build Get All Users REST API // http://localhost:8080/api/users @GetMapping public ResponseEntity getAllUsers() < Listusers = userService.getAllUsers(); return new ResponseEntity<>(users, HttpStatus.OK); > // Build Update User REST API @PutMapping("") // http://localhost:8080/api/users/1 public ResponseEntity updateUser(@PathVariable("id") Long userId, @RequestBody UserDto user)< user.setId(userId); UserDto updatedUser = userService.updateUser(user); return new ResponseEntity<>(updatedUser, HttpStatus.OK); > // Build Delete User REST API @DeleteMapping("") public ResponseEntity deleteUser(@PathVariable("id") Long userId)< userService.deleteUser(userId); return new ResponseEntity<>("User successfully deleted!", HttpStatus.OK); > >

3. Create UserMapper Class

Let’s create a UserMapper class to convert the User entity to UserDto and UserDto to the User entity:

package net.javaguides.springboot.mapper; import net.javaguides.springboot.dto.UserDto; import net.javaguides.springboot.entity.User; public class UserMapper < // Convert User JPA Entity into UserDto public static UserDto mapToUserDto(User user)< UserDto userDto = new UserDto( user.getId(), user.getFirstName(), user.getLastName(), user.getEmail() ); return userDto; >// Convert UserDto into User JPA Entity public static User mapToUser(UserDto userDto) < User user = new User( userDto.getId(), userDto.getFirstName(), userDto.getLastName(), userDto.getEmail() ); return user; >>

4. Change Service Layer to use UserDto

Change UserService Interface

package net.javaguides.springboot.service; import net.javaguides.springboot.dto.UserDto; import net.javaguides.springboot.entity.User; import java.util.List; public interface UserService < UserDto createUser(UserDto user); UserDto getUserById(Long userId); ListgetAllUsers(); UserDto updateUser(UserDto user); void deleteUser(Long userId); >

Change UserServiceImpl class

package net.javaguides.springboot.service.impl; import lombok.AllArgsConstructor; import net.javaguides.springboot.dto.UserDto; import net.javaguides.springboot.entity.User; import net.javaguides.springboot.mapper.UserMapper; import net.javaguides.springboot.repository.UserRepository; import net.javaguides.springboot.service.UserService; import org.apache.logging.log4j.util.Strings; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @Service @AllArgsConstructor public class UserServiceImpl implements UserService < private UserRepository userRepository; @Override public UserDto createUser(UserDto userDto) < // Convert UserDto into User JPA Entity User user = UserMapper.mapToUser(userDto); User savedUser = userRepository.save(user); // Convert User JPA entity to UserDto UserDto savedUserDto = UserMapper.mapToUserDto(savedUser); return savedUserDto; >@Override public UserDto getUserById(Long userId) < OptionaloptionalUser = userRepository.findById(userId); User user = optionalUser.get(); return UserMapper.mapToUserDto(user); > @Override public List getAllUsers() < Listusers = userRepository.findAll(); return users.stream().map(UserMapper::mapToUserDto) .collect(Collectors.toList()); > @Override public UserDto updateUser(UserDto user) < User existingUser = userRepository.findById(user.getId()).get(); existingUser.setFirstName(user.getFirstName()); existingUser.setLastName(user.getLastName()); existingUser.setEmail(user.getEmail()); User updatedUser = userRepository.save(existingUser); return UserMapper.mapToUserDto(updatedUser); >@Override public void deleteUser(Long userId) < userRepository.deleteById(userId); >>

5. Test CRUD REST API’s using Postman Client

Источник

Spring — это не страшно, прослойка из DTO

Java-университет

СОДЕРЖАНИЕ ЦИКЛА СТАТЕЙ Продолжаем говорить про Spring. Сегодня будем разбирать паттерн DTO, для понимания можно почитать тут. Самое сложное в DTO — это понять, зачем оно нужно. Давайте займемся спекуляцией овощей, и заодно, попишем код, может по ходу дела что то и проясниться. Создайте spring-boot проект , подключите h2 и Lombok. Создайте пакеты: entities, repositories, services, utils. В entities создайте сущность Product:

 package ru.java.rush.entities; import lombok.Data; import lombok.experimental.Accessors; import org.hibernate.annotations.GenericGenerator; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Accessors(chain = true) @Entity @Data public class ProductEntity < @Id @Column @GenericGenerator(name = "generator", strategy = "increment") @GeneratedValue(generator = "generator") Integer id; @Column String name; @Column Integer purchasePrice;//закупочная цена >

Реализуйте классы ProducRepository, ProducService и класс ItiiateUtil (аналогично прошлой статье). Допустим мы прикупли картофель по оптовой цене 20 рублей за кг., и морковки по 14 рублей за кг. Приобретенные продукты положим в хранилище. Дополним БД записями: [Id =1, name= “Картофель”, purchasePrice = 20] [Id =2, name= “Морковь”, purchasePrice = 14] Как порядочные спекулянты, мы должны выгодно впарить свой товар, для этого давайте красиво упакуем его и накрутим цену. То есть, были у нас грязные и не красивые овощи, наваленные кучей, а станут чистенькие премиум-веган продукты сегмента лакшери. Согласитесь, это будет уже не тот продукт(объект) который мы купили оптом. Для нового продукта создадим пакет dto и в нем класс ProductDto

 package ru.java.rush.dto; import lombok.Data; @Data public class ProductDto < Integer id; String name; Integer purchasePrice; String packaging;//упаковка Integer salePrice;//цена реализации >

У ProductDto есть две переменные, которых нет у ProductEntity: «упаковка» и «цена реализации». Объект dto может содержать точно такие же переменные, как и entity, или их может быть больше, или меньше. Мы помним, что конвертация одного объекта в другой – это дело маппинга. В пакете utils создадим класс MappingUtils

 package ru.java.rush.utils; import org.springframework.stereotype.Service; import ru.java.rush.dto.ProductDto; import ru.java.rush.entities.ProductEntity; @Service public class MappingUtils < //из entity в dto public ProductDto mapToProductDto(ProductEntity entity)< ProductDto dto = new ProductDto(); dto.setId(entity.getId()); dto.setName(entity.getName()); dto.setPurchasePrice(entity.getPurchasePrice()); return dto; >//из dto в entity public ProductEntity mapToProductEntity(ProductDto dto) < ProductEntity entity = new ProductEntity(); entity.setId(dto.getId()); entity.setName(dto.getName()); entity.setPurchasePrice(dto.getPurchasePrice()); return entity; >> 

Просто заполняем поля из одного объекта, аналогичными полями из другого объекта. В классе ProductService реализуем методы для поиска одного продукта или списка продуктов, но перед эти мы конвертируем entity в dto с помощь написанного выше метода.

 private final ProductRepository productRepository; private final MappingUtils mappingUtils; //для листа продуктов мы использовали стрим public List findAll() < return productRepository.findAll().stream() //создали из листа стирим .map(mappingUtils::mapToProductDto) //оператором из streamAPI map, использовали для каждого элемента метод mapToProductDto из класса MappingUtils .collect(Collectors.toList()); //превратили стрим обратно в коллекцию, а точнее в лист >//для одиночного продукта обошлись проще public ProductDto findById(Integer id) < return mappingUtils.mapToProductDto( //в метод mapToProductDto productRepository.findById(id) //поместили результат поиска по id .orElse(new ProductEntity()) //если ни чего не нашли, то вернем пустой entity ); >

Что будет если мы сейчас положим эти овощи на витрину? А давайте посмотрим. Для этого в ItiiateUtil напишем следующий код и запустим.

 System.out.println("\nВитрина магазина"); for (ProductDto dto : productService.findAll())

На выходе получим: Витрина магазина ProductDto(id=1, name=Картофель, purchasePrice=20, packaging=null, salePrice=null) ProductDto(id=2, name=Морковь, purchasePrice=14, packaging=null, salePrice=null) Ну уж, нет! Такие овощи никто не купит: грязные, не упакованы, да и цена продажи не известна. Настало время бизнес логики. Ее реализуем в классе ProductService. Добавим ка сначала в этот класс пару переменных:

 private final Integer margin = 5;//это наша накрутка на цену private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка 
 // упаковываем товар public void pack(List list) < list.forEach(productDto ->productDto.setPackaging(packaging) ); > // делаем деньги public void makeMoney(List list) < list.forEach(productDto ->productDto.setSalePrice(productDto.getPurchasePrice() * margin) ); > 
 List productDtos = productService.findAll(); productService.pack(productDtos); productService.makeMoney(productDtos); System.out.println("\nВитрина магазина"); for (ProductDto dto : productDtos))

Выполняем: Витрина магазина ProductDto(id=1, name=Картофель, purchasePrice=20, packaging=Упаковано в лучшем виде, salePrice=100) ProductDto(id=2, name=Морковь, purchasePrice=14, packaging=Упаковано в лучшем виде, salePrice=70) Товар красиво упакован, есть цена, но вы где-нибудь видели, что бы на витрине писали цену за которую купили оптом и еще id какой-то. Дорабатываем напильником, написанный выше код:

 List productDtos = productService.findAll(); productService.pack(productDtos); productService.makeMoney(productDtos); System.out.println("\nВитрина магазина"); for (ProductDto dto : productDtos)
 @Service @RequiredArgsConstructor public class InitiateUtils implements CommandLineRunner < private final ProductService productService; @Override public void run(String. args) throws Exception < Listproducts = new ArrayList<>( Arrays.asList( new ProductEntity() .setName("Картофель") .setPurchasePrice(20), new ProductEntity() .setName("Морковь") .setPurchasePrice(14) )); productService.saveAll(products); List productDtos = productService.findAll(); productService.pack(productDtos); productService.makeMoney(productDtos); System.out.println("\nВитрина магазина"); for (ProductDto dto : productDtos) < System.out.println(String.format( "Купите: %s , по цене: %d", dto.getName(), dto.getSalePrice() )); >> > 

Запускаем: Витрина магазина Купите: Картофель , по цене: 100 Купите: Морковь , по цене: 70 Другое дело! Теперь по думаем, что dto принесло хорошего, кроме кучи дополнительного кода: 1. Мы можем совершать бизнес-логику не меняя объекты в БД(допустим ну ненужно нам в этой таблице иметь поля про упаковку и цену продажи). Картофель отлично пролежит в хранилище и без упаковки с ценником, они там даже лишние. 2. В этой строчке List productDtos = productService.findAll() мы создали кэш из объектов с которыми удобно работать в рамках бизнес-логики. Это, если бы мы положили часть товара в подсобку магазина. 3. Это нам позволило, совершить два бизнес действия: упаковка и наценка, но запрос в базу сделали только один раз (запросы в базу довольно тяжелы в плане производительности). Товар можно упаковывать, клеить ценник и выкладывать на витрину — постепенно набирая его из подсобки, а не бегать за ним каждый раз в хранилище. На вопрос: «Зачем так сложно?», люди тоже пытаются найти ответ, почитайте. Следующая статья

Источник

Читайте также:  Obs chat youtube css
Оцените статью