前言
因工作需要,这几天摸索了很久,网上查找的资料大多不齐全,不详细,只有部分讲解及代码...所有我准备尽可能的把这篇博客写的详细易懂一些...好了..废话不多说..下面开始!!!
1.集成支付宝app支付,首先去申请一个支付宝账户..https://open.alipay.com/platform/manageHome.htm
申请完了以后登录 再这里可以看到一个沙箱 看下图
点击进去
到这里我们在沙箱环境下的网页工作差不多就做完了...接下来就应该下载ali支付的jar包了..
下载地址:https://docs.open.alipay.com/54/106370/
下载完成后,添加到你的maven仓库中,如果项目是maven项目,还需要在pom文件中添加
2.我们需要先看一些支付宝的一些文档.
app支付官方文档地址:https://docs.open.alipay.com/204
(1)out_trade_no:商户订单号,由商户自定义设置;
(2)subject:商品标题;
(3)product_code:固定产品码值:QUICK_MSECURITY_PAY;
(4)total_amount:交易订单金额,精确到小数点后2位,最小设置为0.01;
沙箱账号查看地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info
① controller层
/**
* 充值
* @param payDto payDto
* @return R
*/
@PostMapping(value = "/charge")
public R charge(@RequestBody PayDto payDto){
//payDto就是你前端传过来的值,比如充值金额是多少 用户id是多少..
//这个实体类根据你们自己的业务需求去写就好
String orderString = aliPayService.order(payDto);
return R.ok("orderString",orderString);
}
② service层
/**
* 支付宝下单
* @param payDto payDto
* @return String
*/
String order(PayDto payDto);
这个就没什么好说的了..大家都懂..不懂的先去看看三层架构再回来~~~
③serviceImpl
首先这里我们先新建一个AlipayConfig实体类代码我贴出来.有些东西需要你们自己修改我会在代码上方注释的..仔细看...
package com.wenliao.cloud.config;
/**
* @ClassName: AliPayConfig
* @Description: 需要传给支付宝SDK的公共基本参数
* @author: Linn
* @Date: 2019/4/3 9:22
*/
public class AliDevPayConfig {
/**
* 1.商户appid
*/
public String APPID = "这个就是在沙箱环境下你看到你的appId的那一串数字";
/**
* 私钥 pkcs8格式的
*/
public static String RSA_PRIVATE_KEY ="这个就是我上面说的应用私钥生成 注意这里是私钥";
/**
* 3.支付宝公钥
*/
public static String ALIPAY_PUBLIC_KEY = "这个就是你把生成的应用公钥在沙箱网页哪里输入后,就可以查看到支付宝公钥..把看到的支付宝公钥copy过来放这里就ok";
/**
* 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
*/
//这个着重讲一下..支付完成后,支付宝会通过这个url请求到你的服务端..
//这个url一定是要公网可以访问才行...如果需要测试的话..我后面有讲到..
//这里你可以先写你本地项目的url 例如:localhost:8080/项目名/访问路径
public static String notify_url = "http://2hu4349021.wicp.vip/pay/aliNotify";
/**
* 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
*/
//这里同上..不做详细说明了..
public static String return_url = "http://2hu4349021.wicp.vip/pay/returnUrl";
/**
* 正式环境支付宝网关,如果是沙箱环境需更改成https://openapi.alipaydev.com/gateway.do
*/
public static String URL = "https://openapi.alipaydev.com/gateway.do";
/**
* 7.编码
*/
public static String CHARSET = "UTF-8";
/**
* 私钥 pkcs8格式的
*/
// 8.返回格式
public static String FORMAT = "json";
/**
* //签名方式 加密类型
*/
public static String SIGNTYPE = "RSA2";
上面的代码我写了一些注释..希望大家好好看一下..特别是一些刚刚接触支付宝对接的人..有很大帮助的
接下来我们就是在impl中实现了..
@Override
public String order(PayDto payDto) {
//这里你可以做一些存表操作..具体根据你们自己的业务来操作...
String orderString = "";//这个字符串是用来返回给前端的
String orderNo = record.getOrderId();//这行代码是生成一个商户的订单号..根据你们自己的业务需求去生成就可以了..
log.info("==================支付宝下单,商户订单号为:" + orderNo);
try {
AliDevPayConfig aliDevPayConfig= new AliDevPayConfig(); //实例化上面的那个配置类..
//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
AlipayClient alipayClient = new DefaultAlipayClient(AliDevPayConfig.URL, aliDevPayConfig.getAPPID(),
AliDevPayConfig.RSA_PRIVATE_KEY, AliDevPayConfig.FORMAT, AliDevPayConfig.CHARSET,
AliDevPayConfig.ALIPAY_PUBLIC_KEY, AliDevPayConfig.SIGNTYPE);
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
//业务参数传入,可以传很多,参考API
//model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据)
//对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
model.setBody("具体描述信息.例如QQ币充值");
//商品名称
model.setSubject("例:QQ币");
//商户订单号(根据业务需求自己生成)
model.setOutTradeNo(orderNo);
//交易超时时间 这里的30m就是30分钟
model.setTimeoutExpress("30m");
//支付金额 后面保留2位小数点..不能超过2位
model.setTotalAmount(10.00);
//销售产品码(固定值) //这个不做多解释..看文档api接口参数解释
model.setProductCode("QUICK_MSECURITY_PAY");
ali_request.setBizModel(model);
//异步回调地址(后台)//这里我在上面的aliPayConfig有讲..自己去看
ali_request.setNotifyUrl(AliDevPayConfig.notify_url);
log.info("====================异步通知的地址为:" + ali_request.getNotifyUrl());
//同步回调地址(APP)同上
ali_request.setReturnUrl(AliDevPayConfig.return_url);
log.info("====================同步通知的地址为:" + ali_request.getReturnUrl());
// 这里和普通的接口调用不同,使用的是sdkExecute
//返回支付宝订单信息(预处理)
AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request);
//就是orderString 可以直接给APP请求,无需再做处理。
orderString = alipayTradeAppPayResponse.getBody();
System.out.println(orderString);
} catch (AlipayApiException e) {
e.printStackTrace();
log.info("与支付宝交互出错,未能生成订单,请检查代码!");
}
return orderString;
}
好..到这里就拿到了一个orderString返回给前端..
返回信息:
alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=2016101800718925&biz_content=%7B%22out_trade_no%22%3A%22201809251015343222843%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%22app%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF%95%22%2C%22passback_params%22%3A%22%25E5%2585%25AC%25E7%2594%25A8%25E5%259B%259E%25E4%25BC%25A0%25E5%258F%2582%25E6%2595%25B0%25E6%25B5%258B%25E8%25AF%259512334%25EF%25BC%2581%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%7D&charset=utf-8&format=JSON&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2F106.14.187.178%2Fopendevtools%2Fnotify%2Fdo%2Fa9bed896-0fc0-4b05-ba55-6a2550cacd36&return_url=https%3A%2F%2Fwww.baidu.com%2F&sign=qiOEfMcQoObzuPdZNkMOzavHfJLskTUWJxb08YObj8D0SexDStOw%2BHEwOs7x1hGih8Zs3rsT%2BA3aYVnmwp0FTnTYHx2cTbvz1tkNTzoguOG%2BdNR4b5dsJ%2BvUU4UbHV2KDOxg%2FASUcjcbhqitYraWjBgL02QWgTa%2FpA7dpZnxaOKyksZ1tvp7dR3zYvfDdVnfo3vpXlJxc8QTXsYvZdpODvmKG9odw%2FTsP2fZdt3Up7aiq7Ae8rby%2FNg%2BIMcGJjH%2F5MnUC99%2FU9%2Bjwt%2Biqt7jwU4PVfGimDY6ifIYs3PosGwfwrMTSZkI8AzdcsmwHRcqGJJNzlzegl9jQHw9mBzSAw%3D%3D&sign_type=RSA2×tamp=2018-09-25+13%3A09%3A52&version=1.0
前端调用支付宝接口进行支付....这里提供一个支付宝的测试App
测试服务端生成的请求参数是否正常,可使用客户端调试工具。
客户端调试工具:https://openclub.alipay.com/read.php?tid=7695&fid=60
登录沙箱账号点击【下一步】,进入账单详情,点击【确认付款】,进入输入密码页面
注意:未输入密码之前,支付宝订单还是为创建状态,只有输入密码之后,才会生成支付宝订单,所以这个时候用查询接口查询会报错“订单不存在”
到这里支付成功后,支付宝那边会有一个同步返回和异步返回接口
这个同步我暂时还没有弄太明白...同步也只是告诉你,这个订单有没有支付...并不代表支付成功..支付成功还是得看异步通知返回...
同上 controller层
/**
* 支付宝支付成功后.异步请求该接口
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value="/aliNotify",method= RequestMethod.POST)
@ResponseBody
public String aliNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("=支付宝异步返回支付结果开始");
//1.从支付宝回调的request域中取值
//获取支付宝返回的参数集合
Map aliParams = request.getParameterMap();
//用以存放转化后的参数集合
Map conversionParams = new HashMap();
for (Iterator iter = aliParams.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
String[] values = aliParams.get(key);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
conversionParams.put(key, valueStr);
}
System.out.println("==返回参数集合:"+conversionParams);
String status=aliPayService.aliNotify(conversionParams);
return status;
}
service层
/**
* 支付宝异步回调
* @param conversionParams conversionParams
* @return String
*/
String aliNotify( Map conversionParams);
impl层
/**
* 支付宝异步请求逻辑处理
*
* @param
* @return
* @throws IOException
*/
@Override
public String aliNotify(Map conversionParams) {
log.info("=支付宝异步请求逻辑处理=");
//签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false;
try {
//调用SDK验证签名
String alipayPublicKey = AliDevPayConfig.ALIPAY_PUBLIC_KEY;
String charset = AliDevPayConfig.CHARSET;
String signType = AliDevPayConfig.SIGNTYPE;
signVerified = AlipaySignature.rsaCheckV1(conversionParams, alipayPublicKey, charset, signType);
//对验签进行处理.
if (signVerified) {
log.info("+支付宝回调签名认证成功+");
// 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
this.check(conversionParams);
//验签通过 获取交易状态
String tradeStatus = conversionParams.get("trade_status");
//只处理支付成功的订单: 修改交易表状态,支付成功
//只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
if (tradeStatus.equals("TRADE_SUCCESS") ||tradeStatus.equals("TRADE_FINISHED")) {
//TODO 获取支付宝通知完成充值后续业务
//交易成功 获取商户订单号
/**修改订单信息*/
/**余额到账*/
//这里就主要是做你们自己的业务需求了,修改一些表什么的..
}
return "success";
} else {
return "fail";
}
} else{ //验签不通过
log.info("++验签不通过 !++");
return "fail";
}
} catch (AlipayApiException e) {
log.info("+++验签失败 !+++");
e.printStackTrace();
}
return "fail";
}
到这里一整个支付就完了......多注意细节就ok...
如果大家有什么疑问,可以在评论区评论.我看到后会及时回复...有不对的地方请指出..我会及时修改.谢谢~