一:簡介
電腦支付常用於電商和後臺管理系統的賬戶充值等場景。
電腦網站支付 文檔
電腦網站支付流程圖
二:集成步驟
0. 創建應用、配置密鑰
集成前需要先創建應用、配置密鑰、回調地址等以及alipay-sdk-java.jar和alipay-trade-sdk.jar請查看Spring Boot入門教程(三十五):支付寶集成-準備工作
1. dependency
<code><
dependencies
><
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-thymeleafartifactId
>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
>dependencies
> /<code>
2. application.yml
<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://s9v2cw.natappfree.cc/alipay/return
notifyUrl:
http://s9v2cw.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. AlipayPagePayController
<code> ("/alipay/page"
)public
class
AlipayPagePayController
{private
AlipayProperties alipayProperties;private
AlipayClient alipayClient;private
AlipayController alipayController; ("/gotoPayPage"
)public
void
gotoPayPage
(HttpServletResponse response)
throws
AlipayApiException, IOException { String productCode ="FAST_INSTANT_TRADE_PAY"
; AlipayTradePagePayModel model =new
AlipayTradePagePayModel(); model.setOutTradeNo(UUID.randomUUID().toString()); model.setSubject("支付測試"
); model.setTotalAmount("0.01"
); model.setBody("支付測試,共0.01元"
); model.setProductCode(productCode); AlipayTradePagePayRequest pagePayRequest =new
AlipayTradePagePayRequest(); pagePayRequest.setReturnUrl("http://s9v2cw.natappfree.cc/alipay/page/returnUrl"
); pagePayRequest.setNotifyUrl(alipayProperties.getNotifyUrl()); pagePayRequest.setBizModel(model); String form = alipayClient.pageExecute(pagePayRequest).getBody(); 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());boolean
verifyResult = alipayController.rsaCheckV1(request);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
"pagePaySuccess"
; }else
{return
"pagePayFail"
; } } } /<code>
6. AlipayController
<code> ("/alipay"
)public
class
AlipayController {private
AlipayProperties aliPayProperties;private
AlipayClient alipayClient;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());boolean
flag =this
.rsaCheckV1(request);if
(flag) {String
tradeStatus =new
String
(request.getParameter("trade_status"
).getBytes("ISO-8859-1"
),"UTF-8"
);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
total_amount =new
String
(request.getParameter("total_amount"
).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(); } ("/refund"
)public
String
refund(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
String
refundQuery(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
String
close(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(); }public
boolean
rsaCheckV1(HttpServletRequest request){ 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); }try
{boolean
verifyResult = AlipaySignature.rsaCheckV1(params, aliPayProperties.getAlipayPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType());return
verifyResult; }catch
(AlipayApiException e) { log.debug("verify sigin error, exception is:{}"
, e);return
false
; } } } /<code>
7. WebMvcConfiguration
<code>public
class
WebMvcConfiguration
extends
WebMvcConfigurationSupport
{protected
void
addViewControllers
(ViewControllerRegistry registry)
{ registry.addViewController("/gotoWapPage"
).setViewName("gotoWapPay"
); registry.addViewController("/gotoPagePage"
).setViewName("gotoPagePay"
);super
.addViewControllers(registry); } } /<code>
8. templates
gotoPagePay.html
<code> ><
html
lang
="en"
><
head
><
meta
charset
="UTF-8"
><
title
>Titletitle
>head
><
body
style
="font-size: 30px"
><
form
method
="post"
action
="/alipay/page/gotoPayPage"
><
h3
>購買商品:越南新娘h3
><
h3
>價格:20000h3
><
h3
>數量:10個h3
><
button
style
="width: 100%; height: 60px; alignment: center; background: #b49e8f"
type
="submit"
>立即支付button
>form
>body
>html
> /<code>
pagePaySuccess.html
<code> ><
html
lang
="en"
><
head
><
meta
charset
="UTF-8"
><
title
>Titletitle
>head
><
body
><
h1
>電腦網站支付 成功,我們將盡快從越南偷渡過來,收貨後請請及時驗貨!歡迎下次再來h1
>body
>html
> /<code>
三:Demo圖
三:查詢對賬單下載地址
<code> ("/bill"
)public
void
queryBill(String
billDate) { AlipayDataDataserviceBillDownloadurlQueryRequest request =new
AlipayDataDataserviceBillDownloadurlQueryRequest(); AlipayDataDataserviceBillDownloadurlQueryModel model =new
AlipayDataDataserviceBillDownloadurlQueryModel(); model.setBillType("trade"
); model.setBillDate(billDate); request.setBizModel(model);try
{ AlipayDataDataserviceBillDownloadurlQueryResponse response = alipayClient.execute(request);if
(response.isSuccess()) {String
billDownloadUrl = response.getBillDownloadUrl(); System.out.println(billDownloadUrl); List<String
> orderList =this
.downloadBill(billDownloadUrl); System.out.println(orderList); }else
{String
code = response.getCode();String
msg = response.getMsg();String
subCode = response.getSubCode();String
subMsg = response.getSubMsg(); } }catch
(AlipayApiException e) { e.printStackTrace(); }catch
(IOException e) { e.printStackTrace(); } }private
List<String
> downloadBill(String
billDownLoadUrl) throws IOException {String
ordersStr =""
; CloseableHttpClient httpClient = HttpClients.createDefault(); RequestConfig config = RequestConfig.custom() .setConnectTimeout(60000
) .setConnectionRequestTimeout(60000
) .setSocketTimeout(60000
) .build(); HttpGet httpRequest =new
HttpGet(billDownLoadUrl); httpRequest.setConfig(config); CloseableHttpResponse response =null
; byte[] data =null
;try
{ response = httpClient.execute(httpRequest); HttpEntity entity = response.getEntity(); data = EntityUtils.toByteArray(entity); }finally
{ response.close(); httpClient.close(); } ZipInputStream zipInputStream =new
ZipInputStream(new
ByteArrayInputStream(data), Charset.forName("GBK"
)); ZipEntry zipEntry =null
;try
{while
( (zipEntry = zipInputStream.getNextEntry()) !=null
){ ByteArrayOutputStream byteArrayOutputStream =new
ByteArrayOutputStream();try
{String
name = zipEntry.getName();if
(name.contains("彙總"
)){continue
; } byte[] byteBuff =new
byte[4096
]; int bytesRead =0
;while
((bytesRead = zipInputStream.read(byteBuff)) !=-1
) { byteArrayOutputStream.write(byteBuff,0
, bytesRead); } ordersStr = byteArrayOutputStream.toString("GBK"
); }finally
{ byteArrayOutputStream.close(); zipInputStream.closeEntry(); } } }finally
{ zipInputStream.close(); }if
(ordersStr.equals(""
)) {return
null
; }String
[] bills = ordersStr.split("\r\n"
); List<String
> billList = Arrays.asList(bills); billList = billList.parallelStream().map(item -> item.replace("\t"
,""
)).collect(Collectors.toList());return
billList; } /<code>