티스토리 뷰

반응형

페이팔과 연동해서 구매자가 결제한 상세정보를 상점에서 DB처리 및 작업을 하기 위해 페이팔에서 제공하는 주요 기능이 있는데 

그게 바로 PDT방식과 IPN방식이다. 두 가지 방식의 특징을 살펴보자.


PDT

- 실시간으로 결제결과를 상점서비스로 전송해준다.(동기방식)

- 동기방식이므로 만약 구매자가 결제를 완료 후 페이팔서버에서 상점서비스로 

결제정보를 전송전에 브라우저를 닫아버리면 해당 이벤트가 사라지고 다시 결제결과를 받을 수 있는 방법이 없다.


IPN

- 결제가 완료되면 결제결과를 페이팔서버에 보관해두었다가 상점서비스로 전송해준다.(비동기방식)

- 비동기방식이므로 구매자가 결제를 완료 후에 바로 페이팔서버에서 상점서비스로 전송해준다는 보장이 없다.

- 구매자가 결제 완료 후 브라우저를 닫아버려도 페이팔서버는 상점서버가 수신을 할때까지 몇번이고 재전송을 해주므로

결제결과를 무조건 다시 받을 수 있다.


이런 두가지의 특성때문에 사용자가 상품을 구매시 결제결과를 

바로 알려주지 않아도 되는 서비스를 제외하면 PDT, IPN 두가지 방식을 동시에 사용해야한다. 


먼저 그 첫번째 PDT 방식을 적용해보자.


PDT를 사용하기 위해선 먼저 페이팔사이트에 접속해서 아래와 같이 PDT사용설정을 해야한다.

 



My Account > Profile > My Selling Tools 메뉴를 클릭한다.




My selling tools > My business setup > Website preferences의 update를 누르면 PDT를 설정할 수 있는 페이지가 나온다.



Auto Return을 On으로 설정하고

Payment Data Transfer도 On으로 설정한 후 

가장 중요한건 Return URL에 입력하는건데 이 URL로 페이팔서버가 결제정보를 전송해주고 해당 URL에 PDT를 처리하는 핸들러를 구현하면된다.


마지막으로 Save버튼을 누르면 설정 적용이 완료되는데 다시 이 설정페이지로 가서 Payment Data Transfer 영역 아래를 살펴보면 

Identity token에 값이 나올텐데 이 값은 PDT처리핸들러에 구현할때 필요하므로 기억해두자.


이렇게 하면 사이트에서 PDT 사용설정을 끝냈고 이제 상점에서 실제로 연동작업하는 처리를 해보자.

먼저 PDT의 처리하는 과정을 살펴보면서 설명을 시작하겠다.


초록색 배경 : 회원이 눈으로 볼 수 있는 페이지

구름안에 있는 요소들은 내부적으로 페이팔과 상점 서버들이 요청과 응답을 통해서 결제결과에 대한 작업을 진행한다.

그림으로 봤을때 상점결제페이지 -> 페이팔결제팝업 -> 페이팔서버 까지가 이전 포스팅에서 했던 처리 프로세스다.



결제가되면 PDT설정정보의 Return URL로 tx값을 포함한 정보를 전송해주는데 

PDT핸들러에서 응답받은 tx값과 아까 기억해둔 Identity token값을 포함해서 다시 페이팔서버로 POST전송하게되면 

페이팔서버는 인증 확인 후 결제에 대한 상세한 내용을 다시 리턴해준다. 그러면 리턴된 정보를 통해서 

상점은 DB처리와 성공/실패여부처리등의 작업을 진행한 후 사용자에게 알맞은 페이지를 띄워주면 된다.



아래는 자바로 작성된 PDT를 처리하는 핸들러 샘플 소스다.


public class VerifyPaymentByPayPal {

private Logger logger = LoggerFactory.getLogger(getClass());

private static String URL_PAYPAL_VALIDATE; // PDT데이터를 페이팔로 보낼 서버주소


// PDT 첫번째 응답 변수 선

private static final String PARAM_TX = "tx";

private static final String PARAM_CMD = "cmd";

private static final String PARAM_CMD_VALUE = "_notify-synch";

private static final String PARAM_AT = "at";

private static String PARAM_AT_VALUE;


private static final String RESPONSE_SUCCESS = "SUCCESS";

private static final String RESPONSE_FAIL = "FAIL";


static

{

URL_PAYPAL_VALIDATE = "https://www.sandbox.paypal.com/cgi-bin/webscr";

PARAM_AT_VALUE = "페이팔사이트에서 나와있는 Identity token값";

}

private static final String PARAM_ITEM_NAME = "item_name"; // 상품이름

private static final String PARAM_ITEM_NUMBER = "item_number"; // 상품번호

private static final String PARAM_PAYMENT_STATUS = "payment_status";       // 결제 상태

private static final String PARAM_MC_GROSS = "mc_gross"; // 페이팔 결제금액

private static final String PARAM_MC_FEE = "mc_fee"; // 페이팔 수수료금액

private static final String PARAM_MC_CURRENCY = "mc_currency"; // 화폐

private static final String PARAM_TXN_ID = "txn_id"; // 거래번호

private static final String PARAM_RECEIVER_EMAIL = "receiver_email";       // 페이팔 판매자계정 이메일 

private static final String PARAM_PAYER_EMAIL = "payer_email"; // 페이팔 구매자계정 이메일

private static final String PARAM_CUSTOM = "custom"; // 상점회원번호

/** 페이팔 결제 PDT정보 핸들링  */

public void handleRequestPDT(HttpServletRequest request) throws Exception {

// PayPal로부터온 파라미터를 표시한다.

Enumeration en = request.getParameterNames();

String readString = "";

while (en.hasMoreElements()) {

String paramName = (String) en.nextElement();

String paramValue = request.getParameter(paramName);

readString = readString + "&" + paramName + "=" + URLDecoder.decode(paramValue, "UTF-8");

}

logger.info("Received PDT from PayPal:" + readString);

// 다시 PayPal로 게시하기 위해 파라미터를 구성한다.

String str = PARAM_CMD + "=" + PARAM_CMD_VALUE;

en = request.getParameterNames();

while (en.hasMoreElements()) {

String paramName = (String) en.nextElement();

String paramValue = request.getParameter(paramName);

str = str + "&" + paramName + "=" + URLEncoder.encode(paramValue, "UTF-8");

}

str = str + "&" + PARAM_AT + "=" + PARAM_AT_VALUE;

logger.info("Sending PDT to PayPal:" + str);


// 유효성을 검사하기 위해 PayPal로 다시 전송시작.

URL u = new URL(URL_PAYPAL_VALIDATE);

HttpURLConnection uc = (HttpURLConnection) u.openConnection();

uc.setDoOutput(true);

uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

PrintWriter pw = new PrintWriter(uc.getOutputStream());

pw.println(str);

pw.close();


BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));

String res = in.readLine();


if (res.equals(RESPONSE_SUCCESS)) {

logger.info("페이팔서버로 부터 PDT유효성 요청이 성공했습니다.");

String[] temp;

HashMap vars = new HashMap();

while ((res = in.readLine()) != null) {

temp = res.split("=");

if (temp.length == 2) {

vars.put(temp[0], URLDecoder.decode(temp[1], "UTF-8"));

} else {

vars.put(temp[0], "");

}

logger.info("{}{}{}",new Object[]{temp[0],":",temp[1]});

}

String itemName = (String) vars.get(PARAM_ITEM_NAME);

int itemNumber = Integer.parseInt((String) vars.get(PARAM_ITEM_NUMBER));

String paymentStatus = (String) vars.get(PARAM_PAYMENT_STATUS);

double paymentAmount = Double.parseDouble((String) vars.get(PARAM_MC_GROSS));

double paymentFee = Double.parseDouble((String) vars.get(PARAM_MC_FEE));

String paymentCurrency = (String) vars.get(PARAM_MC_CURRENCY);

String txnId = (String) vars.get(PARAM_TXN_ID);

String receiverEmail = (String) vars.get(PARAM_RECEIVER_EMAIL);

String payerEmail = (String) vars.get(PARAM_PAYER_EMAIL);

int userseq = Integer.parseInt((String) vars.get(PARAM_CUSTOM));


.. DB 작업 및 응답페이지 호출 등등 작업을 한다..

} else if (res.equals(RESPONSE_FAIL)) {

logger.warn("페이팔서버로 부터 PDT유효성 요청이 실패했습니다. 상태:"+res);

} else {

logger.error("페이팔서버로 부터 PDT유효성 요청이 실패했습니다. 상태:"+res);

}


}

}

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함