前言
最近在工作中需要使用支付宝 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";
- }
- }
来源: https://www.cnblogs.com/SmallMoodLP/p/10269422.html