JavaRush /Blogue Java /Random-PT /A primavera não é assustadora, uma camada DTO
Павел
Nível 11

A primavera não é assustadora, uma camada DTO

Publicado no grupo Random-PT
CONTEÚDO DO CICLO DE ARTIGOS Continuamos falando sobre a Primavera. Hoje vamos analisar o padrão DTO, para entender você pode ler aqui . A coisa mais difícil sobre o DTO é entender por que ele é necessário. Vamos começar a especular sobre vegetais e, ao mesmo tempo, escrever algum código, talvez algo fique mais claro ao longo do caminho. Crie um projeto spring-boot , conecte h2 e Lombok . Crie pacotes: entidades, repositórios, serviços, utilitários. Nas entidades, crie uma entidade Produto:
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 as classes ProducRepository, ProducService e a classe ItiiateUtil ( semelhante ao artigo anterior ). Digamos que compramos batatas a um preço de atacado de 20 rublos por kg e cenouras a 14 rublos por kg. Colocaremos os produtos adquiridos em armazenamento. Vamos adicionar os seguintes registros ao banco de dados: [Id =1, name= “Batatas”, buyPrice = 20] [Id =2, name= “Cenouras”, buyPrice = 14] Como especuladores decentes, devemos vender nossos produtos com lucro, para isso vamos embalar lindamente e aumentaremos o preço. Ou seja, tínhamos vegetais sujos e pouco atraentes amontoados, mas haverá produtos veganos premium limpos do segmento de luxo. Concordo, este não será mais o mesmo produto (objeto) que compramos a granel. Para um novo produto, crie um pacote dto e nele a classe ProductDto
package ru.java.rush.dto;

import lombok.Data;

@Data
public class ProductDto {
    Integer id;
    String name;
    Integer purchasePrice;
    String  packaging;//упаковка
    Integer salePrice;//цена реализации
}
ProductDto possui duas variáveis ​​que ProductEntity não possui: “embalagem” e “preço de venda”. O objeto dto pode conter exatamente as mesmas variáveis ​​que a entidade, ou pode haver mais ou menos delas. Lembramos que converter um objeto em outro é uma questão de mapeamento. No pacote utils criaremos a classe 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;
    }
}
Simplesmente preenchemos os campos de um objeto com campos semelhantes de outro objeto. Na classe ProductService implementamos métodos para pesquisar um único produto ou uma lista de produtos, mas antes disso convertemos a entidade em dto usando o método escrito acima.
private final ProductRepository productRepository;
private final MappingUtils mappingUtils;


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

//для одиночного продукта обошлись проще
public ProductDto findById(Integer id) {
    return mappingUtils.mapToProductDto( //в метод mapToProductDto
            productRepository.findById(id) //поместor результат поиска по id
                    .orElse(new ProductEntity()) //если ни чего не нашли, то вернем пустой entity
    );
}
O que acontecerá se colocarmos agora esses vegetais na vitrine? Vamos ver. Para fazer isso, escreva o seguinte código em ItiiateUtil e execute-o.
System.out.println("\nВитрина магазина");
for (ProductDto dto : productService.findAll()) {
    System.out.println(dto);
}
A saída é: Exibição da loja ProductDto(id=1, name=Potatoes, PurchasePrice=20, packaging=null, salePrice=null) ProductDto(id=2, name=Carrots, PurchasePrice=14, packaging=null, salePrice=null) Bem Eu não! Ninguém comprará esses vegetais: estão sujos, não embalados e o preço de venda é desconhecido. É hora da lógica de negócios. Nós o implementamos na classe ProductService. Vamos primeiro adicionar algumas variáveis ​​a esta classe:
private final Integer margin = 5;//это наша накрутка на цену
private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка
Para cada ação: embalagem e marcação de preço, criaremos um método separado na mesma classe:
// упаковываем товар
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)
    );
}
Voltamos ao ItiiateUtil e substituímos a exibição no display pelo seguinte 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: Exibição da loja ProductDto(id=1, name=Batatas, PurchasePrice=20, packaging=Embalado da melhor maneira possível, salePrice=100) ProductDto(id=2, name=Cenouras, PurchasePrice=14, packaging=Packed da melhor maneira possível, salePrice = 70) O produto está lindamente embalado, há um preço, mas você viu em algum lugar na vitrine o preço pelo qual o comprou a granel e algum outro id. Modificamos o código escrito acima com um arquivo:
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()
    ));
}
class InitiateUtils deve ficar assim:
@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()
            ));
        }
    }
}
Vamos lançar: Vitrine Compre: Batata, preço: 100 Compre: Cenoura, preço: 70 Outra coisa! Agora pensamos que dto trouxe coisas boas, exceto por um monte de código adicional: 1. Podemos executar lógica de negócios sem alterar objetos no banco de dados (digamos, bem, não precisamos ter campos sobre embalagem e preço de venda em essa mesa). As batatas duram bem armazenadas mesmo sem embalagem com etiqueta de preço, aí são até supérfluas. 2. Nesta linha List<ProductDto> productDtos = productService.findAll() criamos um cache de objetos que são convenientes para trabalhar dentro da lógica de negócios. Isso se colocarmos algumas mercadorias nos fundos da loja. 3. Isso nos permitiu realizar duas ações de negócios: empacotamento e marcação, mas fizemos uma solicitação ao banco de dados apenas uma vez (as consultas ao banco de dados são bastante difíceis em termos de desempenho). Você pode embalar o produto, colocar uma etiqueta de preço nele e exibi-lo - retirando-o gradualmente da despensa, em vez de correr atrás dele todas as vezes até o depósito. À pergunta: “Por que é tão difícil?”, as pessoas também tentam encontrar a resposta, leia . Próximo artigo
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION