JavaRush /وبلاگ جاوا /Random-FA /بهار ترسناک نیست، یک لایه DTO
Павел
مرحله

بهار ترسناک نیست، یک لایه DTO

در گروه منتشر شد
محتویات چرخه مقاله ما همچنان در مورد بهار صحبت می کنیم. امروز ما الگوی DTO را تجزیه و تحلیل خواهیم کرد، برای درک می توانید اینجا را بخوانید . سخت ترین چیز در مورد DTO این است که بفهمیم چرا به آن نیاز داریم. بیایید شروع به حدس و گمان در مورد سبزیجات کنیم و در عین حال یک کد بنویسیم، شاید در طول مسیر چیزی واضح تر شود. یک پروژه Spring-boot ایجاد کنید، h2 و Lombok را متصل کنید . ایجاد بسته ها: موجودیت ها، مخازن، خدمات، ابزارها. در نهادها، یک موجودیت محصول ایجاد کنید:
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;//закупочная цена

}
کلاس های ProducRepository، ProducService و کلاس ItiiateUtil ( مشابه مقاله قبلی ) را پیاده سازی کنید. بیایید بگوییم که ما سیب زمینی را به قیمت عمده فروشی 20 روبل در هر کیلوگرم و هویج را با قیمت 14 روبل در هر کیلوگرم خریداری کردیم. ما محصولات خریداری شده را در انبار قرار می دهیم. بیایید رکوردهای زیر را به پایگاه داده اضافه کنیم: [Id = 1، نام = "سیب زمینی"، buyPrice = 20] [Id =2، name= "Highije"، buyPrice = 14] به عنوان دلالان شایسته، ما باید کالاهای خود را به طور سودآور بفروشیم. برای این، بیایید آن را به زیبایی بسته بندی کنیم و قیمت را افزایش دهیم. یعنی ما سبزیجات کثیف و غیرجذابی داشتیم که در انبوهی انباشته شده بودند، اما محصولات وگان ممتاز تمیزی از بخش لوکس وجود خواهد داشت. موافقم، این دیگر همان محصول (شیئی) نخواهد بود که ما به صورت عمده خریدیم. برای یک محصول جدید، یک بسته dto و در آن کلاس ProductDto ایجاد کنید
package ru.java.rush.dto;

import lombok.Data;

@Data
public class ProductDto {
    Integer id;
    String name;
    Integer purchasePrice;
    String  packaging;//упаковка
    Integer salePrice;//цена реализации
}
ProductDto دو متغیر دارد که ProductEntity ندارد: «بسته‌بندی» و «قیمت فروش». شی dto ممکن است دقیقاً دارای همان متغیرهای موجود باشد یا تعداد آنها کمتر یا بیشتر باشد. به یاد داریم که تبدیل یک شی به شی دیگر یک موضوع نقشه برداری است. در پکیج utils کلاس 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;
    }
}
ما به سادگی فیلدهای یک شی را با فیلدهای مشابه از یک شی دیگر پر می کنیم. در کلاس ProductService ما متدهایی را برای جستجوی یک محصول یا لیستی از محصولات پیاده سازی می کنیم، اما قبل از آن با استفاده از روش نوشته شده در بالا، موجودیت را به dto تبدیل می کنیم.
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
    );
}
اگر اکنون این سبزیجات را روی صفحه نمایش بگذاریم چه اتفاقی می افتد؟ اجازه بدید ببینم. برای این کار کد زیر را در ItiiateUtil بنویسید و اجرا کنید.
System.out.println("\nВитрина магазина");
for (ProductDto dto : productService.findAll()) {
    System.out.println(dto);
}
خروجی عبارت است از: نمایش فروشگاه ProductDto(id=1، نام=سیب زمینی، خریدقیمت=20، بسته بندی=تهی، salePrice=null) ProductDto(id=2، نام=هویج، خرید قیمت=14، بسته بندی=تهی، salePrice=null) خوب، من نه! هیچ کس چنین سبزیجاتی را نخواهد خرید: آنها کثیف هستند، بسته بندی نشده اند و قیمت فروش آنها مشخص نیست. زمان منطق کسب و کار فرا رسیده است. ما آن را در کلاس ProductService پیاده سازی می کنیم. بیایید ابتدا چند متغیر به این کلاس اضافه کنیم:
private final Integer margin = 5;//это наша накрутка на цену
private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка
برای هر اقدام: بسته بندی و نشانه گذاری قیمت، یک روش جداگانه در همان کلاس ایجاد خواهیم کرد:
// упаковываем товар
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)
    );
}
به ItiiateUtil برمی گردیم و کد زیر را جایگزین نمایشگر روی نمایشگر می کنیم
List<ProductDto> productDtos = productService.findAll();

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

System.out.println("\nВитрина магазина");
for (ProductDto dto : productDtos)) {
    System.out.println(dto);
}
ما انجام می دهیم: نمایش محصولDto (id=1، نام=سیب زمینی، خریدقیمت=20، بسته بندی=بسته بندی شده به بهترین شکل ممکن، salePrice=100) ProductDto(id=2، نام=هویج، خرید قیمت=14، بسته بندی=بسته بندی شده به بهترین شکل ممکن salePrice=70) محصول به زیبایی بسته بندی شده است، قیمت دارد، اما آیا جایی روی پنجره دیده اید که قیمتی که آن را به صورت عمده خریداری کرده اید و یک شناسه دیگر را نشان می دهد. کد نوشته شده در بالا را با یک فایل اصلاح می کنیم:
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()
    ));
}
کلاس InitiateUtils باید به این شکل باشد:
@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()
            ));
        }
    }
}
راه اندازی کنیم: ویترین فروشگاه خرید: سیب زمینی، قیمت: 100 خرید: هویج، قیمت: 70 یک چیز دیگر! حالا ما فکر می کنیم که dto چیزهای خوبی آورده است، به جز یک سری کد اضافی: 1. ما می توانیم منطق تجاری را بدون تغییر اشیاء در پایگاه داده انجام دهیم (بگذریم، خوب، نیازی نیست که فیلدهایی در مورد بسته بندی و قیمت فروش داشته باشیم. این جدول). سیب زمینی ها حتی بدون بسته بندی با برچسب قیمت در انبار به خوبی دوام می آورند، حتی در آنجا اضافی هستند. 2. در این خط List<ProductDto> productDtos = productService.findAll() یک کش از اشیاء ایجاد کردیم که کار کردن با آنها در منطق تجاری راحت است. این در صورتی است که مقداری از کالاها را در اتاق پشتی فروشگاه قرار دهیم. 3. این به ما امکان داد تا دو عمل تجاری را انجام دهیم: بسته بندی و نشانه گذاری، اما ما فقط یک بار از پایگاه داده درخواست کردیم (پرس و جو به پایگاه داده از نظر عملکرد بسیار دشوار است). می‌توانید محصول را بسته‌بندی کنید، برچسب قیمتی روی آن بگذارید و آن را در معرض دید قرار دهید - به‌تدریج آن را از اتاق ابزار جمع‌آوری کنید، به‌جای اینکه هر بار دنبال آن به سمت اتاق ذخیره‌سازی بروید. در مورد این سوال: "چرا اینقدر دشوار است؟"، مردم نیز سعی می کنند پاسخ را بیابند، بخوانید . مقاله بعدی
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION