支付宝扫码支付
最近重构项目时,负责了支付模块,微信扫码支付(NATIVE)和 支付宝扫码支付,也是第一次接触,虽然根据官方文档和一些博客写出来了,但是遇到的问题却很多,走了很多弯路,浪费了很多精力和时间,抽出时间来记录一下,以后难免还是会用到。
支付宝支付需要沙箱测试,需要配置沙箱环境。
支付宝官方文档 介绍的很详细,接下来直接上代码,文档和代码结合着思路会更清晰:
获取支付宝二维码支付:
private Map<String, Object> getPayCodeByAliPay(PayCodeRequest payCodeRequest) {
log.info("获取支付宝二维码请求*******");
Map<String, Object> resultMap = new HashMap<>(16);
String currentUserID;
String orderID;
BizContentByAliPay bizContent;
AlipayMakeContent makeCode;
try {
orderID = payCodeRequest.getOrderID();
currentUserID = payCodeRequest.getCurrentUserID();
SystemConfig queryOneSystemConfig = orderPayService.queryOneSystemConfig("cm2_aliPayAccount");
bizContent = new BizContentByAliPay();
bizContent.setOut_trade_no(CommonUtils.genPayId());
bizContent.setSubject(payCodeRequest.getProductName());
String payAmount = payCodeRequest.getPayAmount().replace(",", "");
bizContent.setTotal_amount(new BigDecimal(payAmount));
bizContent.setBody(payCodeRequest.getValidityPeriod());
PayRecord queryOrderPayRecordByOrderID = orderPayService.queryPayRecordByOrderID(orderID);
if (null != queryOrderPayRecordByOrderID && OrderPayStatusEnum.PAID.getValue() == queryOrderPayRecordByOrderID.getPayStatus()) {
log.info("支付的类型:" + queryOrderPayRecordByOrderID.getPayType());
log.debug("订单已存在支付过记录");
resultMap.put("code", -20003);
resultMap.put("desc", "订单已支付,无法再次操作");
return resultMap;
}
makeCode = AliPayUtil.makeCode(queryOneSystemConfig.getConfigValue(), bizContent);
if (null == makeCode || null == makeCode.getAlipay_trade_precreate_response()) {
resultMap.put("code", -20001);
resultMap.put("desc", "获取支付宝支付二维码失败");
payLogService.createPayLog(currentUserID, new Gson().toJson(bizContent), orderID, new Gson().toJson(makeCode), 1);
return resultMap;
}
AliPayMakeResponse alipay_trade_precreate_response = makeCode.getAlipay_trade_precreate_response();
String qr_code = alipay_trade_precreate_response.getQr_code();
//生成二维码
String base64Code = QRCodeUtil.getBase64Code(qr_code);
log.info("生成的二维码:", base64Code);
/**
* 有记录,且非已支付
*/
if (null != queryOrderPayRecordByOrderID) {
queryOrderPayRecordByOrderID.setOrderID(payCodeRequest.getOrderID());
queryOrderPayRecordByOrderID.setPayType(OrderPayTypeEnum.ALIPAY.getValue());
queryOrderPayRecordByOrderID.setSign(makeCode.getSign());
queryOrderPayRecordByOrderID.setEditor(payCodeRequest.getCurrentUserID());
queryOrderPayRecordByOrderID.setEditTime(new Date());
queryOrderPayRecordByOrderID.setPayStatus(OrderPayStatusEnum.UNPAID.getValue());
queryOrderPayRecordByOrderID.setQr_code(qr_code);
queryOrderPayRecordByOrderID.setOut_trade_no(bizContent.getOut_trade_no());
long longValue = (new BigDecimal(payAmount).multiply(new BigDecimal("100"))).longValue();
queryOrderPayRecordByOrderID.setPayAmount(longValue);
orderPayService.updateOrderPayRecord(queryOrderPayRecordByOrderID);
} else {
PayRecord payRecord = new PayRecord();
payRecord.setOrderID(payCodeRequest.getOrderID());
payRecord.setPayType(OrderPayTypeEnum.ALIPAY.getValue());
payRecord.setSign(makeCode.getSign());
payRecord.setOperator(payCodeRequest.getCurrentUserID());
payRecord.setCreateTime(new Date());
payRecord.setPayStatus(OrderPayStatusEnum.UNPAID.getValue());
long longValue = (new BigDecimal(payAmount).multiply(new BigDecimal("100"))).longValue();
payRecord.setPayAmount(longValue);
payRecord.setOut_trade_no(bizContent.getOut_trade_no());
payRecord.setQr_code(qr_code);
orderPayService.createOrderPayRecord(payRecord);
}
resultMap.put("code", 0);
resultMap.put("desc", "获取成功");
resultMap.put("data", base64Code);
resultMap.put("out_trade_no", bizContent.getOut_trade_no());
return resultMap;
} catch (Exception e) {
log.error("获取支付宝二维码处理异常*******", e);
resultMap.put("code", -20001);
resultMap.put("desc", "获取支付宝支付二维码失败");
return resultMap;
}
支付宝支付工具类
public class AliPayUtil {
private static String FORMAT = "json";
private static String CHARSET = "UTF-8";
/**
* @name 阿里获取二维码接口
* @throws AlipayApiException
* @Param out_trade_no 商户订单号,64个字符以内、只能包含字母、数字、下划线;需保证在商户端不重复
* @Param total_amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 如果同时传入了【打折金额】,【不可打折金额】,
* 【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
* @Param subject 订单标题
* @Param store_id 商户门店编号
* @Param timeout_express 该笔订单允许的最晚付款时间,逾期将关闭交易。
* 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。
*/
public static AlipayMakeContent makeCode(String aliPayAccountData, BizContentByAliPay bizContent) {
log.info("获取支付宝支付二维码********");
log.info("aliPayAccountData:" + aliPayAccountData);
log.info("bizContent:" + new Gson().toJson(bizContent));
AlipayMakeContent payMakeContent = null;
try {
AliPayAccount aliPayAccount = new Gson().fromJson(aliPayAccountData, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
String timeout_express = aliPayAccount.getTimeout_express();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
bizContent.setTimeout_express(timeout_express);
if (null != aliPayAccount.getNotifyUrl() && !"".equals(aliPayAccount.getNotifyUrl())) {
request.setNotifyUrl(aliPayAccount.getNotifyUrl());
}
if (null != aliPayAccount.getReturnUrl() && !"".equals(aliPayAccount.getReturnUrl())) {
request.setReturnUrl(aliPayAccount.getReturnUrl());
}
//把订单信息转换为json对象的字符串
request.setBizContent(new Gson().toJson(bizContent));
AlipayTradePrecreateResponse response = alipayClient.execute(request);
payMakeContent = new Gson().fromJson(response.getBody(), AlipayMakeContent.class);
return payMakeContent;
} catch (Exception e) {
log.error("调用支付宝生产二维码异常:", e);
return null;
}
}
/**
* 获取支付宝二维码
* @param aliPayAccountData 支付宝账号json
* @param bizContent 业务参数
* @return
*/
public static Map<String, Object> orderPayByAliPay(String aliPayAccountData, BizContentByAliPay bizContent) {
log.info("获取支付二维码body********");
log.info("aliPayAccountData:" + aliPayAccountData);
log.info("bizContent:" + new Gson().toJson(bizContent));
Map<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("code", 0);
try {
AliPayAccount aliPayAccount = new Gson().fromJson(aliPayAccountData, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
String notifyUrl = aliPayAccount.getNotifyUrl();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
/* alipayRequest.setReturnUrl(returnUrl);*/
alipayRequest.setNotifyUrl(notifyUrl);//在公共参数中设置回跳和通知地址
/* bizContent.setOut_trade_no(BaseUtil.genPayID());
bizContent.setTotal_amount(new BigDecimal("799.90"));
bizContent.setSubject("赛门铁克DV证书");
bizContent.setBody("1年期证书");*/
alipayRequest.setBizContent(new Gson().toJson(bizContent));
AlipayTradePagePayResponse pageExecute = alipayClient.pageExecute(alipayRequest); //调用SDK生成表单
if (pageExecute.isSuccess()) {
String body = pageExecute.getBody();
resultMap.put("data", body);
return resultMap;
}
log.error("未成功获取支付二维码:", new Gson().toJson(pageExecute));
resultMap.put("code", -20001);
resultMap.put("desc", "获取支付宝支付二维码失败");
return resultMap;
} catch (Exception e) {
log.error("获取支付二维码body异常:", e);
resultMap.put("code", -20001);
resultMap.put("desc", "获取支付宝支付二维码失败");
return resultMap;
}
}
/**
* 查看支付交易信息
* @param aliPayAccountData
* @param query
* @return
*/
public static AliPayQueryContent queryPay(String aliPayAccountData, BizContentQueryByAliPay query) {
log.info("查询支付宝交易信息********");
log.info("aliPayAccountData:" + aliPayAccountData);
log.info("query:" + new Gson().toJson(query));
AliPayQueryContent payContent = new AliPayQueryContent();
try {
AliPayAccount aliPayAccount = new Gson().fromJson(aliPayAccountData, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent(new Gson().toJson(query));
AlipayTradeQueryResponse response = alipayClient.execute(request);
log.info("查询结果:" + response.getBody());
payContent = new Gson().fromJson(response.getBody(), AliPayQueryContent.class);
return payContent;
} catch (Exception e) {
log.error("查询支付宝交易信息异常:", e);
return null;
}
}
/**
* 退款操作:
* 退款成功注意事项。
全额退款情况:trade_status= TRADE_CLOSED,而refund_status=REFUND_SUCCESS;
非全额退款情况:trade_status= TRADE_SUCCESS,而refund_status=REFUND_SUCCESS
* @param aliPayAccountData
* @param refund
* @return
*/
public static TradeResponseContent refund(String aliPayAccountData, BizContentRefundByAliPay refund) {
log.info("支付宝进行退款操作********");
log.info("aliPayAccountData:" + aliPayAccountData);
log.info("query:" + new Gson().toJson(refund));
TradeResponseContent tradeContent = null;
try {
AliPayAccount aliPayAccount = new Gson().fromJson(aliPayAccountData, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
//设置请求参数
AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
alipayRequest.setBizContent(new Gson().toJson(refund));
AlipayTradeRefundResponse execute = alipayClient.execute(alipayRequest);
tradeContent = new Gson().fromJson(execute.getBody(), TradeResponseContent.class);
return tradeContent;
} catch (Exception e) {
log.error("支付宝退款异常:", e);
return null;
}
}
/**
* 查询退款信息
* @param aliPayAccountData
* @param tradeRefundQuery
* @return
*/
public static TradeResponseContent refundQuery(String aliPayAccountData, TradeRefundQuery tradeRefundQuery) {
log.info("查询支付宝退款详情操作********");
log.info("aliPayAccountData:" + aliPayAccountData);
log.info("tradeRefundQuery:" + new Gson().toJson(tradeRefundQuery));
TradeResponseContent tradeContent = null;
try {
AliPayAccount aliPayAccount = new Gson().fromJson(aliPayAccountData, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
//设置请求参数
AlipayTradeFastpayRefundQueryRequest alipayRequest = new AlipayTradeFastpayRefundQueryRequest();
alipayRequest.setBizContent(new Gson().toJson(tradeRefundQuery));
//请求
String body = alipayClient.execute(alipayRequest).getBody();
//输出
tradeContent = new Gson().fromJson(body, TradeResponseContent.class);
return tradeContent;
} catch (AlipayApiException e) {
log.error("查询支付宝退款异常:", e);
return null;
}
}
private static void query(String value) {
BizContentQueryByAliPay query = new BizContentQueryByAliPay();
query.setOut_trade_no("1909251da8f845545b6588");
AliPayQueryContent queryPay = queryPay(value, query);
System.err.println(new Gson().toJson(queryPay));
}
private static void pay(String value) throws Exception {
BizContentByAliPay bizContent = new BizContentByAliPay();
bizContent.setOut_trade_no("1909251da8f845545b6588");
bizContent.setTotal_amount(new BigDecimal("0.01"));
bizContent.setSubject("Symantec EV强制型");
bizContent.setBody("1年期证书");
AliPayAccount aliPayAccount = new Gson().fromJson(value, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
String timeout_express = aliPayAccount.getTimeout_express();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();//创建API对应的request类
bizContent.setTimeout_express(timeout_express);
request.setNotifyUrl(aliPayAccount.getNotifyUrl());
//把订单信息转换为json对象的字符串
request.setBizContent(new Gson().toJson(bizContent));
AlipayTradePrecreateResponse response = alipayClient.execute(request);
AlipayMakeContent payMakeContent = new Gson().fromJson(response.getBody(), AlipayMakeContent.class);
QRCodeUtil.encode(payMakeContent.getAlipay_trade_precreate_response().getQr_code(), "D:/" + bizContent.getOut_trade_no() + ".jpg");
System.err.println(new Gson().toJson(payMakeContent));
}
public static void main1(String[] args) throws AlipayApiException {
String value = "{\"applicationUrl\":\"https://openapi.alipaydev.com/gateway.do\",\"app_id\":\"2016082000290858\",\"app_private_key\":\"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZ1RBO92Rl+JwlM8471+rlctOSeKblBz15k1RkGrbv8+dUzvnvBENylG811eIEqEhfWefsIMeqPnbAG3wpeDbyRDgmFWiZZmBGcO2UKAM2+tDI1AfEgDxs2sKeasdigVqzccXJsr5fRfB8+BnLjEceaaXutegQA61Bm45/bhXT8TErFgJWJX5ucHrIVGDX/xqCiuZ5AjKLM0bhSG2cmy7E5bnhtCzMWt9QcM9g3lMSp1745Op7Yw3S+LonEE564GEnR4jUuWMVfEE+dQHuiJ4RKY/n3vzJHVdt5BTj3CR5+J2kHWuHBw4/kuZxPtdAA+aPZYkv05XdPdRfIifr/cxDAgMBAAECggEBAIvFFS5KhYRJIMaEjYu+IQUdEbLxwOIzc920yWazByh6OePKszhCbW38BBesH9IPfMJ2E81t8zxxyL+/uU6MlZAF/+ZKaWGHrU4TaSnGOTWJKo5uaChYQ468LTx21HZiBaEpbIZYy7QQ/fLuEbHp4Ox3HXcI/LMgRBlqV0zdHyQTgYYMFZLOg49vKloNeC+DEqoFhBFskdc2nit0B7WvXTk5qZfdRTcLPHLz2Ih1rJrFz8niwLz5exBGG2jWFIsbhQ/hHFPmiaPYvYX0sCAZz5jxUlgFQ2DRAXrrPW9Qy0j83V9yn2jFBBGf5Ff5PcDb5OgaJppPo9pjw7y3/xzZ/zECgYEA7ARBC2QPh1PdRRUd1MIftN9Wi9q/W+rA1jp9OpCY6t1+CskajqNGLA5z402oHLqq+gOtf7lsZkrZVrlEmnJbojblWejrx7GbZHTLJXrPKxkOCaqPzqPdEaFfqvdVjB8xqJd0JdGxVLAEMWJYavWmqpTpmkdTwJHkoJ5nOKP7D1cCgYEApttvK3ySOBUEcWS6SnDqZvcvKzPe0zSc0v22zIvyxpAGOetRNMKPbWLrJsiYEOeEYlhjVb6Ovh7qjXiSWskSGkytjlDh1ReigEHnDjmKEr/5JqvRSzL7Jh03+ypmGWZ2NUlmee3TEZI5HnU5B2nnlV4MibqZnnq8YCCI4CT8EvUCgYB+aITh8fSzOYKwhm/UzSgoOtpiy4VkWKZx1x/NZzbPzFO+uRlFPkPOQutk2enpgT0j7SZW21woqXwgi9gnlIpppldOwYbPDNw6gKdxaoZdAe1X1gdx2KgF0lWn/xLNmsOBFaU6wEXnIuMMBC1xFCLxCBLZ88vyvvEh6dVFK+bCvwKBgQCTVZ3zazr9tGlI62Wnx87i/o8y+cle+80ibY/VTBoihRhKWmRJTycwsrDrfSLxgk0ePefw1aPbcxcvtnCdI4ENofl6eib/b7A4yniI0fv+lG8fW4YifbDQteoxqP2gnh3w7ZBER+EhWdl/8Ihb6ILqHLK7hv6QttXRl8jlCyNeZQKBgDz4HhUkc1Mig1bD8mgkQPkMiptd6/jidLoRJ/ExoR2Ctab4ixPGEYuPNfTqpK7wdto70z0i/HmtwWY3e3doeMYeF9PiNjDiqElx5266G8r3lFIbMKGj849h41u0k50swshAx3MboJv3y0N+oZ97u3E9a7FA5s319GCf9jE618xv\",\"alipay_public_key\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSpfv47tdtCJCZXhbEUtqoofSQLRCFLYCG6U8Q7wiDytFGVyI1Dby3M6bvHjREjb7imoox4Lrsg66lbnTLeEuetAnukU0GhAM/1zzVBnV6iTDy5fq4tEDVCWCY6+GLn6YNgOC+RVPrko5mYs+GIexWhT+QWvNcrewBYjdWWEY2PeoKf5ZgSkgfZELZcEPOWDaPzdn95J1U90cwakLL360C/E9s0h/mkRjxMSgQVfQef1JmNSpqyc+5uT3VJp4PcqQX1/RpawJG1B0NBaxmrAYJDdA1F7VgUzNIdLW6z+8IvQXG+7NuAayNgaelgdfkz+l3hebaMKrMxMKl2pNiqkpwIDAQAB\n\",\"sign_type\":\"RSA2\",\"returnUrl\":\"http://daguoge.vaiwan.com/callback/return\",\"notifyUrl\":\"http://daguoge.vaiwan.com/callback/notify\"}";
value = "{\"applicationUrl\":\"https://openapi.alipaydev.com/gateway.do\",\"app_id\":\"2016101400684128\",\"app_private_key\":\"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCQsOVWbMEmpCk78dmXFAPM1tofr3OMLExNHKmZ9ysbtffnMAaa5LgLaeAZRaMOgFJuhO25MYAONKPrUfNMTeeqNIR2xf0C5faYSyE2ludrL84BlpufH6Wh6XE+gniagpytndtN7Qa/ZDQ+/jKLWL95NnYPXZiWuQWsrLDbKn10d1BmBF3klfnG0RZR7l7wXg8QvrrT6neU4nS/xqEtR+F/HRgGApq2w5BTINlob2IML7C0YOJiZUAhYBwpa6Tz2s9aafkCE1Xh02uJ5uliur0QFNPgrAKmtfbHJnNv3W45geRRvwq83EYSBsjJttVEKkhr/YpKGPdnnEcpwn7gXIILAgMBAAECggEALDwooRd2pZ2ijZUO9MVFtCYrYWx+YuhYG2sb3tpV747eT2u7WTd7nOGthYxooVJR4T/6fZfIko89XgAb5cQbg0mzBazaATzU+xJdARd5gKeIz6t/wFIojSuVV4sD3Bj6VYnhNh205mZ4IpoMUdW8FA62YVQ4Bjxio7vYBekjmas4u0gwIynFYpn8vaQ3Kg5O9bO09N52cJlCWxu1LD3uopD7aCBxEB0JvOfvB/kDorzrZGMbiU6kDTk5IwvAXuFGkXo1RPmHOmdYpyt0yhepqylBwBQ1ta7alKOFFl9vop79Rm3Ej+naXYQZXuXLlknDnAQM6N2tyHPN+OHUTzOywQKBgQDognTdCiopINAWryux8zrCMa9x0OnJ1p6IwrCtWIYnpTR/zYe35fzFk29MN8iEU/mj8UCaHkq6jQdK2ZSd/w8qZ5BDxvL3DQThvn4mk2jyUIwzYFuoPDJEd2JzTabKrRs2nWlGsb4tjiLTR3EBTzSNyhy3jaHEwz+LMYKt1RCVgwKBgQCfTyGT0pPGRM3zOKXkQjeTwgwiNqEQfvJDvIKNqrTPXH6SRyZjptdTy669y4Is8K2qnj7LdHmdznDB0p0uLG5ajSK0yAvstT2Be6DTtPEmWUfCXmd7dXHBFpmcJGeGCGgcYuGPIAp+BhUJdC14AzOlzwLMVgMZAnufpalJzJZC2QKBgEa6aJJU5T5dnO9JmiEnvFgWhSg6ROQBRXiUwOn6Y9TrjGzUONTYQWxYzSKCVZzrbqVQXjaDwHe/Lti2F194l0Ru/JOhkYdVjoadTAKwFNyhZAS86yTiKuho6KnqlTJSNlUGzV+T8iYpdq6OrPGZBoObV+D+VJdmTY4qIXZ/uevBAoGAaurgziT1qItk7WeHbrpCMph5LD0du8R3M57Av/Nhhgm9qM63pQnEWijJDfgXVbHx3CB4ZHO3a4Gxi2Oeue534a33LP1Vg3ff35bpSSyW6/Xfg0N4kBMyVTSlw3VrRTk/Jk32s+f9IrdSRxYBrhn3/7//UMQpMA/KiErWYwE7l4ECgYAzYfE2zUdUw3+NDFYP3d/rZdAhmlKW7Lx76tCfGYO1Bcbx1TDGYrqa9s12GX+jFsSc03a3QmUednf+NeLR3lYSb8Sm9BoYZKRmLt8p1HYeulsEjYMOd7tPqwXXl4B/HiZm9sPJeglr/pA6Rvp3KTQdk1+i075olUsPmryalsfLgw==\",\"alipay_public_key\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn12eE8oUUiZZIOqj6+1toJ71xyfx74r7GpgiqK9uWaebLMghFkjqqg4NApOgXcNckPRo5oDl5G6j20h8vAPS6zhkeQItph5qqSpCj7i06ieeBUReijmyeHY6jL0gMc8gMJyX4FbdASZQvE2D1B3aveDT1YL0X2AedTziBWxu+qlE5d3QA+KBfoxd6azzTjayi0VrDNN7rpni8/GKILBfty+KypLZc3ZrVUvEa+dkRY4VXAG36wYbU+FIudutra3BM2zTOGWPL+p9pbHrVZ/MGhRS1nWntRy+sCaYJidq9RVgY54UPb8OolvnL56LGi56BT1shFZetDfLnkfLDfIUvwIDAQAB\",\"sign_type\":\"RSA2\",\"returnUrl\":\"http://daguoge.vaiwan.com/callback/return\",\"notifyUrl\":\"http://daguoge.vaiwan.com/callback/notify\"}";
AliPayAccount aliPayAccount = new Gson().fromJson(value, AliPayAccount.class);
String URL = aliPayAccount.getApplicationUrl();
String app_id = aliPayAccount.getApp_id();
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String app_private_key = aliPayAccount.getApp_private_key();
String sign_type = aliPayAccount.getSign_type();
AlipayClient alipayClient = new DefaultAlipayClient(URL, app_id, app_private_key, FORMAT, CHARSET, alipay_public_key, sign_type);
//设置请求参数
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"20150320010101001\"," +
"\"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
"\"total_amount\":88.88," +
"\"subject\":\"Iphone6 16G\"," +
"\"body\":\"Iphone6 16G\"," +
"\"time_expire\":\"2016-12-31 10:05:01\"," +
" \"goods_detail\":[{" +
" \"goods_id\":\"apple-01\"," +
"\"alipay_goods_id\":\"20010001\"," +
"\"goods_name\":\"ipad\"," +
"\"quantity\":1," +
"\"price\":2000," +
"\"goods_category\":\"34543238\"," +
"\"categories_tree\":\"124868003|126232002|126252004\"," +
"\"body\":\"特价手机\"," +
"\"show_url\":\"http://www.alipay.com/xxx.jpg\"" +
" }]," +
"\"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," +
"\"extend_params\":{" +
"\"sys_service_provider_id\":\"2088511833207846\"," +
"\"hb_fq_num\":\"3\"," +
"\"hb_fq_seller_percent\":\"100\"," +
"\"industry_reflux_info\":\"{\\\\\\\"scene_code\\\\\\\":\\\\\\\"metro_tradeorder\\\\\\\",\\\\\\\"channel\\\\\\\":\\\\\\\"xxxx\\\\\\\",\\\\\\\"scene_data\\\\\\\":{\\\\\\\"asset_name\\\\\\\":\\\\\\\"ALIPAY\\\\\\\"}}\"," +
"\"card_type\":\"S0JP0000\"" +
" }," +
"\"goods_type\":\"0\"," +
"\"timeout_express\":\"90m\"," +
"\"promo_params\":\"{\\\"storeIdType\\\":\\\"1\\\"}\"," +
"\"royalty_info\":{" +
"\"royalty_type\":\"ROYALTY\"," +
" \"royalty_detail_infos\":[{" +
" \"serial_no\":1," +
"\"trans_in_type\":\"userId\"," +
"\"batch_no\":\"123\"," +
"\"out_relation_id\":\"20131124001\"," +
"\"trans_out_type\":\"userId\"," +
"\"trans_out\":\"2088101126765726\"," +
"\"trans_in\":\"2088101126708402\"," +
"\"amount\":0.1," +
"\"desc\":\"分账测试1\"," +
"\"amount_percentage\":\"100\"" +
" }]" +
" }," +
"\"sub_merchant\":{" +
"\"merchant_id\":\"19023454\"," +
"\"merchant_type\":\"alipay: 支付宝分配的间连商户编号, merchant: 商户端的间连商户编号\"" +
" }," +
"\"merchant_order_no\":\"20161008001\"," +
"\"enable_pay_channels\":\"pcredit,moneyFund,debitCardExpress\"," +
"\"store_id\":\"NJ_001\"," +
"\"disable_pay_channels\":\"pcredit,moneyFund,debitCardExpress\"," +
"\"qr_pay_mode\":\"1\"," +
"\"qrcode_width\":100," +
"\"settle_info\":{" +
" \"settle_detail_infos\":[{" +
" \"trans_in_type\":\"cardAliasNo\"," +
"\"trans_in\":\"A0001\"," +
"\"summary_dimension\":\"A0001\"," +
"\"settle_entity_id\":\"2088xxxxx;ST_0001\"," +
"\"settle_entity_type\":\"SecondMerchant、Store\"," +
"\"amount\":0.1" +
" }]" +
" }," +
"\"invoice_info\":{" +
"\"key_info\":{" +
"\"is_support_invoice\":true," +
"\"invoice_merchant_name\":\"ABC|003\"," +
"\"tax_num\":\"1464888883494\"" +
" }," +
"\"details\":\"[{\\\"code\\\":\\\"100294400\\\",\\\"name\\\":\\\"服饰\\\",\\\"num\\\":\\\"2\\\",\\\"sumPrice\\\":\\\"200.00\\\",\\\"taxRate\\\":\\\"6%\\\"}]\"" +
" }," +
"\"agreement_sign_params\":{" +
"\"personal_product_code\":\"GENERAL_WITHHOLDING_P\"," +
"\"sign_scene\":\"INDUSTRY|CARRENTAL\"," +
"\"external_agreement_no\":\"test\"," +
"\"external_logon_id\":\"13852852877\"," +
"\"sign_validity_period\":\"2m\"," +
"\"third_party_type\":\"PARTNER\"," +
"\"buckle_app_id\":\"1001164\"," +
"\"buckle_merchant_id\":\"268820000000414397785\"," +
"\"promo_params\":\"{\\\"key\\\",\\\"value\\\"}\"" +
" }," +
"\"integration_type\":\"PCWEB\"," +
"\"request_from_url\":\"https://\"," +
"\"business_params\":\"{\\\"data\\\":\\\"123\\\"}\"," +
"\"ext_user_info\":{" +
"\"name\":\"李明\"," +
"\"mobile\":\"16587658765\"," +
"\"cert_type\":\"IDENTITY_CARD\"," +
"\"cert_no\":\"362334768769238881\"," +
"\"min_age\":\"18\"," +
"\"fix_buyer\":\"F\"," +
"\"need_check_info\":\"F\"" +
" }" +
" }");
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
}
}
生成二维码
public class QRCodeUtil {
private static final String CHARSET = "utf-8";
private static final String FORMAT_NAME = "JPG";
// 二维码尺寸
private static final int QRCODE_SIZE = 300;
// LOGO宽度
private static final int WIDTH = 240;
// LOGO高度
private static final int HEIGHT = 240;
private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception {
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
hints);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
if (imgPath == null || "".equals(imgPath)) {
return image;
}
// 插入图片
QRCodeUtil.insertImage(image, imgPath, needCompress);
return image;
}
/**
* 功能描述: 生成二维码 BufferedImage.
*
* @param content
* @param
* @param
* @return java.awt.image.BufferedImage
* @author yangshao
* @date 2019/9/25 10:13
*/
public static BufferedImage getBufferImage(String content) throws Exception {
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
hints.put(EncodeHintType.MARGIN, 1);
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, WIDTH, HEIGHT, hints);
int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
return image;
}
/**
* 功能描述: 生成base64格式二维码.
*
* @param content content
* @return string
* @author yangshao
* @date 2019/9/25 10:28
*/
public static String getBase64Code(String content) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
BufferedImage image = getBufferImage(content);
//转换成png格式的IO流
ImageIO.write(image, "png", byteArrayOutputStream);
} catch (Exception e) {
e.printStackTrace();
}
byte[] bytes = byteArrayOutputStream.toByteArray();
BASE64Encoder encoder = new BASE64Encoder();
String base64 = encoder.encodeBuffer(bytes).trim();
/*base64 = "data:image/png;base64," + base64;*/
return base64;
}
private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception {
File file = new File(imgPath);
if (!file.exists()) {
System.err.println("" + imgPath + " 该文件不存在!");
return;
}
Image src = ImageIO.read(new File(imgPath));
int width = src.getWidth(null);
int height = src.getHeight(null);
if (needCompress) { // 压缩LOGO
if (width > WIDTH) {
width = WIDTH;
}
if (height > HEIGHT) {
height = HEIGHT;
}
Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(image, 0, 0, null); // 绘制缩小后的图
g.dispose();
src = image;
}
// 插入LOGO
Graphics2D graph = source.createGraphics();
int x = (QRCODE_SIZE - width) / 2;
int y = (QRCODE_SIZE - height) / 2;
graph.drawImage(src, x, y, width, height, null);
Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
}
public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
mkdirs(destPath);
// String file = new Random().nextInt(99999999)+".jpg";
// ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file));
ImageIO.write(image, FORMAT_NAME, new File(destPath));
}
public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
return image;
}
public static void mkdirs(String destPath) {
File file = new File(destPath);
// 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
if (!file.exists() && !file.isDirectory()) {
file.mkdirs();
}
}
public static void encode(String content, String imgPath, String destPath) throws Exception {
QRCodeUtil.encode(content, imgPath, destPath, false);
}
// 被注释的方法
/*
* public static void encode(String content, String destPath, boolean
* needCompress) throws Exception { QRCodeUtil.encode(content, null, destPath,
* needCompress); }
*/
public static void encode(String content, String destPath) throws Exception {
QRCodeUtil.encode(content, null, destPath, false);
}
public static void encode(String content, String imgPath, OutputStream output, boolean needCompress)
throws Exception {
BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress);
ImageIO.write(image, FORMAT_NAME, output);
}
public static void encode(String content, OutputStream output) throws Exception {
QRCodeUtil.encode(content, null, output, false);
}
public static String decode(File file) throws Exception {
BufferedImage image;
image = ImageIO.read(file);
if (image == null) {
return null;
}
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result;
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
hints.put(DecodeHintType.CHARACTER_SET, CHARSET);
result = new MultiFormatReader().decode(bitmap, hints);
String resultStr = result.getText();
return resultStr;
}
public static String decode(String path) throws Exception {
return QRCodeUtil.decode(new File(path));
}
}
支付宝回调接口
这部分 坑就在于 验签功能,验签失败,可能是由于沙箱环境配置问题。注意支付宝公钥和私钥不要对应错。
回调接口 在沙箱中一样要被本地代码对应(回调路径要放到服务器上测试)
public String doNotify() {
Map<String, String> params = new HashMap<String, String>();
String orderID = "";
try {
//获取支付宝POST过来反馈信息
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> 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);
}
log.info("异步的参数:" + params.toString());
SystemConfig queryOneSystemConfig = orderPayService.queryOneSystemConfig("cm2_aliPayAccount");
AliPayAccount aliPayAccount = new Gson().fromJson(queryOneSystemConfig.getConfigValue(), AliPayAccount.class);
String alipay_public_key = aliPayAccount.getAlipay_public_key();
String sign_type = aliPayAccount.getSign_type();
log.info("alipay_public_key:" + alipay_public_key);
log.info("CHARSET:" + CHARSET);
log.info("sign_type:" + sign_type);
/**
* 调用SDK验证签名
*/
boolean signVerified = AlipaySignature.rsaCheckV1(params, alipay_public_key, CHARSET, sign_type);
log.info("验证结果:" + signVerified);
/**
* 实际验证过程建议商户务必添加以下校验:
* 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
* 3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
* 4、验证app_id是否为该商户本身。
*/
/**
* 商户订单号
*/
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), CHARSET);
log.info("out_trade_no : " + out_trade_no);
PayRecord queryOrderPayRecordByOrderID = this.orderPayService.queryOrderPayRecordByOut_Trade_NoAndType(out_trade_no, OrderPayTypeEnum.ALIPAY.getValue());
if (null == queryOrderPayRecordByOrderID) {
log.error("当前商户订单号不存在");
return "fail";
}
orderID = queryOrderPayRecordByOrderID.getOrderID();
if (signVerified) {
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), CHARSET);
log.info("trade_no : " + trade_no);
//付款金额
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), CHARSET);
log.info("total_amount : " + total_amount);
String formatAmountByCent = CommonUtils.formatAmountByCent(queryOrderPayRecordByOrderID.getPayAmount());
if (!total_amount.equals(formatAmountByCent)) {
this.payLogService.createPayLogByReceive(orderID, new Gson().toJson(params), 1, "支付异步调用,支付金额和返回金额不匹配");
log.error("支付的金额和返回的金额不匹配");
return "fail";
}
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), CHARSET);
log.info("交易状态:" + trade_status);
String seller_id = new String(request.getParameter("seller_id").getBytes("ISO-8859-1"), CHARSET);
log.info("seller_id:" + seller_id);
//支付时间
String gmt_payment = new String(request.getParameter("gmt_payment").getBytes("ISO-8859-1"), CHARSET);
log.info("gmt_payment:" + gmt_payment);
String sign = new String(request.getParameter("sign").getBytes("ISO-8859-1"), CHARSET);
if (OrderPayStatusEnum.PAID.getValue() == queryOrderPayRecordByOrderID.getPayStatus() || OrderPayStatusEnum.PAYMENT_END.getValue() == queryOrderPayRecordByOrderID.getPayStatus()) {
log.info("数据库状态已更新,不需要操作:" + queryOrderPayRecordByOrderID.getPayStatus());
this.payLogService.createPayLogByReceive(orderID, new Gson().toJson(params), 1, "支付异步调用,支付状态已完成");
return "success";
}
String buyer_logon_id = new String(request.getParameter("buyer_logon_id").getBytes("ISO-8859-1"), CHARSET);
long longValue = (new BigDecimal(total_amount).multiply(new BigDecimal("100"))).longValue();
queryOrderPayRecordByOrderID.setPayAmount(longValue);
queryOrderPayRecordByOrderID.setTrade_no(trade_no);
queryOrderPayRecordByOrderID.setPayType(OrderPayTypeEnum.ALIPAY.getValue());
queryOrderPayRecordByOrderID.setComment(queryOrderPayRecordByOrderID.getComment() + "时间:" + new Date() + "==>支付宝异步数据");
queryOrderPayRecordByOrderID.setEditTime(new Date());
queryOrderPayRecordByOrderID.setSeller_id(seller_id);
queryOrderPayRecordByOrderID.setBuyer_logon_id(buyer_logon_id);
Date payTime = null;
if (null != gmt_payment && !"".equals(gmt_payment)) {
SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
payTime = sDateFormat.parse(gmt_payment);
}
queryOrderPayRecordByOrderID.setPayTime(payTime);
queryOrderPayRecordByOrderID.setSign(sign);
//交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
if (trade_status.equals("TRADE_FINISHED")) {
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
queryOrderPayRecordByOrderID.setPayStatus(OrderPayStatusEnum.PAYMENT_END.getValue());
this.orderPayService.updateOrderPayRecord(queryOrderPayRecordByOrderID);
} else if (trade_status.equals("TRADE_SUCCESS")) {
queryOrderPayRecordByOrderID.setPayStatus(OrderPayStatusEnum.PAID.getValue());
this.orderPayService.updateOrderPayRecord(queryOrderPayRecordByOrderID);
} else if (trade_status.equals("TRADE_CLOSED")) {
queryOrderPayRecordByOrderID.setPayStatus(OrderPayStatusEnum.PAYMENT_FAILED.getValue());
this.orderPayService.updateOrderPayRecord(queryOrderPayRecordByOrderID);
} else {
log.error("当前状态不作处理,让支付再次异步:" + trade_status);
this.payLogService.createPayLogByReceive(orderID, new Gson().toJson(params), 1, "支付异步调用,状态不处理");
return "fail";
}
this.payLogService.createPayLogByReceive(orderID, new Gson().toJson(params), 0, "支付异步调用");
return "success";
} else {//验证失败
log.error("异步同步数据验证失败");
this.payLogService.createPayLogByReceive(orderID, new Gson().toJson(params), 1, "支付异步调用,验证失败");
return "fail";
}
} catch (Exception e) {
log.error("异步同步数据异常:", e);
this.payLogService.createPayLogByReceive(orderID, new Gson().toJson(params), 1, "支付异步调用异常");
return "fail";
}
}