본문 바로가기

회고록(TIL&WIL)

TIL 2022.11.21 Spring webflux(webclinet), spring cron 간단 예제

Spring webflux 간단 사용

의존성 추가 (gradle)

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-webflux:2.7.5'
}

결제내역 생성 시 구독자 수 증가를 위해 외부 API 호출

App/controller/PaymentApiController.java

// 구독자 수 증가 API 호출
    public void updateSubCount(Payment payment) {
        WebClient webClient = WebClient.create();
        webClient.put()
                .uri("http://"+ Constants.AWS_IP+Constants.PORT_LOOKUP+"/consumer/product/subscriber")
                .body(BodyInserters.fromFormData("product_id", payment.getProductId().toString()))
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

- 결제내역 생성 후 해당 상품의 구독 중인 구독자의 수 증가시키는 외부 API 호출

-> put 요청으로 원하는 uri에 요청을 보내되 body에 form 데이터 형태로 {product_id : 1} 을 포함하여 request 요청

-> 기존은 non-block 형태로 request하나 결제 데이터 생성 후 구독자 수 증가까지 반영 후 마치도록 block() 함수 사용

 

메일 발송과 이를 위한 정보를 조회하여 가져오기 위해서 webClient 를 이용하여 해당 api 호출하여 메일 발송 메서드 구현

// 메일발송
    public void emailSend(String user_email, Payment payment) {
        // product_id 를 이용해 product의 정보 조회
        WebClient findProduct = WebClient.create();
        String responseData = findProduct.get()
                .uri("http://"+ Constants.AWS_IP+Constants.PORT_LOOKUP+"/consumer/product/detail/"+ payment.getProductId())
                .retrieve()
                .bodyToMono(String.class)
                .block();
        JSONObject product_details = new JSONObject(responseData);
        JSONObject product_info = product_details.getJSONObject("detail_product_data");
        String product_name = (String) product_info.get("product_name");
        String subtitle = (String) product_info.get("subtitle");
        String product_group_name = (String) product_info.get("product_group_name");

        // 메일발송 API 호출
        Map<String, Object> mailData = new HashMap<>();
        mailData.put("subject", "결제가 완료되었습니다. - 모아구독");
        mailData.put("message", "결제가 완료되었습니다! - 모아구독 \n" +
                "상품 그룹 : " + product_group_name + "\n" +
                "구독 상품 명 : " + product_name +" - " + subtitle + "\n" +
                "결제 금액 : " + payment.getPrice() + "원 \n" +
                "구독 날짜 : " + payment.getSubscriptionDate() + "\n" +
                "만료 날짜 : " + payment.getExpirationDate() + "\n" +
                "갱신 날짜 : " + payment.getPaymentDueDate() + "\n" +
                "감사합니다.");
        mailData.put("recipient", Arrays.asList(user_email));
        WebClient mailReq = WebClient.create();
        mailReq.post()
                .uri("http://"+ Constants.AWS_IP+Constants.PORT_MAIL+"/mail/api")
                .accept(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(mailData))
                .retrieve()
                .bodyToMono(String.class)
                .block();
    }

-> 최초 product의 정보를 가져와서 JSONObject 를 이용하여 json 형태의 값들을 가져와 원하는 값 각각 String 으로 받아와서 사용하였고 이를 토대로 메일 발송에 데아터로 기입

-> 해당 값들을 Map에 저장해서 webClient에 body에 해당 데이터를 담아서 메일발송하는 api 호출


Spring cron 간단 사용

가상 자동결제 구현을 위해 매일 오전 11시마다 paymentDueDate가 당일인 결제 내역들을 확인하여 날짜가 일치하는 결제 내역들에 기간을 1달 추가하여 새로운 payment 생성되고 이에 따른 메일 발송도 될 수 있도록 Spring cron을 이용하여 메서드가 자동으로 실행될 수 있도록 스케쥴링

 

App/PaymentApplication.java

@SpringBootApplication
@EnableScheduling
public class PaymentApplication {

	public static void main(String[] args) {
		SpringApplication.run(PaymentApplication.class, args);
	}

}

-> 메인 어플리케이션 java 파일에 @EnableScheduling 어노테이션 추가

 

App/util/Scheduler.java

package org.payment.util;

import org.payment.entity.Payment;
import org.payment.entity.PaymentRepository;
import org.payment.service.PaymentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import java.time.LocalDate;
import java.util.List;

@Component
public class Scheduler {
    @Autowired
    private PaymentRepository paymentRepository;
    @Autowired
    private PaymentService paymentService;

    // 가상 정기 결제
    // 실결제는 X , 일정 시간 paymentDueDate 조회하여
    // 날짜 한달 뒤인 새로운 payment 자동 생성
    @Scheduled(cron = "0 0 11 * * *") // 매일 오전 11시 마다
    public void scheduleRun(){
        List<Payment> paymentList = paymentRepository.findByPaymentDueDate(LocalDate.now());
        for(Payment data : paymentList){
            Payment entity = Payment.builder()
                    .price(data.getPrice())
                    .productId(data.getProductId())
                    .consumerId(data.getConsumerId())
                    .sellerId(data.getSellerId())
                    .subscriptionDate(LocalDate.now())
                    .expirationDate(LocalDate.now().plusMonths(1))
                    .paymentDueDate(LocalDate.now().plusMonths(1))
                    .build();
            Payment newPayment = paymentRepository.save(entity);
            // 해당 consumer의 이메일 주소 획득
            WebClient webClient = WebClient.create();
            String email = webClient.get()
                    .uri("http://"+Constants.AWS_IP+Constants.PORT_AUTH+"/user/"+newPayment.getConsumerId())
                    .retrieve()
                    .bodyToMono(String.class)
                    .block();
            // 메일 발송
            paymentService.emailSend(email.replaceAll("\"",""), newPayment);
        }
    }
}

cron을 이용하여 일정 스케쥴에 맞춰서 실행될 함수 위에 @Scheduled 어노테이션 추가

(cron = 초 분 시 일 월 요일) 으로 설정

참고

- https://itworldyo.tistory.com/40

- https://nowonbun.tistory.com/279