JavaRush /Blog Java /Random-ES /La primavera no da miedo, una capa DTO
Павел
Nivel 11

La primavera no da miedo, una capa DTO

Publicado en el grupo Random-ES
CONTENIDOS DEL CICLO DE ARTÍCULOS Seguimos hablando de Primavera. Hoy analizaremos el patrón DTO, para entenderlo puedes leer aquí . Lo más difícil de la DTO es comprender por qué es necesaria. Comencemos a especular sobre las verduras y, al mismo tiempo, escribamos algún código, tal vez algo se aclare en el camino. Cree un proyecto spring-boot , conecte h2 y Lombok . Crear paquetes: entidades, repositorios, servicios, utilidades. En entidades, cree una entidad Producto:
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;//закупочная цена

}
Implemente las clases ProducRepository, ProducService y la clase ItiiateUtil ( similar al artículo anterior ). Digamos que compramos patatas a un precio mayorista de 20 rublos el kg y zanahorias a 14 rublos el kg. Almacenaremos los productos adquiridos. Agreguemos los siguientes registros a la base de datos: [Id =1, nombre = “Patatas”, precio de compra = 20] [Id =2, nombre = “Zanahorias”, precio de compra = 14] Como especuladores decentes, debemos vender nuestros productos de manera rentable, Para esto, empaquetémoslo maravillosamente y aumentaremos el precio. Es decir, teníamos verduras sucias y poco atractivas amontonadas, pero habrá productos veganos premium limpios del segmento de lujo. De acuerdo, este ya no será el mismo producto (objeto) que compramos al por mayor. Para un nuevo producto, cree un paquete dto y en él la clase ProductDto
package ru.java.rush.dto;

import lombok.Data;

@Data
public class ProductDto {
    Integer id;
    String name;
    Integer purchasePrice;
    String  packaging;//упаковка
    Integer salePrice;//цена реализации
}
ProductDto tiene dos variables que ProductEntity no tiene: "embalaje" y "precio de venta". El objeto dto puede contener exactamente las mismas variables que la entidad, o puede haber más o menos. Recordamos que convertir un objeto en otro es cuestión de mapeo. En el paquete utils crearemos la clase 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;
    }
}
Simplemente completamos los campos de un objeto con campos similares de otro objeto. En la clase ProductService implementamos métodos para buscar un solo producto o una lista de productos, pero antes de eso convertimos la entidad en un dto usando el método escrito anteriormente.
private final ProductRepository productRepository;
private final MappingUtils mappingUtils;


//для листа продуктов мы использовали стрим
public List<ProductDto> findAll() {
    return productRepository.findAll().stream() //создали из листа стирим
            .map(mappingUtils::mapToProductDto) //оператором из streamAPI map, использовали для каждого elemento метод mapToProductDto из класса MappingUtils
.collect(Collectors.toList()); //превратo стрим обратно в коллекцию, а точнее в лист
}

//для одиночного продукта обошлись проще
public ProductDto findById(Integer id) {
    return mappingUtils.mapToProductDto( //в метод mapToProductDto
            productRepository.findById(id) //поместo результат поиска по id
                    .orElse(new ProductEntity()) //если ни чего не нашли, то вернем пустой entity
    );
}
¿Qué pasará si ahora exhibimos estas verduras? Vamos a ver. Para hacer esto, escriba el siguiente código en ItiiateUtil y ejecútelo.
System.out.println("\nВитрина магазина");
for (ProductDto dto : productService.findAll()) {
    System.out.println(dto);
}
El resultado es: Visualización de la tienda ProductDto(id=1, nombre=Patatas, preciodecompra=20, empaque=null,preciodeventa=null) ProductDto(id=2, nombre=Zanahorias,Preciodecompra=14, empaque=null,preciodeventa=null) ¡Bueno yo no! Nadie quiere comprar esas verduras: están sucias, no envasadas y se desconoce el precio de venta. Es hora de la lógica empresarial. Lo implementamos en la clase ProductService. Primero agreguemos un par de variables a esta clase:
private final Integer margin = 5;//это наша накрутка на цену
private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка
Para cada acción: embalaje y marcado de precio, crearemos un método separado en la misma clase:
// упаковываем товар
public void pack(List<ProductDto> list) {
    list.forEach(productDto ->
            productDto.setPackaging(packaging)
    );
}

// делаем деньги
public void makeMoney(List<ProductDto> list) {
    list.forEach(productDto ->
            productDto.setSalePrice(productDto.getPurchasePrice() * margin)
    );
}
Regresamos a ItiiateUtil y reemplazamos la visualización en la pantalla con el siguiente código
List<ProductDto> productDtos = productService.findAll();

productService.pack(productDtos);
productService.makeMoney(productDtos);

System.out.println("\nВитрина магазина");
for (ProductDto dto : productDtos)) {
    System.out.println(dto);
}
Realizamos: Visualización en tienda ProductDto(id=1, nombre=Patatas, preciocompra=20, packaging=Empaquetado de la mejor manera posible, preciooferta=100) ProductDto(id=2, nombre=Zanahorias, preciocompra=14, packaging=Empaquetado de la mejor manera posible, salePrice=70) El producto está bellamente empaquetado, hay un precio, pero ¿has visto en algún lugar del escaparate el precio por el que lo compraste al por mayor y alguna otra identificación? Modificamos el código escrito arriba con un archivo:
List<ProductDto> 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()
    ));
}
La clase InitiateUtils finalmente debería verse así:
@Service
@RequiredArgsConstructor
public class InitiateUtils implements CommandLineRunner {

    private final ProductService productService;

    @Override
    public void run(String... args) throws Exception {

        List<ProductEntity> products = new ArrayList<>(
                Arrays.asList(
                        new ProductEntity()
                                .setName("Картофель")
                                .setPurchasePrice(20),
                        new ProductEntity()
                                .setName("Морковь")
                                .setPurchasePrice(14)
                ));

        productService.saveAll(products);

        List<ProductDto> 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()
            ));
        }
    }
}
Lanzamos: Escaparate Comprar: Patatas, precio: 100 Comprar: Zanahorias, precio: 70 ¡ Otra cosa! Ahora creemos que dto trajo cosas buenas, excepto por un montón de código adicional: 1. Podemos realizar lógica de negocios sin cambiar objetos en la base de datos (digamos, bueno, no necesitamos tener campos sobre empaque y precio de venta en Esta mesa). Las patatas durarán bien almacenadas incluso sin un embalaje con una etiqueta de precio, allí incluso son superfluas. 2. En esta línea List<ProductDto> productDtos = productService.findAll() creamos un caché de objetos con los que es conveniente trabajar dentro de la lógica empresarial. Esto es si ponemos algunos de los productos en la trastienda de la tienda. 3. Esto nos permitió realizar dos acciones comerciales: empaquetado y marcado, pero realizamos una solicitud a la base de datos solo una vez (las consultas a la base de datos son bastante difíciles en términos de rendimiento). Puede empaquetar el producto, ponerle una etiqueta de precio y exhibirlo, recogiéndolo gradualmente del cuarto de servicio, en lugar de correr tras él cada vez al cuarto de almacenamiento. A la pregunta: "¿Por qué es tan difícil?", la gente también intenta encontrar la respuesta, lea . Artículo siguiente
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION