沙箱环境-支付宝文档中心
点击进入沙箱环境并用支付宝登陆
沙箱管理界面如图所示
appid,支付宝网关,自定义密钥等
这里是沙箱支付宝(虚拟)的账号和密码,可以用来支付
点击进入密钥工具
点击生成
这时我们拿到两个密钥,将它们保存,这两个密钥很重要
进入最开始的沙箱管理界面,点击自定义密钥,点击设置(查看),我们选择的是RSA2密钥
选择“公钥”这一选项
将上一步骤生成的应用公钥填进来,会得到支付宝公钥这另一个密钥,记住并保存这个支付宝公钥
这里我用的是springboot+maven+themyleaf项目
<dependency>
<groupId>com.alipay.sdkgroupId>
<artifactId>alipay-sdk-javaartifactId>
<version>4.16.2.ALLversion>
dependency>
创建Controller类后,首先设置如下私有属性
@Controller
public class PayController {
@Autowired
DonaItemService donaItemService;
@Autowired
DonaService donaService;
//appid
private final String APP_ID = "2021000119625133";
//应用私钥
private final String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCDA1Y0+IjB/z4sIhJA0sgEaNGXV9+8t0fUMhrbjHjW88tz8d7jR8ev1aFMmyDKy/cSnlsoNDLwx71GCLiNQENYTvqdcsrYLMvQkmeIYT1OWcPYSl65P0TQRDBhakVdAIXvnts7KJ/nCROGMy8qrBG8ilSlNaOkiuXgp1OPIqLe2dCkrJp1spOJ3Wfq9uyqJO5xrgx6tby3MVPLu/nJ2PtzXt62Kpcj/S9Xxxk9FXOw8cwGDStMPU471VKpEP4kMnjfpUpB9/FfQ6oDfokIaq9dehN9xSitAD6p5cFct7oG94DHai5a+ST6X+OfTv03oE2DuA7ejaJn6cDGSB4IYmZRuDGdicqmPmLEHt3Kq79+EPxBYKUcWI4zQPXlA06Kcgb8HrJntjC836svSUrewWaG32g5MlJB8e1Z+1yL75E6k6R4rBJiVW2MC5VW+p/nQiY3FLfRq4a8V+VJ9uXM1h7L8TbOHtCAQKBgQDCSljMB8VnLFMKHOrcHCZNtjnDHsRYJQYEgNhhvwx2xUIgZNhzpiDmUSwR4TOaqF+Eg5bLfC+sQboANXpP5YUyt/rqUWqQ1fmEV5US9cfiYOi5rfjETK0RAJZaqAVZ0b0PAOMoQpNSbiQKBgHtAnpTuE0QFby+7hDsnTz+qC9dyQQWH3cBOn4RQzo1DUxvyQpZjAy0Oqn/F5x6RGMQU6SrirdUQbGWcANOpp9/L3YGHUrUjlT5Ehx2nPO//yTZSTWKM+p6+XALn1DGZbTChnL/5aEZsg5R4f55wL6RYezRzhq+w4wMixTQDyFLZ";
private final String CHARSET = "UTF-8";
// 支付宝公钥
private final String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3CPgueDLkfB66s9ZsEUwyUbmkRknTFVyuBG4PkKI93OTOVC457ijEKknRYi8eKYo4Wl+75KxYO+tTr1u3XQZmjtjlqbty50DmxRCgEqJKYEu6CD+r1vi+2SXOUKnCJzsE8vHojS+Vk5oGbZYnX6Esw2TVeiCkmQ814CBwIDAQAB";
//这是沙箱接口路径,正式路径为https://openapi.alipay.com/gateway.do
private final String GATEWAY_URL ="https://openapi.alipaydev.com/gateway.do";
private final String FORMAT = "JSON";
//签名方式
private final String SIGN_TYPE = "RSA2";
//支付宝异步通知路径,付款完毕后会异步调用本项目的方法,必须为公网地址
private final String NOTIFY_URL = "http://127.0.0.1/notifyUrl";
//支付宝同步通知路径,也就是当付款完毕后跳转本项目的页面,可以不是公网地址
private final String RETURN_URL = "http://localhost:8080/returnUrl";
}
//必须加ResponseBody注解,否则spring会寻找thymeleaf页面
@ResponseBody
@RequestMapping("/pay/alipay")
public String alipay(HttpSession session,Model model,
@RequestParam("dona_money") float dona_money,
@RequestParam("dona_id") int dona_id) throws AlipayApiException {
//把dona_id项目id 放在session中
session.setAttribute("dona_id",dona_id);
//生成订单号(支付宝的要求?)
String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
String user = UUID.randomUUID().toString().replace("-","").toUpperCase();
String OrderNum = time+user;
//调用封装好的方法(给支付宝接口发送请求)
return sendRequestToAlipay(OrderNum,dona_money,"ghjk");
}
/*
参数1:订单号
参数2:订单金额
参数3:订单名称
*/
//支付宝官方提供的接口
private String sendRequestToAlipay(String outTradeNo,Float totalAmount,String subject) throws AlipayApiException {
//获得初始化的AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
//设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(RETURN_URL);
alipayRequest.setNotifyUrl(NOTIFY_URL);
//商品描述(可空)
String body="";
alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","
+ "\"total_amount\":\"" + totalAmount + "\","
+ "\"subject\":\"" + subject + "\","
+ "\"body\":\"" + body + "\","
+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
//请求
String result = alipayClient.pageExecute(alipayRequest).getBody();
return result;
}
解释,在前端页面点击支付后,将跳转Controller的==alipay()==方法
上面三个必填参数很重要且必须遵守支付宝的规定,在扫码支付的时候能看到且有用
图示使用thymeleaf模板引擎
该页面访问的是支付宝官方提供的页面,至此沙箱支付已经完成了一半,接下来还要写return()方法使我们完成支付后有响应和页面跳转。
由于是沙箱环境,是虚拟的,所以上面那个支付宝扫码不能用真的支付宝去扫,而是需要下载一个沙箱支付宝APP
扫码进行下载
下载完成后的登陆账号密码,也是沙箱环境的账号和密码,同时支付时使用的密码也在其中
@RequestMapping("/returnUrl")
public String returnUrlMethod(HttpServletRequest request,HttpSession session,Model model) throws AlipayApiException, UnsupportedEncodingException {
System.out.println("=================================同步回调=====================================");
// 获取支付宝GET过来反馈信息
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);
}
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");
// 付款金额
float money = Float.parseFloat(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("付款金额="+money);
//在这里编写自己的业务代码(对数据库的操作)
/*
################################
*/
//跳转到提示页面(成功或者失败的提示页面)
model.addAttribute("flag",1);
model.addAttribute("msg","支持");
return "common/payTips";
}else{
//跳转到提示页面(成功或者失败的提示页面)
model.addAttribute("flag",0);
model.addAttribute("msg","支持");
return "common/payTips";
}
}
上面为支付宝同步调用处理,但是官方建议应在异步调用方法中处理付款成功后的操作,但因异步调用的路径必须为公网地址,支付宝才可以发送请求给我们,故这里不写异步调用的方法了,需要注意的是,异步调用为post请求,且传递来的参数会多一些,但基本与同步调用的操作一致
异步回调方法必须为公网IP,因为这个URL地址是支付宝官方来调用我们本机的,是我们完成支付操作后,支付宝需要进行一些金额的处理(与银行对接)所以需要几秒的时间,当支付宝处理完成后异步的调用我们的notify方法(一般在这个方法中进行数据库的操作),这个过程异步进行,所以用户一般感觉不到(用户感觉到的是同步调用的方法)。
设置公网IP有两种方案,1、内网穿透,2、将项目部署到服务器,这里就不说了