2024-04-30 96일차 - Spring batch

민짱·2024년 4월 30일

📅 2024. 04. 30 96일차


Spring batch

토스페이먼츠 결제 프론트엔드 연동

  • 토스페이먼츠
  • 저번에 했었던 todo_app처럼 토스페이먼츠에 가입해서 API test키를 가져와서 적용시키면 된다!
<script src="https://js.tosspayments.com/v1"></script>

    <script th:inline="javascript">
        const orderId = /*[[ ${order.id} ]]*/ null;
        const buyerName = /*[[ ${order.buyer.name} ]]*/ null;
        const orderName = /*[[ ${order.name} ]]*/ null;
        const orderPayPrice = /*[[ ${order.calculatePayPrice} ]]*/ null;
    </script>

    <script>
        const tossPayments = TossPayments("본인 API text 키");

        function payment(){
            const method = "카드"; // 카드 or 가상계좌

            const paymentData ={
                amount: orderPayPrice,
                orderId: "order__" + orderId,
                orderName,
                customerName: buyerName,
                successUrl: window.location.origin + "/success",
                failUrl: window.location.origin + "/fail",
            };

            tossPayments.requestPayment(method,paymentData);
        }

    </script>

토스페이먼츠 결제 백엔드 연동

 private final String SECRET_KEY = "test_sk_6bJXmgo28eBnx5GDX4Nj3LAnGKWx";

   @PostConstruct
   private void init() {
       restTemplate.setErrorHandler(new ResponseErrorHandler() {
           @Override
           public boolean hasError(ClientHttpResponse response) {
               return false;
           }

           @Override
           public void handleError(ClientHttpResponse response) {
           }
       });
   }

   @RequestMapping("/{id}/success")
   public String confirmPayment(
           @RequestParam String paymentKey, @RequestParam String orderId, @RequestParam Long amount,
           Model model) throws Exception {

       HttpHeaders headers = new HttpHeaders();
       // headers.setBasicAuth(SECRET_KEY, ""); // spring framework 5.2 이상 버전에서 지원
       headers.set("Authorization", "Basic " + Base64.getEncoder().encodeToString((SECRET_KEY + ":").getBytes()));
       headers.setContentType(MediaType.APPLICATION_JSON);

       Map<String, String> payloadMap = new HashMap<>();
       payloadMap.put("orderId", orderId);
       payloadMap.put("amount", String.valueOf(amount));

       HttpEntity<String> request = new HttpEntity<>(objectMapper.writeValueAsString(payloadMap), headers);

       ResponseEntity<JsonNode> responseEntity = restTemplate.postForEntity(
               "https://api.tosspayments.com/v1/payments/" + paymentKey, request, JsonNode.class);

       if (responseEntity.getStatusCode() == HttpStatus.OK) {
           JsonNode successNode = responseEntity.getBody();
           model.addAttribute("orderId", successNode.get("orderId").asText());
           String secret = successNode.get("secret").asText(); // 가상계좌의 경우 입금 callback 검증을 위해서 secret을 저장하기를 권장함
           return "order/success";
       } else {
           JsonNode failNode = responseEntity.getBody();
           model.addAttribute("message", failNode.get("message").asText());
           model.addAttribute("code", failNode.get("code").asText());
           return "order/fail";
       }
   }

   @RequestMapping("/{id}/fail")
   public String failPayment(@RequestParam String message, @RequestParam String code, Model model) {
       model.addAttribute("message", message);
       model.addAttribute("code", code);
       return "order/fail";
   }

백엔드에서 결제 무결성 체크

	// OrderController
 	@RequestMapping("/{id}/success")
    public String confirmPayment(
            @PathVariable long id,
            @RequestParam String paymentKey,
            @RequestParam String orderId,
            @RequestParam Long amount,
            Model model
    ) throws Exception {

        Order order = orderService.findForPrintById(id).get();

        long orderIdInputed = Integer.parseInt(orderId.split("__")[1]);

        if (id != orderIdInputed) {
            throw new OrderIdNotMatchedException();
        }
       // ......=>

백엔드에서 무결성체크시 문제가 없다면 결제 완료 처리

    @Transactional
   public void payByTossPayments(Order order) {
       Member buyer = order.getBuyer();
       int payPrice = order.calculatePayPrice();

       memberService.addCash(buyer, payPrice, "주문결제충전__토스페이먼츠결제");
       memberService.addCash(buyer, payPrice * -1, "주문결제__토스페이먼츠결제");

       order.setPaymentDone();
       orderRepository.save(order);

   }

구조 파악

  • 결제
    • 예치금 10000 => 2000원만 빼다 쓰고 싶다.
    • 토스 페이먼츠
  • 충전 시켜놓은 무언가에서 차감을 시키는건 어떻게 해야할까?
    예시)
  • 4800원을 나눠서 결제하고 싶어..

예상 시나리오

  • 어떤식으로 나눈다는걸까 4000원은 예치금에서 빼서 쓰고 800원은 토스페이먼츠로 결제한단 소린가?

0개의 댓글