工具类
package com.lmc.erp.core.utils;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.codec.Base64;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.lmc.business.api.web.exception.LmcBizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.Map;
/**
* @author yiren
* @title: AliPayService
* @description: TODO
* @date 2023/3/17 11:45
*/
@Component("aliPayUtil")
@Slf4j
public class AliPayUtil {
/** 支付宝网关 **/
@Value(value = "${ali.pay.gatewayHost:}")
private String gatewayHost;
@Value(value = "${ali.pay.appId:}")
private String appId;
/** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
@Value(value = "${ali.pay.privateKey:}")
private String privateKey;
/** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
@Value(value = "${ali.pay.aliPayPublicKey:}")
private String aliPayPublicKey;
//异步回调地址
@Value(value = "${ali.pay.notifyUrl:}")
private String notifyUrl;
//同步回调地址
@Value(value = "${ali.pay.returnUrl:}")
private String returnUrl;
@Value(value = "${ali.pay.signType:RSA2}")
private String signType;
public AlipayClient getAlipayClient() {
return new DefaultAlipayClient(gatewayHost,appId,privateKey,"json","UTF-8",aliPayPublicKey,signType);
}
/**
* 支付宝网页支付调用
* @param outTradeNo
* @param totalMount
* @param subject
* @return
*/
public AlipayTradePagePayResponse alipayTradePagePay(String outTradeNo,
BigDecimal totalMount,
String subject,
Object o
) {
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 异步接收地址,仅支持http/https,公网可访问
request.setNotifyUrl(notifyUrl);
// 同步跳转地址,仅支持http/https
request.setReturnUrl(returnUrl);
/****** 必传参数 ******/
JSONObject bizContent = new JSONObject();
// 商户订单号,商家自定义,保持唯一性
bizContent.put("out_trade_no", outTradeNo);
// 支付金额,最小值0.01元
bizContent.put("total_amount", totalMount);
// 订单标题,不可使用特殊符号
bizContent.put("subject", subject);
// 电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
/****** 可选参数 ******/
// bizContent.put("time_expire", "2022-08-01 22:00:00");
商品明细信息,按需传入
// JSONArray goodsDetail = new JSONArray();
// JSONObject goods1 = new JSONObject();
// goods1.put("goods_id", "goodsNo1");
// goods1.put("goods_name", "子商品1");
// goods1.put("quantity", 1);
// goods1.put("price", 0.01);
// goodsDetail.add(goods1);
// bizContent.put("goods_detail", goodsDetail);
扩展信息,按需传入
// JSONObject extendParams = new JSONObject();
// extendParams.put("sys_service_provider_id", "2088511833207846");
// bizContent.put("extend_params", extendParams);
request.setBizContent(bizContent.toString());
AlipayClient alipayClient = this.getAlipayClient();
AlipayTradePagePayResponse response = null;
try {
response = alipayClient.pageExecute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
log.error("支付宝网页支付调用错误,{}, {}",e.getErrCode(),e.getErrMsg());
throw new LmcBizException("支付宝网页支付调用失败");
}
return response;
}
//验签
public boolean checkKey(Map<String,String> params) throws AlipayApiException {
return AlipaySignature.rsaCheckV1(params, aliPayPublicKey, "UTF-8", signType);
}
}
注意:
- 支付金额,最小值0.01元 只能是两位小数
支付回调:
/**
* 支付宝回调
*
* @return
*/
@ApiOperation("支付宝回调")
@WapNotLogin
@RequestMapping("/notify")
public String payNotify(HttpServletRequest request) {
String message = "failure";
String orderId = "";
Map<String,String> params =new HashMap<>();
String data = readData(request);
try {
String[] split = data.split("&");
Arrays.stream(split).forEach(r->{
String[] spl = r.split("=");
if (spl[0] != null) {
try {
params.put(spl[0], URLDecoder.decode(spl[1], "UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error("aliPay_decode错误, {}", e.getMessage());
}
}
});
log.info("readData,{}",data);
log.info("params,{}",params);
try {
if (!payUtil.checkKey(params)) {
return message;
}
} catch (AlipayApiException e) {
log.error("aliPay_验签错误, {}", e.getMessage());
return message;
}
// 商家订单号
orderId = CommonUtils.convertString(params.get("out_trade_no"));
// 支付宝交易号
String tradeNo = CommonUtils.convertString(params.get("trade_no"));
String totalAmount = CommonUtils.convertString(params.get("total_amount"));
String trade_status = CommonUtils.convertString(params.get("trade_status"));
if ("TRADE_FINISHED".equals(trade_status) || "TRADE_SUCCESS".equals(trade_status)) {
try {
if (// 业务处理 比对订单 和金额是否正确) {
log.info(orderId+"aliPay_success");
return "success";
}
} catch (Exception e) {
log.error("aliPay_回调业务处理错误, {}", e.getMessage());
return message;
}
}
} catch (Exception e) {
log.error("aliPay_回调错误, {}", e.getMessage());
return message;
}
log.info(orderId+"aliPay_回调结束"+message);
return message;
}
/**
* 处理返回对象
*
* @param request 请求信息
* @return 数据
*/
protected static String readData(HttpServletRequest request) {
try (BufferedReader br = request.getReader()){
StringBuilder result = new StringBuilder();
for (String line; (line = br.readLine()) != null; ) {
if (result.length() > 0) {
result.append("\n");
}
result.append(line);
}
return result.toString();
} catch (IOException e) {
e.printStackTrace();
throw new LmcBizException("解析返回对象失败");
}
}
注意点:
- 支付宝回调参数目前是post 提交 参数放到body体里 且参数为文本提交比如:gmt_create=2023-03-27+14%3A32%3A13&charset=UTF-8&gmt_payment=2023-03-27+14%3A32%3A17(很坑B)要使用request.getReader()进行接收
- 要对参数进行解码 URLDecoder.decode (支付宝工具类里面没有提供 也是很坑)
- 验签是使用支付宝公钥进行验签