springboot + Thymeleaf 做的 VISA 支付 做个笔记。
在开发中一直想行项目中抽离出来
以下是 大概的流程图
第一步先确定数据的发送
源码是这样的
package com.vb.controller;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.asiapay.secure.PaydollarSecureUtil;
/**
* 此類將用於數據封裝提交到VISA
* @author
*
*/
@Controller
public class OnliePay {
/**
* The merchant ID we provide to you 百度翻譯 ----我们提供给你的商人身份证
*
* 意思就是我們跟銀行申請支付功能,銀行反饋給我們這邊的id,來標識身份
*/
private static final String merchantId = "88061970";
/**
* The currency of the payment i.e.
* 貨幣的類型
* “344” – HKD 港幣
“840” – USD 美元
“702” – SGD
“156” – CNY (RMB) 毛爺爺
“392” – JPY 日元
“901” – TWD
“036” – AUD
“978” – EUR
“826” – GBP
“124” – CAD
*/
private static final String currCode = "344" ;
@RequestMapping("/VISARequest")
public ModelAndView virtualRequest(HttpServletRequest request,HttpServletResponse reponse) throws Exception{
Map<String, String> map = new ConcurrentHashMap<String,String>();
String bankId = "258465466";//插入數據庫生成的流水帳號id ,有助於客戶付款成功後返回給我們的唯一標識
String amount = "100";//支付銀行100塊錢
String payType = "N";//正常付款
/**
* 必須获取加密的字符,作用餘銀行收錢成功後返回數據時,做校驗,以防安全隱患 里面源码访问secureHashSecret.config文件里面的字符 去生成
*/
String secureHash = PaydollarSecureUtil.generatePaymentSecureHash(merchantId, bankId, currCode, amount, payType);
map.put("amount", amount);
map.put("merchantId", merchantId);
map.put("secureHash", secureHash);
map.put("orderRef", bankId);
map.put("remark", "備註隨意");//不超過 Text (200) 字符
return new ModelAndView("vbank/submitfFormBank","map",map);
}
}
接下来就是跳到页面代码
扫描二维码关注公众号,回复:
8644442 查看本文章
<div style="margin-left: 25%; margin-top: 15%;">
<h1>VISA支付demo參數</h1>
<!-- <form name="payFormCcard" method="post" action="https://www.paydollar.com/b2c2/eng/payment/payForm.jsp"> -->
<form name="payFormCcard" method="post" action="http://192.168.41.58:8088/virtualBank/pay/virtualRequest">
<input type="text" name="merchantId" th:value="${map.merchantId}"><br/>
<input type="text" name="amount" th:value="${map.amount}" ><br/>
<input type="text" name="orderRef" th:value="${map.orderRef}"><br/>
<input type="text" name="remark" th:value="${map.remark}"><br/>
<input type="text" name="secureHash" th:value="${map.secureHash}"><br/>
<!--
支付方式 一下可以選 直接定義全部都可以
“ALL” – All the available payment method
“CC” – Credit Card Payment
“PPS” – PayDollar PPS Payment
“PAYPAL” – PayPal By PayDollar Payment
“CUP” – PayDollar CUP Payment
“ALIPAY” – PayDollar ALIPAY Payment
-->
<input type="hidden" name="payMethod" th:value="ALL" ><br/>
<!--
The payment card type ---》 支付卡类型
可選 (“VISA”,“Master”,”Diners”,”JCB”, “AMEX”)
具體可參照文檔
-->
<input type="text" name="pMethod" th:value="VISA" ><br/>
<!-- 支付貨幣類型 344 HKD 156 RMB -->
<input type="text" name="currCode" th:value="344" ><br/>
<!-- 立即付款 ,具體可看文檔-->
<input type="text" name="payType" th:value="N"><br/>
<!-- 語言 E,英,C,中文 -->
<input type="text" name="lang" th:value="E"><br/>
<!--
本項目給銀行返回的結果的連接,告知操作人支付成功還是失敗
PS: 自定義連接
-->
<input type="text" name="successUrl" value="http://www.yourdomain.com/Success.html"><br/>
<input type="text" name="failUrl" value="http://www.yourdomain.com/Fail.html"><br/>
<input type="text" name="cancelUrl" value="http://www.yourdomain.com/Cancel.html"><br/>
<input type="submit" name="submit" value="提交">
</form>
</div>
接下来第二步
package com.vb.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RestController
@RequestMapping("/pay")
public class BankHandleAction {
public String map;
public static Map<String, String> paramMap = new ConcurrentHashMap<String,String>();
@RequestMapping("/hello")
@ResponseBody
public String hello() {
return "hello world2222";
}
//請求過來的請求
@RequestMapping("/virtualRequest")
public ModelAndView virtualRequest(HttpServletRequest request,HttpServletResponse reponse){
Map<String, String> map = new ConcurrentHashMap<String,String>();
try {
Enumeration<String> names = request.getParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
String value = request.getParameter(name);
System.err.println(name+":"+value);
paramMap.put(name, value);
if(name.equals("failUrl")){
map.put("failUrl", value);
}
if(name.equals("successUrl")){
map.put("successUrl", value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return new ModelAndView("vbank/bankhandle","map",map);
}
/**
* 支付成功
* @param request
* @param reponse
* @return
*/
@RequestMapping("/virtualSuccess")
public void virtualSuccess(HttpServletRequest request,HttpServletResponse reponse){
try {
String merchantId=paramMap.get("merchantId");
String orderRef=paramMap.get("orderRef");
String currCode=paramMap.get("currCode");
String amount=paramMap.get("amount");
String payType=paramMap.get("payType");
String secureHash=paramMap.get("secureHash");
String errorUrl=paramMap.get("errorUrl");
StringBuffer buffer = new StringBuffer();
buffer.append(merchantId).append("|").append(orderRef)
.append("|").append(currCode).append("|")
.append(amount)
.append("|")
.append(payType).append("|")
.append("YwkkhiEV55OLGKGRJ1RBBO3oA5OXS8M0");
String hash =null;
try {
hash = operationAlgorithm(buffer.toString());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(!secureHash.equals(hash))
{
paramMap.put("successcode", "1");
}else{
paramMap.put("successcode", "0");
}
new Thread(new Runnable() {
String s = null;
@Override
public void run() {
HttpURLConnection conn = null;
PrintWriter out = null;
BufferedReader reader = null;
try {
String query = buildQuery(paramMap, "utf-8");
/**********************************注意此連接是銀行成功回調連接************************************/
URL url = new URL("http://192.168.41.58:8088/virtualBank/VISAdataback");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Length", "200000");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("User-Agent", "top-sdk-java");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
conn.setRequestProperty("Connection", "keep-alive");
conn.setConnectTimeout(5000);
conn.setUseCaches(false);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
out.write(query);
out.flush();
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
while(true){
if((s=reader.readLine()) != null){
System.err.println(s);
}else{
break ;
}
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(out != null){
out.close();
}
if(reader != null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(conn != null){
conn.disconnect();
}
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
private static String buildQuery1(Map<String, String> params, String charset) throws IOException {
if (params == null || params.isEmpty()) {
return "";
}
StringBuilder query = new StringBuilder();
Set<Entry<String, String>> set = params.entrySet();
Iterator<Entry<String, String>> iterator = set.iterator();
Boolean flag = true;
while (iterator.hasNext()) {
Entry<String,String> p = iterator.next();
String name = p.getKey();
String value = p.getValue();
if(flag){
query.append(name+"=").append(URLEncoder.encode(value, charset));
flag = !flag;
}else{
query.append("&"+name+"=").append(URLEncoder.encode(value, charset));
}
}
return query.toString();
}
public String operationAlgorithm(String secureData) throws NoSuchAlgorithmException,UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(secureData.getBytes("utf-8"), 0, secureData.length());
byte[] sha1hash = md.digest();
return convertToHex(sha1hash);
}
private String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString();
}
private String buildQuery(Map<String, String> params, String charset) throws IOException {
if (params == null || params.isEmpty()) {
return "";
}
String src = "0";
String prc = "0";
String successCode =params.get("successcode"); //0- succeeded, 1- failure, Others - error
String ref = params.get("orderRef");
String payRef = "123456789"; //paydollar支付编号 //PayDollar Payment Reference Number
String amt = params.get("amount"); //交易金额 //Transaction Amount
String cur = params.get("currCode"); //交易货币种类 344 - HKD ; 156 – CNY (RMB) //Transaction Currency
String payerAuth = "Y";
StringBuffer buffer = new StringBuffer();
buffer.append(src).append("|").append(prc).append("|").append(
successCode).append("|").append(ref)
.append("|").append(payRef).append("|")
.append(cur).append("|").append(amt).append("|")
.append(payerAuth).append("|").append(
"YwkkhiEV55OLGKGRJ1RBBO3oA5OXS8M0");
String secureHash =null;
try {
secureHash = operationAlgorithm(buffer.toString());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
StringBuilder query = new StringBuilder();
query.append("src=").append(URLEncoder.encode(src, charset));
query.append("&prc=").append(URLEncoder.encode(prc, charset));
query.append("&successcode=").append(URLEncoder.encode(params.get("successcode"), charset));
query.append("&Ref=").append(URLEncoder.encode(ref, charset));
query.append("&Ord=").append("12345678");
query.append("&PayRef=").append(URLEncoder.encode(payRef, charset));
query.append("&Amt=").append(URLEncoder.encode(params.get("amount"), charset));
query.append("&Cur=").append(URLEncoder.encode(cur, charset));
query.append("&payerAuth=").append(URLEncoder.encode(payerAuth, charset));
query.append("&remark=").append(URLEncoder.encode(params.get("remark"), charset));
query.append("&secureHash=").append(URLEncoder.encode(secureHash, charset));
return query.toString();
}
public String getMap() {
return map;
}
public void setMap(String map) {
this.map = map;
}
}
第三步
package com.vb.controller;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.asiapay.secure.PaydollarSecureUtil;
@Controller
public class DataBack {
@RequestMapping("/VISAdataback")
public void databack(HttpServletRequest request,HttpServletResponse reponse) throws Exception{
System.out.println(request.getParameterMap()+"--------"
+ request.getParameterNames()
+"Ord="+request.getParameter("Ord")
+"holder="+request.getParameter("Holder")
+"Ref="+request.getParameter("Ref")
+"successcode="+request.getParameter("successcode")
+"remark="+request.getParameter("remark")
+"PayRef="+request.getParameter("PayRef")
+"Amt="+request.getParameter("Amt")
+"src="+request.getParameter("src")
+"prc="+request.getParameter("prc")
+"Cur="+request.getParameter("Cur")
+"payerAuth="+request.getParameter("payerAuth")
+"secureHash="+request.getParameter("secureHash"));
//打印
Enumeration paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String name =(String) paramNames.nextElement();
String value = request.getParameter(name);
System.out.println(name+"="+value);
}
String reqsuccesscode = request.getParameter("successcode") == null ? "": request.getParameter("successcode");
String reqremark = request.getParameter("remark") == null ? "": request.getParameter("remark");
//付款成功標識
if ("0".equals(reqsuccesscode)) {
String src = request.getParameter("src");
String prc = request.getParameter("prc");
String successcode = request.getParameter("successcode"); //0- succeeded, 1- failure, Others - error
String ref = request.getParameter("Ref");//银行的交易编号
String payRef = request.getParameter("PayRef"); //paydollar支付编号 //PayDollar Payment Reference Number
String amt = request.getParameter("Amt"); //交易金额 //Transaction Amount
String cur = request.getParameter("Cur"); //交易货币种类 344 - HKD ; 156 – CNY (RMB) //Transaction Currency
String payerAuth = request.getParameter("payerAuth");
String[] secureHash = request.getParameterValues("secureHash");
//解密過程 start
List tempList = new ArrayList();
if (secureHash != null) {
for (int k = 0; k < secureHash.length; k++) {
if (secureHash[k].indexOf(",") > 0) {
String[] data = secureHash[k].split(",");
for (int j = 0; data != null & j < data.length; j++) {
tempList.add(data[j]);
}
} else {
tempList.add(secureHash[k]);
}
}
}
int size = tempList.size();
if (size > 0) {
secureHash = new String[size];
for (int i = 0; i < size; i++) {
secureHash[i] = (String) tempList.get(i);
}
}
//解密的過程 end
//會看到密鑰會讀取 secureHashSecret.config 裏面有個 SHA 哈希,這個 是 開發者加 secureHashSecret 密過程中 加岩(添加自定字符串)
boolean verifyResult = PaydollarSecureUtil.verifyPaymentDatafeed(src, prc, successcode, ref,payRef, cur, amt, payerAuth, secureHash);
if (verifyResult) {//匹配SHA1
System.out.println("the same secureHash 匹配SHA1 成功");
}else{
System.out.println("not the same secureHash 匹配SHA1失败 ");
return;
}
//接下來就 根據流水帳號去查詢,處理數據信息
String bankId = request.getParameter("Ref")==null?"": request.getParameter("Ref"); //流水帐号id
String reqAmount = request.getParameter("Amt") == null ? "": request.getParameter("Amt");//总金额
//最後完成後得通知銀行已處理,否者銀行那邊會再次請求看文檔是知己 put “ok” 就可以了
PrintWriter pw1 = reponse.getWriter();
pw1.write("OK");
pw1.flush();
pw1.close();
}else {
System.out.println("付款失敗");
return;
}
}
}
时间有点紧急忙写完
项目源码以放github 官网 https://github.com/MJFuture/Springboot-VISA-PAy
以及相应的开发文档 1.pdf
任何问题欢迎留言