一、适用场景:pc端拉起付款二维码 用户扫码付款(非证书模式下单)
二、接入准备
1:支付宝-appId
2:支付宝公钥-appPublicKey
(是支付宝公钥,不是应用公钥,拿错会无法拉起支付)
3:支付宝应用私钥-appPrivateKey
三、官方DEMO下载地址
支付宝sdk官方下载地址
https://opendocs.alipay.com/open/270/106291?ref=api
四、代码
1:maven依赖
<!-- 支付宝支付SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.100.ALL</version>
</dependency>
2:配置文件
介绍下其他参数
returnUrl:阿里同步通知接口地址—后边会有代码展示
notifyUrl:支付后阿里通知支付状态的接口地址—后边会有代码展示
requestUrl:主要用于支付成功后页面跳转的网站地址(支付宝支付前端会用阿里自己的页面,所以支付成功以后要跳转到自己的页面)
配置类
@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AliPayProperties {
private String appId;
private String gatewayUrl;
private String format;
private String charset;
private String signType;
private String returnUrl;
private String notifyUrl;
private String appPrivateKey;
private String appPublicKey;
private String requestUrl;
//支付宝支付页面超时时间
private String overTime;
}
3:下单接口
//支付宝拉起统一下单
public Map<String, String> prePay(UserOrders order, String clientIP) {
log.info("支付宝统一下单接收到请求,下单用户ip :{}", clientIP);
Map<String, String> map = new HashMap<>();
AlipayClient alipayClient=new DefaultAlipayClient(properties.getGatewayUrl(),
properties.getAppId(),properties.getAppPrivateKey(),properties.getFormat(),
properties.getCharset(),properties.getAppPublicKey(),properties.getSignType()
);
try {
//商户订单号,商户网站订单系统中唯一订单号,必填
String out_trade_no = new String(order.getOrderNum().getBytes("UTF-8"),"UTF-8");
//付款金额,必填
Double payPrice = order.getPayPrice();
String total_amount = new String(payPrice.toString().getBytes("UTF-8"),"UTF-8");
//订单名称,必填
String subject = new String(order.getPackageName().getBytes("UTF-8"),"UTF-8");
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
String encode = URLEncoder.encode(order.getOperatorInfo(), "UTF-8");
request.setNotifyUrl(properties.getNotifyUrl());
request.setReturnUrl(properties.getReturnUrl());
request.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+ "\"total_amount\":\""+ total_amount +"\","
+ "\"subject\":\""+ subject +"\","
+ "\"passback_params\":\""+ encode +"\","
+ "\"timeout_express\":\""+ properties.getOverTime()+"\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
AlipayTradePagePayResponse response = null;
response = alipayClient.pageExecute(request);
map.put("success", "true");
map.put("body", response.getBody());
map.put("msg", response.getMsg());
} catch (AlipayApiException e) {
e.printStackTrace();
}catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return map;
}
对当前返回的map进行校验返回前端
4:异步回调
controller
@RequestMapping("/ali/notify")
public String notify(HttpServletRequest request){
log.info("支付宝异步回调接收到请求!!!");
Map<String,String> flag = aliPayService.aliPayNotify(request);
if("success".equals(flag.get("status"))){
//这块做自己的业务逻辑
AsyncManager.me().execute(AsyncFactory.updateCourseSignNum(flag.get("courseId")));
}
return flag.get("status");
}
service
public Map<String, String> aliPayNotify(HttpServletRequest request) {
Map<String, String> map = new HashMap<>();
try {
Map<String, String> params = new HashMap<String, String>();
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] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("UTF-8"), "UTF-8");
params.put(name, valueStr);
}
log.info("alipay支付回调:" + JSON.toJSONString(params));
boolean flag = AlipaySignature.rsaCertCheckV1(params, properties.getPublicKeyFilePath(), properties.getCharset(), properties.getSignType());
if (flag) {
log.info("支付宝回调签名通过");
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("UTF-8"), "UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("UTF-8"), "UTF-8");
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("UTF-8"), "UTF-8");
//订单的金额
String total_amount = new String(request.getParameter("total_amount").getBytes("UTF-8"), "UTF-8");
//商户id
String sellerId = new String(request.getParameter("seller_id").getBytes("UTF-8"), "UTF-8");
log.info("此次订单金额为==>> {}", total_amount);
if ("TRADE_FINISHED".equals(trade_status)) {
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
log.info("交易finish非success");
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
} else if ("TRADE_SUCCESS".equals(trade_status)) {
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//如果有做过处理,不执行商户的业务程序
//注意:
//付款完成后,支付宝系统发送该交易状态通知
log.info("交易成功,更新订单状态");
OrderInfo orderInfo = orderInfoMapper.selectOrderInfoByOrderNum(out_trade_no);
BigDecimal aliPrice = new BigDecimal(total_amount);
if (aliPrice.compareTo(orderInfo.getPayPrice()) != 0) {
log.info("支付宝返回成交额与当前订单金额不符,返回fail");
map.put("status", "fail");
return map;
}
if ("1".equals(orderInfo.getPayStatus())) {
//首次回调成功更新订单状态,给学员开课
orderInfoService.updateOrderPayStatus(out_trade_no);
}
map.put("status", "success");
map.put("courseId", String.valueOf(orderInfo.getCourseId()));
return map;
}
} else {
log.info("异步签名校验有误,返回fail");
map.put("status", "fail");
return map;
}
} catch (Exception e) {
e.printStackTrace();
map.put("status", "fail");
return map;
}
map.put("status", "fail");
return map;
}
5:同步回调
controller
@RequestMapping("/ali/return")
public void aliReturn(HttpServletRequest request, HttpServletResponse response){
aliPayService.aliReturn(request,response);
}
service
public void aliReturn(HttpServletRequest request, HttpServletResponse response) {
try {
log.info("支付宝同步回调接收到请求");
Map<String, String> params = new HashMap<String, String>();
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] + ",";
}
//乱码解决,这段代码在出现乱码时使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//调用SDK验证签名
boolean flag = AlipaySignature.rsaCertCheckV1(params, properties.getPublicKeyFilePath(), properties.getCharset(), properties.getSignType());
if (flag) {
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
//付款金额
String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");
log.info("支付宝同步回调参数 out_trade_no: {} ,trade_no: {}, total_amount : {}", out_trade_no, trade_no, total_amount);
response.sendRedirect(properties.getRequestUrl());
} else {
System.out.println("验签失败");
response.sendRedirect(properties.getRequestUrl());
}
} catch (Exception e) {
e.printStackTrace();
try {
response.sendRedirect(properties.getRequestUrl());
} catch (IOException ex) {
ex.printStackTrace();
}
}
}