支付宝接入指引
- 通过进入蚂蚁金服商家中心(https://b.alipay.com/?ynsrc=zhuzhanA),进行选择你所要接入的产品,我在这次项目中接入的是手机网站支付。因为以前没有做过支付相关的产品,感觉很高大上,但是实际接入支付宝还是很easy的,只要细心,你可以在几个小时内完成对支付宝的接入,因为我门项目在接入支付宝的同时,还要接入微信,我在接入完这两个产品后,我只能对微信的支付文档说声ZTMS,不废话了,进入正题。
- https://auth.alipay.com/login/index.htm?goto=https%3A%2F%2Fenterpriseportal.alipay.com%2Findex.htm 通过这个链接进入支付的登录
支付宝java版demo
支付宝代码流程:
1.调接口,获取支付宝支付需要的参数
/* 支付宝 */
$.postJsonToken(payback,{'orderNo': no}, function(data){
var obj = JSON.parse(data.obj);
console.log(data)
var orderNo = obj.orderNo;
var totalPrice = obj.totalPrice;
if (data.result == "1") {
location.href = '../../wappay/pay.jsp?orderNo='+orderNo+'&totalPrice='+totalPrice;
}else{
location.href = '../../html/result/fail.html'
}
});
2.通过跳转跳到支付宝demo提供的pay.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.axigo.config.AlipayConfig" %>
<%@page import="com.alipay.api.AlipayClient"%>
<%@page import="com.alipay.api.DefaultAlipayClient"%>
<%@page import="com.alipay.api.AlipayApiException"%>
<%@page import="com.alipay.api.response.AlipayTradeWapPayResponse"%>
<%@page import="com.alipay.api.request.AlipayTradeWapPayRequest"%>
<%@page import="com.alipay.api.domain.AlipayTradeWapPayModel" %>
<%@page import="com.alipay.api.domain.AlipayTradeCreateModel"%>
<%
/* *
* 功能:支付宝手机网站支付接口(alipay.trade.wap.pay)接口调试入口页面
* 版本:2.0
* 修改日期:2016-11-01
* 说明:
* 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
请确保项目文件有可写权限,不然打印不了日志。
*/
%>
<%
if(request.getParameter("WIDout_trade_no")!=null){
// 商户订单号,商户网站订单系统中唯一订单号,必填
String orderNo = new String(request.getParameter("orderNo").getBytes("UTF-8"),"UTF-8");
System.out.println("orderNo=========="+orderNo);
// 商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("UTF-8"),"UTF-8");
// 订单名称,必填
String subject = new String(request.getParameter("WIDsubject").getBytes("UTF-8"),"UTF-8");
System.out.println(subject);
// 付款金额,必填
String total_amount=new String(request.getParameter("WIDtotal_amount").getBytes("UTF-8"),"UTF-8");
// 商品描述,可空
String body = new String(request.getParameter("WIDbody").getBytes("UTF-8"),"UTF-8");
// 超时时间可空
String timeout_express="2m";
// 销售产品码必填
String product_code="QUICK_WAP_PAY";
/**********************/
// SDK 公共请求类,包含公共请求参数,以及封装了签名与验签,开发者无需关注签名与验签
//调用RSA签名方式
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();
// 封装请求支付信息
AlipayTradeWapPayModel model=new AlipayTradeWapPayModel();
model.setOutTradeNo(out_trade_no);
model.setSubject(subject);
model.setTotalAmount(total_amount);
model.setBody(body);
model.setTimeoutExpress(timeout_express);
model.setProductCode(product_code);
alipay_request.setBizModel(model);
// 设置异步通知地址
alipay_request.setNotifyUrl(AlipayConfig.notify_url);
// 设置同步地址
alipay_request.setReturnUrl(AlipayConfig.return_url);
// form表单生产
String form = "";
try {
// 调用SDK生成表单
form = client.pageExecute(alipay_request).getBody();
response.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
response.getWriter().write(form);//直接将完整的表单html输出到页面
response.getWriter().flush();
response.getWriter().close();
} catch (AlipayApiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
%>
<!DOCTYPE html>
<html>
<head>
<title>支付宝手机网站支付接口</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
<style>
*{
margin:0;
padding:0;
}
ul,ol{
list-style:none;
}
body{
font-family: "Helvetica Neue",Helvetica,Arial,"Lucida Grande",sans-serif;
}
.hidden{
display:none;
}
.new-btn-login-sp{
padding: 1px;
display: inline-block;
width: 75%;
}
.new-btn-login {
background-color: #02aaf1;
color: #FFFFFF;
font-weight: bold;
border: none;
width: 100%;
height: 30px;
border-radius: 5px;
font-size: 16px;
}
#main{
width:100%;
margin:0 auto;
font-size:14px;
}
.red-star{
color:#f00;
width:10px;
display:inline-block;
}
.null-star{
color:#fff;
}
.content{
margin-top:5px;
}
.content dt{
width:100px;
display:inline-block;
float: left;
margin-left: 20px;
color: #666;
font-size: 13px;
margin-top: 8px;
}
.content dd{
margin-left:120px;
margin-bottom:5px;
}
.content dd input {
width: 85%;
height: 28px;
border: 0;
-webkit-border-radius: 0;
-webkit-appearance: none;
}
#foot{
margin-top:10px;
position: absolute;
bottom: 15px;
width: 100%;
}
.foot-ul{
width: 100%;
}
.foot-ul li {
width: 100%;
text-align:center;
color: #666;
}
.note-help {
color: #999999;
font-size: 12px;
line-height: 130%;
margin-top: 5px;
width: 100%;
display: block;
}
#btn-dd{
margin: 20px;
text-align: center;
}
.foot-ul{
width: 100%;
}
.one_line{
display: block;
height: 1px;
border: 0;
border-top: 1px solid #eeeeee;
width: 100%;
margin-left: 20px;
}
.am-header {
display: -webkit-box;
display: -ms-flexbox;
display: box;
width: 100%;
position: relative;
padding: 7px 0;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
background: #1D222D;
height: 50px;
text-align: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
box-pack: center;
-webkit-box-align: center;
-ms-flex-align: center;
box-align: center;
}
.am-header h1 {
-webkit-box-flex: 1;
-ms-flex: 1;
box-flex: 1;
line-height: 18px;
text-align: center;
font-size: 18px;
font-weight: 300;
color: #fff;
}
</style>
</head>
<body text=#000000 bgColor="#ffffff" leftMargin=0 topMargin=4>
<header class="am-header">
<h1>支付宝支付</h1>
</header>
<div id="main">
<form name=alipayment action='' method=post target="_blank">
<div id="body" style="clear:left">
<dl class="content">
<dt>商户订单号:</dt>
<dd>
<input id="WIDout_trade_no" name="WIDout_trade_no" />
</dd>
<hr class="one_line">
<dt>订单名称:</dt>
<dd>
<input id="WIDsubject" name="WIDsubject" />
</dd>
<hr class="one_line">
<dt>付款金额:</dt>
<dd>
<input id="WIDtotal_amount" name="WIDtotal_amount" />
</dd>
<hr class="one_line"/>
<dt>商品描述:</dt>
<dd>
<input id="WIDbody" name="WIDbody" />
</dd>
<hr class="one_line">
<dt></dt>
<dd id="btn-dd">
<span class="new-btn-login-sp">
<button class="new-btn-login" type="submit" style="text-align:center;">确认</button>
</span>
<span class="note-help">如果您点击“确认”按钮,即表示您同意该次的执行操作。</span>
</dd>
</dl>
</div>
</form>
<div id="foot">
<ul class="foot-ul">
<li>
支付宝版权所有 2015-2018 ALIPAY.COM
</li>
</ul>
</div>
</div>
</body>
<script language="javascript">
var package_number = "<%=request.getParameter("orderNo")%>";
var totalPrice = "<%=request.getParameter("totalPrice")%>";
// alert(totalPrice+"=============="+package_number);
function GetDateNow() {
var vNow = new Date();
var sNow = "";
sNow += String(vNow.getFullYear());
sNow += String(vNow.getMonth() + 1);
sNow += String(vNow.getDate());
sNow += String(vNow.getHours());
sNow += String(vNow.getMinutes());
sNow += String(vNow.getSeconds());
sNow += String(vNow.getMilliseconds());
document.getElementById("WIDout_trade_no").value = package_number;
document.getElementById("WIDsubject").value = "****";
document.getElementById("WIDtotal_amount").value = totalPrice;
document.getElementById("WIDbody").value = "****-购物支付";
}
GetDateNow();
</script>
</html>
3.异步回调通知页面,不用理会
<%@page import="net.sf.json.JSONObject"%>
<%@page import="com.alipay.api.internal.util.AlipaySignature"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.Map"%>
<%@ page import="com.axigo.config.*"%>
<%@ page import="com.alipay.api.*"%>
<%
//获取支付宝POST过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
String aa = "";
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
params.put(name, valueStr);
String bb = "";
bb = name+"="+valueStr;
/* System.out.println("验证成功<br />==============》"+name+"========="+valueStr); */
aa+="&"+bb;
}
/* System.out.println("==================================》"+aa); */
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
//计算得出通知验证结果
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
/* System.out.println("verify_result==============》"+verify_result); */
if(verify_result){//验证成功
//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
if(trade_status.equals("TRADE_FINISHED")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//如果签约的是可退款协议,退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
//如果没有签约可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
} else if (trade_status.equals("TRADE_SUCCESS")){
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_fee、seller_id与通知时获取的total_fee、seller_id为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//如果签约的是可退款协议,那么付款完成后,支付宝系统发送该交易状态通知。
}
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
out.clear();
out.println("success"); //请不要修改或删除
//
}else{//验证失败
System.out.println("222222222");
out.println("fail");
}
%>
4.同步回调页面,业务逻辑在这个页面进行处理
<%@page import="net.sf.json.JSONObject"%>
<%@page import="com.alipay.api.internal.util.AlipaySignature"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.Map"%>
<%@ page import="com.axigo.config.*"%>
<%@ page import="com.alipay.api.*"%>
<%@ page import="org.apache.commons.httpclient.HttpClient"%>
<%@ page import="org.apache.commons.httpclient.methods.PostMethod"%>
<%@ page import="org.apache.commons.lang.StringUtils"%>
<%@ page import="org.apache.commons.httpclient.Header"%>
<%@ page import="javax.servlet.http.HttpServletRequest"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>支付宝页面跳转同步通知页面</title>
</head>
<body>
<%
//获取支付宝GET过来反馈信息
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
/* System.out.println("验证成功<br />11111111111"); */
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
/* System.out.println("验证成功<br />==============》"+name+"========="+valueStr); */
}
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
/* System.out.println("out_trade_no==============》"+out_trade_no); */
//支付宝交易号
/* String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8"); */
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
/* System.out.println("trade_no==============》"+trade_no); */
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
//计算得出通知验证结果
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, "RSA2");
/* System.out.println("verify_result==============》"+verify_result); */
if(verify_result){//验证成功
System.out.println("222222222222222222222222222222222222222222222222222222222");
//
//请在这里加上商户的业务逻辑程序代码
String url=AlipayConfig.CALL_BACK;
/* String str = "{\"out_trade_no\":\""+out_trade_no+"\",\"trade_no\":\""+trade_no+"\",\"trade_status\":\""+trade_status+"\"}"; */
String str = "{\"out_trade_no\":\""+out_trade_no+"\",\"trade_no\":\""+trade_no+"\",\"payType\":\"ali_pay\"}";
System.out.println("str=============="+str);
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url);
post.addRequestHeader("Content-Type","application/json;charset=utf-8");
post.setRequestBody(str);
client.executeMethod(post);
Header[] headers = post.getResponseHeaders();
int statusCode = post.getStatusCode();
String result = new String(post.getResponseBody());
/* System.out.println("result===========================>"+result); */
post.releaseConnection();
JSONObject jsStr = JSONObject.fromObject(result);
System.out.print(jsStr.toString());
//判断支付成功
if(String.valueOf(jsStr.get("result")).equals("1")){
request.getRequestDispatcher("/html/result/success.html").forward(request,response);
}else{
request.getRequestDispatcher("/html/result/fail.html").forward(request,response);
}
//
}else{
//该页面可做页面美工编辑
out.clear();
out.println("验证失败");
}
%>
</body>
</html>
5、支付成功回调后的业务处理controller
@Controller
@RequestMapping("/aliPay/")
public class AliPayApi {
@Autowired OrderService orderService;
@RequestMapping("pay.htm")
public @ResponseBody ResultBase pay(@RequestBody Map<String, String> map){
return null;
}
@RequestMapping("callBack.htm")
public @ResponseBody ResultBase callBack(@RequestBody Map<String, String> map){
return orderService.alipayCallBack(map);
}
}
6、进入逻辑处理层进行处理
@Override
@Transactional
public ResultBase wxCallBack(Map<String, String> map) {
ResultBase res = new ResultBase();
String tradeNo = "";
String wxNo = "";
String payType = "wx_pay";
Date paytime =null;
String total_fee ="";
Map<String, Object> param = new HashMap<String, Object>();
String where = "";
if (CommonUtil.notEmpty(String.valueOf(map.get("out_trade_no")))) {
tradeNo = String.valueOf(map.get("out_trade_no"));
where += "and order_no =:tradeNo ";
param.put("tradeNo", tradeNo);
}
System.out.println("--------------------------------"+tradeNo);
if (CommonUtil.notEmpty(String.valueOf(map.get("time_end")))) {
paytime = DateUtil.parse(String.valueOf(map.get("time_end")), "yyyyMMddHHmmss");
}
System.out.println("--------------------------------"+paytime);
if (CommonUtil.notEmpty(String.valueOf(map.get("transaction_id")))) {
wxNo = String.valueOf(map.get("transaction_id"));
}
System.out.println("--------------------------------"+wxNo);
if (CommonUtil.notEmpty(String.valueOf(map.get("total_fee")))) {
total_fee = String.valueOf(map.get("total_fee"));
}
System.out.println("--------------------------------"+total_fee);
Order order = (Order)orderDAO.setUpQuery(" order_no=? ", null,Long.valueOf(tradeNo)).setMaxResults(1).uniqueResult();
System.out.println("--------------------------------"+MoneyUtil.changeY2F(String.valueOf(order.getAmount())));
//判断金额
// if (!total_fee.equals(MoneyUtil.changeY2F(String.valueOf(order.getAmount())))) {
//
// }
order.setPayTime(paytime);
order.setPayType(payType);
order.setTradeStatus("SUCCESS");
order.setStatus(1);
orderDAO.update(order);
System.out.println("-------------------订单状态改完-------------");
//改库存
List<OrderItem> OrderItemList = (List<OrderItem>)orderItemDao.setUpQuery(" order_no = ?", null,Long.valueOf(tradeNo)).list();
if(OrderItemList.size()>0){
for (OrderItem orderItem : OrderItemList) {
Ptype ptype = orderItem.getPtype();
System.out.println("-------------------库存ptype.getStock()------------" +ptype.getStock());
System.out.println("-------------------库存orderItem.getQuantity()------------"+orderItem.getQuantity());
ptype.setStock(ptype.getStock()-orderItem.getQuantity());
ptypeDao.update(ptype);
}
}
System.out.println("-------------------库存改完-------------");
/**
*
* 这块改库存!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/
PaymentSerial payment = new PaymentSerial();
payment.setOrderNo(String.valueOf(order.getOrderNo()));
payment.setTradeNo(wxNo);
payment.setAmount(order.getAmount());
payment.setStatus(0);
payment.setTradeStatus("SUCCESS");
payment.setPayType(payType);
payment.setPaytime(paytime);
payment.setUser(order.getUser());
payment.setCreateDate(new Date());
if (order.getUser().getIdentity()==0) {
if (CommonUtil.notEmpty(order.getUser().getGuide())) {
payment.setGuiuser(order.getUser().getGuide());
}
if (CommonUtil.notEmpty(order.getUser().getTravelAgency())) {
payment.setTravelAgency(order.getUser().getTravelAgency());
}
}else{
payment.setGuiuser(order.getUser());
if (CommonUtil.notEmpty(order.getUser().getTravelAgency())) {
payment.setTravelAgency(order.getUser().getTravelAgency());
}
}
//结算单
paymentSerialDao.insert(payment);
/*
System.out.println(tradeNo);
System.out.println(aliNo);
System.out.println("已进入!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");*/
res.setResult(ResultBase.RESULT_SUCC);
return res;
}
到这里所有的支付流程都走完了,最麻烦的一个点就是验签,主要就是配置公钥和秘钥的配置,其中公钥一定是支付宝公钥而不是应用公钥,切记、切记、切记,如果你理解了相信你也会有慢慢的收获,有什么不明白可以加QQ2409656933.共同探讨