반응형
외부 결제 API를 연동하라고 적혀 있어서
사용해본 적 없는 결제 API 중에 토스 결제 API를 써보기로 했다.
1. 토스 개발자센터에서 시크릿키 발급받기
https://developers.tosspayments.com/
테스트키를 사용하면 실제 결제는 이뤄지지 않는다.
2.토스 결제 Entity
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TossPayment extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "payment_id", nullable = false, unique = true)
private Long paymentId;
@Column(nullable = false, unique = true)
private String paymentKey;
@Column(nullable = false)
private String orderId;
@Column(nullable = false)
private String orderName;
@Column(nullable = false, name="amount")
private Long amount;
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "customer_id")
private Customer customer;
}
3. 응답 Response Dto
@Getter
@Setter
public class TossConfirmRequestDto {
String orderId;
Long amount;
String paymentKey;
}
/*
* Record 클래스
* -Java 14부터 도입
* -필드별 getter가 자동으로 생성됨
* -모든 버변수를 인자로 하는 public 생성자를 자동으로 생성함.
*/
public record TossResponseDto (
String paymentKey,
String orderId,
Long amount
) {
public static TossResponseDto from(TossPayment tossPayment) {
return new TossResponseDto(tossPayment.getPaymentKey(), tossPayment.getOrderId(), tossPayment.getAmount());
}
}
4. Controller
@Controller
@RequiredArgsConstructor
public class TossController {
private final CustomerService customerService;
private final TossService tossService;
@GetMapping("/pay")
public String pay(Principal principal, Model model) {
Customer customer = customerService.getCustomerInfo(principal.getName());
model.addAttribute("customer", customer);
return "/toss/checkout";
}
@GetMapping("/success")
public String success(HttpServletRequest request, Model model) {
String paymentKey = request.getParameter("paymentKey");
String orderId = request.getParameter("orderId");
String amount = request.getParameter("amount");
model.addAttribute("paymentKey", paymentKey);
model.addAttribute("orderId", orderId);
model.addAttribute("amount", amount);
return "/product/success";
}
@GetMapping("/fail")
public String fail(HttpServletRequest request, Model model) {
String code = request.getParameter("code");
String message = request.getParameter("message");
String orderId = request.getParameter("orderId");
model.addAttribute("code", code);
model.addAttribute("message", message);
model.addAttribute("orderId", orderId);
return "/product/fail";
}
@RequestMapping(value = "/confirm")
public ResponseEntity<TossResponseDto> confirmPayment(Principal principal, @Valid @RequestBody TossConfirmRequestDto requestDto) throws Exception {
Customer customer = customerService.getCustomerInfo(principal.getName());
TossPayment tossPayment = tossService.confirm(requestDto);
tossPayment.setAmount(requestDto.getAmount());
tossPayment.setCustomer(customer);
tossService.save(tossPayment);
return ResponseEntity.ok().body(TossResponseDto.from(tossPayment));
}
}
5. 프론트단
getOrderTotal, chkAll
function getOrderTotal(){
var orderTotal = 0;
$("input:checkbox[name=cartChkbox]:checked").each(function() {
var cartProductId = $(this).val();
var price = $("#price_" + cartProductId).attr("data-price"); // 가격을 숫자로 처리
var count = $("#count_" + cartProductId).val(); // 수량을 숫자로 처리
orderTotal += price*count;
});
$("#orderTotal").html(orderTotal+'원');
}
function changeCount(obj){
var count = obj.value;
var cartProductId = obj.id.split('_')[1];
var price = $("#price_" + cartProductId).data("price");
var total = count*price;
$("#totalPrice_" + cartProductId).html(total+"원");
getOrderTotal();
}
function chkAll(){
if($("#checkall").is(":checked")){
$("input:checkbox[name=cartChkbox]").prop("checked",true);
}else{
$("input:checkbox[name=cartChkbox]").prop("checked",false);
}
getOrderTotal();
}
requestPayment
const clientKey = "test_클라이언트키"; //토스 결제 개발 연동 클라이언트키
const customerKey = generateRandomString();
const secretKey = "test_시크릿키";
const tossPayments = TossPayments(clientKey);
const payment = tossPayments.payment({ customerKey });
async function requestPayment() {
var nameList = '';
var checkbox = $("input:checkbox[name=cartChkbox]:checked");
checkbox.each(function(i) {
var tr = checkbox.parent().parent().eq(i);
var td = tr.children();
var name = td.eq(1).find("#productName").text();
nameList += ', ' + name;
});
const productName = nameList.substring(1);
const totalText = $("#orderTotal").text();
const total = totalText.substring(0, totalText.length -1);
const orderId = generateRandomString();
console.log(orderId);
await payment.requestPayment({
method: "CARD", // 카드 결제
amount: {
currency: "KRW",
value: parseInt(total),
},
orderId: orderId, // 고유 주분번호
orderName: productName,
successUrl: window.location.origin + "/success", // 결제 요청이 성공하면 리다이렉트되는 URL
failUrl: window.location.origin + "/fail", // 결제 요청이 실패하면 리다이렉트되는 URL
customerEmail: [[${customerEmail}]],
customerName: [[${customerName}]],
customerMobilePhone: null,
// 카드 결제에 필요한 정보
card: {
useEscrow: false,
flowMode: "DEFAULT", // 통합결제창 여는 옵션
useCardPoint: false,
useAppCardOnly: false,
},
});
}
function generateRandomString() {
return window.btoa(Math.random()).slice(0, 20);
}
결제 버튼
<h2 class="text-center">
총 주문 금액 : <span id="orderTotal" class="text-danger">0원</span>
</h2>
<div class="text-center">
<button type="button" class="btn btn-primary btn-lg" onclick="requestPayment()">토스로 결제하기</button>
</div>
체크박스 클릭 시 주문 금액 바뀜
토스 결제창 띄우기
반응형
'💻 my code archive > 🏷️JAVA & Spring(Boot)' 카테고리의 다른 글
스프링부트 Spring Boot + JPA 쇼핑몰 상품 목록, 장바구니 기능 구현 (0) | 2025.01.13 |
---|---|
프로젝트 #1 스프링부트 SpringBoot 3x Swagger 적용법 (1) | 2024.04.20 |
SheetJS 테이블 내용 엑셀 다운로드, 스타일 적용 방법 (0) | 2023.08.18 |
[스프링부트 블로그 만들기] 댓글 기능, 댓글 목록, 삭제까지 구현하기 (0) | 2022.03.25 |
[스프링부트 블로그 만들기] 카카오 로그인 API 서비스 구현하기 (0) | 2022.03.25 |