常量配置AlipayConfig
// 请求网关地址
public static final String URL = "https://openapi.alipay.com/gateway.do";
// 编码格式
public static final String CHARSET = "UTF-8";
// 返回格式
public static final String FORMAT = "json";
// 加密类型RSA2
public static final String SIGNTYPE = "RSA2";
//h5 appid
public static final String h5APPID="*****";
//h5 支付公钥
public static final String h5_ALIPAY_PUBLIC_KEY="";
//h5 应用私钥
public static final String h5_PRIVATE_KEY="";
回调地址和通知页面地址在application.yml 配置
#h5端 阿里云支付回调(官方)这里配置回调用于处理支付成功后的逻辑
h5_alis_gf_notify_url: http://7dtuqg.natappfree.cc/uncheck/h5AliNotifyUrl
#h5端 阿里云支付成功跳转(官方)这里配置支付完后跳转的页面
h5_alis_gf_query_url: https://7dtuqg.natappfree.cc/paySuccess
支付宝支付业务层接口
public interface AliPayAppService {
//查询订单状态
Map<String,Object> getStatus(OrderVo orderVo);
//统一下单拉起支付
Map<String,Object>geth5AliPayOrderStr(OrderVo orderVo);
//支付完回调
String h5AliNotifyUrl(Map<String, String> conversionParams);
}
支付实现 AliPayAppServiceImpl
//支付回调地址
@Value(value="${h5_alis_gf_notify_url}")
private String h5_alis_gf_notify_url;
//支付成功地址
@Value(value="${h5_alis_gf_query_url}")
private String h5_alis_gf_query_url;
/**
*
* @param orderVo 订单实体类
* @return
*/
@Override
public Map<String, Object> geth5AliPayOrderStr(OrderVo orderVo) {
/*********************** 先校验订单有效性*********************************/
Map<String, Object> map = new HashMap<>();
// 最终返回加签之后的,app需要传给支付宝app的订单信息字符串
String orderString = "0";
logger.info("h5支付宝下单,商户订单号为:" + orderVo.geteName());
//这个类对应的表存储支付完回调信息的
Alipaymentorder alipaymentOrder = new Alipaymentorder();
if (orderVo.geteId() != null) {
alipaymentOrder.setOrderId(orderVo.geteId().longValue()); // 商户订单主键
}
alipaymentOrder.setOutTradeNo(orderVo.geteName());// 商户订单号
alipaymentOrder.setTradeStatus(0);// 交易状态
//这个金额正式的需要根据订单号去查
alipaymentOrder.setTotalAmount(new BigDecimal(0.01));// 订单金额
alipaymentOrder.setRefundFee(0.00); // 总退款金额
try {
// 实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.h5APPID,
AlipayConfig.h5_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
AlipayConfig.h5_ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
// SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setSubject("此订单"); // 商品名称
model.setOutTradeNo(orderVo.geteName()); // 商户订单号
// model.setTimeoutExpress("30m"); //交易超时时间
model.setTotalAmount("0.01");
/****************************/
model.setProductCode("QUICK_WAP_WAY"); // 销售产品码(固定值)
request.setBizModel(model);
request.setNotifyUrl(h5_alis_gf_notify_url); // 异步回调地址(后台)
request.setReturnUrl(h5_alis_gf_query_url);//设置支付成功跳转页面的地址
//ali_request.setReturnUrl(AlipayAppConfig.return_url); // 同步回调地址(APP)
//Requestcontent 是一个请求报文表与支付业务无关
Requestcontent requestcontent=new Requestcontent();
requestcontent.setContent(request.toString());//报文内容
requestcontent.setContentType(Constants.CALLBACK_ALI_APP);//支付方式
requestcontent.setContenTime(new Date());//时间
requestcontent.setEntrydetailId(orderVo.geteName());//订单号
requestcontentMapper.insertSelective(requestcontent);//添加报文
// 这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeWapPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(request); // 返回支付宝订单信息(预处理)
if(alipayTradeAppPayResponse.isSuccess()){
// 如果商家订单表没有该订单数据则添加
if (alipaymentorderService.getAlipaymentorder(orderVo.geteName()).size() == 0) {
alipaymentorderService.addAlipaymentorder(alipaymentOrder); //创建新的商户支付宝订单
}
DateAndStrUtil strUtil = DateAndStrUtil.getDateAndStr();
//DateAndStrUtil 是一个时间工具类 requestTimestamp格式为yyyy-MM-dd HH:mm:ss
String requestTimestamp = strUtil.dateToStr(new Date());
orderString = alipayTradeAppPayResponse.getBody();
map.put("orderString", "https://openapi.alipay.com/gateway.do?"+orderString+"×tamp="+requestTimestamp);
//前端直接访问orderString", "https://openapi.alipay.com/gateway.do?"+orderString+"×tamp="+requestTimestamp 即可拉起支付
return Utils.packageResponseData(MapConstants.mapSuccessCode, "拉起成功", map);
}else{
return Utils.packageResponseData(MapConstants.mapErrorCode, "拉起失败", map);
}
} catch (Exception e) {
e.printStackTrace();
logger.info("与支付宝交互出错,未能生成订单,请检查代码!");
return Utils.packageResponseData(MapConstants.mapErrorCode, "拉起失败", map);
}
}
/**
*功能描述: h5 支付宝查询订单状态
* @author
* @date 2020/7/2
* @param orderVo
* @return java.util.Map
*/
@Override
public Map<String, Object> getStatus(OrderVo orderVo) {
Map<String,Object> map=new HashMap<>();
if(Strings.isNullOrEmpty(orderVo.geteName())) {
return Utils.packageResponseData(MapConstants.mapNullCode, "订单号不能为空", map);
}
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.h5APPID,
AlipayConfig.h5_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
AlipayConfig.h5_ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" + "\"out_trade_no\" : \"" + orderVo.geteName() + "\"}");
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
switch (response.getTradeStatus()) // 判断交易结果
{
case "TRADE_FINISHED": // 交易结束并不可退款
map.put("status",3);
break;
case "TRADE_SUCCESS": // 交易支付成功
map.put("status",2);
break;
case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
map.put("status",1);
break;
case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
map.put("status",0);
break;
default:
break;
}
return Utils.packageResponseData(MapConstants.mapSuccessCode, "查询成功", map);
} else {
logger.info("调用支付宝查询接口失败!");
return Utils.packageResponseData(MapConstants.mapErrorCode, "调用支付宝查询接口失败!", map);
}
} catch (Exception e) {
e.printStackTrace();
return Utils.packageResponseData(MapConstants.mapErrorCode, "查询失败", map);
}
}
//h5官方支付宝异步请求逻辑处理
@Override
public String h5AliNotifyUrl(Map<String, String> conversionParams) {
logger.info("h5官方支付宝异步请求逻辑处理");
// 签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false;
try {
// 调用SDK验证签名
signVerified = AlipaySignature.rsaCheckV1(conversionParams, AlipayConfig.h5_ALIPAY_PUBLIC_KEY,
AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
} catch (AlipayApiException e) {
logger.info("验签失败 !");
e.printStackTrace();
}
// 对验签进行处理
if (signVerified) {
System.out.println("h5支付宝回调验签通过");
// 验签通过
// 获取需要保存的数据
String appId = conversionParams.get("app_id");
Alipaymentorder alipaymentOrder=getAlipayMent(conversionParams);
if (AlipayConfig.h5APPID.equals(appId)) {
EntrydetailExample entrydetailExample=new EntrydetailExample();
entrydetailExample.createCriteria().andENameEqualTo(alipaymentOrder.getOutTradeNo());
List<Entrydetail> list=entrydetailMapper.selectByExample(entrydetailExample);
alipaymentOrder.setUserId(list.get(0).geteUid());
//更新回调表中的内容
int returnResult = alipaymentorderService.updateAlipaymentorder(alipaymentOrder); // 更新交易表中状态
// 修改交易表状态,支付成功
if (returnResult > 0) {
logger.info("======h5官方支付宝更新商户订单表成功======");
return "SUCCESS";//如果不反回将会持续回调24小时
} else {
logger.info("更新表状态失败");
return "FAILED";
}
} else {
logger.info("支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id),不一致!返回fail");
return "FAILED";
}
} else { // 验签不通过
logger.info("验签不通过 !");
return "FAILED";
}
}
//回调用到的getAlipayMent方法
public Alipaymentorder getAlipayMent(Map<String, String> conversionParams){
DateAndStrUtil dateAndStrUtil = new DateAndStrUtil();
String appId = conversionParams.get("app_id");// 支付宝分配给开发者的应用Id
String notifyTime = conversionParams.get("notify_time");// 通知时间:yyyy-MM-dd HH:mm:ss
String gmtCreate = conversionParams.get("gmt_create");// 交易创建时间:yyyy-MM-dd HH:mm:ss
String gmtPayment = conversionParams.get("gmt_payment");// 交易付款时间
String tradeNo = conversionParams.get("trade_no");// 支付宝的交易号
String outTradeNo = conversionParams.get("out_trade_no");// 获取商户之前传给支付宝的订单号(商户系统的唯一订单号)
String totalAmount = conversionParams.get("total_amount");// 订单金额:本次交易支付的订单金额,单位为人民币(元)
String receiptAmount = conversionParams.get("receipt_amount");// 实收金额:商家在交易中实际收到的款项,单位为元
String buyerPayAmount = conversionParams.get("buyer_pay_amount");// 付款金额:用户在交易中支付的金额
String tradeStatus = conversionParams.get("trade_status");// 获取交易状态
// 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
List<Alipaymentorder> alipaymentOrderList = alipaymentorderService.getAlipaymentorder(outTradeNo);
Alipaymentorder alipaymentOrder = alipaymentOrderList.get(0);
alipaymentOrder.setNotifyTime(dateAndStrUtil.strToDate(notifyTime)); // 通知时间
alipaymentOrder.setGmtCreate(dateAndStrUtil.strToDate(gmtCreate)); // 交易创建时间
alipaymentOrder.setGmtPayment(dateAndStrUtil.strToDate(gmtPayment)); // 交易付款时间
//alipaymentOrder.setGmt_refund(DateUtils.parse(gmtRefund)); // 交易退款时间
//alipaymentOrder.setGmt_close(DateUtils.parse(gmtClose)); // 交易结束时间
alipaymentOrder.setTradeNo(tradeNo); // 支付宝交易号
//alipaymentOrder.setOut_biz_no(outBizNo); // 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
alipaymentOrder.setTotalAmount(new BigDecimal(totalAmount)); //订单金额:本次交易支付的订单金额,单位为人民币(元)
alipaymentOrder.setReceiptAmount(new BigDecimal(receiptAmount)); // 实收金额:商家在交易中实际收到的款项,单位为元
//alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount)); // 开票金额:用户在交易中支付的可开发票的金额
alipaymentOrder.setBuyerPayAmount(new BigDecimal(buyerPayAmount)); // 付款金额:用户在交易中支付的金额
Utils.getStatus(alipaymentOrder,tradeStatus);
return alipaymentOrder;
}
Utils 工具类
public class Utils {
public static void getStatus(Alipaymentorder alipaymentorder,String status){
switch (status) // 判断交易结果
{
case "TRADE_FINISHED": // 交易结束并不可退款
alipaymentorder.setTradeStatus(3);
break;
case "TRADE_SUCCESS": // 交易支付成功
alipaymentorder.setTradeStatus(2);
break;
case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
alipaymentorder.setTradeStatus(1);
break;
case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
alipaymentorder.setTradeStatus(0);
break;
default:
break;
}
}
/**
*
* Map转String
* @param map
* @return
*/
public static String getMapToString(Map<String,String> map){
Set<String> keySet = map.keySet();
//将set集合转换为数组
String[] keyArray = keySet.toArray(new String[keySet.size()]);
//给数组排序(升序)
Arrays.sort(keyArray);
//因为String拼接效率会很低的,所以转用StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keyArray.length; i++) {
// 参数值为空,则不参与签名 这个方法trim()是去空格
if ((String.valueOf(map.get(keyArray[i]))).trim().length() > 0) {
sb.append(keyArray[i]).append(":").append(String.valueOf(map.get(keyArray[i])).trim());
}
if(i != keyArray.length-1){
sb.append(",");
}
}
return sb.toString();
}
}
支付控制层 AliPayAppController
/**
*功能描述:H5支付宝拉起支付
* @author 666
* @date 2020/7/6
* @return java.util.Map
*/
@RequestMapping(value="/geth5AliPayOrderStr",method= RequestMethod.POST)
public Map<String,Object> geth5AliPayOrderStr(@RequestBody OrderVo orderVo){
return aliPayAppService.geth5AliPayOrderStr(orderVo);
}
/**
*功能描述:查询订单状态
* @author 666
* @date 2020/7/2
* @param orderVo
* @return java.util.Map
*/
@RequestMapping(value = "/getStatus", method = RequestMethod.POST)
public Map<String, Object> getStatus(@RequestBody OrderVo orderVo) {
return aliPayAppService.getStatus(orderVo);
}
/**
* h5支付宝官方回调
* @param request
* @param response
* @return
*/
@RequestMapping(value="/h5AliNotifyUrl",method= RequestMethod.POST)
public String h5AliNotifyUrl(HttpServletRequest request, HttpServletResponse response){
logger.info("h5官方支付宝异步返回支付结果开始");
String map = aliPayAppService.h5AliNotifyUrl(Utils.map(request,response));
return map;
}
最后附上alipaymentorder表:
CREATE TABLE `alipaymentorder` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`order_id` bigint(20) DEFAULT NULL COMMENT '商家订单主键',
`out_trade_no` varchar(255) DEFAULT NULL COMMENT '商户订单号',
`notify_time` datetime DEFAULT NULL COMMENT '通知时间',
`gmt_create` datetime DEFAULT NULL COMMENT '交易创建时间',
`gmt_payment` datetime DEFAULT NULL COMMENT '交易付款时间',
`gmt_refund` datetime DEFAULT NULL COMMENT '交易退款时间',
`gmt_close` datetime DEFAULT NULL COMMENT '交易结束时间',
`trade_no` varchar(255) DEFAULT NULL COMMENT '支付宝的交易号',
`out_biz_no` varchar(255) DEFAULT NULL COMMENT '商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)',
`seller_email` varchar(255) DEFAULT NULL COMMENT '卖家账号',
`seller_id` varchar(255) DEFAULT NULL COMMENT '卖家用户号',
`buyer_logon_id` varchar(255) DEFAULT NULL COMMENT '买家账号',
`total_amount` decimal(10,2) DEFAULT NULL COMMENT '订单金额',
`receipt_amount` decimal(10,2) DEFAULT NULL COMMENT '实收金额',
`buyer_pay_amount` decimal(10,2) DEFAULT NULL COMMENT '付款金额:用户在交易中支付的金额',
`trade_status` int(255) DEFAULT NULL COMMENT '交易状态',
`refund_fee` double(10,2) DEFAULT NULL COMMENT '总退款金额',
`buyer_id` varchar(255) DEFAULT NULL COMMENT '买家唯一用户号',
`fund_change` varchar(255) DEFAULT NULL COMMENT '本次退款是否发生了资金变化',
`store_name` varchar(255) DEFAULT NULL COMMENT '交易在支付时候的门店名称',
`trade_type` int(255) DEFAULT NULL COMMENT '1.代表微信 2.代表支付宝 3.代表苹果内购',
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=206 DEFAULT CHARSET=utf8 COMMENT='商户支付宝订单表';
第一次发微博欢迎大家一起交流一起学习