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ł
GO TO FULL VERSION