用沙箱支付宝代替支付宝的支付功能:
a.官方文档已经提供了详细的接入教程,接入支付的类型有:
手机APP接入、手机网站接入、当面付、电脑网站支付
文档入口:https://docs.open.alipay.com/270
沙箱文档入口:https://docs.open.alipay.com/200/105311
b.准入条件
企业支付宝账户或个体工商户均可申请,
提供真实有效的营业执照,且支付宝账户名称需与营业执照主体一致;
提供能正常访问的网站地址且页面显示完整,且页面有完整商品和价格信息;
网站通过ICP备案,有明确的运营内容与完整的商品和价格信息。
目前我们没有办法满足准入条件,但是支付宝提供了沙箱环境供我们学习、测试。
正常环境的申请: https://opendocs.alipay.com/open/270/105899
1.创建应用
添加需要的功能:
设置加签(设置密钥):
下载并密钥工具:https://opendocs.alipay.com/open/291/106097/
生成密钥:
关于密钥的配置,我们需要完成如下操作:
- 在商户端,配置商户的私钥和支付宝的公钥
- 在支付宝端,配置商户的公钥
将生成的商户公钥,配置给支付宝:
支付宝根据商户的公钥,生成对应的支付宝方的公钥和私钥,将支付宝方的公钥返回给我们,我们将支付宝公钥保存下来:
提交审核:
需要1天时间等待审核通过:
2.沙箱接入
沙箱文档入口:https://docs.open.alipay.com/200/105311
准入条件
企业支付宝账户或个体工商户均可申请,
提供真实有效的营业执照,且支付宝账户名称需与营业执照主体一致;
提供能正常访问的网站地址且页面显示完整,且页面有完整商品和价格信息;
网站通过ICP备案,有明确的运营内容与完整的商品和价格信息。
目前我们没有办法满足准入条件,但是支付宝提供了沙箱环境供我们学习、测试。
沙箱模拟了与真实的环境,唯一不同的就是:真实环境是可以直接支付、投入生产的,沙箱环境是支付宝预先提供一个虚拟的环境供我们使用,除了appId和应用环境不一样,其他的开发、使用是一样的,你可以认为沙箱是和真实环境一模一样的测试环境,将来沙箱环境的代码想要上线,只需要将对应的AppID等信息改为真实环境的即可。
沙箱环境:https://openhome.alipay.com/platform/appDaily.htm
支付宝沙箱预先给我们一个测试用的APPID,在真实环境中,这个APPID是我们申请,并审核通过的。
沙箱环境生成密钥:
返回支付宝的公钥,并保存:
编写代码时,请将:
请求网关修改为:https://openapi.alipaydev.com/gateway.do,真实环境的网关是:https://openapi.alipay.com/gateway.do
appid 切换为沙箱预先给你的 appid,真实环境的appid是你申请,并审核通过的appid
签名方式使用 RSA2
应用私钥(private_key)使用第 1 步生成的 RSA2 (SHA256) 的私钥(请根据开发语言进行选择原始或 pkcs8 格式)。
支付宝公钥(public_key)切换为第 1 步配置后应用公钥后,点击查看支付宝公钥看到的公钥。
3.测试示例代码
编程步骤:
- 创建支付宝客户端,在创建的时候,填写支付宝的相关信息
AlipayClient alipayClient = new DefaultAlipayClient(填入各种需要填写信息)
2、封装支付请求的参数
AlipayTradePagePayRequest alipayRequest
关于上述两个步骤,用到的各种参数:https://opendocs.alipay.com/apis/api_1/alipay.trade.page.pay
- 请求支付宝,支付宝返回页面,直接返回给用户
- 用户在支付宝方付款后,支付宝再回到我们的指定的页面中!
- 验证支付状态,然后如果成功,就确认订单支付成功。
根据支付宝回调传回来的参数来分析,是哪个买家支付了哪个订单,然后存到表中。
测试代码:
3.1:使用阿里云提供的第三方支付接口所需依赖:
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-sdk-java -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.10.70.ALL</version>
</dependency>
3.2:封装一个实体类:PayEntity.java
用于封装商户与支付宝交互时,传输的参数
/**
* 封装商户与支付宝交互时,传输的参数
*/
public class PayEntity {
private String out_trade_no;//商家和买家产生的订单
private final String product_code = "FAST_INSTANT_TRADE_PAY";
private String total_amount;//金额
private String subject;
private String body;//主体
public PayEntity(String out_trade_no, String total_amount, String subject, String body) {
this.out_trade_no = out_trade_no;
this.total_amount = total_amount;
this.subject = subject;
this.body = body;
}
/**
* 很多第三方框架,使用你的实体类的时候,往往调用的是无参构造方法
*/
public PayEntity() {
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getProduct_code() {
return product_code;
}
public String getTotal_amount() {
return total_amount;
}
public void setTotal_amount(String total_amount) {
this.total_amount = total_amount;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
@Override
public String toString() {
return "PayEntity{" +
"out_trade_no='" + out_trade_no + '\'' +
", product_code='" + product_code + '\'' +
", total_amount='" + total_amount + '\'' +
", subject='" + subject + '\'' +
", body='" + body + '\'' +
'}';
}
}
3.3:PayController.java 中测试代码:
@Controller
public class PayController {
@Value("${aliPay.serverUrl}")
private String serverUrl;//网关地址
@Value("${aliPay.appId}")
private String appId; //应用ID,如果是真实环境,是你自己申请的,沙箱环境是支付宝给的
@Value("${aliPay.appPrivateKey}")
private String appPrivateKey; //私钥
@Value("${aliPay.format}")
private String format; //JSON
@Value("${aliPay.charset}")
private String charset;//UTF-8
@Value("${aliPay.aliPayPublicKey}")
private String aliPayPublicKey;//公钥
@Value("${aliPay.signTYpe}")
private String signTYpe ;//加密算法RSA2
@ResponseBody
@GetMapping("/returnPay")
public String returnPay(HttpServletRequest request){
//获取支付宝回掉时,传回来的参数
Map<String, String[]> parameterMap = request.getParameterMap();
//
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
System.out.println(entry.getKey()+": ");
String[] value = entry.getValue();
System.out.println("\t\t"+ Arrays.asList(value));
}
return "支付完毕";
}
@ResponseBody
@GetMapping("/NotifyUrl")
public String NotifyUrl(){
return "支付成功";
}
@GetMapping("/toPay.do")
public void toPay (String out_trade_no,String total_amount,String subject,String body,HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException {
//创建支付宝的客户端
AlipayClient alipayClient = new DefaultAlipayClient(
serverUrl,//网关地址
appId, //应用ID,如果是真实环境,是你自己申请的,沙箱环境是支付宝给的
appPrivateKey, //私钥
format, //JSON
charset, //UTF-8
aliPayPublicKey,//公钥
signTYpe //加密算法RSA2
);
//创建当前项目商户 访问 支付宝的请求对象,填写订单信息、交易金额。。。。。
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); //创建API对应的request
// 支付完毕后,支付宝访问你的这个页面,告诉你支付完毕了
alipayRequest.setReturnUrl( "http://localhost:80/returnPay" );
// 支付成功后,支付宝异步告诉你支付成功
alipayRequest.setNotifyUrl( "http://localhost:80/NotifyUrl" ); //在公共参数中设置回跳和通知地址
//设置一些其他参数
// alipayRequest.putOtherTextParam("app_auth_token", "201611BB8xxxxx34343xxxxxxxxxxedcecde6");//如果 ISV 代商家接入电脑网站支付能力,则需要传入 app_auth_token,使用第三方应用授权;自研开发模式请忽略
PayEntity payEntity = new PayEntity(out_trade_no,total_amount,subject,body);
//将java对象,转为json字符串
String s = JSON.toJSONString(payEntity);
alipayRequest.setBizContent(s); //填充业务参数
String form= "" ;
try {
//得到支付宝回传的一个页面信息!!!!!这个页面信息,就是支付页面,给用户看的,用户通过这个页面去付款
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType( "text/html;charset=UTF-8" );
httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
}
3.4:application.yml
aliPay:
serverUrl: "https://openapi.alipaydev.com/gateway.do"
appId: "2021000116664769"
appPrivateKey: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDQqSu6VzS+tLdphRaD2jg57nsHsFvGDIEzVqGjA27Oaxbs2mdwxgm2mYJc30pGHDhHLvRXj0xkuKEG3MkNx/O/B4sTPSpoESSKFtkOxQWLlKWhKf2i4QcY1/CTe+C8XkbluO0l+UGAr6gm+KoUdeD4eykKGFD0N5QWjynYJCxH+QHPQmLQDHqgshBr6qVFMXW4MGjVDj5I/X7cnAttawun2A3IkcZ7DOd1INNNAlAQK3Nzsc+kixVf/u930VOP67GvJjob7QCJZ8drsJtwFITfMt7aM+ahH4KUyNtW3rdB9T5pTi5t2IO9mIusIE7XYaTK5ONAa2Lr4XnHf8Pbe4CVAgMBAAECggEAf55oK0D49oarAvOuMJh/+Rad0rcPelLdlpuuongQBlnDHLv7tiK5gB/ldo3u7HCIDyltsjvnmla9zeetZCteLgEcE3k+fYW2lmqg+QKRgKw6nRaElWESKSSxdFK4whzbOddf2/DWGjHVI3jE9VyfavpQwGbc5HE1tpJ7IkIFf0J20uou20lib++CLf7TSsxcbd5tJLd1WgfpU3+GjTVEh7tCr2B5Q9yyL9ECQqafkbBbhMl/+3j0z20W40lrzrSUMKjOchuVoRQ0IAGuE4Ou9e20fliKK7LvV/c8Ticw89MAxt5TB0Y/Fi1exm6O5X0JOUQPrxg3Db3wBBlLKNkFRQKBgQDxyGpHuZzWZPZDtE/B0GP/pPjvbUJgSBisbb+tcWPr/giauJbcmO9y0AxpXkwx/8VY72IR4YnTsDtjPX9XcnMZjTM572nzPvtq8oIi6DqP5LqGQo7/U3zlsh+Jp33qdKY1puFIcS1/TICf0TnI+GWlBsgMX45CP79tqovjOBNJvwKBgQDc7iptEkHz15Oz89uKKmFJlWEpFBM07ItCJBrZLh7IKJNq8nqOFz2CqrfOMz+SVTKF26TNKrARAr9cyN7YDGCu1gLE1cyB8L9/B9zaouGzdzLzjBwGna+fU2WFo4cMsEMX8q7ZPdlz/XB2Cj5JmvqNFw/ZWv3nSamEpmMYO+pCqwKBgBpN7ZIkFXYVwd0Xzt2NKHP1pMeXoXMMJPMNdZ8PCQnxt0nt7yvMz7A0BkWoZq3B39yPHqJHYVFQiQWA+UuwPel3vSz+aQ53ua6m95WIomZpQgm9UAVjNeFfgaLeQAqz6ilIIJZbCdIhppS8lIbSz2wm0rjV5Io8mTz7IwDzZtXNAoGBANJYW8J/GJYOEU3LBqI0mW4SsHAI8gR4lloBwCI4/Au8Picb+D1iuSi4W8oSFxu+zByQNAc29m0rvYCcqzbuCftMPVSk7lJlIh3TIZ50aAmTmsoxAtn1tikuoMEtIb6d7zNU1s51SZ1aloF8XTN9P8GnTGq4bHeSNbjbJgwDt5WDAoGARN01oT+tVJwRAxuID4pd4/LsSW7vqYfKm8Veywzar9NK6rEgBkZ8hCmdMHgvPlb868ecIB7a5Y/bO1hif0obByal5HK1DA/avb6oD2XrcRT3ESRKWT2mSvpN9ZG/2tRuu8FjrLbWH66pPCoaZEWSIBQuCqNhAe4vEVM5CjdmJfg="
format: "JSON"
charset: "UTF-8"
aliPayPublicKey: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi8EEXCeFDrEGc2otxLFFM6gu8yOijvq4oaKBtRgXzhmEd8bmMIJYbGLwegvFLJ2xh0zmvv3z2edXQu2atmMmzx2wZ+JHjKj57Tnb0mx2Q8iarJHKzmOmrsxDCUUZpSYKzdz9MYsb4CBcMLk+i7XFrHwwUnD+bpFCC+1iycDLqG3sqQcIGsYNxfgEv3scB8bY1+Ox4uk7v3c1TGXuEdn1WIo6McFgvylWnXuMnqgPh0pu4eXGDzq4ArTUpdhqS5hqQ+UnOnNnGc8tC5xY0pI88A/va3tZm5Al1spA0tpAzvXkVBN6x5d0eFUDqwDI7NAyQ1f3ZPSyd8znvbv/a9bjwQIDAQAB"
signTYpe: "RSA2"
3.5:前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>收银台</h1>
<form action="toPay.do">
<!-- String out_trade_no
,String total_amount
,String subject
,String body-->
商品名称:<input name="subject" /> <br>
商品介绍:<input name="body" /> <br>
订 单 ID:<input name="out_trade_no" /> <br>
金    额:<input name="total_amount" /><br>
<input type="submit" value="点击去支付宝收银" />
</form>
</body>
</html>
3.6:效果: