需求:VUE + SpringMVC前后端分离项目使用支付宝API接口实现付款。
提示为:验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配
1.密钥真的不匹配,检查是否输出错误或者出现了空格。
2.确认密钥无误,可能是数据传输回前端的时候出现了问题,编码格式不对,出现了中文,解析出现问题,导致失败!!建议在填写订单信息的时候不要出现中文。
3.如果真的需要中文信息,可将返回的结果转换为 utf-8的编码格式,如下:
@PostMapping(value = "pay/alipay" , produces = "text/html;charset=utf-8")
打开支付宝开放平台:https://open.alipay.com/develop/sandbox/tool
打开沙箱工具,后使用自定义密钥:
建议使用密钥生成器来生成密钥:
按照要求安装下载:
默认即可,点击生成密钥,生成后这个程序先不要关闭,记录下生成的密钥,之后会用到。
如果你是使用SSM或SpringBoot + Mybatis plus写的后端,那么可以直接复制到你的项目,代码进行少量修改即可。
<!--支付宝Api-->
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency>
<!-- 支付宝支付jar包 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.22.57.ALL</version>
</dependency>
<!--支付宝Api end-->
package cn.edu.nchu.bookstore.entity;
/**
* 支付实体对象
* 根据支付宝接口协议,其中的属性名,必须使用下划线,不能修改
*/
public class AlipayBean {
/**
* 商户订单号,必填
*
*/
private String out_trade_no;
/**
* 订单名称,必填
*/
private String subject;
/**
* 付款金额,必填
* 根据支付宝接口协议,必须使用下划线
*/
private String total_amount;
/**
* 商品描述,可空
*/
private String body;
/**
* 超时时间参数
*/
private String timeout_express= "10m";
/**
* 产品编号
*/
private String product_code= "FAST_INSTANT_TRADE_PAY";
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 getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getTotal_amount() {
return total_amount;
}
public void setTotal_amount(String total_amount) {
this.total_amount = total_amount;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getTimeout_express() {
return timeout_express;
}
public void setTimeout_express(String timeout_express) {
this.timeout_express = timeout_express;
}
public String getProduct_code() {
return product_code;
}
public void setProduct_code(String product_code) {
this.product_code = product_code;
}
}
package cn.edu.nchu.bookstore.utils.alipay.config;
import cn.edu.nchu.bookstore.dao.OrderDao;
import cn.edu.nchu.bookstore.entity.AlipayBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
@Component
public class Alipay {
@Autowired
private AlipayConfig alipayConfig;
/**
* 支付接口
* @param alipayBean
* @return
* @throws AlipayApiException
*/
public String pay(AlipayBean alipayBean) throws AlipayApiException {
// 1、获得初始化的AlipayClient
String serverUrl = alipayConfig.getGatewayUrl();
String appId = alipayConfig.getAppId();
String privateKey = alipayConfig.getPrivateKey();
String format = "json";
String charset = alipayConfig.getCharset();
String alipayPublicKey = alipayConfig.getPublicKey();
String signType = alipayConfig.getSignType();
String returnUrl = alipayConfig.getReturnUrl();
String notifyUrl = alipayConfig.getNotifyUrl();
AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, appId, privateKey, format, charset, alipayPublicKey, signType);
// 2、设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
// 页面跳转同步通知页面路径
alipayRequest.setReturnUrl(returnUrl);
// 服务器异步通知页面路径
alipayRequest.setNotifyUrl(notifyUrl);
// 封装参数
alipayRequest.setBizContent(JSON.toJSONString(alipayBean));
// 3、请求支付宝进行付款,并获取支付结果
String result = alipayClient.pageExecute(alipayRequest).getBody();
System.out.println(result);
// 返回付款信息
return result;
}
}
注意在这个页面内填入你的APPID,商户私钥,支付宝公钥:
package cn.edu.nchu.bookstore.utils.alipay.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
@Component
public class AlipayConfig {
/**
* 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
*/
private String appId = "";
/**
* 商户私钥,您的PKCS8格式RSA2私钥
*/
private String privateKey =
"";
/**
* 支付宝公钥,
*/
private String publicKey = "";
/**
* 服务器异步通知页面路径需http://格式的完整路径,不能加?id=123这类自定义参数
*/
private String notifyUrl = "http://localhost:8081/#/success";
/**
* 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数
*/
private String returnUrl = "http://localhost:8081/#/success";
/**
* 签名方式
*/
private String signType = "RSA2";
/**
* 字符编码格式
*/
private String charset = "utf-8";
/**
* 支付宝网关
*/
private String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
/**
* 支付宝网关
*/
private String logPath = "C:\\";
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}
public String getPublicKey() {
return publicKey;
}
public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getReturnUrl() {
return returnUrl;
}
public void setReturnUrl(String returnUrl) {
this.returnUrl = returnUrl;
}
public String getSignType() {
return signType;
}
public void setSignType(String signType) {
this.signType = signType;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public String getGatewayUrl() {
return gatewayUrl;
}
public void setGatewayUrl(String gatewayUrl) {
this.gatewayUrl = gatewayUrl;
}
public String getLogPath() {
return logPath;
}
public void setLogPath(String logPath) {
this.logPath = logPath;
}
}
package cn.edu.nchu.bookstore.service;
import cn.edu.nchu.bookstore.entity.AlipayBean;
import com.alipay.api.AlipayApiException;
public interface PayService {
/**
* 支付宝支付接口
* @param alipayBean
* @return
* @throws AlipayApiException
*/
String aliPay(AlipayBean alipayBean) throws AlipayApiException;
}
package cn.edu.nchu.bookstore.service.impl;
import cn.edu.nchu.bookstore.entity.AlipayBean;
import cn.edu.nchu.bookstore.service.PayService;
import cn.edu.nchu.bookstore.utils.alipay.config.Alipay;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alipay.api.AlipayApiException;
@Service("payService")
public class PayServiceImpl implements PayService {
@Autowired
private Alipay alipay;
@Override
public String aliPay(AlipayBean alipayBean) throws AlipayApiException {
return alipay.pay(alipayBean);
}
}
package cn.edu.nchu.bookstore.controller;
import cn.edu.nchu.bookstore.entity.AlipayBean;
import cn.edu.nchu.bookstore.service.PayService;
import cn.edu.nchu.bookstore.utils.JsonResult;
import com.alipay.api.AlipayApiException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.UnsupportedEncodingException;
@RestController
//可修改为Controller
public class PayController {
@Autowired
private PayService payService;
/**
* 阿里支付
* @param outTradeNo
* @param subject
* @param totalAmount
* @param body
* @return
* @throws AlipayApiException
*/
@PostMapping(value = "pay/alipay" , produces = "text/html;charset=utf-8")
/*可替换为:
@RequestMapping(value = "pay/alipay" , produces = "text/html;charset=utf-8")
@ResponseBody
*/
public String alipay(String outTradeNo, String subject, String totalAmount, String body) throws AlipayApiException, UnsupportedEncodingException {
AlipayBean alipayBean = new AlipayBean();
alipayBean.setOut_trade_no(outTradeNo);
alipayBean.setSubject(subject);
alipayBean.setTotal_amount(totalAmount);
alipayBean.setBody(body);
System.out.println(outTradeNo);
System.out.println(subject);
System.out.println(totalAmount);
System.out.println(body);
return payService.aliPay(alipayBean);
}
}
该部分使用vue实现,通过点击支付按钮点击实现跳转到支付界面吗,将订单填写在params里面
submitOrder() {
// 修改为你自己的地址
var url = "/pay/alipay";
this.axios({
method: 'post',
url: url,
params: {
outTradeNo: ,//订单的唯一ID
subject: ,//订单名称
totalAmount: ,//订单总价,即付款的钱
body: ,//订单主题内容
},
}).then(response => {
// 添加之前先删除一下,如果单页面,页面不刷新,添加进去的内容会一直保留在页面中,二次调用form表单会出错
const divForm = document.getElementsByTagName('div')
if (divForm.length) {
document.body.removeChild(divForm[0])
}
const div = document.createElement('div')
console.log(response.data);
div.innerHTML = response.data // data就是接口返回的form 表单字符串
document.body.appendChild(div)
document.forms[0].setAttribute('target', '_blank') // 新开窗口跳转
document.forms[0].submit()
}).catch(err => {
console.log(err)
})
这个success界面需要在前面的AlipayConfig 类里面定义,你也可以设置为跳转到其他页面。
我是在这个页面实现了支付后的对数据更新的操作,你也可以直接在后端实现业务,而不必在前端再发一次请求。
以下代码仅供参考,你需要自己写post/get请求的方式,界面自行美化
<template>
<div>
支付成功!!
</div>
</template>
<script>
export default {
mounted() {
console.log(this.$route.query.out_trade_no);
// 获取订单号
//你也可以通过this.$route.query.xxx 获取订单价格,等信息,
//在支付之前,通过F12查看“network” ,支付后,你会看到带有订单信息的请求,找到请求的内容
// 以下代码是支付成功之后的操作,请在这修改你自己的处理方式
// 以下代码是经过封装的请求,不能直接使用
// 我这里的意思是支付后,根据订单ID对订单状态进行修改
this.$post("order/payForOrderByGen", {
orderGeneratedId: this.$route.query.out_trade_no,
}).then(res => {
this.$message({
message: res.data ? '支付成功!' : "支付失败",
type: res.data ? 'success' : 'error'
});
// 跳转到订单页面
this.$router.push("/customer/order");
}).catch(err => {
console.log(err);
});
}
}
</script>
<style>
</style>
https://blog.csdn.net/weixin_51324855/article/details/124097792
如文章中有侵权,请及时联系删除。
本文用于记录作者本人的学习,其中遇到的问题,欢迎大家在讨论区交流。