spring boot整合支付宝支付(沙盒环境)
1.1、注册支付宝开放平台账号
https://openhome.alipay.com/platform/home.htm
1.2进入管理中心
1.3进入研发服务
1.4下载支付宝支付SDK
https://opendocs.alipay.com/open/54/106682(提供参考)
1.5在项目中新建一个配置类
AlipayConfig 配置类代码示例
package com.alipay.config;
public class AlipayConfig {
//在这里填入沙箱应用中的信息
// 商户appid
public static String APPID = "";
// 私钥 pkcs8格式的
public static String RSA_PRIVATE_KEY = "";
// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";
// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
public static String return_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
// 请求网关地址
public static String URL = "https://openapi.alipay.com/gateway.do";
// 编码
public static String CHARSET = "UTF-8";
// 返回格式
public static String FORMAT = "json";
// 支付宝公钥
public static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjrEVFMOSiNJXaRNKicQuQdsREraftDA9Tua3WNZwcpeXeh8Wrt+V9JilLqSa7N7sVqwpvv8zWChgXhX/A96hEg97Oxe6GKUmzaZRNh0cZZ88vpkn5tlgL4mH/dhSr3Ip00kvM4rHq9PwuT4k7z1DpZAf1eghK8Q5BgxL88d0X07m9X96Ijd0yMkXArzD7jg+noqfbztEKoH3kPMRJC2w4ByVdweWUT2PwrlATpZZtYLmtDvUKG/sOkNAIKEMg3Rut1oKWpjyYanzDgS7Cg3awr1KPTl9rHCazk15aNYowmYtVabKwbGVToCAGK+qQ1gT3ELhkGnf3+h53fukNqRH+wIDAQAB";
// 日志记录目录定义在 logFile 中
public static String log_path = "/log";
// RSA2
public static String SIGNTYPE = "RSA2";
}
notify_url和return_url必须要外网能访问
1.6提交页面
配置类填好之后修改订单提交页面
参数列表:https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay
1.7 支付宝支付控制器
//支付
@RequestMapping("/aliPay")
@ResponseBody
public String pay(Pay pay) throws AlipayApiException {
AlipayConfig alipayConfig = new AlipayConfig();
//1.封装Rsa签名方式
AlipayClient alipayClient = new DefaultAlipayClient(
alipayConfig.URL,
alipayConfig.APPID,
alipayConfig.RSA_PRIVATE_KEY,
alipayConfig.FORMAT,
alipayConfig.CHARSET,
alipayConfig.ALIPAY_PUBLIC_KEY,
alipayConfig.SIGNTYPE);
//2.创建Request请求
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
//3.封装传入参数
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo(pay.getOut_trade_no());//商品Id
model.setSubject(pay.getSubject());//商品名称
model.setBody(pay.getBody());//商品描述
model.setProductCode(pay.getProduct_code());//商品码
model.setTimeoutExpress(pay.getTimeout_express());//支付超时时间
model.setTotalAmount(pay.getTotal_amount());//商品金额
request.setBizModel(model);
//设置异步回调地址
request.setNotifyUrl(AlipayConfig.notify_url);
//设置同步回调地址
request.setReturnUrl(AlipayConfig.return_url);
String form = alipayClient.pageExecute(request).getBody();
System.out.println(form);
//返回请求体
return form;
到这里就已经可以完成支付宝支付了,在支付完成后,支付宝会发给我们支付完成的通知,包括同步通知(return_url)和异步通知(notify_url),所以我们需要写控制器来接收通知。
1.7通知回调(异步和同步)
日志和线程:
private static Logger logger = LoggerFactory.getLogger(AlipayCallBackController.class);
private ExecutorService executorService = Executors.newFixedThreadPool(20);
1.7.1处理请求体信息
private static Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
Map<String, String> retMap = new HashMap<>();
Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
for (Map.Entry<String, String[]> entry : entrySet) {
String name = entry.getKey();
String[] values = entry.getValue();
int valLen = values.length;
if (valLen == 1) {
retMap.put(name, values[0]);
} else if (valLen > 1) {
StringBuilder stringBuilder = new StringBuilder();
for (String value : values) {
stringBuilder.append(",").append(value);
}
retMap.put(name, stringBuilder.toString().substring(1));
} else {
retMap.put(name, "");
}
}
return retMap;
}
1.7.2JSON字符串的处理
private AlipayNotifyParam buildAliPayNotifyParam(Map<String, String> params) {
//将json数据转为字符串
String json = JSON.toJSONString(params);
//将字符串转为object对象
return JSON.parseObject(json, AlipayNotifyParam.class);
}
1.7.3检验订单信息是否一致
private void check(Map<String, String> params) throws AlipayApiException {
String outTradeNo = params.get("out_trade_no");
//1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
Order order = orderService.findIdByOrderNum(outTradeNo);
if (order == null) {
throw new AlipayApiException("out_trade_no错误");
}
//2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额)
long total_amount = new BigDecimal(params.get("total_amount")).multiply(new BigDecimal(1)).longValue();
if (total_amount != order.getOrder_total().longValue()) {
throw new AlipayApiException("total_amount错误");
}
//3、校验通知中的seller_id(或者seller_email)是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
// 第三步可根据实际情况省略
// 4、验证app_id是否为该商户本身。
if (!params.get("app_id").equals(AlipayConfig.APPID)) {
throw new AlipayApiException("app_id不一致");
}
}
1.7.4调用异步回调
@RequestMapping("/alipay_callback")
@ResponseBody
public String callback(HttpServletRequest request) {
System.out.println("--------异步调用成功--------");
Map<String, String> params = convertRequestParamsToMap(request);
String paramsJson = JSON.toJSONString(params);
logger.info("支付宝回调,{}", paramsJson);
try {
AlipayConfig alipayConfig = new AlipayConfig();
//支付宝验签
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
if (signVerified) {
logger.info("支付宝回调签名认证成功");
//按照支付结果异步通知中描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
this.check(params);
executorService.execute(new Runnable() {
@Override
public void run() {
AlipayNotifyParam param = buildAliPayNotifyParam(params);
String trade_status = param.getTradeStatus();
//支付成功
if (trade_status.equals("TRADE_SUCCESS")) {
try {
//修改订单状态
String out_trade_no = params.get("out_trade_no");
orderService.updateOrderStatus(out_trade_no, "1");
System.out.println("------订单付款成功------");
} catch (Exception e) {
logger.error("支付宝回调业务处理报错,params:" + paramsJson, e);
}
} else {
logger.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}", trade_status, paramsJson);
}
//订单完成
if (trade_status.equals("TRADE_FINISHED")) {
try {
//修改订单状态
String out_trade_no = params.get("out_trade_no");
orderService.updateOrderStatus(out_trade_no, "1");
System.out.println("------订单已经付款,请勿重复付款------");
} catch (Exception e) {
logger.error("支付宝回调业务处理报错,params:" + paramsJson, e);
}
} else {
logger.error("没有处理支付宝回调业务,支付宝交易状态:{},params:{}", trade_status, paramsJson);
}
}
});
// 如果签名验证正确,立即返回success,后续业务另起线程单独处理
// 业务处理失败,可查看日志进行补偿,跟支付宝已经没多大关系。
return "success";
} else {
logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);
return "failure";
}
} catch (AlipayApiException e) {
logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
return "failure";
}
}
1.7.5调用同步回调
@RequestMapping("/return_callback")
public String returnCallback(HttpServletRequest request, Model model) {
System.out.println("--------同步调用成功--------");
OrderInfoDTO orderInfoDTO = new OrderInfoDTO();
Map<String, String> params = convertRequestParamsToMap(request);
String paramsJson = JSON.toJSONString(params);
try {
AlipayConfig alipayConfig = new AlipayConfig();
//支付宝验签
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
if (signVerified) {
//按照支付结果异步通知中描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
this.check(params);
//获取支付金额
Double totalAmount = Double.valueOf(params.get("total_amount"));
//获取支付单号
String outTradeNo = params.get("out_trade_no");
//校验
if (outTradeNo != null && totalAmount != null) {
orderInfoDTO.setOrder_total(totalAmount);
orderInfoDTO.setOrder_num(outTradeNo);
model.addAttribute("order", orderInfoDTO);
return "returnCallback";
}
model.addAttribute("error", "订单处理失败,请联系管理员处理!!!");
return "returnCallback";
} else {
logger.info("支付宝回调签名认证失败,signVerified=false, paramsJson:{}", paramsJson);
model.addAttribute("error", "订单验签失败,请联系管理员处理!!!");
return "returnCallback";
}
} catch (AlipayApiException e) {
logger.error("支付宝回调签名认证失败,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
model.addAttribute("error", "订单异常,请联系管理员处理!!!");
return "returnCallback";
}
}
调用完成后在沙盒平台里配置同步和异步地址
到这里支付宝支付就成功了,这里仅限于沙盒环境!!!
注意!!!
同步回调和异步回调的地址需要在拦截器配置中放开,不然会被拦截!!
注意!!!
同步回调和异步回调的地址需要在拦截器配置中放开,不然会被拦截!!
回调参考自:https://blog.csdn.net/thc1987/article/details/80269181
仅供自己参考,勿喷。有错欢迎指点。