应用私钥放代码里 merPrivateKey
应用公钥放沙箱保存得到支付宝公钥->支付宝公钥也是放代码里 alipayPublicKey
https://natapp.cn/
https://opendocs.alipay.com/apis/00y8k9
alipay:
appId: "2021000116662953" #沙箱的appid
merPrivateKey: "MIIEvAIBADxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=" #商家应用私钥
alipayPublicKey: "MIIBIjANBgxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" #支付宝公钥
gateway: "openapi.alipaydev.com" #沙箱网关固定
notifyUrl: "http://edrutb.natappfree.cc/alipay/notify" #异步通知回调,用于用户支付成功后,支付宝调用的接口,会给我们返回订单的支付情况,以此修改我们的订单状态,或积分等等
returnUrl: "http://edrutb.natappfree.cc/return_url.html" #这个地址配置是用来前端支付成功后的跳转地址
errorUrl: "http://localhost:8720/error_url.html"
回调接口如下:可在这里进行业务逻辑处理,支付状态的改变,积分等等
/**
* @param request: 请求
* @return java.lang.String
* @description: 支付宝异步回调
*/
@PostMapping("/notify")
public String notify(HttpServletRequest request) throws Exception {
log.info("=========支付宝异步回调========");
if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
log.info(name + " = " + request.getParameter(name));
}
// 支付宝验签
if (Factory.Payment.Common().verifyNotify(params)) {
log.info("交易名称: " + params.get("subject"));
log.info("交易状态: " + params.get("trade_status"));
log.info("支付宝交易凭证号: " + params.get("trade_no"));
log.info("商户订单号: " + params.get("out_trade_no"));
log.info("交易金额: " + params.get("total_amount"));
log.info("买家在支付宝唯一id: " + params.get("buyer_id"));
log.info("买家付款时间: " + params.get("gmt_payment"));
log.info("买家付款金额: " + params.get("buyer_pay_amount"));
}
return "success";
}
return "failed";
}
如上找到appid
appId: “2021000116662953” #沙箱的appid
merPrivateKey: “MIIEvAIBADxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=” #商家应用私钥
alipayPublicKey: “MIIBIjANBgkqhkiG9xxxxxxxxxxxxxxxxxxxxxxxxxxxB” #支付宝公钥
下载密钥工具https://ideservice.alipay.com/ide/getPluginUrl.htm?clientType=assistant&platform=win&channelType=WEB
保存后得到支付宝公钥
notifyUrl: “http://edrutb.natappfree.cc/alipay/notify”
natapp官网: https://natapp.cn/
注册实名后搞个免费隧道,注意设置端口号要与springboot程序启动的一致,或者用nginx监听转发
客户端下载后,在用一目录搞个config.ini配置文件,把上面复制的token放上去
#将本文件放置于natapp同级目录 程序将读取 [default] 段
#在命令行参数模式如 natapp -authtoken=xxx 等相同参数将会覆盖掉此配置
#命令行参数 -config= 可以指定任意config.ini文件
[default]
authtoken= #对应一条隧道的authtoken
clienttoken= #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
log=none #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
loglevel=ERROR #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
http_proxy= #代理设置 非代理上网用户请务必留空
双击exe运行得到对应的公网域名,放入代码的配置文件即可
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.1.0</version>
</dependency>
alipay:
appId: "2021000116662953"
merPrivateKey: "MIIEvgIxxxxxxxxxxxxxxxxxxx"
alipayPublicKey: "MIIBIjANBgxxxxxxxxxxxxxxxxxxxxxxx"
gateway: "openapi.alipaydev.com"
notifyUrl: "http://edrutb.natappfree.cc/alipay/notify"
returnUrl: "http://localhost:8720/return_url.html"
errorUrl: "http://localhost:8720/error_url.html"
/**
* @author kamu
* @date 2020-12-09 15:38
*/
@Log4j2
@Component
public class AlipayConfig implements ApplicationRunner {
@Value("${alipay.appId}")
private String appId;
@Value("${alipay.merPrivateKey}")
private String privateKey;
@Value("${alipay.alipayPublicKey}")
private String publicKey;
@Value("${alipay.gateway}")
private String gateway;
@Value("${alipay.notifyUrl}")
private String notifyUrl;
@Override
public void run(ApplicationArguments args){
Factory.setOptions(getOptions());
log.warn("==================================支付宝SDK初始化完成");
}
private Config getOptions() {
Config config = new Config();
config.protocol = "https";
config.gatewayHost = this.gateway;
config.signType = "RSA2";
config.appId = this.appId;
config.merchantPrivateKey = this.privateKey;
config.alipayPublicKey = this.publicKey;
config.notifyUrl = notifyUrl;
return config;
}
}
/**
* @author kamu
* @date 2020-12-08 15:26
*/
@Log4j2
@Api(tags = "alipay")
@RestController
@RequestMapping("/alipay")
public class AliPayController {
private AliPayService alipayService;
@Autowired
public void AlipayController(AliPayService alipayService) {
this.alipayService = alipayService;
}
/**
* app支付
*/
@PostMapping("/app")
public String app() {
String subject = "测试支付";
String total = "0.03";
return alipayService.app(subject, total);
}
/**
* 支付宝电脑网页支付
*/
@PostMapping("/page")
public String page() {
String subject = "page";
String total = "0.02";
return alipayService.page(subject, total);
}
/**
* 支付宝手机网页支付
*/
@PostMapping("/wap")
public String wap() {
String subject = "wap";
String total = "0.01";
return alipayService.wap(subject, total);
}
/**
* 查询交易
*/
@GetMapping("/getTrade/{outTradeNo}")
public String getTrade(@PathVariable String outTradeNo) {
return alipayService.getTrade(outTradeNo);
}
/**
* 支付宝异步回调
*/
@PostMapping("/notify")
public String notify(HttpServletRequest request) throws Exception {
log.info("=========支付宝异步回调========");
if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
log.info(name + " = " + request.getParameter(name));
}
// 支付宝验签
if (Factory.Payment.Common().verifyNotify(params)) {
log.info("交易名称: " + params.get("subject"));
log.info("交易状态: " + params.get("trade_status"));
log.info("支付宝交易凭证号: " + params.get("trade_no"));
log.info("商户订单号: " + params.get("out_trade_no"));
log.info("交易金额: " + params.get("total_amount"));
log.info("买家在支付宝唯一id: " + params.get("buyer_id"));
log.info("买家付款时间: " + params.get("gmt_payment"));
log.info("买家付款金额: " + params.get("buyer_pay_amount"));
}
return "success";
}
return "failed";
}
/**
* 支付宝退款
*/
@PostMapping("/refund")
public String refund(String outTradeNo, String refundAmount) {
return alipayService.refund(outTradeNo, refundAmount);
}
/**
* 下载账单
*/
@PostMapping("/downloadBill")
public String downloadBill(String billType, String billDate) {
billType = "trade";
billDate = "2020-11";
return alipayService.downloadBill(billType, billDate);
}
}
/**
* @author kamu
* @date 2020-12-09 14:36
*/
public interface AliPayService {
/**
* 支付宝电脑网页支付
*/
String page(String subject, String total);
/**
* 支付宝手机网页支付
*/
String wap(String subject, String total);
/**
* 支付宝退款
*/
String refund(String outTradeNo, String refundAmount);
/**
* app支付
*/
String app(String subject, String total);
String getTrade(String outTradeNo);
String downloadBill(String billType, String billDate);
}
/**
* @author kamu
* @date 2020-12-09 14:37
*/
@Log4j2
@Service
public class AliPayServiceImpl implements AliPayService {
// 支付成功后要跳转的页面
@Value("${alipay.returnUrl}")
private String returnUrl;
@Value("${alipay.errorUrl}")
private String errorUrl;
@Override
public String page(String subject, String total) {
try {
String orderId = getOrderId();
AlipayTradePagePayResponse response = Factory.Payment
// 选择电脑网站
.Page()
// 调用支付方法(订单名称, 商家订单号, 金额, 成功页面)
.pay(subject + orderId, orderId, total, returnUrl);
return response.body;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public String wap(String subject, String total) {
try {
String orderId = getOrderId();
AlipayTradeWapPayResponse response = Factory.Payment
//选择手机网站
.Wap()
// 调用支付方法(订单名称, 商家订单号, 金额, 中途退出页面, 成功页面)
.pay(subject + orderId, orderId, total, errorUrl, returnUrl);
return response.body;
} catch (Exception e) {
e.printStackTrace();
}
return "付款失败";
}
@Override
public String refund(String outTradeNo, String refundAmount) {
try {
AlipayTradeRefundResponse response = Factory.Payment
.Common()
// 调用交易退款(商家订单号, 退款金额)
.refund(outTradeNo, refundAmount);
if ("Success".equals(response.getMsg())) {
return "退款成功";
}
} catch (Exception e) {
e.printStackTrace();
}
return "退款失败";
}
@Override
public String app(String subject, String total) {
try {
AlipayTradeAppPayResponse response = Factory.Payment.App().pay(subject, getOrderId(), total);
return response.body;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public String getTrade(String outTradeNo) {
AlipayTradeQueryResponse query = null;
try {
query = Factory.Payment.Common().query(outTradeNo);
String httpBody = query.getHttpBody();
if ("10000".equals(query.getCode()))
return httpBody;
else
return query.getMsg() + query.getSubMsg();
} catch (Exception e) {
e.printStackTrace();
}
return "failed";
}
@Override
public String downloadBill(String billType, String billDate) {
return "";
}
public String getOrderId() {
String idStr = IdWorker.getIdStr().substring(15);
log.info("======================== " + idStr);
return idStr;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试支付</title>
<script src="./js/vue.min.js"></script>
<script src="./js/axios.min.js"></script>
<script src="./js/vue-resource.min.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/[email protected]/lib/index.js"></script>
<script src="https://cdn.staticfile.org/jquery/3.4.0/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<link rel="stylesheet" href="./css/bootstrap.min.css">
<link rel="stylesheet" href="./css/style.css">
</head>
<body>
<div id="app">
<h2>测试支付</h2>
<form enctype="multipart/form-data" action="/alipay/page" method="post">
<button type="submit">电脑确认支付</button>
</form>
<form enctype="multipart/form-data" action="/alipay/wap" method="post">
<button type="submit">手机确认支付</button>
</form>
<form enctype="multipart/form-data" action="/alipay/app" method="post">
<button type="submit">app确认支付</button>
</form>
<el-button type="primary" @click="downloadBill">账单</el-button>
<!--搜索条 start-->
<div class="searchBar">
<div class="form-group">
<label>单号:</label>
<label>
<input type="text" class="form-control" v-model="outTradeNo"
placeholder="单号">
</label>
</div>
<el-button type="primary" @click="filterBtn">交易查询</el-button>
<el-button type="info" @click="clearSearch">重 置</el-button>
</div>
<!--搜索条 end-->
<div class="orderInfo">
<dl class="dl-horizontal">
<dt>buyer_logon_id</dt>
<dd>{{orderList.buyer_logon_id}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>buyer_pay_amount</dt>
<dd>¥{{orderList.total_amount}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>buyer_user_id</dt>
<dd>{{orderList.buyer_user_id}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>out_trade_no</dt>
<dd>{{orderList.out_trade_no}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>trade_no</dt>
<dd>{{orderList.trade_no}}</dd>
</dl>
<dl class="dl-horizontal">
<dt>trade_status</dt>
<dd>{{orderList.trade_status}}</dd>
</dl>
</div>
<!-- <div class="cantainer">
<el-table style="width: 100%;"
:data="orderList"
:row-class-name="tableRowClassName"
:header-cell-style="{background:'#eef1f6',color:'#606266'}"
>
<el-table-column label="buyer_logon_id" prop="buyer_logon_id" width="200">
</el-table-column>
<el-table-column label="buyer_pay_amount" prop="buyer_pay_amount" width="200">
</el-table-column>
<el-table-column label="buyer_user_id" prop="buyer_user_id" width="200">
</el-table-column>
<el-table-column label="out_trade_no" prop="out_trade_no" width="200">
</el-table-column>
<el-table-column label="total_amount" prop="total_amount" width="200">
</el-table-column>
<el-table-column label="trade_no" prop="trade_no" width="200">
</el-table-column>
<el-table-column label="trade_status" prop="trade_status" width="200">
</el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<el-popover
placement="right"
width="100%"
trigger="click">
<el-table :data="orderLotList" :row-class-name="tableOrderLotList"
:header-cell-style="{background:'#eef1f6',color:'#606266'}"
:row-style="{background:'#eef1f6',color:'#606266'}"
>
<el-table-column width="160" property="productionTime"
label="生产日期"></el-table-column>
<el-table-column width="160" property="lotNo" label="批次号"></el-table-column>
<el-table-column width="160" property="expiredTime"
label="有效期"></el-table-column>
<el-table-column width="160" property="qty" label="数量"></el-table-column>
<el-table-column width="160" property="price" label="单价"></el-table-column>
<el-table-column width="160" property="purchasePrice"
label="采购价"></el-table-column>
</el-table>
<el-button type="primary" slot="reference" @click="getLotList(scope.row)">批号详情
</el-button>
</el-popover>
</template>
</el-table-column>–>
</el-table>
<el-pagination
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="searchBarParams.pageIndex"
:page-sizes="[10, 20, 50, 80, 100]"
:page-size="searchBarParams.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount">
</el-pagination>
</div>-->
</div>
</body>
<script type="text/javascript">
window.onload = function () {
var api = ''
var app = new Vue({
el: '#app',
data: {
outTradeNo: '2',
orderList: [],//列表数据
},
methods: {
clearSearch() {
this.outTradeNo = '';
},
filterBtn() {
this.getorderList(this.outTradeNo)
},
getorderList(outTradeNo) {
axios({
method: 'get',
url: '/alipay/getTrade/'+outTradeNo
}).then(res => {
console.log(res)
this.orderList = res.data.alipay_trade_query_response
console.log("==========================")
console.log(this.orderList)
console.log("==========================")
}).catch(error => {
console.log('请求失败 ', error)
})
},
tableRowClassName({row, rowIndex}) {
if (rowIndex % 2 === 0) {
return 'warning-row';
} else if (rowIndex % 2 === 1) {
return 'success-row';
}
return '';
},
downloadBill() {
axios({
method: 'post',
url: '/alipay/downloadBill',
data: {billType: 'billType', billDate: 'billDate'}
}).then(res => {
console.log(res)
}).catch(error => {
console.log('请求失败 ', error)
})
}
},
created() {
// this.getorderList(this.outTradeNo)
}
})
}
</script>
</html>