티스토리 뷰

ProductApiController

 

먼저 판매글을 저장하는 로직을 만들어보자. 위 사진을 보면 사용자가 /new url에서 판매글에 대한 정보를 입력 후 저장을 하게 되면 ProductRequestDto에 데이터가 담겨져 오게 된다. 이 데이터는 서비스 계층, createProduct 메서드에서 처리된다. 

그럼 ProductRequestDto를 한번 보자. 

 

 

ProductRequestDto

 

사용자가 입력한 데이터가 해당 DTO로 담겨지는데, 이 때 from-data로 입력을 받는다. 그래서 Controller에서 @RequestBody를 붙이지 않고 DTO 클래스에 setter까지 추가를 했다. 어떤 이유인지는 모르겠지만 setter를 열어두지 않으면 데이터가 담기지 않는다. 

toEntity 메서드를 보면 Product 엔티티 객체로 변환해준다. 

 

 

Product

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "PRODUCTS")
public class Product extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "products_id")
    private Long id;

    @Column(nullable = false)
    private String title;

    private String imgPath;

    private int price;

    @Column(columnDefinition = "TEXT")
    private String content;

    @Builder
    public Product(String title, int price, String content) {
        this.title = title;
        this.price = price;
        this.content = content;
    }

    public void updateProduct(String title, int price, String content) {
        this.title = title;
        this.price = price;
        this.content = content;
    }

    public void updateImgPath(String imgPath) {
        this.imgPath = imgPath;
    }

}

 

데이터베이스에 이미지 자체를 저장할 순 있지만, 추천하지 않는다고 한다. 그래서 이미지 경로를 저장한다. 자세한 내용은 여기를 참고하자. 

 

 

ProductRepository

 

 

ProductService

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Slf4j
public class ProductService {

    private final ProductsRepository productsRepository;
    private final FileService fileService;

    @Transactional
    public Long createProduct(ProductRequestDto requestDto) throws IOException {
        Product product = requestDto.toEntity();

        product.updateImgPath(fileService.saveFile(requestDto.getFile()));

        productsRepository.save(product);
        return product.getId();
    }
}

 

여기서 중요한 점은 아래코드다. 

product.updateImgPath(fileService.saveFile(requestDto.getFile()));

 

updateImgPath는 Product 엔티티 필드인 이미지 경로를 초기화해주는 메서드이다. 즉, 이미지를 내 로컬에다 저장하고 해당 이미지의 경로를 저장한다. 그럼 어떻게 이미지를 저장하고 경로를 반환해주는지 보자. 

 

 

FileService

 

요청한 이미지를 들고와서, 이미지 자체는 내 로컬에다 저장하고 이미지 경로를 반환해주는 메서드이다. 자세히 보면 원래 이미지 경로 앞에 랜덤한 문자를 추가했다. 그 이유는 만약 사용자 A가 이름이 C인 이미지를 저장했다고 가정해보자. 그리고 사용자 B가 우연히 똑같이 이름이 C인 이미지를 추가한다면, A가 추가한 이미지는 덮여지게 되어 사라진다. 이를 방지하기 위해 이미지 경로를 유일하게 한다. 

fileDir이나 transferTo에 대해서는 여기를 참고하자. 그럼 판매글을 수정할 때는 어떻게 할까 ?

 

 

ProductService

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
@Slf4j
public class ProductService {

    private final ProductsRepository productsRepository;
    private final FileService fileService;

    @Transactional
    public Long updateProduct(Long productId, ProductRequestDto requestDto) throws IOException {
        Product product = productsRepository.findById(productId)
                .orElseThrow(() -> new IllegalArgumentException("판매글이 존재하지 않습니다."));

        if(!product.getImgPath().isEmpty()) {
            fileService.deleteFile(product.getImgPath());
        }

        product.updateImgPath(fileService.saveFile(requestDto.getFile()));
        product.updateProduct(requestDto.getTitle(), requestDto.getPrice(), requestDto.getContent());

        return product.getId();
    }
}

 

간단하다. 먼저 기존 판매글의 이미지를 삭제시키고 다시 추가하는 방법이다. 

만약 기존이미지가 남아있다면, 만약 이미지를 수정하지 않았다면 등등 골치아픈 조건을 없애준다. 

그럼 이미지를 어떻게 삭제하는지 알아보자. 

 

 

FileService

 

이미지 경로로 해당 이미지를 불러온다음, 삭제시킨다. 그럼 판매글을 삭제하는 로직도 할 수 있을 것이다. 

 

 

ProductService

@Transactional
    public Long deleteProduct(Long productId) {
        Product product = productsRepository.findById(productId)
                .orElseThrow(() -> new IllegalArgumentException("판매글이 존재하지 않습니다."));

        if(!product.getImgPath().isEmpty()) {
            fileService.deleteFile(product.getImgPath());
        }
        productsRepository.delete(product);

        return product.getId();
    }

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday