JavaRush /Java Blog /Random-ID /Musim semi tidak menakutkan, lapisan DTO
Павел
Level 11

Musim semi tidak menakutkan, lapisan DTO

Dipublikasikan di grup Random-ID
ISI SIKLUS PASAL Kami terus berbicara tentang Musim Semi. Hari ini kita akan menganalisa pola DTO, untuk pemahamannya bisa anda baca disini . Hal tersulit tentang DTO adalah memahami mengapa hal itu diperlukan. Mari kita mulai berspekulasi tentang sayuran, dan pada saat yang sama, tulis beberapa kode, mungkin sesuatu akan menjadi lebih jelas seiring berjalannya waktu. Buat proyek spring-boot , sambungkan h2 dan Lombok . Buat paket: entitas, repositori, layanan, utilitas. Di entitas, buat entitas Produk:

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;//закупочная цена

}
Implementasikan kelas ProducRepository, ProducService dan kelas ItiiateUtil ( mirip dengan artikel sebelumnya ). Katakanlah kita membeli kentang dengan harga grosir 20 rubel per kg, dan wortel dengan harga 14 rubel per kg. Kami akan menempatkan produk yang dibeli di penyimpanan. Mari tambahkan catatan berikut ke database: [Id =1, nama= “Kentang”, harga beli = 20] [Id =2, nama= “Wortel”, harga beli = 14] Sebagai spekulan yang baik, kita harus menjual barang kita secara menguntungkan, untuk ini mari kita kemas dengan indah dan kita akan menaikkan harganya. Artinya, kita mempunyai sayuran kotor dan tidak menarik yang menumpuk, tetapi akan ada produk vegan premium yang bersih dari segmen mewah. Setuju, ini bukan lagi produk (barang) yang sama dengan yang kita beli dalam jumlah besar. Untuk produk baru, buat paket dto dan di dalamnya kelas ProductDto

package ru.java.rush.dto;

import lombok.Data;

@Data
public class ProductDto {
    Integer id;
    String name;
    Integer purchasePrice;
    String  packaging;//упаковка
    Integer salePrice;//цена реализации
}
ProductDto memiliki dua variabel yang tidak dimiliki ProductEntity: “pengemasan” dan “harga jual”. Objek dto mungkin berisi variabel yang sama persis dengan entitas, atau mungkin lebih banyak atau lebih sedikit. Kita ingat bahwa mengubah satu objek ke objek lainnya adalah masalah pemetaan. Dalam paket utils kita akan membuat kelas 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;
    }
}
Kita cukup mengisi field dari satu objek dengan field serupa dari objek lain. Di kelas ProductService kami menerapkan metode untuk mencari satu produk atau daftar produk, tetapi sebelum itu kami mengonversi entitas menjadi dto menggunakan metode yang ditulis di atas.

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
    );
}
Apa jadinya jika sekarang kita memajang sayuran ini? Mari kita lihat. Untuk melakukannya, tulis kode berikut di ItiiateUtil dan jalankan.

System.out.println("\nВитрина магазина");
for (ProductDto dto : productService.findAll()) {
    System.out.println(dto);
}
Outputnya adalah: Tampilan toko ProductDto(id=1, name=Potatoes, purchasePrice=20, package=null, salePrice=null) ProductDto(id=2, name=Wortel, purchasePrice=14, package=null, salePrice=null) Ya, saya tidak melakukannya! Tidak ada yang mau membeli sayuran seperti itu: kotor, tidak dikemas, dan harga jualnya tidak diketahui. Sudah waktunya untuk logika bisnis. Kami mengimplementasikannya di kelas ProductService. Mari kita tambahkan beberapa variabel ke kelas ini terlebih dahulu:

private final Integer margin = 5;//это наша накрутка на цену
private final String packaging = "Упаковано в лучшем виде";//так будет выглядеть упаковка
Untuk setiap tindakan: pengemasan dan markup harga, kami akan membuat metode terpisah di kelas yang sama:

// упаковываем товар
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)
    );
}
Kita kembali ke ItiiateUtil dan mengganti tampilan pada display dengan kode berikut

List<ProductDto> productDtos = productService.findAll();

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

System.out.println("\nВитрина магазина");
for (ProductDto dto : productDtos)) {
    System.out.println(dto);
}
Kami melaksanakan: Tampilan toko ProductDto(id=1, nama=Kentang, harga beli=20, kemasan=Dikemas sebaik mungkin, Harga jual=100) ProductDto(id=2, nama=Wortel, harga beli=14, kemasan=Dikemas dengan cara terbaik, harga jual=70) Produk dikemas dengan indah, ada harganya, tetapi pernahkah Anda melihat di suatu tempat di etalase harga pembelian dalam jumlah besar dan beberapa ID lainnya. Kami memodifikasi kode yang ditulis di atas dengan file:

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 pada akhirnya akan terlihat seperti ini:

@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()
            ));
        }
    }
}
Ayo luncurkan: Jendela toko Beli: Kentang, harga: 100 Beli: Wortel, harga: 70 Satu lagi! Sekarang kita berpikir bahwa dto membawa hal-hal baik, kecuali sekumpulan kode tambahan: 1. Kita dapat menjalankan logika bisnis tanpa mengubah objek di database (misalkan, kita tidak perlu memiliki kolom tentang pengemasan dan harga jual di meja ini). Kentang akan bertahan lama dalam penyimpanan meski tanpa kemasan dengan label harga, bahkan tidak ada gunanya di sana. 2. Pada baris ini List<ProductDto> productDtos = productService.findAll() kita membuat cache objek yang mudah digunakan dalam logika bisnis. Ini jika kita meletakkan sebagian barang di ruang belakang toko. 3. Hal ini memungkinkan kami melakukan dua tindakan bisnis: pengemasan dan markup, namun kami hanya membuat permintaan ke database satu kali (kueri ke database cukup sulit dalam hal performa). Anda dapat mengemas produk, memberi label harga, dan memajangnya - secara bertahap mengambilnya dari ruang utilitas, daripada terus mengejarnya ke ruang penyimpanan. Terhadap pertanyaan: “Mengapa begitu sulit?”, orang pun berusaha mencari jawabannya, baca . Artikel berikutnya
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION