오류 및 문제점
1. cannot deserialize from Object value
- 문제점: Entity 클래스를 반환하는 중 JSON Serialize 과정에서 에러가 발생했다.
- 해결방안: DTO에 @NoArgsConstructor을 추가한다.
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ShoppingDTO {
}
2. 외부 API 호출
- 문제점: Service 내부에서 api를 호출해야 한다.
- 해결방안: WebClient를 이용해 요청을 생성한다.
implementation 'org.springframework.boot:spring-boot-starter-webflux'
진행 상황
1. History 트리거를 위한 시퀀스 생성
create TABLE SEQUENCES(
name varchar(32) primary key,
currval BIGINT unsigned
);
DELIMITER
create procedure `create_sequence` (IN seq_name text, IN start_val int)
modifies sql data
deterministic
begin
delete from SEQUENCES where name = seq_name;
insert into SEQUENCES values(seq_name, start_val);
END
DELIMITER ;
DELIMITER
create function `seq_nextval` (seq_name VARCHAR(32))
RETURNS BIGINT unsigned
MODIFIES SQL DATA
Deterministic
begin
declare ret BIGINT unsigned;
update SEQUENCES set currval = currval +1 where name = seq_name;
select currval into ret from SEQUENCES where name = seq_name limit 1;
return ret;
END
DELIMITER ;
CALL create_sequence('seq_history', 0);
2. 트리거를 이용해 ExportProductHistory에 추가
- 출고 완료, 주문 취소로 상태가 변경되면 히스토리에 추가
DELIMITER
CREATE TRIGGER trigger_history_export_product
AFTER UPDATE ON export_product
FOR EACH ROW
BEGIN
INSERT INTO export_product_history(history_export_product_no, updated_date, updated_type, amount, export_date, export_no, export_product_no, invoice_no, order_status, product_no, selling_price)
VALUES(seq_nextval('seq_history'), CURRENT_TIMESTAMP(), 'UPDATE', OLD.amount, OLD.export_date, OLD.export_no, OLD.export_product_no, OLD.invoice_no, OLD.order_status, OLD.product_no, OLD.selling_price);
END
DELIMITER ;
3. 송장 출력
- 트리거
- 쇼핑몰 상품 상태: 배송준비중 -> 배송중
- 쇼핑몰 상품 송장 번호, 출고 일자 추가
- 상품 재고 감소
DELIMITER
CREATE TRIGGER print_invoice
AFTER UPDATE ON export_product
FOR EACH ROW
BEGIN
UPDATE shopping_product SET order_status = '배송중', export_date=NEW.export_date, invoice_no=NEW.invoice_no
WHERE export_no = NEW.export_no AND product_no = NEW.product_no;
UPDATE product SET current_stock = current_stock - NEW.amount
WHERE product_no = NEW.product_no;
END
DELIMITER ;
@Transactional
public List<ExportInvoiceDTO> printInvoice(String exportNo, List<ExportInvoiceDTO> invoiceProducts) {
List<ExportInvoiceDTO> exportInvoiceDTOs = new ArrayList<>();
List<ExportProduct> exportProducts = new ArrayList<>();
String invoiceNo = String.valueOf(new Date().getTime());
for(ExportInvoiceDTO invoiceProduct : invoiceProducts) {
int amount = invoiceProduct.getAmount();
String productNo = invoiceProduct.getProductNo();
ExportInvoiceDTO exportInvoiceDTO = ExportInvoiceDTO
.builder()
.amount(amount)
.invoiceNo(isAvailableForExport(productNo, amount) ? invoiceNo : null)
.productNo(invoiceProduct.getProductNo())
.build();
if(exportInvoiceDTO.getInvoiceNo() != null) {
ExportProduct exportProduct = exportProductRepository.findByExports_ExportNoAndProduct_ProductNo(exportNo, productNo);
ExportProductHistory exportProductHistory = exportProduct.toExportProductHistory();
exportProduct.updateExportProductByExportInvoiceDTO(exportInvoiceDTO);
exportProducts.add(exportProduct);
}
exportInvoiceDTOs.add(exportInvoiceDTO);
}
exportProductRepository.saveAll(exportProducts);
return exportInvoiceDTOs;
}
private boolean isAvailableForExport (String productNo, int amount) {
Product product = productService.findByProductNo(productNo);
return amount <= product.getCurrentStock();
}
4. 상품 현재 재고 히스토리 테이블 생성
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class CurrentStockHistory {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long currentStockHistoryNo;
@NotNull
private String productNo;
@CreationTimestamp
private Timestamp updatedDate;
@NotNull
private int preStock;
@NotNull
private int currentStock;
@NotNull
private int updatedCount;
}
5. 출고 주문건 수집 쇼핑몰 요청으로 수정중
- 변경전: shoppingService를 이용해 직접 shopping 테이블에서 주문건 수집
- 변경후: WebClient를 이용해 쇼핑몰로 주문 수집 요청 전달
@GetMapping("/shop/order/send/{sellerNo}")
public List<ShoppingDTO> sendOrderToWMS(@PathVariable Long sellerNo) {
return shoppingService.sendOrderToWMS(sellerNo);
}
@Transactional
public List<ExportsDTO> register(Long sellerNo, int pageNum, int countPerPage) {
Seller seller = sellerService.findById(sellerNo);
WebClient webClient = WebClient.builder().baseUrl("http://localhost:4885").build();
List<ShoppingDTO> shoppingDTOs = webClient
.get()
.uri(UriBuilder -> UriBuilder.path("/shop/order/send/" + sellerNo).build())
.retrieve()
.bodyToMono(List.class)
.block();
for(ShoppingDTO shoppingDTO: shoppingDTOs) {
List<ExportProduct> exportProducts = new ArrayList<>();
Exports exports = shoppingDTO.toExports(seller);
Exports savedExports = exportsRepository.save(exports);
for(ShoppingProductDTO shoppingProductDTO : shoppingDTO.getOrderedProducts()) {
Product product = productService.findByProductNo(shoppingProductDTO.getProductNo());
ExportProduct exportProduct = shoppingProductDTO.toExportProduct(savedExports, product);
exportProducts.add(exportProduct);
}
List<ExportProduct> savedExportProducts = exportProductRepository.saveAll(exportProducts);
if(savedExports == null || savedExportProducts == null) findExports(sellerNo, 0, countPerPage);
}
return findExports(sellerNo, 0, countPerPage);
}
6. 컨트롤러 테스트
참고 자료