前言
最近在工作中需要使用支付宝app支付,在初次使用过程中也不可避免的出现了一些问题,那么本次随笔主要是概述支付宝app支付服务端的整个实现过程以及就服务端出现的一些问题做一些总结。
1.准备工作
1.1 入驻蚂蚁金服开放平台
https://open.alipay.com/platform/home.htm
1.2 创建应用
首先需要创建一个应用。
然后需要设置应用公钥。
下载支付宝密钥生成器。生成成功之后将公钥复制到这里。
最后提交审核,等待。
2.Maven依赖
首先需要下载SDK,https://docs.open.alipay.com/54/104509。
完成之后,需要切换命令行,进入SDK所在目录,执行如下命令。如果命令无法执行,请百度如何配置maven环境变量,配置好之后再执行。
mvn install:install-file -DgroupId=com.alipay.sdk -DartifactId=alipay-sdk-java -Dversion=3.1.0 -Dpackaging=jar -Dfile=SDK文件名.jar
groupId:可以自己定义,pom文件依赖依据与此
artifactId:可以自己定义,pom文件依赖依据与此
version:可以自己定义,pom文件依赖依据与此
packaging:打包方式(jar)
file:文件的路径的路径
在pom.xml中引入依赖,如下。
<!-- 支付宝支付相关start --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>3.1.0</version> </dependency> <!-- 支付宝支付相关end -->
3.配置文件中配置支付宝相关参数
#支付宝支付相关配置
#支付宝分配给开发者的应用Id aliPayAppId=XXX
#卖家支付宝用户号(对应异步通知返回参数seller_id)(可以不配置,只是异步通知时为了进一步校验而配置) aliPaySellerId=XXX
#卖家支付宝账号(对应异步通知返回参数seller_email)(可以不配置,只是异步通知时为了进一步校验而配置) alipayAccount=XXX
#商户公钥 rsaPublicKey=XXX
#商户私钥(注意,如果是Java语言,需要使用pkcs8格式的私钥,避免出现不可预知的错误) rsaPrivatKey=XXX
#支付宝公钥 rsaAlipayPublicKey=XXX
#加密方式 signType=XXX
#仅支持JSON alipayFormat=json
#请求使用的编码格式,如utf-8,gbk,gb2312等 alipayCharset=utf-8
4.生成安卓端需要的orderString信息的接口方法
/** *app支付 * *@author lp *@date 2019/1/4 16:32 */ @ApiOperation("app支付") @RequestMapping(value = "alipay", method = RequestMethod.POST) public String alipay(@RequestBody CombinedPaymentDto dto, HttpServletResponse response, HttpServletRequest request) { response.setHeader("Access-Control-Allow-Origin", "*"); // 获取项目中实际的订单的信息 // 此处是相关业务代码 // 获取配置文件中支付宝相关信息 String aliPayGateway = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayGateway"); String aliPayAppId = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayAppId"); String rsaPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPublicKey"); String rsaPrivatKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPrivatKey"); String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey"); String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType"); String alipayFormat = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayFormat"); String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset"); AlipayClient alipayClient = new DefaultAlipayClient(aliPayGateway, aliPayAppId, rsaPrivatKey, alipayFormat, alipayCharset, rsaAlipayPublicKey, signType); AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest(); AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.setBody("XXX"); model.setSubject("XXX"); // 唯一订单号 根据项目中实际需要获取相应的 model.setOutTradeNo(""); // 支付超时时间(根据项目需要填写) model.setTimeoutExpress("30m"); // 支付金额(项目中实际订单的需要支付的金额,金额的获取与操作请放在服务端完成,相对安全) model.setTotalAmount(""); model.setProductCode("QUICK_MSECURITY_PAY"); alipayRequest.setBizModel(model); // 支付成功后支付宝异步通知的接收地址url alipayRequest.setNotifyUrl("XXX/getAlipayNotifyInfo"); AlipayTradeAppPayResponse alipayResponse = null; try { alipayResponse = alipayClient.sdkExecute(alipayRequest); } catch (AlipayApiException e) { e.printStackTrace(); } // 返回支付相关信息(此处可以直接将getBody中的内容直接返回,无需再做一些其他操作) return alipayResponse.getBody(); }
5.支付成功后服务端接收支付宝发来的异步通知的接口方法
/** *接收支付宝异步通知消息 * *@author lp *@date 2019/1/4 17:19 */ @ApiOperation("接收支付宝异步通知消息") @RequestMapping(value = "getAlipayNotifyInfo", method = RequestMethod.POST) public String getAlipayNotifyInfoOfCombinedPayment(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException { response.setHeader("Access-Control-Allow-Origin", "*"); // 解决POST请求中文乱码问题(推荐使用此种方式解决中文乱码,因为是支付宝发送异步通知使用的是POST请求) request.setCharacterEncoding("UTF-8"); //获取支付宝POST过来反馈信息 Map<String,String> params = new HashMap<>(); 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] + ","; } // 官方demo中使用如下方式解决中文乱码,在此本人不推荐使用,可能会出现中文乱码解决无效的问题。 // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8"); params.put(name, valueStr); } // 支付宝公钥(请注意,不是商户公钥) String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey"); String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType"); String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset"); boolean signVerified = false; try { //调用SDK验证签名 signVerified = AlipaySignature.rsaCheckV1(params, rsaAlipayPublicKey, alipayCharset, signType); if(signVerified) { // 验证通知后执行自己项目需要的业务操作 // 一般需要判断支付状态是否为TRADE_SUCCESS // 更严谨一些还可以判断 1.appid 2.sellerId 3.out_trade_no 4.total_amount 等是否正确,正确之后再进行相关业务操作。 // 成功要返回success,不然支付宝会不断发送通知。 return "success"; } // 验签失败 笔者在这里是输出log,可以根据需要做一些其他操作 // 失败要返回success,不然支付宝会不断发送通知。 return "fail"; } catch (AlipayApiException e) { e.printStackTrace(); // 验签异常 笔者在这里是输出log,可以根据需要做一些其他操作 return "fail"; } }