JavaRush /Blog Java /Random-PL /Wiosna nie straszna, warstwa DTO
Павел
Poziom 11

Wiosna nie straszna, warstwa DTO

Opublikowano w grupie Random-PL
TREŚĆ CYKLU ARTYKUŁÓW Kontynuujemy rozmowę o wiośnie. Dzisiaj przeanalizujemy wzór DTO, o zrozumienie możesz przeczytać tutaj . Najtrudniejszą rzeczą w DTO jest zrozumienie, dlaczego jest ono potrzebne. Zacznijmy spekulować na temat warzyw, a jednocześnie napiszmy jakiś kod, może przy okazji coś się wyjaśni. Utwórz projekt rozruchu wiosennego , połącz h2 i Lombok . Twórz pakiety: encje, repozytoria, usługi, narzędzia. W encjach utwórz encję Produkt:
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;//закупочная цена

}
Zaimplementuj klasy ProducRepository, ProducService i klasę ItiiateUtil ( podobnie jak w poprzednim artykule ). Załóżmy, że kupiliśmy ziemniaki w cenie hurtowej 20 rubli za kg, a marchewki po 14 rubli za kg. Zakupione produkty umieścimy w magazynie. Dodajmy do bazy następujące rekordy: [Id =1, nazwa= „Ziemniaki”, cena zakupu = 20] [Id =2, nazwa= „Marchew”, cena zakupu = 14] Jako porządni spekulanci musimy z zyskiem sprzedać nasz towar, w tym celu pięknie go zapakujmy i podnieśmy cenę. Oznacza to, że mieliśmy brudne i nieatrakcyjne warzywa piętrzące się w stosie, ale będą czyste wegańskie produkty premium z segmentu luksusowego. Zgadzam się, to nie będzie już ten sam produkt (przedmiot), który kupiliśmy hurtowo. Dla nowego produktu utwórz pakiet dto i w nim klasę ProductDto
package ru.java.rush.dto;

import lombok.Data;

@Data
public class ProductDto {
    Integer id;
    String name;
    Integer purchasePrice;
    String  packaging;//упаковка
    Integer salePrice;//цена реализации
}
ProductDto ma dwie zmienne, których nie ma ProductEntity: „opakowanie” i „cena sprzedaży”. Obiekt dto może zawierać dokładnie te same zmienne co encja lub może być ich więcej lub mniej. Pamiętamy, że konwersja jednego obiektu na drugi to kwestia mapowania. W pakiecie utils utworzymy klasę 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;
    }
}
Po prostu wypełniamy pola z jednego obiektu podobnymi polami z innego obiektu. W klasie ProductService implementujemy metody wyszukiwania pojedynczego produktu lub listy produktów, ale wcześniej konwertujemy encję na dto metodą opisaną powyżej.
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()); //превратLub стрим обратно в коллекцию, а точнее в лист
}

//для одиночного продукта обошлись проще
public ProductDto findById(Integer id) {
    return mappingUtils.mapToProductDto( //в метод mapToProductDto
            productRepository.findById(id) //поместLub результат поиска по id
                    .orElse(new ProductEntity()) //если ни чего не нашли, то вернем пустой entity
    );
}
Co się stanie, jeśli teraz wystawimy te warzywa na wystawę? Zobaczmy. Aby to zrobić, napisz następujący kod w ItiiateUtil i uruchom go.
System.out.println("\nВитрина магазина");
for (ProductDto dto : productService.findAll()) {
    System.out.println(dto);
}
Dane wyjściowe to: Wyświetlacz sklepu ProductDto(id=1, nazwa=Ziemniaki, cena zakupu=20, opakowanie=null, cena sprzedaży=null) ProductDto(id=2, nazwa=Marchew, cena zakupu=14, opakowanie=null, cena sprzedaży=null) Cóż ja nie! Takich warzyw nikt nie kupi: są brudne, nieopakowane, a cena sprzedaży nie jest znana. Czas na logikę biznesową. Implementujemy go w klasie ProductService. Dodajmy najpierw kilka zmiennych do tej klasy:
private final Integer margin = 5;//это наша накрутка на цену
private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка
Dla każdej akcji: opakowania i narzutu cenowego utworzymy osobną metodę w tej samej klasie:
// упаковываем товар
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)
    );
}
Wracamy do ItiiateUtil i zastępujemy wyświetlanie na wyświetlaczu następującym kodem
List<ProductDto> productDtos = productService.findAll();

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

System.out.println("\nВитрина магазина");
for (ProductDto dto : productDtos)) {
    System.out.println(dto);
}
Wykonujemy: Ekspozycję sklepową ProductDto(id=1, nazwa=Ziemniaki, cena zakupu=20, opakowanie=Zapakowane w najlepszy możliwy sposób, cena sprzedaży=100) ProductDto(id=2, nazwa=Marchew, cena zakupu=14, opakowanie=Pakowane w najlepszy możliwy sposób salePrice=70) Produkt jest pięknie opakowany, jest cena, ale czy widziałeś gdzieś na wystawie cenę, za jaką kupiłeś hurtowo i jakiś inny identyfikator. Napisany powyżej kod modyfikujemy za pomocą pliku:
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 powinien ostatecznie wyglądać tak:
@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()
            ));
        }
    }
}
Uruchomiliśmy: Wystawa sklepowa Kupuję: Ziemniaki, cena: 100 Kupuję: Marchew, cena: 70 Kolejna rzecz! Teraz uważamy, że dto wniosło dobre rzeczy, z wyjątkiem kilku dodatkowych kodów: 1. Możemy wykonywać logikę biznesową bez zmiany obiektów w bazie danych (powiedzmy, cóż, nie musimy mieć pól dotyczących opakowania i ceny sprzedaży w ten stół). Ziemniaki dobrze zniosą przechowywanie nawet bez opakowania z ceną, są tam wręcz zbędne. 2. W tej linii List<ProductDto> produktDtos = produktService.findAll() utworzyliśmy pamięć podręczną obiektów, z którymi wygodnie jest pracować w ramach logiki biznesowej. Dzieje się tak w przypadku, gdy część towaru umieścimy na zapleczu sklepu. 3. Pozwoliło nam to wykonać dwie akcje biznesowe: pakowanie i znaczniki, ale żądanie do bazy danych złożyliśmy tylko raz (zapytania do bazy są dość trudne pod względem wydajności). Możesz zapakować produkt, opatrzyć go ceną i wystawić na wystawę - stopniowo wynosząc go z pomieszczenia gospodarczego, zamiast biegać za nim za każdym razem do magazynu. Na pytanie: „Dlaczego to takie trudne?”, ludzie też próbują znaleźć odpowiedź, czytają . Następny artykuł
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION