本文包括支付宝沙箱支付及退款功能
前期查看相关网页:
https://blog.csdn.net/weixin_44520739/article/details/89214609
http://www.3qphp.com/java/framework/3306.html
https://blog.csdn.net/qq_21179737/article/details/80407294
支付宝文档:https://docs.open.alipay.com/291/106103/
支付宝文档中心:https://docs.open.alipay.com/catalog
开发者中心:https://developers.alipay.com/platform/appDaily.htm?tab=info
不用非得选他推荐的那种方式
设置后就有应用公钥和支付宝公钥了
一、引入maven依赖
com.alipay.sdk
alipay-sdk-java
3.3.49.ALL
二、代码,建议不要在网页上观看,拉到IDE上看效果更好。
@Controller
public class ClientPayController {
@Autowired
private OrderServiceorderService;
@Autowired
private OrderItemServiceorderItemService;
//应用的APPID,收款账号即是APPID对应支付宝账号
private final StringAPP_ID ="";
//生成的应用私钥
private final StringAPP_PRIVATE_KEY ="";
private final StringCHARSET ="UTF-8";
//支付宝公钥
private final StringALIPAY_PUBLIC_KEY ="";
//这是沙箱接口路径,正式路径为https://openapi.alipay.com/gateway.do
private final StringGATEWAY_URL ="https://openapi.alipaydev.com/gateway.do";
private final StringFORMAT ="JSON";
//签名方式
private final StringSIGN_TYPE ="RSA2";
//支付宝异步通知路径,付款完毕后会异步调用本项目的方法,必须为公网地址
// private final String NOTIFY_URL = "http://192.168.0.101:8080/notifyUrl";
//支付宝同步通知路径,也就是当付款完毕后跳转本项目的页面,可以不是公网地址
private final StringRETURN_URL ="http://127.0.0.1:8080/returnUrl";
@CrossOrigin(allowCredentials="true")//用来保存session,第一次登陆时不管用,第二次就可以了,我也不知道为啥
@RequestMapping("alipay")
public void alipay(HttpServletResponse httpResponse,int oid,float total)throws IOException {
Random r =new Random();
//实例化客户端,填入所需参数
AlipayClient alipayClient =new DefaultAlipayClient(GATEWAY_URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
AlipayTradePagePayRequest request =new AlipayTradePagePayRequest();
//在公共参数中设置回跳和通知地址
request.setReturnUrl(RETURN_URL);
// request.setNotifyUrl(NOTIFY_URL);
Order order =orderService.get(oid);
OrderItem orderItem =orderItemService.getOrderItem(order);
//商户订单号,商户网站订单系统中唯一订单号,必填
//订单id
String out_trade_no = order.getOrderCode();
//付款金额,必填
String total_amount = Float.toString(total);
//订单名称,必填
String subject = orderItem.getProduct().getName();
//商品描述,可空
String body = orderItem.getProduct().getSubTitle();
request.setBizContent("{\"out_trade_no\":\"" + out_trade_no +"\","
+"\"total_amount\":\"" + total_amount +"\","
+"\"subject\":\"" + subject +"\","
+"\"body\":\"" + body +"\","
+"\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
String form ="";
try {
form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
}catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" +CHARSET);
httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
@CrossOrigin(allowCredentials="true")
@RequestMapping(value ="/returnUrl", method = RequestMethod.GET)
public StringreturnUrl(HttpServletRequest request, HttpServletResponse response)
throws IOException, AlipayApiException {
System.out.println("=================================同步回调=====================================");
// 获取支付宝GET过来反馈信息
Map params =new HashMap();
Map requestParams = request.getParameterMap();
for (Iterator 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);
}
System.out.println(params);//查看参数都有哪些
boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE); // 调用SDK验证签名
//验证签名通过
if (signVerified) {
// 商户订单号
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");
System.out.println("商户订单号=" + out_trade_no);
System.out.println("支付宝交易号=" + trade_no);
System.out.println("付款金额=" + total_amount);
//支付成功,修复支付状态
//payService.updateById(Integer.valueOf(out_trade_no));
Order order =orderService.getByOrderCode(out_trade_no).get(0);
order.setStatus("waitDelivery");
order.setAliCode(trade_no);
orderService.add(order);
return "fore/payed";//跳转付款成功页面
}else {
return "支付失败";//跳转付款失败页面
}
}
@CrossOrigin(allowCredentials="true")
@RequestMapping(value ="/notifyUrl", method = RequestMethod.POST)
public void notifyUrl(HttpServletRequest request, HttpServletResponse response)
throws AlipayApiException, IOException {
System.out.println("#################################异步回调######################################");
// 获取支付宝POST过来反馈信息
Map params =new HashMap();
Map requestParams = request.getParameterMap();
for (Iterator 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);
}
System.out.println(params);
boolean signVerified = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE); // 调用SDK验证签名
// ——请在这里编写您的程序(以下代码仅作参考)——
/*
* 实际验证过程建议商户务必添加以下校验: 1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
* 2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额), 3、校验通知中的seller_id(或者seller_email)
* 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
* 4、验证app_id是否为该商户本身。
*/
if (signVerified) {// 验证成功
// 商户订单号
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 trade_status =new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
System.out.println("商户订单号="+out_trade_no);
System.out.println("支付宝交易号="+trade_no);
System.out.println("交易状态="+trade_status);
if (trade_status.equals("TRADE_FINISHED")) {
// 判断该笔订单是否在商户网站中已经做过处理
// 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
// 如果有做过处理,不执行商户的业务程序
// 注意:
// 退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
}else if (trade_status.equals("TRADE_SUCCESS")) {
// 判断该笔订单是否在商户网站中已经做过处理
// 如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
// 如果有做过处理,不执行商户的业务程序
// 注意:
// 付款完成后,支付宝系统发送该交易状态通知
}
System.out.println("异步回调验证成功");
response.getWriter().write("success");
}else {// 验证失败
System.out.println("异步回调验证失败");
response.getWriter().write("fail");
// 调试用,写文本函数记录程序运行情况是否正常
// String sWord = AlipaySignature.getSignCheckContentV1(params);
// AlipayConfig.logResult(sWord);
}
response.getWriter().flush();
response.getWriter().close();
}
//退款
@CrossOrigin(allowCredentials="true")
@RequestMapping(value ="/refund", method = RequestMethod.GET)
public Stringrefund(HttpServletResponse httpResponse,HttpServletResponse response,HttpSession session,String oid)throws IOException, AlipayApiException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
//获得初始化的AlipayClient
AlipayClient alipayClient =new DefaultAlipayClient(GATEWAY_URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
//设置请求参数
AlipayTradeRefundRequest alipayRequest =new AlipayTradeRefundRequest();
Order order=orderService.get(Integer.parseInt(oid));
OrderItem orderItem =orderItemService.getOrderItem(order);
//商户订单号,必填
String out_trade_no =new String(order.getOrderCode());
//需要退款的金额,该金额不能大于订单金额,必填
String refund_amount = String.valueOf(orderItem.getNumber()*orderItem.getProduct().getPromotePrice());
//标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
String out_request_no = order.getOrderCode();
alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
+"\"trade_no\":\""+ order.getAliCode() +"\","
+"\"refund_amount\":\""+ refund_amount +"\","
+"\"out_request_no\":\""+ out_request_no +"\"}");
//请求
String result = alipayClient.execute(alipayRequest).getBody();
//输出
out.println(result);
//订单退款代码
order.setStatus("refund");
orderService.add(order);
return "admin/refundPage";
}
}
支付宝开放平台开发助手点击生成密钥