1、支付宝开发平台:https://openhome.alipay.com/

2、进去沙箱,配置支付密钥

记录下appid,然后设置秘钥;

 3、后端代码,配置类

pom文件sdk添加依赖

<!--pom.xml  支付宝sdk -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
@Configuration
public class AppPayConfig {
/**
* 1.商户appid
*/
public static String APPID = ""; /**
* 私钥 pkcs8格式的
* 这个就是我上面说的应用私钥生成 注意这里是私钥
*/
public static String RSA_PRIVATE_KEY =""
* 3.支付宝公钥
*/
public static String ALIPAY_PUBLIC_KEY = ""; /**
* 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
*/
//这个着重讲一下..支付完成后,支付宝会通过这个url请求到你的服务端..
//这个url一定是要公网可以访问才行...如果需要测试的话..我后面有讲到..
//这里你可以先写你本地项目的url 例如:localhost:8080/项目名/访问路径
public static String notify_url = "http://4e69yn.natappfree.cc/api/v1/aliPayApp/notify_url"; /**
* 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
*/
//这里同上..不做详细说明了..
public static String return_url = "http://4e69yn.natappfree.cc/api/v1/aliPayApp/notify_url"; /**
* 正式环境支付宝网关,如果是沙箱环境需更改成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";
}

4、控制层

@RestController
@RequestMapping("api/v1/aliPayApp")
@Slf4j
public class AliPayAppController {
@Autowired
private AliPayAppService aliPayAppService; /**
* 获取支付宝加签后台的订单信息字符串,唤起支付宝APP
* @Title: getAliPayOrderStr
* @description
*/
@RequestMapping("/getAliPayOrderStr")
@ResponseBody
public JsonData getAliPayOrderStr(@RequestParam("userId") Integer userId, @RequestParam("videoId") Integer videoId) {
String aliPayOrderStr = aliPayAppService.getAliPayOrderStr(userId, videoId);
return JsonData.buildSuccess(aliPayOrderStr);
} /**
* 支付宝支付成功后.异步请求该接口
* @Title: notify
*/
@RequestMapping(value="/notify_url",method= RequestMethod.POST)
@ResponseBody
public JsonData notify(HttpServletRequest request, HttpServletResponse response) throws IOException {
log.info("支付宝异步返回支付结果开始");
// 1.从支付宝回调的request域中取值
// 获取支付宝返回的参数集合
Map<String, String[]> aliParams = request.getParameterMap();
// 用以存放转化后的参数集合
Map<String, String> conversionParams = new HashMap<String, String>();
for (Iterator<String> 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"), "uft-8");
conversionParams.put(key, valueStr);
}
log.info("返回参数集合:" + conversionParams);
String status = aliPayAppService.notify(conversionParams);
if (status.equals("fail")){
return JsonData.buildError("订单修改失败");
}else {
return JsonData.buildSuccess("订单修改失败");
} } /**
* 向支付宝发起订单查询请求
* @Title: checkAlipay
* @description
* @param orderNo 商户订单号
*/
@RequestMapping("/checkAlipay")
@ResponseBody
public JsonData checkAlipay(String orderNo) {
int result = aliPayAppService.checkAlipay(orderNo);
return JsonData.buildSuccess(result);
} /**
* 向支付宝发起退款请求
* @Title: alipayTradeRefund
* @description
* @param orderNo 商户订单号
* @param refundFee 退款金额
*/
@RequestMapping("/alipayTradeRefund")
@ResponseBody
public JsonData alipayTradeRefund(String orderNo, Double refundFee) {
String tradeRefund = aliPayAppService.alipayTradeRefund(orderNo, refundFee);
return JsonData.buildSuccess(tradeRefund);
}
}

5、service层

/**
* 支付宝APP支付业务层接口
*/
public interface AliPayAppService { /**
* 获取支付宝加签后台的订单信息字符串
*/
public String getAliPayOrderStr(Integer userId, Integer videoId); /**
* 支付宝异步请求逻辑处理
*/
public String notify(Map<String, String> conversionParams); /**
* 向支付宝发起订单查询请求
*/
public int checkAlipay(String order_no); /**
* 向支付宝发起退款请求
*/
public String alipayTradeRefund(String order_no, Double refund_fee);
}

6、serviceImpl层

/**
* 阿里支付实现类
*/
@Service
@Slf4j
public class AliPayAppServiceImpl implements AliPayAppService { @Autowired
private AliPayAppService aliPayAppService; @Autowired
private VideoOrderMapper videoOrderMapper; @Autowired
private VideoMapper videoMapper; /**
* 获取支付宝加签后台的订单信息字符串
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public String getAliPayOrderStr(Integer userId, Integer videoId) {
String orderString = "";
try {
Video video = videoMapper.selectById(videoId);
//AppUser appUser = appUserMapper.selectById(userId); //生成订单
VideoOrder videoOrder = new VideoOrder();
videoOrder.setVideoId(video.getId());
videoOrder.setOutTradeNo(CommonUtils.generateUUID());
videoOrder.setState(0);
videoOrder.setCreateTime(new Date());
videoOrder.setTotalFee(video.getPrice());
videoOrder.setVideoId(video.getId());
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setVideoImg(video.getCoverImg());
videoOrder.setUserId(userId);
//生成未支付订单
videoOrderMapper.insert(videoOrder);
//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID,
AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8",
AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2");
//实例化具体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("云讯网购买视频课程");
//商品名称
model.setSubject(videoOrder.getVideoTitle());
//商户订单号
model.setOutTradeNo(videoOrder.getOutTradeNo());
//交易超时时间 这里的30m就是30分钟
model.setTimeoutExpress("30m");
//支付金额 后面保留2位小数点..不能超过2位
// model.setTotalAmount(String.valueOf(BigDecimal.valueOf(videoOrder.getTotalFee()).divide(BigDecimal.valueOf(100),2,BigDecimal.ROUND_DOWN)));
model.setTotalAmount("0.01"); //销售产品码(固定值) //这个不做多解释..看文档api接口参数解释
model.setProductCode("FACE_TO_FACE_PAYMENT"); //model.setPassbackParams(JSON.toJSONString(alipayBean)); ali_request.setBizModel(model);
//异步回调地址
ali_request.setNotifyUrl(AppPayConfig.notify_url);
//log.info("====================异步通知的地址为:" + ali_request.getNotifyUrl());
//同步回调地址(APP)同上
ali_request.setReturnUrl(AppPayConfig.return_url);
//log.info("====================同步通知的地址为:" + ali_request.getReturnUrl()); // 这里和普通的接口调用不同,使用的是sdkExecute
//返回支付宝订单信息(预处理)
AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request);
//就是orderString 可以直接给APP请求,无需再做处理。
orderString = alipayTradeAppPayResponse.getBody();
System.out.println(orderString); } catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
log.info("与支付宝交互出错,未能生成订单,请检查代码!");
}
return orderString;
} /**
* 向支付宝发起订单查询请求
*/
@Override
public int checkAlipay(String orderNo) {
log.info("向支付宝发起查询,查询商户订单号为:" + orderNo); try {
// 实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型)
AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID,
AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8",
AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2"); AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
alipayTradeQueryRequest.setBizContent("{" + "\"out_trade_no\" : \"" + orderNo + "\"}"); AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);
if (alipayTradeQueryResponse.isSuccess()) { VideoOrder videoOrder = videoOrderMapper.selectById(orderNo); switch (alipayTradeQueryResponse.getTradeStatus()) // 判断交易结果
{
case "TRADE_FINISHED": // 交易结束并不可退款
videoOrder.setState(3);
break;
case "TRADE_SUCCESS": // 交易支付成功
videoOrder.setState(1);
break;
case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
videoOrder.setState(2);
break;
case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
videoOrder.setState(0);
break;
default:
break;
} videoOrderMapper.updateById(videoOrder);// 更新表记录
return videoOrder.getState();
} else {
log.info("调用支付宝查询接口失败!");
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
return 0;
} /**
* 支付宝异步请求逻辑处理
*/
@Override
public String notify(Map<String, String> conversionParams) {
log.info("支付宝异步请求逻辑处理"); // 签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
boolean signVerified = false; try {
// 调用SDK验证签名
signVerified = AlipaySignature.rsaCheckV1(conversionParams, AppPayConfig.ALIPAY_PUBLIC_KEY,
"utf-8", "RSA2"); } catch (AlipayApiException e) {
log.info("验签失败 !");
e.printStackTrace();
} // 对验签进行处理
if (signVerified) {
System.out.println("验签通过");
// 验签通过
// 获取需要保存的数据
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 gmtRefund = conversionParams.get("gmt_refund");// 交易退款时间
//String gmtClose = conversionParams.get("gmt_close");// 交易结束时间
String tradeNo = conversionParams.get("trade_no");// 支付宝的交易号
String outTradeNo = conversionParams.get("out_trade_no");// 获取商户之前传给支付宝的订单号(商户系统的唯一订单号)
//String outBizNo = conversionParams.get("out_biz_no");// 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
String buyerLogonId = conversionParams.get("buyer_logon_id");// 买家支付宝账号
String buyerId = conversionParams.get("buyer_id"); //买家支付宝用户号(唯一)
String sellerId = conversionParams.get("seller_id");// 卖家支付宝用户号
String sellerEmail = conversionParams.get("seller_email");// 卖家支付宝账号
String totalAmount = conversionParams.get("total_amount");// 订单金额:本次交易支付的订单金额,单位为人民币(元)
String receiptAmount = conversionParams.get("receipt_amount");// 实收金额:商家在交易中实际收到的款项,单位为元
//String invoiceAmount = conversionParams.get("invoice_amount");// 开票金额:用户在交易中支付的可开发票的金额
String buyerPayAmount = conversionParams.get("buyer_pay_amount");// 付款金额:用户在交易中支付的金额
String tradeStatus = conversionParams.get("trade_status");// 获取交易状态 // 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
VideoOrder videoOrder = videoOrderMapper.selectOne(new QueryWrapper<VideoOrder>().eq("out_trade_no", outTradeNo)); if (videoOrder != null && totalAmount.equals(videoOrder.getTotalFee().toString())) {
// 修改数据库支付宝订单表(因为要保存每次支付宝返回的信息到数据库里,以便以后查证) // alipaymentOrder.setNotify_time(DateUtils.parse(notifyTime)); // 通知时间
// alipaymentOrder.setGmt_create(DateUtils.parse(gmtCreate)); // 交易创建时间
// alipaymentOrder.setGmt_payment(DateUtils.parse(gmtPayment)); // 交易付款时间
// //alipaymentOrder.setGmt_refund(DateUtils.parse(gmtRefund)); // 交易退款时间
// //alipaymentOrder.setGmt_close(DateUtils.parse(gmtClose)); // 交易结束时间
// alipaymentOrder.setTrade_no(tradeNo); // 支付宝交易号
// //alipaymentOrder.setOut_biz_no(outBizNo); // 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)
// alipaymentOrder.setBuyer_logon_id(buyerLogonId); // 买家支付宝账号
// alipaymentOrder.setBuyer_id(buyerId); // 买家支付宝用户号(唯一)
// alipaymentOrder.setSeller_id(sellerId); // 卖家支付宝用户号
// alipaymentOrder.setSeller_email(sellerEmail); // 卖家支付宝账号
// alipaymentOrder.setTotal_amount(Double.parseDouble(totalAmount)); //订单金额:本次交易支付的订单金额,单位为人民币(元)
// alipaymentOrder.setReceipt_amount(Double.parseDouble(receiptAmount)); // 实收金额:商家在交易中实际收到的款项,单位为元
// //alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount)); // 开票金额:用户在交易中支付的可开发票的金额
// alipaymentOrder.setBuyer_pay_amount(Double.parseDouble(buyerPayAmount)); // 付款金额:用户在交易中支付的金额 switch (tradeStatus) // 判断交易结果
{
case "TRADE_FINISHED": // 交易结束并不可退款
videoOrder.setState(3);
break;
case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款
videoOrder.setState(2);
break;
case "TRADE_SUCCESS": // 交易支付成功
videoOrder.setState(1);
break; case "WAIT_BUYER_PAY": // 交易创建并等待买家付款
videoOrder.setState(0);
break;
default:
break;
}
int returnResult = videoOrderMapper.updateById(videoOrder); // 更新交易表中状态 if (tradeStatus.equals("TRADE_SUCCESS")) { // 只处理支付成功的订单:
// 修改交易表状态,支付成功
if (returnResult > 0) {
log.info("======更新商户订单表成功======");
return "success";
} else {
return "fail";
}
} else {
return "fail";
} } else {
log.info("支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id),不一致!返回fail");
return "fail";
} } else { // 验签不通过
log.info("验签不通过 !");
return "fail";
}
} /**
* 向支付宝发起退款请求
*/
@Transactional(propagation = Propagation.REQUIRED)
@Override
public String alipayTradeRefund(String order_no, Double refund_fee) {
String returnStr = null;
int code;
try { AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID,
AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8",
AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2"); AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();//创建API对应的request类
request.setBizContent("{" +
" \"out_trade_no\":\"" + order_no + "\"," +
" \"refund_amount\":\"" + refund_fee + "\"" +
" }");//设置业务参数
AlipayTradeRefundResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类 log.info("退款返回参数====" + response); if (response.isSuccess()) {
log.info("====支付宝退款成功");
// 通过订单号查询到商家支付宝订单信息
VideoOrder videoOrder = videoOrderMapper.selectOne(new QueryWrapper<VideoOrder>().eq("out_trade_no", order_no)); if (videoOrder == null) {
log.info("该订单不存在");
}
// // 退款总金额
// videoOrder.setRefund_fee(Double.valueOf(response.getRefundFee()));
// // 退款时间
// alipaymentOrder.setGmt_refund(response.getGmtRefundPay());
// // 退款状态
// alipaymentOrder.setTrade_status(AlipayReturnEnum.TRADE_CLOSED.getIndex());
// // 本次退款是否发生了资金变化
// alipaymentOrder.setFund_change(response.getFundChange());
// // 交易在支付时候的门店名称
// alipaymentOrder.setStore_name(response.getStoreName());
videoOrder.setState(2);
// 修改商家支付宝订单状态以及退款金额
videoOrderMapper.updateById(videoOrder); returnStr = response.getMsg();
} else {
// 返回退款失败消息
log.info("===退款失败===原因:" + response.getSubMsg());
returnStr = response.getSubMsg();
}
code = Integer.parseInt(response.getCode()); } catch (Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
return returnStr;
}
}

最新文章

  1. [转]js 将图片连接转换称base64格式
  2. IP验证正则表达式
  3. JSOM 对User的操作
  4. 使用Fiddler对Android或者iOS设备进行抓包
  5. SIP学习(实例详解)
  6. 【sublime】在终端下手动安装sublime text 2
  7. Java 集合系列 14 hashCode
  8. Jquery.KinSlideshow图片轮播插件
  9. [置顶] Android开发之MediaPlayerService服务详解(一)
  10. Teradata 的rank() 和 row_number() 函数
  11. Spark Streaming揭秘 Day8 RDD生命周期研究
  12. IE, FF, Safari前端开发常用调试工具
  13. Python 基础【第二篇】python操作模式
  14. 如何解决升级WIN服务的时候,不暴力停止服务 达到升级的目的
  15. window.open 使用方法总结
  16. 安装oracle后,Tomcat 登陆 localhost 要求用户名和密码
  17. 8数码,欺我太甚!&lt;bfs+康拓展开&gt;
  18. 简单使用sp_executesql 参数化
  19. Python入门基础之list和tuple
  20. py库: django (web框架)

热门文章

  1. uniapp 实现APP强更新,热更新
  2. java学习日记20230227-java代码规范
  3. gcc 内联汇编简介
  4. SOJ1728 题解
  5. 文字icon
  6. 看图王 10.9.1.9791 With X64 去广告绿色版
  7. c++ class派生与多态
  8. go语言 cmd执行命令,遇到空格或者双引号无法执行成功的解决方案
  9. UE打LOG整理
  10. queryWrapper 拼接日期查询