一:簡介
手機網站支付常用於HTML5應用,常見於微信公眾號上的應用。手機網站支付文檔
手機網站支付的流程圖:
- 用戶點擊H5應用中的支付按鈕
- 點擊支付按鈕會請求後臺接口,後臺接口請求支付寶的支付接口,支付接口會返回一段html代碼其中包括一個form表單和一段js代碼用於自動提交表單,表單提交後就會自動跳轉到支付寶的支付頁面(如果手機中裝了支付App就去打開APP,如果沒有就在網頁版支付
- 支付成功後會調用支付時設置的同步url, 然後跳轉到商戶的後臺系統,一般情況下商戶系統會展示一下支付成功,以及購買的商品信息等視圖
流程圖
二:集成步驟
0. 創建應用、配置密鑰
集成前需要先創建應用、配置密鑰、回調地址等,具體操作請查看Spring Boot入門教程(三十五):支付寶集成-準備工作
1. dependency
<code><
dependency
><
groupId
>org.springframework.bootgroupId
><
artifactId
>spring-boot-starter-webartifactId
>dependency
><
dependency
><
groupId
>org.springframework.bootgroupId
><
artifactId
>spring-boot-starter-testartifactId
><
scope
>testscope
>dependency
><
dependency
><
groupId
>org.springframework.bootgroupId
><
artifactId
>spring-boot-starter-thymeleaf
artifactId
>dependency
><
dependency
><
groupId
>com.alipaygroupId
><
artifactId
>alipay-sdk-javaartifactId
><
version
>20170725114550version
>dependency
><
dependency
><
groupId
>com.alipaygroupId
><
artifactId
>alipay-trade-sdkartifactId
><
version
>20161215version
>dependency
><
dependency
><
groupId
>com.google.code.gsongroupId
><
artifactId
>gsonartifactId
>dependency
><
dependency
><
groupId
>commons-configurationgroupId
><
artifactId
>commons-configurationartifactId
><
version
>1.10version
>dependency
><
dependency
><
groupId
>com.google.zxinggroupId
><
artifactId
>coreartifactId
><
version
>3.2.1version
>dependency
><
dependency
><
groupId
>org.projectlombokgroupId
><
artifactId
>lombokartifactId
>dependency
> /<code>
2. application.yml
手機網站支付需要支付成功後同步的地址returnUrl,支付成功後跳轉到的頁面,這個值既可以配在這裡也可以在Java代碼調用支付寶接口時也可以設置為別的值
<code>pay:
alipay:
gatewayUrl:
https://openapi.alipaydev.com/gateway.do
appid:
2016091400508498
appPrivateKey:
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtXKWs+trRSuCxEUvlsEeSAuLWs3B/Dh74R8223BnfzoA29aGeoycAqfKlBMcbzU2G1KayESvZKGpwBLeejSbecRYjgZsQDyEaDimQQJtGFvZVV6u4XNnvIJ72eQzEaEIQfuiorjBTLm6DQuds4R0GxftqON6QFoIZkWB9ZrZKd02cuy16dW+UqtLVGGAHcCIAkB63zUiKSNfweMddneZ7MVs3lvu3xhMnD+5us/+n2Vp4qhfmpYLcdqIW6InU4GypeoOpyUTrfUGpgdR0l924vHy/GQJZEKFaRcK3cYK+ECyKpSIoqaJJFLHbkqsliuPpMUG+rM3jiqeIAH4psAznAgMBAAECggEBAJ5jyEbbxrJzrAh7GhHX1fwUQPYSadTbrPYAfHX2cHlnrQMJtsk+nTLhEv0r+VJwZ8WpYkfMong8kcqYtL7ajcmsHqMAFhE9EWxBxj2ymWsXLabZe93sj30IG9Rq0nxcGQgDO0RqKWLGSFgK93Al2KRInKT3InkY53K+vR61ihVLmGf7+GwPtIZteBy+tuAyvcj2RlkYvjiFi3ySyZ1wA3sJIlgrGiixd6fj20XFGNE3CnAwu0BJgXXbP/S9J4C0RRa3ZXj8fX7oONhVxz2xKxn7AT4e8OWjt7J41H2LRct8Fgl9pqgz2FJYv/WfbkG8x9fGiKYYvPXoxjjrk/tkewkCgYEA8f9Lcu5JPrE9rpw9zlwhm5cOO81xLxdwL5R5/1bRP48BZGIYuqlCbVvjJVqtO8eTnLhUwH7fG8B7cmoeO9bGr9GQrtfyCqz6FtVymTBieJlfgZDVhtzyv2qKOBMIFE8jsbSBK/NHHMvykJ+XdQ1riwCeQDdXICRuYTTFwGk2OsUCgYEAt2SoN95tVmVrvKG6ATLNEtge/ozeVywA4GjltrSw/G9vqp+DkkT2pY19uROuzMazoTzKWpPho2q/qzNlv/ANbOFM2GEmKamQ7CO88JgRxMsPTvc/HxCLU/ClMJU8LcOf9LfP2KYZpPwuheKJoF4vDGj8NsbFmccJyYSdpkNEk7sCgYBJlL2FMaz1sgC2Ue19DIhvfaunRV1P20mSPgwmNmijccETm7w3LXX0OIdFeV/JGHLqqSWj7i+6iXk/ncKZoUGCfi8G6sQ+uL/GJ5qTt6GJV+ExTS+PtSjeSO/EAw1m13Vb+C16hpstx1l23f+4aJ81gbecgPct38XsKpaiXZtOnQKBgQCMsN7QRYYxwoq9YoDUzIlAzKYyeBVWYL6najHYUZR5hG/xQIBqZRem9/4cTvpJxKInrwA6LrrqaEl0aHDFp75U6h7O3PCvA5PXZK9dD/yJsZIj7U/yX/nTQokn1UUegrYiwiTkusBvrrtuINWePsLvTVc4GpObHnPmsiNTWsWwYwKBgENaeTNOCHV2km/ysXQSEIhKbtlAMQPsgWHCt/bzHlF9m18izb1LrJyjzcSsd+Zy78R+pv4G50Q27c3e/DFPz/wYxN/yHWRbyLBA8ipJbCtMtPEdS9krpmN6cChIdLGbz4CVUqOPSRzNb9lhhgPCcCNRq6DG3HBceb1Se9VnO3zk
alipayPublicKey:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApFQKccMq+wPoWh93DcX3XYrnT7FJ3gntJA/jEwgk6Jd3iEVS2CyUCCgFVcQn8xjXT81YbZHYvoC50IBuu+A+Ey+J8VIgsBm5g9uwbOLRf66GrZjuKOlalHm5gHXjcL2gZRMBJEStOxstcO2YQriqhQzdL3EKp+HQc9u14IOVFpZdR8qq1l7CzKHn1vQo/1fUPfUrTLQqSuQTU9Ospv/QHFqOJA7DPetUQ+jnaZ082f3clr4ITw4EE8A6IWqTXcETTx5j/udCGP84g2Y4j+8i9DqYGyD5ePVgt4G0ICBX1bi1qNlylfxRg8Y3c1DFrRGyr0NpKQxSVXkYaVNvrCoudQIDAQAB
returnUrl:
http://yxep7y.natappfree.cc/alipay/return
notifyUrl:
http://yxep7y.natappfree.cc/alipay/notify
spring:
thymeleaf:
prefix:
classpath:/templates/
suffix:
.html
mode:
HTML5
encoding:
UTF-8
/<code>
3.AlipayProperties
<code> (prefix ="pay.alipay"
)public
class
AlipayProperties {private
String
gatewayUrl;private
String
appid;private
String
appPrivateKey;private
String
alipayPublicKey;private
String
signType ="RSA2"
;private
String
formate ="json"
;private
String
charset ="UTF-8"
;private
String
returnUrl;private
String
notifyUrl;private
static
int maxQueryRetry =5
;private
static
long queryDuration =5000
;private
static
int maxCancelRetry =3
;private
static
long cancelDuration =3000
;private
AlipayProperties() {}public
void
init() { log.info(description()); }public
String
description() { StringBuilder sb =new
StringBuilder("\nConfigs{"
); sb.append("支付寶網關: "
).append(gatewayUrl).append("\n"
); sb.append(", appid: "
).append(appid).append("\n"
); sb.append(", 商戶RSA私鑰: "
).append(getKeyDescription(appPrivateKey)).append("\n"
); sb.append(", 支付寶RSA公鑰: "
).append(getKeyDescription(alipayPublicKey)).append("\n"
); sb.append(", 簽名類型: "
).append(signType).append("\n"
); sb.append(", 查詢重試次數: "
).append(maxQueryRetry).append("\n"
); sb.append(", 查詢間隔(毫秒): "
).append(queryDuration).append("\n"
); sb.append(", 撤銷嘗試次數: "
).append(maxCancelRetry).append("\n"
); sb.append(", 撤銷重試間隔(毫秒): "
).append(cancelDuration).append("\n"
); sb.append("}"
);return
sb.toString(); }private
String
getKeyDescription(String
key) { int showLength =6
;if
(StringUtils.isNotEmpty(key) && key.length() > showLength) {return
new
StringBuilder(key.substring(0
, showLength)).append("******"
) .append(key.substring(key.length() - showLength)).toString(); }return
null
; } } /<code>
4.AlipayConfiguration
<code>@Configuration
@EnableConfigurationProperties(AlipayProperties.class) public class AlipayConfiguration {@Autowired
private AlipayProperties properties;@Bean
public AlipayTradeService alipayTradeService() {return
new
AlipayTradeServiceImpl
.ClientBuilder
().setGatewayUrl
(properties
.getGatewayUrl
()).setAppid
(properties
.getAppid
()).setPrivateKey
(properties
.getAppPrivateKey
()).setAlipayPublicKey
(properties
.getAlipayPublicKey
()).setSignType
(properties
.getSignType
()).build
(); }@Bean
public AlipayClient alipayClient(){return
new
DefaultAlipayClient
(properties
.getGatewayUrl
(),properties
.getAppid
(),properties
.getAppPrivateKey
(),properties
.getFormate
(),properties
.getCharset
(),properties
.getAlipayPublicKey
(),properties
.getSignType
()); } } /<code>
5. AlipayWAPPayController
<code> 4j ("/alipay/wap"
)public
class
AlipayWAPPayController
{private
AlipayProperties alipayProperties;private
AlipayClient alipayClient; ("/alipage"
)public
void
gotoPayPage
(HttpServletResponse response)
throws
AlipayApiException, IOException { String productCode="QUICK_WAP_WAY"
; AlipayTradeWapPayModel model =new
AlipayTradeWapPayModel(); model.setOutTradeNo(UUID.randomUUID().toString()); model.setSubject("支付測試"
); model.setTotalAmount("0.01"
); model.setBody("支付測試,共0.01元"
); model.setTimeoutExpress("2m"
); model.setProductCode(productCode); AlipayTradeWapPayRequest wapPayRequest =new
AlipayTradeWapPayRequest(); wapPayRequest.setReturnUrl("http://yxep7y.natappfree.cc/alipay/wap/returnUrl"
); wapPayRequest.setNotifyUrl(alipayProperties.getNotifyUrl()); wapPayRequest.setBizModel(model); String form = alipayClient.pageExecute(wapPayRequest).getBody(); System.out.println(form); response.setContentType("text/html;charset="
+ alipayProperties.getCharset()); response.getWriter().write(form); response.getWriter().flush(); response.getWriter().close(); } ("/returnUrl"
)public
StringreturnUrl
(HttpServletRequest request, HttpServletResponse response)
throws
UnsupportedEncodingException, AlipayApiException { response.setContentType("text/html;charset="
+ alipayProperties.getCharset()); Map params =new
HashMap<>(); Map requestParams = request.getParameterMap();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] +","
; } valueStr =new
String(valueStr.getBytes("ISO-8859-1"
),"utf-8"
); params.put(name, valueStr); }boolean
verifyResult = AlipaySignature.rsaCheckV1(params, alipayProperties.getAlipayPublicKey(), alipayProperties.getCharset(),"RSA2"
);if
(verifyResult){ 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"
);return
"wapPaySuccess"
; }else
{return
"wapPayFail"
; } } ("/refund"
)public
Stringrefund
(String orderNo)
throws
AlipayApiException { AlipayTradeRefundRequest alipayRequest =new
AlipayTradeRefundRequest(); AlipayTradeRefundModel model=new
AlipayTradeRefundModel(); model.setOutTradeNo(orderNo); model.setRefundAmount("0.01"
); model.setRefundReason("無理由退貨"
); alipayRequest.setBizModel(model); AlipayTradeRefundResponse alipayResponse = alipayClient.execute(alipayRequest); System.out.println(alipayResponse.getBody());return
alipayResponse.getBody(); } ("/refundQuery"
)public
StringrefundQuery
(String orderNo, String refundOrderNo)
throws
AlipayApiException { AlipayTradeFastpayRefundQueryRequest alipayRequest =new
AlipayTradeFastpayRefundQueryRequest(); AlipayTradeFastpayRefundQueryModel model=new
AlipayTradeFastpayRefundQueryModel(); model.setOutTradeNo(orderNo); model.setOutRequestNo(refundOrderNo); alipayRequest.setBizModel(model); AlipayTradeFastpayRefundQueryResponse alipayResponse = alipayClient.execute(alipayRequest); System.out.println(alipayResponse.getBody());return
alipayResponse.getBody(); } ("/close"
)public
Stringclose
(String orderNo)
throws
AlipayApiException { AlipayTradeCloseRequest alipayRequest =new
AlipayTradeCloseRequest(); AlipayTradeCloseModel model =new
AlipayTradeCloseModel(); model.setOutTradeNo(orderNo); alipayRequest.setBizModel(model); AlipayTradeCloseResponse alipayResponse= alipayClient.execute(alipayRequest); System.out.println(alipayResponse.getBody());return
alipayResponse.getBody(); } } /<code>
6. AlipayController
<code> ("/alipay"
)public
class
AlipayController {private
AlipayProperties aliPayProperties;private
AlipayTradeService alipayTradeService; ("/notify"
)public
String
notify(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException { Map<String
,String
[]> parameterMap = request.getParameterMap(); StringBuilder notifyBuild =new
StringBuilder("/****************************** alipay notify ******************************/\n"
); parameterMap.forEach((key, value) -> notifyBuild.append(key +"="
+ value[0
] +"\n"
) ); log.info(notifyBuild.toString()); Map<String
,String
> params =new
HashMap<>(); Map requestParams = request.getParameterMap();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] +","
; } params.put(name, valueStr); }boolean
flag = AlipaySignature.rsaCheckV1(params, aliPayProperties.getAlipayPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType());if
(flag) {String
tradeStatus =new
String
(request.getParameter("trade_status"
).getBytes("ISO-8859-1"
),"UTF-8"
);if
(tradeStatus.equals("TRADE_FINISHED"
)){ }else
if
(tradeStatus.equals("TRADE_SUCCESS"
)){ }return
"success"
; }return
"fail"
; } ("/query"
)public
String
query(String
orderNo){ AlipayTradeQueryRequestBuilder builder =new
AlipayTradeQueryRequestBuilder() .setOutTradeNo(orderNo); AlipayF2FQueryResult result = alipayTradeService.queryTradeResult(builder);switch
(result.getTradeStatus()) {case
SUCCESS: log.info("查詢返回該訂單支付成功: )"
); AlipayTradeQueryResponse resp = result.getResponse(); log.info(resp.getTradeStatus());break
;case
FAILED: log.error("查詢返回該訂單支付失敗!!!"
);break
;case
UNKNOWN: log.error("系統異常,訂單支付狀態未知!!!"
);break
;default
: log.error("不支持的交易狀態,交易返回異常!!!"
);break
; }return
result.getResponse().getBody(); } } /<code>
7. WebMvcConfiguration
通過訪問
http://localhost:8080/toPay來跳轉到toPay.html頁面
<code>public
class
WebMvcConfiguration
extends
WebMvcConfigurationSupport
{
protected
void
addViewControllers
(ViewControllerRegistry registry)
{ registry.addViewController("/toPay"
).setViewName("toPay"
);super
.addViewControllers(registry); } } /<code>
8. templates
toPay.html
<code> ><
html
lang
="en"
><
head
><
meta
charset
="UTF-8"
><
title
>Title
title
>head
><
body
style
="font-size: 30px"
><
form
method
="post"
action
="/alipay/wap/alipage"
><
h3
>購買商品:越南新娘h3
><
h3
>價格:20000h3
><
h3
>數量:2個h3
><
button
style
="width: 100%; height: 60px; alignment: center; background: blue"
type
="submit"
>支付button
>form
>body
>html
> /<code>
wapPaySuccess.html
<code> ><
html
lang
="en"
><
head
><
meta
charset
="UTF-8"
><
title
>Titletitle
>head
><
body
><
h1
>WAP 支付成功,請及時享用!歡迎下次再來h1
>body
>html
> /<code>
wapPayFail.html
<code> ><
html
lang
="en"
><
head
><
meta
charset
="UTF-8"
><
title
>Titletitle
>head
><
body
><
h2
>WAP 支付失敗,請重新支付h2
>body
>html
> /<code>
三:運行結果
首先訪問去支付頁面:
http://localhost:8080/toPay
獲取源碼
關注並私信“支付寶手機網站支付”獲取源代碼。