JavaRush /Java Blog /Random-KO /봄은 무섭지 않아, DTO 레이어
Павел
레벨 11

봄은 무섭지 않아, DTO 레이어

Random-KO 그룹에 게시되었습니다
기사주기의 내용 우리는 계속해서 Spring에 대해 이야기합니다. 오늘 우리는 DTO 패턴을 분석할 것입니다. 이해를 위해 여기에서 읽을 수 있습니다 . DTO에서 가장 어려운 점은 DTO가 필요한 이유를 이해하는 것입니다. 야채에 대한 추측을 시작하고 동시에 코드를 작성해 봅시다. 어쩌면 뭔가가 더 명확해질 수도 있습니다. spring-boot 프로젝트를 생성하고 h2 Lombok을 연결합니다 . 패키지 생성: 엔터티, 저장소, 서비스, 유틸리티. 엔터티에서 Product 엔터티를 만듭니다.
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 클래스를 구현합니다( 이전 기사와 유사 ). 우리가 감자를 kg당 20루블의 도매가로, 당근을 kg당 14루블의 도매가로 구입했다고 가정해 보겠습니다. 구매한 제품은 보관해 드립니다. 데이터베이스에 다음 레코드를 추가해 보겠습니다. [Id =1, name= “Potatoes”, buyPrice = 20] [Id =2, name= “Carrots”, 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, name=Potatoes, buyPrice=20, Packaging=null, salePrice=null) ProductDto(id=2, name=Carrots, buyPrice=14, Packaging=null, 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);
}
우리는 다음을 수행합니다: 매장 디스플레이 ProductDto(id=1, 이름=감자, buyPrice=20, 포장=가장 좋은 방법으로 포장, salePrice=100) ProductDto(id=2, 이름=당근, buyPrice=14, 포장=포장됨 가능한 최선의 방법은 salePrice=70) 제품이 아름답게 포장되어 있고 가격이 있지만 창 어딘가에서 대량 구매 가격과 기타 ID가 표시되는 것을 본 적이 있습니까? 위에 작성된 코드를 파일로 수정합니다.
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