JavaRush /Blog Java /Random-FR /Le printemps ne fait pas peur, une couche DTO
Павел
Niveau 11

Le printemps ne fait pas peur, une couche DTO

Publié dans le groupe Random-FR
CONTENU DU CYCLE DES ARTICLES Nous continuons à parler du Printemps. Aujourd'hui, nous allons analyser le modèle DTO, pour comprendre, vous pouvez lire ici . La chose la plus difficile à propos du DTO est de comprendre pourquoi il est nécessaire. Commençons par spéculer sur les légumes, et en même temps, écrivons du code, peut-être que quelque chose deviendra plus clair en cours de route. Créez un projet spring-boot , connectez h2 et Lombok . Créez des packages : entités, référentiels, services, utils. Dans les entités, créez une entité Produit :
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;//закупочная цена

}
Implémentez les classes ProducRepository, ProducService et la classe ItiiateUtil ( similaire à l'article précédent ). Supposons que nous achetions des pommes de terre au prix de gros de 20 roubles par kg et des carottes à 14 roubles par kg. Nous placerons les produits achetés en stock. Ajoutons les enregistrements suivants à la base de données : [Id =1, name= « Pommes de terre », PurchasePrice = 20] [Id =2, name= « Carrots », PurchasePrice = 14] En tant que spéculateurs honnêtes, nous devons vendre nos marchandises de manière rentable, pour cela, emballons-le joliment et nous augmenterons le prix. Autrement dit, nous avions des légumes sales et peu attrayants entassés en tas, mais il y aura des produits végétaliens propres et haut de gamme du segment du luxe. D'accord, ce ne sera plus le même produit (objet) que nous avons acheté en gros. Pour un nouveau produit, créez un package dto et dedans la 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 a deux variables que ProductEntity n'a pas : « emballage » et « prix de vente ». L'objet dto peut contenir exactement les mêmes variables que l'entité, ou il peut y en avoir plus ou moins. On rappelle que la conversion d'un objet en un autre est une question de mappage. Dans le package utils, nous allons créer la 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;
    }
}
Nous remplissons simplement les champs d'un objet avec des champs similaires d'un autre objet. Dans la classe ProductService, nous implémentons des méthodes pour rechercher un seul produit ou une liste de produits, mais avant cela, nous convertissons l'entité en dto en utilisant la méthode écrite ci-dessus.
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
    );
}
Que se passera-t-il si nous exposons désormais ces légumes ? Voyons. Pour ce faire, écrivez le code suivant dans ItiiateUtil et exécutez-le.
System.out.println("\nВитрина магазина");
for (ProductDto dto : productService.findAll()) {
    System.out.println(dto);
}
Le résultat est le suivant : Affichage du magasin ProductDto(id=1, name=Potatoes, PurchasePrice=20, packaging=null, salePrice=null) ProductDto(id=2, name=Carrots, PurchasePrice=14, packaging=null, salePrice=null) Eh bien, moi non! Personne n’achètera de tels légumes : ils sont sales, non emballés et leur prix de vente est inconnu. Il est temps de passer à la logique métier. Nous l'implémentons dans la classe ProductService. Ajoutons d'abord quelques variables à cette classe :
private final Integer margin = 5;//это наша накрутка на цену
private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка
Pour chaque action : packaging et majoration de prix, nous allons créer une méthode distincte dans la même 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)
    );
}
Nous revenons à ItiiateUtil et remplaçons l'affichage sur l'écran par le code suivant
List<ProductDto> productDtos = productService.findAll();

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

System.out.println("\nВитрина магазина");
for (ProductDto dto : productDtos)) {
    System.out.println(dto);
}
Nous réalisons : Affichage en magasin ProductDto(id=1, name=Pommes de terre, PurchasePrice=20, packaging=Emballé de la meilleure façon possible, salePrice=100) ProductDto(id=2, name=Carrots, PurchasePrice=14, packaging=Emballé de la meilleure façon possible, salePrice=70) Le produit est joliment emballé, il y a un prix, mais avez-vous vu quelque part sur la vitrine afficher le prix pour lequel vous l'avez acheté en gros et une autre pièce d'identité. On modifie le code écrit ci-dessus avec un fichier :
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 classe InitiateUtils devrait finalement ressembler à ceci :
@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()
            ));
        }
    }
}
Lançons : Vitrine Acheter : Pommes de terre, prix : 100 Acheter : Carottes, prix : 70 Autre chose ! Nous pensons maintenant que dto a apporté de bonnes choses, à l'exception d'un tas de code supplémentaire : 1. Nous pouvons exécuter une logique métier sans modifier les objets dans la base de données (disons, eh bien, nous n'avons pas besoin d'avoir des champs sur l'emballage et le prix de vente dans cette table). Les pommes de terre se conservent bien au stockage même sans emballage avec étiquette de prix, elles y sont même superflues. 2. Dans cette ligne List<ProductDto> productDtos = productService.findAll() nous avons créé un cache d'objets faciles à utiliser dans la logique métier. C'est si nous mettons une partie des marchandises dans l'arrière-boutique du magasin. 3. Cela nous a permis d'effectuer deux actions commerciales : le packaging et le balisage, mais nous n'avons fait une requête à la base de données qu'une seule fois (les requêtes vers la base de données sont assez difficiles en termes de performances). Vous pouvez emballer le produit, y apposer une étiquette de prix et l'exposer - en le récupérant progressivement dans la buanderie, plutôt que de courir après lui à chaque fois jusqu'à la salle de stockage. A la question : « Pourquoi est-ce si difficile ? », les gens essaient aussi de trouver la réponse, lisez . Article suivant
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION