本人也是第一次做这个,是一个刚刚学习自学支付的萌新,目的是在于学习,只是为了记录自己的学习过程,怕以后会忘记,因为我没有企业账号,所以用的是自己的支付宝登录,所以第一次要先在平台上注册。
支付宝对接:网页&移动开发流程文档 第一步:支付宝开放平台
打开这个页面后点击首页,选择网页&移动应用(鼠标放上去会有立即创建,点击立即创建后会让你扫描你自己的支付宝账号登录,用手机打开你自己的支付宝扫一扫登录即可)
扫码完成后填写相应的信息提交后,会来到这个界面,然后选择支付接入(因为我目前是学习,所以先暂时选择这个)
点击支付接入后填写相应的信息确认创建即可(我这里是只填写了应用名称和上传图片,然后选择的是网页应用)
确认创建后来到如下界面:
能力列表里面目前暂时只选择了这4个
开发设置
然后我们开始进行开发信息的设置,接口加签方式设置(我这里需要短信验证,验证通过后,弹出如下界面)
公钥字符需要用到支付宝秘钥生成器或者OpenSSL,我这里点击的是支付宝秘钥生成器,点击后来到如下界面:
支付宝秘钥生成器链接地址:
支付宝秘钥生成器如果你的电脑是windows,那就下载windows版本,MAC_OSX就下载MAC_OSX版本
下载完成后然后安装打开刚刚下载的这个应用(支付宝开放平台开发助手),然后直接点击生成秘钥,会生成应用私钥和应用公钥,将应用公钥复制到你的公钥字符里面点击保存设置即可,保存设置后会弹出一个应用公钥和支付宝公钥,我这里是把支付宝公钥新建了一个txt文件复制保存下来了。支付宝开放平台开发助手里面的获取CSR文件我没弄,因为我是个人就没管这个。
然后我点击了接口内容加密方式,会弹出一个窗口,然后我点击了生成新秘钥,其他的选项都没设置,只设置了这2个,如下图:
设置完成后勾选同意协议后,点击页面最上方提交审核按钮,等待官方审核,因为我是晚上大概20.30提交的申请,所以在第二天下午13.30左右审核完成
官方审核通过后,状态已变更为已上线(这里我们申请的这个就相当于是正式环境,沙箱环境是用来给你测试的)
接下来我们进入沙箱,点击研发服务即可进入自己的沙箱
点击沙箱后,我们可以看到系统为我们生成的一些信息
沙箱账号也是系统给我们的,我们可以看到有商家信息和买家信息,这个账号用来模拟真实的支付宝账户,毕竟我们开发进行支付时不会使用自己的真实支付宝进行支付。
接下来我们回到沙箱应用进行设置,这里我设置了三个,如下图:
RSA2(SHA256)密钥(推荐)设置,点击保存设置后,会看到多出来了一个支付宝公钥,我这里是保存了。这里和接口加签方式一样,当然如果你不想用接口加签方式的公钥,可以用支付宝开放平台助手在重新生成一个新的
应用公钥设置,这里我也用的是我的第一个支付中心里面接口加签方式里面生成的公钥
应用公钥设置好后页面如下,我们可以看到多了个支付宝公钥,依旧把这个支付宝公钥复制保存在txt文件中
再就是AES秘钥设置,直接点击生成新秘钥即可。
这三个设置完成后,就是我们最重要的代码开发了
代码开发
手机网站支付Demo 这是手机网站支付demo里面AlipayConfig类中的内容,详情自己可下载去查看
public class AlipayConfig {
// 商户appid
public static String APPID = "";
// 私钥 pkcs8格式的
public static String RSA_PRIVATE_KEY = "";
// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";
// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
public static String return_url = "http://商户网关地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
// 请求网关地址
public static String URL = "https://openapi.alipay.com/gateway.do";
// 编码
public static String CHARSET = "UTF-8";
// 返回格式
public static String FORMAT = "json";
// 支付宝公钥
public static String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjrEVFMOSiNJXaRNKicQuQdsREraftDA9Tua3WNZwcpeXeh8Wrt+V9JilLqSa7N7sVqwpvv8zWChgXhX/A96hEg97Oxe6GKUmzaZRNh0cZZ88vpkn5tlgL4mH/dhSr3Ip00kvM4rHq9PwuT4k7z1DpZAf1eghK8Q5BgxL88d0X07m9X96Ijd0yMkXArzD7jg+noqfbztEKoH3kPMRJC2w4ByVdweWUT2PwrlATpZZtYLmtDvUKG/sOkNAIKEMg3Rut1oKWpjyYanzDgS7Cg3awr1KPTl9rHCazk15aNYowmYtVabKwbGVToCAGK+qQ1gT3ELhkGnf3+h53fukNqRH+wIDAQAB";
// 日志记录目录
public static String log_path = "/log";
// RSA2
public static String SIGNTYPE = "RSA2";
}
在自己的springboot项目中的pom.xml先引入SDK依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
然后在自己的实体类文件夹下新建一个AlipayConfig类,如下:
AlipayConfig类代码如下:
package com.hjl.shop.dto;
import lombok.Data;
import java.io.FileWriter;
import java.io.IOException;
@Data
public class AlipayConfig {
//因为是在沙箱环境下进行测试,所以下面的信息填的值都是沙箱应用里面的值
// 商户appid 测试环境用的都是沙箱应用里面的值,正式环境换成你自己申请的,比如我申请的(我的第一个支付中心)里面对应的值
public static String APPID = "你的沙箱应用APPID";
// 私钥 pkcs8格式的 因为公钥我用的是自己申请的那个(我的第一个支付中心)里面的那个公钥,所以私钥填的也是我的第一个中心里面对应公钥生成的私钥
//公钥类似于一把锁,私钥类似于钥匙,一个公钥对应一个私钥,1对1关系
public static String RSA_PRIVATE_KEY ="你自己的私钥";
// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
//这里我没填,因为我主要目的是学习怎么支付,所以notify_url和return_url就没管,这2个并不影响支付过程
public static String notify_url = "http://localhost:8080/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";
// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
public static String return_url = "http://localhost:8080/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
// 请求网关地址 填写沙箱应用里面的 这是正式环境的请求网址https://openapi.alipay.com/gateway.do,下方是沙箱环境的
public static String URL = "https://openapi.alipaydev.com/gateway.do";
// 编码
public static String CHARSET = "UTF-8";
// 返回格式
public static String FORMAT = "json";
// 支付宝公钥 这里我填的是沙箱应用里面RSA2(SHA256)密钥(推荐)这个生成的支付宝的公钥,正式环境是接口加签方式里面的支付宝公钥
public static String ALIPAY_PUBLIC_KEY = "你自己沙箱应用的支付宝公钥";
// 日志记录目录 日志生成位置,E盘下必须要有先有这个文件夹,不然会报错
public static String log_path = "E:/logs/";
// RSA2
public static String SIGNTYPE = "RSA2";
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
*
* @param sWord
* 要写入日志里的文本内容
*/
public static void logResult(String sWord) {
FileWriter writer = null;
try {
writer = new FileWriter(log_path + "alipay_log_"
+ System.currentTimeMillis() + ".txt");
writer.write(sWord);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
手机网站支付Java请求示例 这里只列出官网给的普通公钥方式的请求示例,公钥证书的请求方式可点击上方链接查看具体代码:
//开放平台 SDK 封装了签名实现,只需在创建 DefaultAlipayClient 对象时,
//设置请求网关 (gateway),
//应用 id (app_id),
//应用私钥 (private_key),
//编码格式 (charset),
//支付宝公钥 (alipay_public_key),
//签名类型 (sign_type)
AlipayClient alipayClient = new DefaultAlipayClient(gateway,app_id,private_key,"json",charset,alipay_public_key,sign_type);
// 创建API对应的request
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
// 在公共参数中设置同步回跳和异步通知地址?
alipayRequest.setReturnUrl("外网能正常访问地址");
alipayRequest.setNotifyUrl("外网能正常访问地址");
// 填充业务参数
alipayRequest.setBizContent("{" + "\"out_trade_no\":\"20161XXXXX2223\"," + "\"total_amount\":\"0.01\","
+ "\"subject\":\"11112xxx9203\"," + "\"product_code\":\"QUICK_WAP_PAY\""
+ "}");
AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest);// 返回form表单
//通过以下代码进行提交请求会默认返回请求url字符串
//AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest,"GET");
String form = response.getBody();
System.out.println(form);
<form name="punchout_form" method="post" action="https://openapi.alipay.com/gateway.do?charset=UTF-8&method=alipay.trade.wap.pay&sign=jL5t3z0dqEl62RekHvX%2BsFlKPqPv5jYZNG2WbJds%2BFB3XG8FTLrH8yYHa4xAcLBIyKQqqlKcD%2FKe9ATwCVQBUHyDTVE4ZROfESuabtrMpnPyxsrmraFljZCeFKZACaVQiBnlDTlSapyKsi8b4ZVjddlV3ScGIC1Hcbhwuk%2BKnPz4M1bETO3u1lDljwZxT3hSfgirPb6U0Wp80ZmxCGBdhc9LUMa3qmW531prP8r8kfazkX2C5KChf1c9dhZkDkJW9V3B9BERGFyW%2B5vCEfnTverP5D%2FjvlibNdxwAuZbSVqwNdjQhYn9gD6alocN0gZPlDJxfitQ%3D%3D&return_url=http%3A%2F%2Fdomain.com%2FCallBack%2Freturn_url.jsp¬ify_url=http%3A%2F%2F114.55.81.185%2Fopendevtools%2Fnotify%2Fdo%2Fa7bc86e9-9b74-447f-97ab-d8c167c0d6d4&version=1.0&app_id=238*******22&sign_type=RSA2×tamp=2019-09-17+13%3A41%3A45&alipay_sdk=alipay-sdk-java-4.5.0.ALL&format=json">
<input type="hidden" name="biz_content" value="{"out_trade_no":"201934369242223","total_amount":"0.23","subject":"111120190509203","product_code":"QUICK_WAP_PAY","quit_url":"https://www.000.com","timeout_express":"2m"}">
<input type="submit" value="立即支付" style="display:none" > </form>
<script>document.forms[0].submit();</script>
然后再在实体类新建一个类接收前端传来的参数类:
import lombok.Data;
/**
* 支付商品信息类
* Created by macro on 2018/4/26.
*/
@Data
public class PayItemInformationParam {
@ApiModelProperty(value = "商品订单号", required = true)
private String outTradeNo;
@ApiModelProperty(value = "付款金额", required = true)
private String totalAmount;
@ApiModelProperty(value = "订单名称", required = true)
private String subject;
@ApiModelProperty(value = "销售产品码", required = true)
private String productCode="QUICK_WAP_PAY";//必填 付款方式 如果值是FAST_INSTANT_TRADE_PAY的话就是扫二维码付款,需要用手机下载一个沙箱支付宝支付
}
然后在Controller层写一个支付接口给前端调用,我这里没有写service层和dao层,如果你们需要存到数据库的话,请自己完成。
@RequestMapping(value = "/pay",method = RequestMethod.POST)
@ResponseBody
public void pay(@RequestBody PayItemInformationParam payItemInformationParam,HttpServletResponse response){
//开放平台 SDK 封装了签名实现,只需在创建 DefaultAlipayClient 对象时,下面是设置顺序
//1.设置请求网关 (gateway),
//2.应用 id (app_id),
//3,应用私钥 (private_key),
//4.返回格式 (format),
//5.编码格式 (charset),
//6.支付宝公钥 (alipay_public_key),
//7.签名类型 (sign_type)
//根据你的AlipayConfig里面的变量名来设置对应的值,获取AlipayConfig里面初始值
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,AlipayConfig.APPID,AlipayConfig.RSA_PRIVATE_KEY,AlipayConfig.FORMAT,AlipayConfig.CHARSET,AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
// 创建API对应的request
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
// 在公共参数中设置同步回跳和异步通知地址
alipayRequest.setReturnUrl(AlipayConfig.return_url);
alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
//将前端获取到的值放到这个里面中,商品订单号,付款金额,订单名称,销售产品码是必填项,不能为空
/*alipayRequest.setBizContent("{\"out_trade_no\":\"201934369242223\","
+ "\"total_amount\":\"88.88\","
+ "\"subject\":\"小米手机\","
+ "\"product_code\":\"QUICK_WAP_PAY\"}");*/
alipayRequest.setBizContent("{" +
" \"out_trade_no\":\""+ payItemInformationParam.getOutTradeNo()+"\"," +
" \"total_amount\":\""+ payItemInformationParam.getTotalAmount() +"\"," +
" \"subject\":\""+ payItemInformationParam.getSubject() +"\"," +
" \"product_code\":\""+ payItemInformationParam.getProductCode() +"\"" +
" }");//填充业务参数
String form="";
try {
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
response.setContentType("text/html;charset=" + AlipayConfig.CHARSET);
AlipayConfig.logResult(form);// 记录支付日志
try {
response.getWriter().write(form);//直接将完整的表单html输出到页面
response.getWriter().flush();
response.getWriter().close();
} catch (IOException e) {
e.printStackTrace();
}
}
到这里后端的支付代码就写完了! 前端用的vue3.0实现的,感兴趣的小伙伴可以看下
<template>
<div>
<el-form :rules="rules" :model="payForm" class="loginRoot">
<h3 class="loginTitle">商品支付信息</h3>
<el-form-item prop="outTradeNo">
<el-input type="text" v-model="payForm.outTradeNo" auto-complete="off" placeholder="请输入订单号"/>
</el-form-item>
<el-form-item prop="totalAmount">
<el-input type="text" v-model="payForm.totalAmount" auto-complete="off" placeholder="请输入付款金额"/>
</el-form-item>
<el-form-item prop="subject">
<el-input type="subject" v-model="payForm.subject" auto-complete="off" placeholder="请输入订单名称"/>
</el-form-item>
<el-button type="primary" @click="pay()" style="width: 100%">下单</el-button>
</el-form>
</div>
</template>
<script>
import axios from '../../utils/myaxios.js'//这里面用了反向代理和权限token验证的,如果需要用到axios,你自己需要重新import一个,myaxios.js是自己新建的一个js文件
export default {
name: "PayItemInformation",
data() {
return {
payForm: {
outTradeNo: '',//设置默认值 如果里面填写admin ,界面上就会默认为admin
totalAmount: '',
subject: ''
},
rules: {
outTradeNo: [{required: true, message: '请输入订单号', trigger: 'blur'}],//required: true必填,失去焦点时验证,如果为空,提示信息为 '请输入用户名称'
totalAmount: [{required: true, message: '请输入付款金额', trigger: 'blur'}],
subject: [{required: true, message: '请输入订单名称', trigger: 'blur'}]
},
}
},
methods:{
pay () {
axios.post('/api/demo/pay',
{
'outTradeNo':this.payForm.outTradeNo,
'totalAmount':this.payForm.totalAmount,
'subject':this.payForm.subject
})
.then((res) =>{//返回成功调用此方法
//console.info(res);
document.querySelector('body').innerHTML = res.data;//查找到当前页面的body,将后台返回的form替换掉他的内容
document.forms[0].submit(); //执行submit表单提交,让页面重定向,跳转到支付宝页面
})
.catch((err)=>{
console.log(err)
})
}
}
}
</script>
<style scoped>
</style>
到这里代码就写完毕了,接下来我们先看看自己的沙箱账号各是多少钱!
然后我们在看看页面效果,首先是下单页面:我这里用的是谷歌浏览器
订单号,订单名称以及支付金额我们随便填写
然后我们点击下单后会跳转到这个页面:
第一个使用支付宝APP付款是在手机端操作的,如果你是用手机端打开的这个网页,那个点击这个它会唤起你手机里面的支付宝客户端来进行付款,因为这里我们用的是沙箱环境,所以你要下载一个沙箱版的支付宝,沙箱应用下沙箱钱包就是用来下载手机版的沙箱支付宝,因为这里我是用的PC端开发的,所以这个我用不了,于是我们点击第二个继续浏览器支付,点击进去后我们发现有2种方式,一种是短信验证方式,这种方式我试了发现手机接收不到验证码,就放弃了,第二种是账号密码登录,我直接换成了账号密码登录
用你沙箱账号里面的买家账号去进行登录
登录成功后,会跳转到确认付款界面
然后点击确认付款,输入支付密码即可完成支付
然后我们看下沙箱账号里面的余额是否变动了,我们看到商家信息的余额多999元,说明我们成功了,在这里这个demo算是完成了。
总结:这里很遗憾没有用到二维码支付,本来想的是下单后会弹出一个支付的二维码,然后我在手机端上用买家信息登录沙箱支付宝进行二维码扫码支付,没想到做着做着就变成这样了,这是一次遗憾(不过我觉得是productCode=FAST_INSTANT_TRADE_PAY这个值的话应该就是那种扫描二维码的方式支付),不过自己算是知道了大概的支付流程,收获了不少,到这里支付就结束了。
做完后我才发现测试的话自己申请的那个我的第一个支付中心好像不怎么需要,只需要直接用沙箱环境做就可以全部完成了,哈哈多走了点弯路,希望这篇文章对大家学习有帮助。