코딩 노트
결제02 - 단건결제 본문
KakaoPayServiceImpl 수정
@Override
public KakaoPayApproveResponseVO approve(KakaoPayApproveRequestVO request) throws URISyntaxException {
URI uri = new URI("https://kapi.kakao.com/v1/payment/approve");
//body 부분 (5개 중 4개는 request에 들어있다)
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("cid", kakaoPayProperties.getCid());
body.add("tid",request.getTid()); //거래번호
body.add("partner_order_id", request.getPartnerOrderId());
body.add("partner_user_id", request.getPartnerUserId());
body.add("pg_token", request.getPgToken());
HttpEntity entity = new HttpEntity(body,headers);
KakaoPayApproveResponseVO response = template.postForObject(uri, entity, KakaoPayApproveResponseVO.class);
return response;
}
}
KakaopayController 수정
@Controller
@RequestMapping("/pay")
public class KakaoPayController {
@Autowired
private KakaoPayService kakaoPayService;
@GetMapping("/test1")
public String test1() {
//return "/WEB-INF/views/pay/test1.jsp";
return "pay/test1";
}
@PostMapping("/test1")
public String test1(@ModelAttribute KakaoPayReadyRequestVO request,
HttpSession session) throws URISyntaxException {
request.setPartnerOrderId(UUID.randomUUID().toString()); //임시로 추가
KakaoPayReadyResponseVO response = kakaoPayService.ready(request);
//session에 flash value를 저장(잠시 쓰고 지우는 데이터)
//- 사용자를 거치지 않는 범위 내에서 사용해야 안전하게 쓸 수 있다.
//하나하나 넣기
// session.setAttribute("partnerOrderId", request.getPartnerOrderId());
// session.setAttribute("partnerUserId",request.getPartnerUserId());
// session.setAttribute("tid", response.getTid());
//객체로 넣기
session.setAttribute("approve", KakaoPayApproveRequestVO.builder()
.partnerOrderId(request.getPartnerOrderId())
.partnerUserId(request.getPartnerUserId())
.tid(response.getTid())
.build());
return "redirect:" + response.getNextRedirectPcUrl();
}
@GetMapping("/test1/success")
public String test1Success(HttpSession session, @RequestParam String pg_token) throws URISyntaxException {
//session에 저장되어 있는 flash value를 꺼내어 pg_token을 추가한 뒤 승인 요청
KakaoPayApproveRequestVO request = (KakaoPayApproveRequestVO) session.getAttribute("approve");
session.removeAttribute("approve");
request.setPgToken(pg_token); //토큰 추가
//결제 승인 요청
KakaoPayApproveResponseVO response = kakaoPayService.approve(request);
return "redirect:successResult";
}
@GetMapping("/test1/successResult")
public String successResult() {
return "/pay/successResult";
}
}
결제과정
p.o.id와 p.u.id, tid를 저장하기 위해 세션을 사용한다.
사용자를 거치지 않고 두 개의 페이지를 건너 뛸 때...
successResult.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h1>결제가 완료되었습니다.</h1>
Test07 생성
@Slf4j
@SpringBootTest
public class Test07Detail {
@Autowired RestTemplate template;
@Autowired HttpHeaders headers;
@Autowired KakaoPayProperties kakaoPayProperties;
@Test
public void test() throws URISyntaxException {
URI uri = new URI("https://kapi.kakao.com/v1/payment/order");
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("cid", kakaoPayProperties.getCid());
body.add("tid", "T53876a82b8b1abb0e59");
HttpEntity entity = new HttpEntity(body, headers);
Map response = template.postForObject(uri, entity, Map.class);
log.debug("response = {}", response);
}
}
결과
KakaoPayDetailRequestVO 생성
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class KakaoPayDetailRequestVO {
private String tid;
}
KakaoPayDetailResponseVO 생성
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class KakaoPayDetailResponseVO {
private String tid, cid, status;
private String partnerOrderId, partnerUserID;
private String paymentMethodType;
private KakaoPayAmountVO amount, canceledAmount, cancelAvailableAmount;
private String itemName, itemCode;
private int quantity;
private Date createdAt, approvedAt, canceledAt;
private KakaoPaySelectedCardInfoVO selectedCardInfo;
// private KakaoPayPaymentActionDetailsVO[] paymentActionDetails;
private List<KakaoPayPaymentActionDetailVO> paymentActionDetails;
}
KakaoPayPaymentActionDetailVO 파일 생성
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class KakaoPayPaymentActionDetailVO {
private String aid, approvedAt;
private int amount, pointAmount, discountAmount, greenDeposit;
private String paymentActionType, payload;
KakaoPaySelectedCardInfoVO 파일 생성
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class KakaoPaySelectedCardInfoVO {
private String cardBin, cardCorpName, interestFreeInstall;
private int installMonth;
}
KakaoPayService 구문 추가
KakaoPayDetailResponseVO detail(KakaoPayDetailRequestVO request) throws URISyntaxException;
KakaoPayServiceImpl 구문 추가
@Override
public KakaoPayDetailResponseVO detail(KakaoPayDetailRequestVO request) throws URISyntaxException {
URI uri = new URI("https://kapi.kakao.com/v1/payment/order");
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("cid", kakaoPayProperties.getCid());
body.add("tid", request.getTid());
HttpEntity entity = new HttpEntity(body, headers);
KakaoPayDetailResponseVO response = template.postForObject(uri, entity, KakaoPayDetailResponseVO.class);
return response;
}
KakaoPayController 구문 추가
@GetMapping("/test1/detail")
public String detail(Model model, @RequestParam String tid) throws URISyntaxException {
KakaoPayDetailResponseVO response = kakaoPayService.detail(KakaoPayDetailRequestVO.builder()
.tid(tid)
.build());
model.addAttribute("vo", response);
return "pay/detail";
}
detail.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<h1>결제 상세 내역</h1>
<ul>
<li>거래번호 = ${vo.tid}</li>
<li>결제상태 = ${vo.status}</li>
<li>partner_order_id = ${vo.partnerOrderId}</li>
<li>partner_user_id = ${vo.partnerUserId}</li>
<li>
결제유형 =
<c:choose>
<c:when test="${vo.paymentMethodType == 'MONEY'}">현금</c:when>
<c:otherwise>카드</c:otherwise>
</c:choose>
</li>
<li>상품명 = ${vo.itemName}</li>
<li>
결제 시작시각 =
<fmt:formatDate value="${vo.createdAt}" pattern="yyyy-MM-dd E HH:mm:ss"/>
</li>
<li>
결제 승인시각 =
<fmt:formatDate value="${vo.approvedAt}" pattern="yyyy-MM-dd E HH:mm:ss"/>
</li>
<li>
결제 취소시각 =
<fmt:formatDate value="${vo.canceledAt}" pattern="yyyy-MM-dd E HH:mm:ss"/>
</li>
<li>
결제금액 :
<fmt:formatNumber value="${vo.amount.total}" pattern="#,##0"/>
원
</li>
<li>
부가세 :
<fmt:formatNumber value="${vo.amount.vat}" pattern="#,##0"/>
원
</li>
<li>
실상품가 :
<fmt:formatNumber value="${vo.amount.total - vo.amount.vat}" pattern="#,##0"/>
원
</li>
<c:if test="${vo.selectedCardInfo != null}">
<li>
카드정보
<ul>
<li>카드번호 = ${vo.selectedCardInfo.cardBin}</li>
<li>할부개월수 = ${vo.selectedCardInfo.installMonth}</li>
<li>카드사명 = ${vo.selectedCardInfo.cardCorpName}</li>
<li>무이자할부 = ${vo.selectedCardInfo.interestFreeInstall}</li>
</ul>
</li>
</c:if>
</ul>
<hr>
<h1>결제 진행내역</h1>
<ul>
<c:forEach var="paymentActionDetailVO" items="${vo.paymentActionDetails}">
<li>${paymentActionDetailVO}</li>
</c:forEach>
</ul>
KakaoPayCancelRequestVO 생성
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class KakaoPayCancelRequestVO {
private String tid, payload;
private int cancelAmount;
}
KakaoPayCancelResponseVO 생성
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonIgnoreProperties(ignoreUnknown = true)
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class KakaoPayCancelResponseVO {
private String aid, cid, tid, status, partnerOrderId, partnerUserId, paymentMethodType;
private KakaoPayAmountVO amount;
private KakaoPayAmountVO approvedCancelAmount, canceledAmount, cancelAvailableAmount;
private String itemName, itemCode, payload;
private int quantity;
private Date createdAt, approvedAt, canceledAt;
}
KakaoPayService 구문 추가
KakaoPayCancelResponseVO cancel(KakaoPayCancelRequestVO request) throws URISyntaxException;
KakaoPayServiceImpl 구문 추가
@Override
public KakaoPayCancelResponseVO cancel(KakaoPayCancelRequestVO request) throws URISyntaxException {
URI uri = new URI("https://kapi.kakao.com/v1/payment/cancel");
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("cid", kakaoPayProperties.getCid());
body.add("tid", request.getTid());
body.add("cancel_amount", String.valueOf(request.getCancelAmount()));
HttpEntity entity = new HttpEntity(body, headers);
KakaoPayCancelResponseVO response =
template.postForObject(uri, entity, KakaoPayCancelResponseVO.class);
return response;
}
Test08Cancel 생성
@Slf4j
@SpringBootTest
public class Test08Cancel {
@Autowired
private KakaoPayService kakaoPayService;
@Test
public void test() throws URISyntaxException {
KakaoPayCancelRequestVO request = KakaoPayCancelRequestVO.builder()
.tid("T538a35a51b66fd40a89")
.cancelAmount(100)
.build();
KakaoPayCancelResponseVO response = kakaoPayService.cancel(request);
log.debug("response = {}", response);
}
detail.jsp에 구문 추가
<h1>결제 상세 내역</h1>
<c:if test = "${vo.status != 'CANCEL_PAYMENT'}">
<a href="cancel?tid=${vo.tid}&cancelAmount=${vo.cancelAvailableAmount.total}">취소</a>
</c:if>
KakaoPayController에 구문 추가
@RequestMapping("/test1/cancel")
public String cancel(@ModelAttribute KakaoPayCancelRequestVO request) throws URISyntaxException {
KakaoPayCancelResponseVO response = kakaoPayService.cancel(request);
return "redirect:detail?tid="+request.getTid();
}
남은 금액이 다 취소된다.
KakaoPayController 구문 추가
/////////////////////////////////////////////////////////////////////////////
@Autowired
private ProductDao productDao;
@RequestMapping("/test2")
public String test2(Model model) {
model.addAttribute("list", productDao.selectList());
return "pay2/home";
}
home.jsp 추가
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h1>상품을 기반으로 한 구매(DB 포함)</h1>
<c:forEach var="productDto" items="${list}">
<li>
${productDto.productName} (${productDto.productPrice} 원)
<a href="#">구매하기</a>
</li>
</c:forEach>
ProductDto 파일 생성
@Data @AllArgsConstructor @NoArgsConstructor @Builder
public class ProductDto {
private int productNo;
private String productName;
private int productPrice;
}
mybatis 폴더 생성 후 product-mapper.xml 생성
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="product">
<select id="list" resultType="ProductDto">
select * from product order by product_no asc
</select>
</mapper>
ProductDao 생성
public interface ProductDao {
List<ProductDto> selectList();
}
ProductDaoImpl 생성
@Repository
public class ProductDaoImpl implements ProductDao {
@Autowired
private SqlSession sqlSession;
@Override
public List<ProductDto> selectList() {
return sqlSession.selectList("product.list");
}
}j
product 테이블 데이터베이스 구문
create table product(
product_no number primary key,
product_name varchar2(90) not null,
product_price number not null check(product_price >= 0)
);
create sequence product_seq;
SELECT * FROM product;
insert into product values(product_seq.nextval, '처음처럼', 1200);
insert into product values(product_seq.nextval, '참이슬', 1100);
insert into product values(product_seq.nextval, '새로', 1500);
insert into product values(product_seq.nextval, '별빛청하', 2200);
insert into product values(product_seq.nextval, '카스', 2100);
insert into product values(product_seq.nextval, '테라', 2300);
insert into product values(product_seq.nextval, '땅콩', 3000);
insert into product values(product_seq.nextval, '마른오징어', 2500);
insert into product values(product_seq.nextval, '쥐포', 4000);
insert into product values(product_seq.nextval, '떡볶이', 5000);
insert into product values(product_seq.nextval, '오뎅탕', 7500);
insert into product values(product_seq.nextval, '콘치즈', 3100);
insert into product values(product_seq.nextval, '일회용젓가락', 1700);
insert into product values(product_seq.nextval, '일회용종이컵', 990);
COMMIT;
home.jsp 파일 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h1>상품을 기반으로 한 구매(DB 포함)</h1>
<c:forEach var="productDto" items="${list}">
<li>
${productDto.productName} (${productDto.productPrice} 원)
<a href="test2/purchase?productNo=${productDto.productNo}">구매하기</a>
</li>
</c:forEach>
ProductDao 구문 추가
public interface ProductDao {
List<ProductDto> selectList();
ProductDto selectOne(int productNo);
}
product-mapper.xml 에 구문 추가
<select id="find" resultType="ProductDto">
select * from product where product_no = #{productNo}
</select>
ProductDaoImpl에 구문 추가
@Override
public ProductDto selectOne(int productNo) {
return sqlSession.selectOne("product.find", productNo);
}
KakaoPayController에 구문 추가
@GetMapping("/test2/purchase")
public String purchase(HttpSession session, @RequestParam int productNo) throws URISyntaxException {
//상품정보 조회
ProductDto productDto = productDao.selectOne(productNo);
//상품정보를 이용하여 결제준비요청
KakaoPayReadyRequestVO request = KakaoPayReadyRequestVO.builder()
.itemName(productDto.getProductName())
.itemPrice(productDto.getProductPrice())
.partnerOrderId(UUID.randomUUID().toString())
.partnerUserId("testuser1")
.build();
KakaoPayReadyResponseVO response = kakaoPayService.ready(request);
//session에 flash value를 저장(잠시 쓰고 지우는 데이터)
//- 사용자를 거치지 않는 범위 내에서 사용해야 안전하게 쓸 수 있다.
//객체로 넣기
session.setAttribute("approve", KakaoPayApproveRequestVO.builder()
.partnerOrderId(request.getPartnerOrderId())
.partnerUserId(request.getPartnerUserId())
.tid(response.getTid())
.build());
//결제페이지를 사용자에게 안내
return "redirect:"+response.getNextRedirectPcUrl();
}
//결제 성공
@GetMapping("/test2/purchase/success")
public String test2Success(HttpSession session, @RequestParam String pg_token) throws URISyntaxException {
//session에 저장되어 있는 flash value를 꺼내어 pg_token을 추가한 뒤 승인 요청
KakaoPayApproveRequestVO request = (KakaoPayApproveRequestVO) session.getAttribute("approve");
session.removeAttribute("approve");
request.setPgToken(pg_token); //토큰 추가
//결제 승인 요청
KakaoPayApproveResponseVO response = kakaoPayService.approve(request);
return "redirect:successResult";
}
@RequestMapping("/test2/purchase/successResult")
public String test2SuccessResult() {
return "pay2/successResult";
}
}
결제 내역을 남기기 위해
데이터베이스 payment 결제 테이블 생성
-- 결제에 필요한 테이블 생성 (결제내역이 사라지면 안 되는, 기록이기 때문에 외래키를 쓰면 안 된다)
-- 외래키를 쓰는 게 안전하지만 그렇게 되면 회원이나 상품이 탈퇴되면 안 된다.
CREATE TABLE payment(
payment_no NUMBER PRIMARY key,
payment_member varchar2(20) NOT null,
payment_product NUMBER NOT null,
payment_tid varchar2(20) NOT null,
payment_name varchar2(300) NOT null,
payment_price NUMBER NOT null,
payment_time date DEFAULT sysdate NOT null
);
CREATE SEQUENCE payment_seq;
PaymentDto 생성
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class PaymentDto {
private int paymentNo, paymentPrice; //PG사 결제 가격
private int paymentProduct; //구매상품번호
private String paymentMember; //구매회원ID
private String paymentTid; //PG사 결제 거래번호
private String paymentName; //PG사 결제 상품명
private Date paymentTime;
}
payment-mapper.xml 생성
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="payment">
<select id="sequence" resultType="int">
select payment_seq.nextval from dual
</select>
<insert id ="save">
insert into payment(
payment_no, payment_member, payment_product, payment_tid, payment_name, payment_price
)
values(
#{paymentNo}, #{paymentMember, #{paymentProduct}, #{paymentTid}, #{paymentName}, #{paymentPrice}
)
</insert>
</mapper>
PaymentDao 생성
public interface PaymentDao {
int sequence();
void insert(PaymentDto paymentDto);
}
PaymentDaoImpl 생성
@Repository
public class PaymentDaoImpl implements PaymentDao {
@Autowired
private SqlSession sqlSession;
public int sequence() {
return sqlSession.selectOne("payment.sequence");
}
@Override
public void insert(PaymentDto paymentDto) {
sqlSession.insert("payment.save", paymentDto);
}
}
KakaoPayController에 구문 추가
@Controlle
@RequestMapping("/pay")
public class KakaoPayController {
@Autowired
private KakaoPayService kakaoPayService;
@Autowired
private PaymentDao paymentDao; //추가
@GetMapping("/test1")
public String test1() {
//return "/WEB-INF/views/pay/test1.jsp";
return "pay/test1";
}
@PostMapping("/test1")
public String test1(@ModelAttribute KakaoPayReadyRequestVO request,
HttpSession session) throws URISyntaxException {
request.setPartnerOrderId(UUID.randomUUID().toString());
KakaoPayReadyResponseVO response = kakaoPayService.ready(request);
//session에 flash value를 저장(잠시 쓰고 지우는 데이터)
//- 사용자를 거치지 않는 범위 내에서 사용해야 안전하게 쓸 수 있다.
//하나하나 넣기
// session.setAttribute("partnerOrderId", request.getPartnerOrderId());
// session.setAttribute("partnerUserId",request.getPartnerUserId());s
// session.setAttribute("tid", response.getTid());
session.setAttribute("approve", KakaoPayApproveRequestVO.builder()
.partnerOrderId(request.getPartnerOrderId())
.partnerUserId(request.getPartnerUserId())
.tid(response.getTid())
.build());
return "redirect:" + response.getNextRedirectPcUrl();
}
@GetMapping("/test1/success")
public String test1Success(HttpSession session, @RequestParam String pg_token) throws URISyntaxException {
//session에 저장되어 있는 flash value를 꺼내어 pg_token을 추가한 뒤 승인 요청
KakaoPayApproveRequestVO request =
(KakaoPayApproveRequestVO) session.getAttribute("approve");
session.removeAttribute("approve");
request.setPgToken(pg_token);//토큰 추가
//결제 승인 요청
KakaoPayApproveResponseVO response = kakaoPayService.approve(request);
return "redirect:successResult";
}
@GetMapping("/test1/successResult")
public String successResult() {
//return "/WEB-INF/views/pay/successResult.jsp";
return "pay/successResult";
}
@GetMapping("/test1/detail")
public String detail(Model model, @RequestParam String tid) throws URISyntaxException {
KakaoPayDetailResponseVO response =
kakaoPayService.detail(KakaoPayDetailRequestVO.builder()
.tid(tid)
.build());
model.addAttribute("vo", response);
//return "/WEB-INF/views/pay/detail.jsp";
return "pay/detail";
}
@RequestMapping("/test1/cancel")
public String cancel(@ModelAttribute KakaoPayCancelRequestVO request) throws URISyntaxException {
KakaoPayCancelResponseVO response = kakaoPayService.cancel(request);
return "redirect:detail?tid="+request.getTid();
}
///////////////////////////////////////////////////////////////////////////////////////////
@Autowired
private ProductDao productDao;
@RequestMapping("/test2")
public String test2(Model model) {
model.addAttribute("list", productDao.selectList());
//return "/WEB-INF/views/pay2/home.jsp";
return "pay2/home";
}
@GetMapping("/test2/purchase")
public String purchase(HttpSession session, @RequestParam int productNo) throws URISyntaxException {
//상품정보 조회
ProductDto productDto = productDao.selectOne(productNo);
//상품정보를 이용하여 결제준비요청
KakaoPayReadyRequestVO request = KakaoPayReadyRequestVO.builder()
.itemName(productDto.getProductName())
.itemPrice(productDto.getProductPrice())
.partnerOrderId(UUID.randomUUID().toString())
.partnerUserId("testuser1")
.build();
KakaoPayReadyResponseVO response = kakaoPayService.ready(request);
//session에 flash value를 저장(잠시 쓰고 지우는 데이터)
//- 사용자를 거치지 않는 범위 내에서 사용해야 안전하게 쓸 수 있다
session.setAttribute("approve", KakaoPayApproveRequestVO.builder()
.partnerOrderId(request.getPartnerOrderId())
.partnerUserId(request.getPartnerUserId())
.tid(response.getTid())
.build());
session.setAttribute("productNo", productNo);
//결제페이지를 사용자에게 안내
return "redirect:"+response.getNextRedirectPcUrl();
}
//결제 성공
@GetMapping("/test2/purchase/success")
public String test2Success(HttpSession session, @RequestParam String pg_token) throws URISyntaxException {
//session에 저장되어 있는 flash value를 꺼내어 pg_token을 추가한 뒤 승인 요청
KakaoPayApproveRequestVO request =
(KakaoPayApproveRequestVO) session.getAttribute("approve");
int productNo = (int)session.getAttribute("productNo");
session.removeAttribute("approve");
session.removeAttribute("productNo");
request.setPgToken(pg_token);//토큰 추가
//결제 승인 요청
KakaoPayApproveResponseVO response = kakaoPayService.approve(request);
//결제 승인이 완료되었다면 DB에 결제 정보를 저장
int paymentNo = paymentDao.sequence();
paymentDao.insert(PaymentDto.builder()
.paymentNo(paymentNo)
.paymentMember(response.getPartnerUserId())
.paymentProduct(productNo)
.paymentTid(response.getTid())
.paymentName(response.getItemName())
.paymentPrice(response.getAmount().getTotal())
.build());
return "redirect:successResult";
}
@RequestMapping("/test2/purchase/successResult")
public String test2SuccessResult() {
return "pay2/successResult";
}
}
'Spring' 카테고리의 다른 글
결제04 - 마무리 (0) | 2023.10.27 |
---|---|
결제03 - 수량추가 + 조회 + 단건취소 (0) | 2023.10.26 |
결제01 - (카카오페이 api) + 카멜케이스 변환 (0) | 2023.10.24 |
DM을 어떻게 보내는가 (0) | 2023.10.23 |
웹소켓 - 실시간 채팅, 반응형 디자인 (0) | 2023.10.23 |