首先配置沙箱应用环境沙箱环境 | 开放平台
进入页面后,使用支付宝进行登录(你也可以根据官方的说明进行操作,这个页面的数据会随版本变化而变化) 登录后来到支付宝开发平台
生成密钥,我是下载了软件,看你怎么操作生成密钥 | 开放平台,
如果是下载软件方式打开这个软件 ,点击生成密钥,点击复制公钥(注意是应用公钥,通过应用公钥获取支付宝公钥) 这个应用私钥下面也需要
选择自定义私钥 (我是弄过了的,你没有弄过就点击设置并查看)
把复制的公钥粘贴到上面对应的那个框,点击确定就生成了支付宝公钥,点击确定
点击左侧栏的沙箱账号,就可以看到买家和买家基本信息(下面会使用),这个金额都可以进行修改的
至此,沙箱模拟最主要的几个数据得到了
APPID 应用私钥 支付宝公钥
创建springboot工程,我这里采用thymeleaf作为模板引擎实现页面间的跳转,需要引入阿里提供的沙箱的依赖
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.16.2.ALL</version></dependency>
开启内网穿透,双击start.bat (内网穿透我博客也有详细说明)
创建pojo,写四个变量
package com.alipay.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ConfigurationProperties("alipay")
public class Pay {/*** APPID */private String appId;/** * 应用私钥 */private String appPrivateKey;/*** 支付宝公钥*/private String alipayPublicKey;/** * 支付宝异步通知路径 */private String notifyUrl;}
在配置文件yml中配置,这几个数据是按照你的数据来的,代表什么参照上一张图,因为值几个值可能会该变,尤其是公网,当关闭start.bat时网址会改变。所以不写死
server:port: 9090 #端口号,要与在内网穿透中配置的端口号一致alipay: appId: 2021000121639754 appPrivateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHIur+5aCc6rmxlG/gSixVUgLzdoiJmmAdmRW06a9VWwHkSzicsSSmm9sWMgGJzMU1bKy/vf+i2HG2Xsb2otzqVomhwJCBD09zzFmil49fDDfRnjBmomxZHeTzgs5i+lJRU7NzIYoe9l2ZTtkaaWbRim9Cju9VLmqmKQyoMihTpi98RBRRlnTTz1XlgwLBzbvj9AX+gfgebEZLmohpej2L7EuDydiN1Pmw24b0A49IpIKwRUQP1Es6IUXl7JfH12nbZgU9FpKFFEi9Bv9brhXrODjk6HaggeJzsQ604q28S2cvJrcfmxXU0AG2sLPCcw5OQnEfQJRuEjDfPF/8YffrAgMBAAECggEAedc4y6OcIX7c+EheanpV6INuF7cque5PdMA+uwPrSukoFn7fxx9MbU+exC9IBcdzk4ytYJ/dKiU+uXBQsbT7u+lUZFurrkFwoHaB5sABy2/HsB6Rgyg0ylDSyd+JV+Jcb+kopch6sRnuIDjgNBkOVCUd1YPsNAAKtk/Skp/OjkO7jjQB5E+uYbIiYVEqgI8m1qe9V9alKseDRQKxfGY1G6vDXzGJZ+awpnfXE45KJm99SofN+KQzhDtOZwzLzBgrs7+raXNr93XIHHXMWU43q7d758cr5AxAOw7pz1+KYUEygRfERz/B3Gs0JWgTrr5fpoZfyH43+hB/XDPAL1V4GQKBgQC+/TObX0hrfrP23y0LMlzWP5U3sdPD0OAWFmBiDnQnOdRAFp3H12/nLPybIiTXfh1JcHLwzcJX7KE0VYuCIodouBd2gDQQMq62Po33ECgj65uc19Z13h8n4cGsyWtxCZZoW1bE0sgSfMCnVBw4xRgA63Rw/VfGIBn8hq4pG0xgdQKBgQC1IrYhwBJrQdNGTCnxBP6rmv4O14Jt4jZtY3M/1HfLXq9ATvmxkwmMBs7n9TeDQc5v8A1ZK4GIKwg2iRmQrvPNW1qoS1790ZyMbFihf6LCsVmJSCFCSn0nz7cVOb4vs51EhJRN7U1kJ/X61I6cDSWu+UQi6Nr6n9Drmv0hzBPq3wKBgQCnBQZ8eXb7inIXElRx1jkZo8D6U6i9NYzBxA/FsJ4jL49N/Hk+qkhSAiVmBRXy3Xb/IjdiHo42FdljyuuVglyoV1UtbDAbejcPaOT9ikOQJhqPrrD9oqHcXrDgScSLtbayzC21Mh+FC1PvAL8tZi73nvDVXrfDq48OJzlm+VhxgQKBgGVjxKcnqCe5dNWIlIGA1jygSU1tfGidkvGwFTbJazS/D0Hj8whe0Z07wl08eZJTJ4aozA/5tkvOKo68Nz8xbu6oEBrb9ZQF3KcNjp73ntd0BjY91cARifTa5BRReg+hboqH26uzBPrnE10P1bOr+Ef05xrTVJ+tDXiUDNT6MrvpAoGADureFLYwUwXXSP2JaO8njguIf7saYW/YvBl4C0C/veAYeH+PCSAkbURVi0IygGb0xshQ8BhSIp0eu1YUheLGKKyygu7CzO0Z8lnYLvGZeRTJwvwxO3MyQxbvdzy4M3/jrxUNb0xOyjB+92zjJOA4ux/E4rd7fgmL9I6n3cLvmCY=alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhO+kUXPHJE2L5ZEnCPllcpD3hcjXF1+fsIDQxsgLDqQIpuX7+WvQGz4/4Qg5SRvd1g8Miy1uvmxrT4rzVM42QQYqgVH07E9Z6FCieTqYh1GWE0ceXKpD5k0fe8dez39Hph/njoMBiGGFpKMPg80r6LZd1NApm4Mfz5LETeH7AAiwexYBpRhs2x7+wtwfAcGop2a0hWP10PZJWdG0rViAyx2TbRCBAemqW8B3gmBueb3kVyi4XxgOE8hjyqxGWJRx4S+dWJDtDFr0lGyAdl2cSczQqY2Y9VIxPE4AKAUrnsOPIrZp7ko2iRIVgH/m10vHP8zZhWm6IZ5me9d+Gu6aWwIDAQABnotifyUrl: http://t8529w.natappfree.cc/notifyUrl
创建controller,首先定义变量
/*APPID*/@Value("${alipay.appId}")private String appId;/*应用私钥*/@Value("${alipay.appPrivateKey}")private String appPrivateKey;/*支付宝公钥*/@Value("${alipay.alipayPublicKey}")private String alipayPublicKey;/*支付宝异步通知路径*/@Value("${alipay.notifyUrl}")private String notifyUrl;// 字符编码private final String charSet = "UTF-8";//沙箱接口路径private final String gatewayUrl ="https://openapi.alipaydev.com/gateway.do";//格式private final String format = "JSON";//签名方式private final String signType = "RSA2";//支付宝同步通知路径 这里要写你的 private final String returnUrl = "http://localhost:9090/returnUrl";
在index.js中写一个表单,注意是在templates下,并配置"/"的请求路径(因为使用到了thymeleaf作为模板引擎)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form method="get" th:action="@{/alipay}">输入价格 <input type="text" name="money"> <br><input type="submit" value="提交">
</form>
</body>
</html>
参照上一步,写出下面代码,执行项目。通过输入数据后,响应(@ResponseBody)会加载支付宝登录界面,用户名就是沙箱账户中的买家账号,登录密码和支付密码与之对应。之后会进行页面跳转,但还没有写跳转的请求路径
@ResponseBody@GetMapping("/alipay")public String alipay(@RequestParam("money") float money) throws AlipayApiException {// UUID生成订单号String currenTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());String orderNumber = UUID.randomUUID().toString().replace("-","").toUpperCase();// 订单号String Order = currenTime+orderNumber;//调用封装好的方法(给支付宝接口发送请求)return sendRequestToAlipay(Order,money,"请支付相关物品");}//支付宝官方提供的接口private String sendRequestToAlipay(String outTradeNo,Float totalAmount,String subject) throws AlipayApiException {//获得初始化的AlipayClientAlipayClient alipayClient = new DefaultAlipayClient(gatewayUrl,appId,appPrivateKey,format,charSet,alipayPublicKey,signType);//设置请求参数AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();alipayRequest.setReturnUrl(returnUrl);alipayRequest.setNotifyUrl(notifyUrl);//商品描述(可空)String body="";alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","+ "\"total_amount\":\"" + totalAmount + "\","+ "\"subject\":\"" + subject + "\","+ "\"body\":\"" + body + "\","+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");//返回数据return alipayClient.pageExecute(alipayRequest).getBody();}
下面是同步回调的请求地址以及相关代码,复制到上一步下面就行了,现在重启系统,重新进行操作,操作完后就会跳转到对应的页面
@RequestMapping("/returnUrl")public String returnUrlMethod(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {// 获取支付宝GET过来反馈信息System.out.println("------------------------同步回调----------------------------------");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, alipayPublicKey, charSet, signType); // 调用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);/*** 这里可以对数据进行crud操作*///跳转到提示页面(成功或者失败的提示页面)return "success";}else{return "error";}}
至此,同步回调就完成了。还有异步回调,异步回调我还有点问题没有解决,就是通过手机或者另外的电脑登录公网时,最后页面加载不出来,但start.bat页面显示能加载这个post请求. 代码与同步回调基本一致,注意是post请求
@PostMapping("/notifyUrl")public String notifyUrlethod(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {// 获取支付宝GET过来反馈信息System.out.println("------------------------异步回调----------------------------------");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, alipayPublicKey, charSet, signType); // 调用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);/*** 这里可以对数据进行crud操作*///跳转到提示页面(成功或者失败的提示页面)return "success";}elsereturn "error";}}