영수증 미리보기

구분 | IP | 비고 |
---|---|---|
테스트 | 211.193.35.11 | STG |
운영 - 결제 | 211.193.35.20 | |
운영 - 재통보 | 211.193.35.216 211.193.35.217 |
재통보 서비스 사용시 |
파라미터 | 항목명 | 길이(char) | 필수여부 | 설명 |
---|---|---|---|---|
PayMethod | 지불수단 | 10 | 필수 | VBANK:가상계좌
※ 가상계좌 이용 시, 입금통보 URL( RetryUrl ) 설정은 필수입니다. (좌측 재통보 메뉴 참고) |
GoodsCnt | 결제상품 품목 개수 | 2 | 필수 | 기본값: 1 |
GoodsName | 거래 상품명 | 40 | 필수 | |
Amt | 거래 금액 | 12 | 필수 | 숫자만 가능, 문장부호 제외 |
Moid | 상품주문번호 | 40 | 필수 | 특수문자 포함 불가 |
EdiDate | 전문생성일시 | 14 | 필수 | YYYYMMDDHHmmss(형식) |
Mid | 상점아이디 | 10 | 필수 | |
TransType | 거래형태 | 2 | 필수 | 기본값: 00, 일괄채번: 04 |
SubId | 서브아이디 | 20 | 선택 | 일괄채번일 경우 요청 가상계좌번호 입력 |
BuyerName | 구매자명 | 30 | 필수 | |
BuyerTel | 구매자연락처 | 40 | 필수 | 숫자만 입력 (문자 입력 시 10자 미만으로 설정 하셔야합니다. - 초과 시 승인 오류 발생) |
BuyerEmail | 구매자메일주소 | 60 | 필수 | |
VbankBankCode | 가상계좌 은행코드 | 3 | 필수 | 매뉴얼 사이트의 '통합코드 조회-은행사 코드' 참조 후 설정해 주세요. |
VbankExpDate | 입급만료일 | 12 | 필수 |
쿠콘 : 8자리(yyyyMMdd) 검증 더즌 : 8자리(yyyyMMdd), 12자리(yyyyMMddhhmm) 검증 |
CashReceiptType | 현금영수증 용도구분 | 1 | 선택 | 0: 미발행, 1: 개인 소득공제 발행, 2: 사업자 지출증빙 발행 |
ReceiptAmt | 현금영수증 총금액 | 12 | 선택 | 값이 없을 경우 '0' 설정 |
ReceiptTaxAmt | 현금영수증 과세 | 12 | 선택 | 값이 없을 경우 '0' 설정 |
ReceiptTaxFreeAmt | 현금영수증 비과세 | 12 | 선택 | 값이 없을 경우 '0' 설정 |
ReceiptSupplyAmt | 현금영수증 공급가액 | 12 | 선택 | 값이 없을 경우 '0' 설정 |
ReceiptVatAmt | 현금영수증 부가세 | 12 | 선택 | 값이 없을 경우 '0' 설정 |
ReceiptIdentity | 현금영수증 발급번호 | 40 | 선택 | 사업자번호, 전화번호, 주민번호 등 |
파라미터 | 항목명 | 길이(char) | 설명 |
---|---|---|---|
ResultCode | 결과코드 | 4 | 성공: 4100, 실패: 그 외 |
ResultMsg | 결과메시지 | 100 | |
Tid | 거래번호 | 30 | |
VbankName | 가상계좌 발급은행 | 10 | |
VbankBankCode | 가상계좌 은행코드 | 3 | |
VbankNum | 가상계좌번호 | 30 | 가상계좌 채번요청 시 선택한 은행의 계좌번호 |
SubId | 요청 가상계좌번호 | 30 | 일괄채번 요청 시 입력한 계좌번호 |
VerifyValue | 위·변조 사인값 | 가변 | SHA256로 처리한 값을 Base64로 전송 |
// REAL 전환 시 TargetURL = "https://approval.smartropay.co.kr";
String TargetURL = "https://tapproval.smartropay.co.kr";
String Vacct = "/payment/approval/vacct.do";
JSONObject body = new JSONObject();
JSONObject snd = new JSONObject();
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String EdiDate = getyyyyMMddHHmmss();
String Moid = "";
Timestamp toDay = new Timestamp((new Date()).getTime());
Timestamp nxDay = null;
try {
nxDay = getTimestampWithSpan(toDay, 7);
} catch(Exception e){}
String VbankExpDate = nxDay.toString();
VbankExpDate = VbankExpDate.substring(0, 10);
VbankExpDate = VbankExpDate.replaceAll("-", "");
// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
body.put("PayMethod" ,"VBANK");
body.put("GoodsCnt" ,1);
body.put("GoodsName" ,"My Macarong");
body.put("Amt" ,"1004");
body.put("Moid" ,Moid);
body.put("EdiDate" ,EdiDate);
body.put("Mid" , Mid);
body.put("TransType" ,"00"); // 00: default , 04: 일괄 채번
body.put("SubId" ,""); // TransType 04일 경우 가상계좌번호 입력
body.put("BuyerName" ,"ME");
body.put("BuyerTel" ,"01025965546");
// 가상계좌 관련 정보
body.put("VbankExpDate" ,VbankExpDate);
body.put("VbankBankCode" ,""); // 매뉴얼 사이트의 '통합코드 조회-은행사 코드' 참조 후 설정해 주세요.
// 현금 영수증 관련 정보
// 부가세 직접 계산 가맹점의 경우 아래 값들을 각각 계산하여 설정해야 합니다.
body.put("ReceiptAmt", "1004"); // 현금영수증 총 금액
body.put("ReceiptTaxAmt", "0"); // 현금영수증 과세
body.put("ReceiptTaxFreeAmt", "0"); // 현금영수증 비과세
body.put("ReceiptSupplyAmt", "0"); // 현금영수증 공급가액
body.put("ReceiptVatAmt", "0"); // 현금영수증 부가세
body.put("ReceiptIdentity", ""); // 현금영수증 발급번호
body.put("CashReceiptType", "0"); // 현금영수증 용도구분 (0: 미발행, 1 : 발행(개인 소득공제), 2 : 발행(사업자 지출증빙))
// 날짜 생성 함수
public static String getyyyyMMddHHmmss() {
/** yyyyMMddHHmmss Date Format */
SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
return yyyyMMddHHmmss.format(new Date());
}
public static Timestamp getTimestampWithSpan(Timestamp sourceTS, long day) throws Exception {
Timestamp targetTS = null;
if (sourceTS != null) {
targetTS = new Timestamp(sourceTS.getTime() + (day * 1000 * 60 * 60 * 24));
}
return targetTS;
}
// json 데이터 AES256 암호화
try {
snd.put("EncData", AES256Cipher.AES_Encode(body.toString(), merchantKey.substring(0, 32)));
snd.put("Mid", Mid);
} catch(Exception e){
e.printStackTrace();
}
// URL 호출로 승인 요청 후 결과 받기
URL url = null;
HttpsURLConnection connection = null;
int connectTimeout = 1000;
int readTimeout = 10000; // 가맹점에 맞게 TimeOut 조절
StringBuilder responseBody = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(TargetURL + Vacct);
connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = snd.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
} catch(Exception e) {
e.printStackTrace();
}
RetryUrl
) 설정은 가맹점관리자 사이트에서 가능합니다. (좌측 재통보 메뉴 참고)
상세 파라미터
파라미터 | 항목명 | 길이(char) | 필수여부 | 설명 |
---|---|---|---|---|
PayMethod | 지불수단 | 10 | 필수 | CASHRCPT:현금영수증 |
GoodsCnt | 결제상품 품목 개수 | 2 | 필수 | 기본값: 1 |
GoodsName | 거래 상품명 | 40 | 필수 | |
Amt | 거래 금액 | 12 | 필수 | 숫자만 가능, 문장부호 제외 |
Moid | 상품주문번호 | 40 | 필수 | 특수문자 포함 불가 |
EdiDate | 전문생성일시 | 14 | 필수 | YYYYMMDDHHmmss(형식) |
Mid | 상점아이디 | 10 | 필수 | |
BuyerName | 구매자명 | 30 | 필수 | |
BuyerTel | 구매자연락처 | 40 | 필수 | 숫자만 입력 (문자 입력 시 10자 미만으로 설정 하셔야합니다. - 초과 시 승인 오류 발생) |
ReceiptAmt | 현금영수증 총금액 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptSupplyAmt | 현금영수증 공급가액 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptTaxAmt | 현금영수증 과세 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptTaxFreeAmt | 현금영수증 비과세 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptVatAmt | 현금영수증 부가세 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptServiceAmt | 현금영수증 봉사료 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptIdentity | 현금영수증 발급번호 | 40 | 필수or선택 | 사업자번호, 전화번호, 주민번호 |
CashReceiptType | 현금영수증 용도구분 | 1 | 필수or선택 | 0: 미발행, 1 : 발행(개인 소득공제), 2 : 발행(사업자 지출증빙) |
VerifyValue | 위·변조 체크 검증값 | 500 | 필수 |
파라미터 | 항목명 | 길이(char) | 설명 |
---|---|---|---|
PayMethod | 지불수단 | 10 | |
ResultCode | 결과코드 | 4 | |
ResultMsg | 결과메시지 | 100 | |
Mid | 상점ID | 10 | |
Moid | 주문번호 | 100 | |
AuthCode | 승인번호 | 30 | |
AuthDate | 승인일시 | 12 | YYMMDDHHMMSS(형식) |
ReceiptIdentity | 현금영수증 발급번호 | 40 | |
CashReceiptType | 현금영수증 용도구분 | 1 | 0: 미발행, 1: 개인 소득공제 발행, 2: 사업자 지출증빙 발행 |
MallReserved | 상점예비정보 | 500 | 결제 요청 시 설정한 값 전달 |
Tid | 거래번호 | 30 |
STEP 1 요청 데이터 설정하기
// REAL 전환 시 TargetURL = "https://approval.smartropay.co.kr";
String TargetURL = "https://tapproval.smartropay.co.kr";
String CashRcpt = "/payment/approval/cashrcpt.do";
JSONObject body = new JSONObject();
JSONObject snd = new JSONObject();
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String EdiDate = getyyyyMMddHHmmss();
String Moid = "";
// 요청 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
body.put("PayMethod", "CASHRCPT");
body.put("EdiDate", EdiDate);
body.put("GoodsCnt", "1");
body.put("GoodsName", "My Macarong");
body.put("Amt", "1004");
body.put("Moid", Moid);
body.put("Mid", Mid);
body.put("BuyerName", "ME");
body.put("BuyerTel", "01099991111");
body.put("ReceiptAmt", ReceiptAmt); // 현금영수증 총금액
body.put("ReceiptTaxAmt", ReceiptTaxAmt); // 현금영수증 과세금액
body.put("ReceiptTaxFreeAmt", ReceiptTaxFreeAmt); // 현금영수증 비과세금액
body.put("ReceiptVatAmt", ReceiptVatAmt); //현금영수증 부가세
body.put("ReceiptSupplyAmt", ReceiptSupplyAmt); // 현금영수증 공급가
body.put("ReceiptServiceAmt", ReceiptServiceAmt); // 현금영수증 봉사료
body.put("ReceiptIdentity", "01012345678"); // 현금영수증 인증번호
body.put("CashReceiptType", "1"); // 현금영수증 용도구분 ,0: 미발행, 1 : 발행(개인 소득공제), 2 : 발행(사업자 지출증빙)
String serverEncryptData = ReceiptIdentity + Moid + merchantKey + EdiDate + ReceiptSupplyAmt + ReceiptVatAmt + ReceiptServiceAmt + Amt;
body.put("VerifyValue", encodeSHA256Base64(serverEncryptData));
// 날짜 생성 함수
public static String getyyyyMMddHHmmss() {
/** yyyyMMddHHmmss Date Format */
SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
return yyyyMMddHHmmss.format(new Date());
}
// 암호화 함수
public static final synchronized String encodeSHA256Base64(String strPW) {
String passACL = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
e.printStackTrace();
}
md.update(strPW.getBytes());
byte[] raw = md.digest();
byte[] encodedBytes = Base64.encodeBase64(raw);
passACL = new String(encodedBytes);
return passACL;
}
STEP 2 HTTPS URL Call로 승인 요청 후 결과 받기
// json 데이터 AES256 암호화
try {
snd.put("EncData", AES256Cipher.AES_Encode(body.toString(), merchantKey.substring(0, 32)));
snd.put("Mid", Mid);
} catch(Exception e){
e.printStackTrace();
}
// URL 호출로 승인 요청 후 결과 받기
URL url = null;
HttpsURLConnection connection = null;
int connectTimeout = 1000;
int readTimeout = 10000; // 가맹점에 맞게 TimeOut 조절
StringBuilder responseBody = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(TargetURL + CashRcpt);
connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = snd.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
} catch(Exception e) {
e.printStackTrace();
}
파라미터 | 항목명 | 길이(char) | 필수여부 | 설명 |
---|---|---|---|---|
공통 | ||||
PayMethod | 지불수단 | 10 | 필수 | REFD: 환불 |
Mid | 상점아이디 | 10 | 필수 | |
Amt | 거래 금액 | 12 | 필수 | 숫자만 가능, 문장부호 제외 |
BuyerName | 구매자명 | 30 | 필수 | |
BuyerTel | 구매자연락처 | 40 | 필수 | 숫자만 입력 (문자 입력 시 10자 미만으로 설정 하셔야합니다. - 초과 시 승인 오류 발생) |
GoodsName | 거래 상품명 | 40 | 필수 | |
EdiDate | 전문생성일시 | 14 | 필수 | YYYYMMDDHHmmss(형식) |
GoodsCnt | 결제상품 품목 개수 | 2 | 필수 | 기본값: 1 |
Moid | 상품주문번호 | 40 | 선택 | 특수문자 포함 불가 |
MallReserved | 상점예비정보 | 100 | 선택 | Base64 인코딩필요
(평문으로 전달시 한글 및 특수문자가 정상적으로 전달되지 않음) |
UserIp | 고객 IP | 20 | 선택 | |
MallIp | 상점서버IP | 20 | 선택 | |
ChannelType | 채널타입 | 3 | 선택 | PC: WEB(기본값), 모바일: MOB |
Currency | 통화구분 | 3 | 필수 | 기본값: KRW |
성명조회 및 환불이체 | ||||
Tid | 거래번호 | 30 | 필수 | 원거래 Tid로 설정 |
Memo | 이체사유 | 100 | 선택 | |
CancelPwd | 이체패스워드 | 20 | 필수 | 취소패스워드와 동일 |
CancelId | 이체요청자 | 20 | 필수 | 가맹점사용자 ID |
BankCode | 은행코드 | 3 | 필수 | |
BankAccount | 계좌번호 | 20 | 필수 | |
BankAccountName | 계좌예금주 | 30 | 필수 | 테스트 서버에서 계좌성명조회 사용시 '홍길동테스트' 로 고정 |
AccnUseYn | 계좌성명조회사용 여부 | 1 | 선택 | 계좌주 성명조회 사용시 : "Y" , 미사용시 "N" |
VerifyValue | 검증값 | 100 | 필수 | SHA256 암호화 |
SummaryMemo | 요약메모 | 50 | 선택 | 통장표시내용 |
PartialCancelCode | 부분환불 여부 | 1 | 선택 | 0: 전체환불, 1: 부분환불 |
ReceiptAmt | 현금영수증 총금액 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptSupplyAmt | 현금영수증 공급가액 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptTaxAmt | 현금영수증 과세 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptTaxFreeAmt | 현금영수증 비과세 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
ReceiptVatAmt | 현금영수증 부가세 | 12 | 필수or선택 | 값이 없을 경우 '0' 설정 |
DivideInfo | 분할정산 정보 | 가변 | 선택 | 분할정산 가맹점 전용 |
파라미터 | 항목명 | 길이(char) | 필수여부 | 설명 |
---|---|---|---|---|
PayMethod | 지불수단 | 10 | ||
ResultCode | 결과코드 | 4 | ||
ResultMsg | 결과메시지 | 100 | ||
Mid | 상점ID | 10 | ||
Amt | 금액 | 12 | ||
BuyerName | 구매자명 | 30 | ||
GoodsName | 상품명 | 40 | ||
Moid | 주문번호 | 100 | ||
MallUserId | 구매자ID | 20 | ||
AuthCode | 승인번호 | 30 | ||
Tid | 거래번호 | 30 | ||
PTid | 부분환불 Tid | 30 | 부분환불 시 | |
BankAccountName | 계좌예금주 | 30 | ||
MallReserved | 상점예비정보 | 100 | 가맹점에서 설정한 값 전달 |
// REAL 전환 시 TargetURL = "https://approval.smartropay.co.kr";
String TargetURL = "https://tapproval.smartropay.co.kr";
String UnionRefund = "/payment/approval/unionRefund.do";
JSONObject body = new JSONObject();
JSONObject snd = new JSONObject();
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
String EdiDate = getyyyyMMddHHmmss();
String Moid = "";
// 공통 요청 파라미터 셋팅 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
body.put("PayMethod", "REFD");
body.put("Mid", Mid);
body.put("Tid", ""); // 환불 또는 성명조회 할 거래의 Tid
body.put("Amt", "1004");
body.put("BuyerName", "구매자명");
body.put("BuyerEmail", "noname@smartro.co.kr");
body.put("BuyerTel", "01012345678");
body.put("GoodsName", "테스트 상품");
body.put("GoodsCnt", "1");
body.put("MallUserId", "");
body.put("Moid", Moid);
body.put("UserIp", "10.0.0.1");
body.put("MallIp", "10.0.0.1");
body.put("ChannelType", "MOB");
body.put("Currency", "KR");
body.put("EdiDate", EdiDate);
// 계좌 성명 조회, 환불 공통 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
body.put("BankCode", ""); // 은행코드 참조
body.put("BankAccount", "");
body.put("BankAccountName", "");
// PlainTxt = EdiDate + Mid + Amt + merchantKey
String svrHashPlainTxt = EdiDate + Mid + "1004" + merchantKey;
body.put("VerifyValue", encodeSHA256Base64(svrHashPlainTxt));
// 환불 요청 시 파라미터
body.put("Memo", "");
body.put("CancelPwd", ""); // 취소 패스워드(가맹점관리자 페이지에서 설정)
body.put("SummaryMemo", "summary");
body.put("PartialCancelCode", "0"); // 부분환불 여부(0: 전체환불, 1: 부분환불)
// 날짜 생성 함수
public static String getyyyyMMddHHmmss() {
/** yyyyMMddHHmmss Date Format */
SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
return yyyyMMddHHmmss.format(new Date());
}
// 암호화 함수
public static final synchronized String encodeSHA256Base64(String strPW) {
String passACL = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
e.printStackTrace();
}
md.update(strPW.getBytes());
byte[] raw = md.digest();
byte[] encodedBytes = Base64.encodeBase64(raw);
passACL = new String(encodedBytes);
return passACL;
}
// json 데이터 AES256 암호화
try {
snd.put("EncData", AES256Cipher.AES_Encode(body.toString(), merchantKey.substring(0, 32)));
snd.put("Mid", Mid);
} catch(Exception e){
e.printStackTrace();
}
// URL 호출로 승인 요청 후 결과 받기
URL url = null;
HttpsURLConnection connection = null;
int connectTimeout = 1000;
int readTimeout = 10000; // 가맹점에 맞게 TimeOut 조절
StringBuilder responseBody = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(TargetURL + UnionRefund);
connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = snd.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
} catch(Exception e) {
e.printStackTrace();
}
파라미터 | 항목명 | 길이(char) | 필수여부 | 설명 |
---|---|---|---|---|
Mid | 상점아이디 | 10 | 필수 | |
BankCode | 은행코드 | 3 | 필수 | |
BankAccount | 계좌번호 | 20 | 필수 | |
BankAccountName | 계좌예금주 | 30 | 필수 | 테스트 서버에서 계좌성명조회 사용시 '홍길동테스트' 로 고정 |
파라미터 | 항목명 | 길이(char) | 필수여부 | 설명 |
---|---|---|---|---|
PayMethod | 지불수단 | 10 | ||
ResultCode | 결과코드 | 4 | ||
ResultMsg | 결과메시지 | 100 | ||
Mid | 상점ID | 10 | ||
Tid | 거래번호 | 30 | ||
BankAccountName | 계좌예금주 | 30 |
// REAL 전환 시 TargetURL = "https://approval.smartropay.co.kr";
String TargetURL = "https://tapproval.smartropay.co.kr";
String AccntNameSearch = "/payment/approval/accntNameSearch.do";
JSONObject body = new JSONObject();
JSONObject snd = new JSONObject();
String merchantKey = ""; // 발급받은 테스트 상점키 설정(Real 전환 시 운영 상점키 설정)
String Mid = ""; // 발급받은 테스트 Mid 설정(Real 전환 시 운영 Mid 설정)
// 공통 요청 파라미터 셋팅 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
body.put("Mid", Mid);
// 계좌 성명 조회, 환불 공통 파라미터 (각 값들은 가맹점 환경에 맞추어 설정해 주세요.)
body.put("BankCode", ""); // 은행코드 참조
body.put("BankAccount", ""); // 계좌번호
body.put("BankAccountName", ""); // 계좌주 성명(Staging 서버일 경우 '홍길동테스트' 로 설정된 경우에만 성공 응답 , Real 서버에서는 실 계좌주 Name 으로 Setting)
// 암호화 함수
public static final synchronized String encodeSHA256Base64(String strPW) {
String passACL = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
e.printStackTrace();
}
md.update(strPW.getBytes());
byte[] raw = md.digest();
byte[] encodedBytes = Base64.encodeBase64(raw);
passACL = new String(encodedBytes);
return passACL;
}
// json 데이터 AES256 암호화
try {
snd.put("EncData", AES256Cipher.AES_Encode(body.toString(), merchantKey.substring(0, 32)));
snd.put("Mid", Mid);
} catch(Exception e){
e.printStackTrace();
}
// URL 호출로 조회 요청 후 결과 받기
URL url = null;
HttpsURLConnection connection = null;
int connectTimeout = 1000;
int readTimeout = 10000; // 가맹점에 맞게 TimeOut 조절
StringBuilder responseBody = null;
try {
SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
sslCtx.init(null, null, new SecureRandom());
url = new URL(TargetURL + AccntNameSearch);
connection = (HttpsURLConnection) url.openConnection();
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(readTimeout);
OutputStreamWriter osw = new OutputStreamWriter(new BufferedOutputStream(connection.getOutputStream()) , "utf-8" );
char[] bytes = snd.toString().toCharArray();
osw.write(bytes,0,bytes.length);
osw.flush();
osw.close();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
String line = null;
responseBody = new StringBuilder();
while ((line = br.readLine()) != null) {
System.out.println(" response " + line);
responseBody.append(line);
}
br.close();
} catch(Exception e) {
e.printStackTrace();
}
Illegal key size
예외가 발생했을 경우 여기를 클릭해 주세요.
import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
public class AES256Cipher {
public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
public static String AES_Encode(String str, String key) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] textBytes = str.getBytes("UTF-8");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = null;
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
return Base64.encodeBase64String(cipher.doFinal(textBytes));
}
public static String AES_Decode(String str, String key, byte[] ivBytes) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] textBytes = Base64.decodeBase64(str.getBytes());
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return new String(cipher.doFinal(textBytes), "UTF-8");
}
public static String AES_Decode(String str, String key) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
return AES_Decode(str, key, ivBytes);
}
}
(참고) AES256 암호화 중 예외 발생 시 조치사항
'java.security.InvalidKeyException: Illegal key size' 라는 예외가 발생했을 경우 아래와 같이 해결해 주세요.
1. 현재 사용중인 Java 버전에 맞춰 Unlimited Strength 정책 파일을 다운받습니다.
2. 다운받은 파일의 local_policy.jar, US_export_policy.jar 파일을 <JAVA_HOME>/jre/lib/security/ 폴더로 옮겨 기존 정책을 덮어씌웁니다.
그러면 JCE로 사용 가능한 모든 암호화의 키 길이 제한이 해제됩니다.
※ 8u151 Release Notes에서는 해당 버전부터 별도의 다운로드 없이 Unlimited Strength 정책을 설정할 수 있게 추가 번들이 같이 제공됩니다.
해당 버전에서 정책 파일은 <JAVA_HOME>/jre/lib/security/policy 경로에 limited와 unlimited 폴더로 구성되며,
unlimited 설정은 <JAVA_HOME>/jre/lib/security/java.security 파일을 열어
crypto.policy=unlimited
부분의 주석 처리를 지워주면 제한 해제된 정책을 사용할 수 있습니다.
※ 변경된 기본 정책
2018년 1월 업데이트된 Java8u161 Release Notes에 따르면, Java8u161 버전부터는 JCE 기본 정책이 unlimited이며,
길이를 제한하고 싶다면 crypto.policy=unlimited
부분을 주석처리하면 됩니다.
Unlimited를 기본으로 사용하는 Java 버전은 'JDK-8170157 : Enable unlimited cryptographic policy by default in Oracle JDK builds'에서 확인할 수 있습니다.