java APP支付宝支付
因项目中有用到支付宝支付,这里对java微信支付的开发流程和注意事项到做一次记录,以遍后面有需要的时候翻阅,方便回顾
接入前准备工作可自行参考支付宝官方文档配置,参考地址:https://opendocs.alipay.com/open/204/105051
支付宝支付交互流程如下图:
笔者使用的是java,应用maven依赖引入,最新版本依赖资源下载https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java,可自行查看引入
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.10.192.ALL</version></dependency>
支付宝支付Java 代码
配置信息
alipay:serverUrl: https://openapi.alipay.com/gateway.doappId: ###privateKey: ######notifyUrl: ###
package com.hjy.ft.config;import com.hjy.pay.AliPayUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.io.*;/*** @version 1.0* @className AliPayStartUpRunner* @description 程序启动后加载* @since 2021/5/13 16:46*/
@Component
@Order(value = 0)
public class AliPayStartUpRunner implements CommandLineRunner {/*** 服务网关*/@Value("${alipay.serverUrl}")private String serverUrl;/*** 应用id*/@Value("${alipay.appId}")private String appId;/*** 应用私钥*/@Value("${alipay.privateKey}")private String privateKey;/*** 异步通知地址*/@Value("${alipay.notifyUrl}")private String notifyUrl;@Overridepublic void run(String... args) throws Exception {AliPayUtil.appId = appId;AliPayUtil.serverUrl = serverUrl;AliPayUtil.privateKey = privateKey;AliPayUtil.notifyUrl = notifyUrl;//应用公钥证书路径AliPayUtil.certPath = aliPayPath("appCertPublicKey_2021002113644216.crt");//支付宝公钥证书路径AliPayUtil.alipayPublicCertPath = aliPayPath("alipayCertPublicKey_RSA2.crt");//支付宝根证书路径AliPayUtil.rootCertPath = aliPayPath("alipayRootCert.crt");}/*** 读取临时文件(jar)* @param fileName (文件路径)* @return 临时文件路径*/public String aliPayPath(String fileName) {String url = null;//返回读取指定资源的输入流InputStream is = this.getClass().getResourceAsStream("/alipay/"+fileName);//InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("/alipay/"+fileName);String path = System.getProperty("user.dir");//create folderString dirPath = path + File.separator + "uploadAlipayFiles";File dir = new File(dirPath);dir.mkdirs();//create fileString filePath = dirPath + File.separator + fileName;File file = new File(filePath);//判断文件是否存在if (!file.exists()) {try {file.createNewFile();//文件不存,创建流输入数据到新文件inputStreamToFile(is, file);} catch (IOException e) {e.printStackTrace();}url = filePath;}else{url = filePath;}return url;}public void inputStreamToFile(InputStream ins, File file) {OutputStream os = null;try {os = new FileOutputStream(file);int bytesRead = 0;byte[] buffer = new byte[1024];while ((bytesRead = ins.read(buffer, 0, 1024)) != -1) {os.write(buffer, 0, bytesRead);}os.close();ins.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}
生成支付宝订单:
/*** 生成支付宝订单信息* @return 订单信息* @throws AlipayApiException*/@Overridepublic String alipayRecharge(AliPayModel aliPayModel) throws Exception {//初始化配置信息AlipayClient alipayClient = initAlipay();//生成订单号Long orderNumber = 0L;//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.payAlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();model.setBody(aliPayModel.getBody());model.setSubject(aliPayModel.getSubject());model.setOutTradeNo(String.valueOf(orderNumber));model.setTimeoutExpress(AliPayUtil.TIMEOUTEXPRESS);model.setTotalAmount(aliPayModel.getTotalAmount());model.setProductCode(AliPayUtil.PRODUCT_CODE);request.setBizModel(model);//异步通知地址request.setNotifyUrl(AliPayUtil.notifyUrl);try {//业务处理//dosomething//这里和普通的接口调用不同,使用的是sdkExecuteAlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);return response.getBody(); //就是orderString 可以直接给客户端请求,无需再做处理。}catch(AlipayApiException e) {logger.error("生成支付订单错误:",e);return null;}}
//配置信息public AlipayClient initAlipay() throws AlipayApiException {//构造clientCertAlipayRequest certAlipayRequest = new CertAlipayRequest();//设置网关地址certAlipayRequest.setServerUrl(AliPayUtil.serverUrl);//设置应用IdcertAlipayRequest.setAppId(AliPayUtil.appId);//设置应用私钥certAlipayRequest.setPrivateKey(AliPayUtil.privateKey);//设置请求格式,固定值jsoncertAlipayRequest.setFormat(AliPayUtil.FORMAT);//设置字符集certAlipayRequest.setCharset(AliPayUtil.CHARSET);//设置签名类型certAlipayRequest.setSignType(AliPayUtil.SIGN_TYPE);//设置应用公钥证书路径certAlipayRequest.setCertPath(AliPayUtil.certPath);//设置支付宝公钥证书路径certAlipayRequest.setAlipayPublicCertPath(AliPayUtil.alipayPublicCertPath);//设置支付宝根证书路径certAlipayRequest.setRootCertPath(AliPayUtil.rootCertPath);//构造clientAlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);return alipayClient;}
支付宝回调
/*** 支付宝 - 回调接口* @param request 请求* @return 验签状态*/@Overridepublic String alipayCallbackNotify(HttpServletRequest request) {// 将异步通知中收到的待验证所有参数都存放到map中Map<String, String> params = AliPayUtil.convertRequestParamsToMapWith(request);String paramsJson = JSON.toJSONString(params);logger.info("支付宝回调,{}", paramsJson);try {// 调用SDK验证签名boolean signVerified = AlipaySignature.rsaCertCheckV1(params, AliPayUtil.alipayPublicCertPath,AliPayUtil.CHARSET, AliPayUtil.SIGN_TYPE);if (signVerified) {// 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failurethis.check(params);String tradeStatus = params.get("trade_status");String outTradeNo = params.get("out_trade_no");//通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功if(tradeStatus.equals(AliPayUtil.TRADE_SUCCESS) || tradeStatus.equals(AliPayUtil.TRADE_FINISHED)){//业务逻辑处理//do something}return "success";} else {logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);return "failure";}} catch (AlipayApiException e) {logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());return "failure";}}
/*** request 转 map* @param request* @return*/public static Map<String,String> convertRequestParamsToMapWith(HttpServletRequest request){Map<String,String> params = new HashMap <String,String >();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 );}return params;}
/*** 1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),* 3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),* 4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。* 在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。* 在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。** @param params 支付宝回调参数* @throws AlipayApiException*/private void check(Map<String, String> params) throws AlipayApiException {//订单号String outTradeNo = params.get("out_trade_no");//商户订单实际金额String totalAmount = params.get("total_amount");//APPIdString appId = params.get("app_id");//验证订单号UserRechargeRecord userRechargeRecord = checkOutTradeNo(outTradeNo);if(userRechargeRecord == null){throw new AlipayApiException("out_trade_no错误");}//验证订单实际金额if(userRechargeRecord != null && !totalAmount.equals(userRechargeRecord.getPayAmount().toString())){throw new AlipayApiException("支付金额不一致");}//验证app_id是否为商户本身if(!appId.equals(AliPayUtil.appId)){throw new AlipayApiException("app_id不一致");}}
同步验签
/*** 客户端同步验签* @param request* @return true:验证成功,false:验证失败* @throws AlipayApiException*/@Overridepublic Boolean getVerifySignResult(HttpServletRequest request) throws AlipayApiException {Map<String, String> params = AliPayUtil.convertRequestParamsToMapWith(request);String paramsJson = JSON.toJSONString(params);logger.info("支付宝回调,{}", paramsJson);boolean signVerified = AlipaySignature.rsaCertCheckV1(params, AliPayUtil.alipayPublicCertPath,AliPayUtil.CHARSET,AliPayUtil.SIGN_TYPE);return signVerified;}
需要注意的是,params参数一定要严格按照支付宝提供的参数顺序,不然会一直验签错误,返回false
支付宝订单查询
/*** 获取支付宝交易订单* @param outTradeNo 商户订单号* @param tradeNo 支付宝交易号* @return 支付结果*/@Overridepublic String getAlipayOutTradeNo(Long outTradeNo, Long tradeNo) throws AlipayApiException {//初始化支付宝配置AlipayClient alipayClient = initAlipay();AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();AlipayTradeQueryModel model = new AlipayTradeQueryModel();model.setOutTradeNo(outTradeNo.toString());if(tradeNo != null){model.setTradeNo(tradeNo.toString());}request.setBizModel(model);AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);return response.getBody();}
其他接口可自行到支付宝官方Api接口查阅
java APP支付宝支付相关推荐
- java对接支付宝支付
java对接支付宝支付演示 现在有不少的项目都需要对接支付,这里主要是进行讲解对接支付宝H5支付 废话不多说 上代码 引入支付宝官方的sdk <!-- https://mvnrepository ...
- 【超详细,全流程】java对接支付宝支付
支付流程 一.对接前的准备 1.1创建应用,获取参数:APPID(使用沙箱环境可跳过) 1.1.1添加产品 1.1.2配置密钥,获取第二个参数:商户的私钥 1.1.3支付宝网关 1.1.4生成参数密钥 ...
- 【APP支付】关于APP支付宝支付那些事
昨天整理了关于APP微信支付的东西,今天在整理代码之后,来谈谈支付宝的APP支付. 两者有很大相似之处,也有区别,只要理解了一个,另一个就很好理解了,如果是第一次做服务端的支付的话,建议先看看上面那篇 ...
- JAVA对接支付宝支付(超详细,一看就懂)
Java对接支付宝支付 更多内容 冷文博客: 传送门 引入 为什么要发这篇帖子呢?原因很简单,就是因为在一个稍稍正规一点的应用上都会有支付这个环节,我们日常的在线支付如今包括支付宝,微信钱包,QQ钱包 ...
- Java接入支付宝支付测试买iPhone13 pro max
Java接入支付宝支付 一.介绍 二.沙箱 三.支付流程 四.准备支付宝 五.代码 1.前端代码 2.后端代码 六.测试 一.介绍 支付宝官方网站 支付宝(中国)网络技术有限公司是国内的第三方支付平台 ...
- node egg APP支付宝支付
1.首先安装 npm包 npm install alipay-sdk 2.使用 const AlipaySdk = require('alipay-sdk').default const aliUti ...
- Java接入支付宝支付超级详细教程——从入门到精通
Java接入支付宝支付教程 源码下载 源码获取:点击获取源码 本文介绍了"二维码付款"的代码.其他支付方式的代码都在源码中. 一.创建应用 1.登录支付宝开放平台 支付宝开放平 ...
- Java接入支付宝支付教程
Java接入支付宝支付教程 一.创建应用 1.登录支付宝开放平台 支付宝开放平台网址:https://open.alipay.com/platform/developerIndex.htm 2.创建一 ...
- app支付宝支付java后台_支付宝app支付java后台流程demo
支付宝app支付java后台流程demo 使用ssm框架实现支付宝支付功能. 支付宝测试环境代码测试 源代码 https://github.com/OUYANGSIHAI/sihai-maven-ss ...
- JAVA集成支付宝支付 周期扣费 (证书方式)
依赖 <!-- <dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-s ...
最新文章
- 最新:2022校友会中国大学排名发布!
- Flutter开发之ListView下拉刷新上拉加载更多(35)
- uva 610(割边)
- 最详细的phpmailer的使用方法
- CentOS7安装Docker详细教程
- 【LeetCode-SQL每日一练】—— 627. 变更性别
- ClickHouse入门
- Echart 地图实例
- dmv io读写高的sql_使用内置的动态管理视图(DMV)发现更多SQL Server信息
- 浅析微信支付:1前篇大纲
- vue 父子之间通信及非父子之间通信
- 四川大学计算机学院 学术委员会,学术委员会完整列表
- linux搭建虚拟ftp,linux下搭建ftp服务器(虚拟用户)
- 添加最顶层js广告_js实现网站最上边可关闭的浮动广告条代码
- 多元线性回归矩阵求导
- 单日复利,单月复利计算java实现
- Rust websocket 客户端实现
- 又一视频下载神器,一键下载b站收藏夹视频和up主所有视频
- post模拟传数据的几种方法
- ArcGis之椭球面积计算工具