一. 调用微信统一下单接口
1.支付流程
商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,
商户后台系统将code_url值生成二维码图片
2.调用统一下单接口
https://api.mch.weixin.qq.com/pay/unifiedorder
3.前端安装二维码插件
a.下载依赖 npm install vue-qriously --save-dev
b.找到plugins—nuxt-swiper-plugin.js
import VueQriously from ‘vue-qriously’
Vue.use(VueQriously)
4.查询订单支付状态
a.支付成功之后的流程
b.修改订单表里面的状态
c.往支付记录表里面添加一条记录
5.前端之后成功之后页面跳转
a.通过前端的定时任务(*)
b.通过通知地址回调
二. java代码实现二维码扫码支付
1.微信统一下订单
//3.微信统一下订单
@GetMapping("createPayQrCode/{orderNo}")
//通过订单id创建支付订单
public RetVal createPayQrCode(@PathVariable String orderNo) throws Exception {
Map<String, Object> retMap = orderService.createPayQrCode(orderNo);
return RetVal.success().data(retMap);
}
2.调用微信下单API,需用到工具类HttpClient
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/**
* set http post,put param
*/
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // 参数
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 设置参数
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// 响应内容
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}
3.编写service层业务逻辑
注入配置文件中需要传递的信息
@Value("${wx.pay.app_id}")
private String WX_PAY_APP_ID;
@Value("${wx.pay.mch_id}")
private String WX_PAY_MCH_ID;
@Value("${wx.pay.spbill_create_ip}")
private String WX_PAY_SPBILL_IP;
@Value("${wx.pay.notify_url}")
private String WX_PAY_NOTIFY_URL;
@Value("${wx.pay.xml_key}")
private String WX_PAY_XML_KEY;
4.对照微信支付官网,找到必须传递的数据,不是必须的数据看具体业务逻辑添加
@Override
public Map<String, Object> createPayQrCode(String orderNo) throws Exception {
QueryWrapper<EduOrder> wrapper = new QueryWrapper<>();
wrapper.eq("order_no", orderNo);
EduOrder order = baseMapper.selectOne(wrapper);
//把传递的参数封装成一个map结构
Map<String, String> requestParams = new HashMap<>();
//公众账号ID appid
requestParams.put("appid",WX_PAY_APP_ID);
//商户号 mch_id
requestParams.put("mch_id",WX_PAY_MCH_ID);
//随机字符串 nonce_str
requestParams.put("nonce_str", WXPayUtil.generateNonceStr());
//商品描述 body
requestParams.put("body",order.getCourseTitle());
//商户订单号 out_trade_no
requestParams.put("out_trade_no",orderNo);
//标价金额 total_fee 商品的金额0.01分-->0.01元
BigDecimal totalFee = order.getTotalFee();
String totalFeeStr=totalFee.multiply(new BigDecimal(100)).intValue()+"";
requestParams.put("total_fee",totalFeeStr);
//终端IP spbill_create_ip
requestParams.put("spbill_create_ip",WX_PAY_SPBILL_IP);
//通知地址 notify_url
requestParams.put("notify_url",WX_PAY_NOTIFY_URL);
//交易类型 trade_type 是
requestParams.put("trade_type","NATIVE");
//把map接口的参数转换成xml并且签名
String paramsXml = WXPayUtil.generateSignedXml(requestParams, WX_PAY_XML_KEY);
//调用微信下单API
HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
httpClient.setXmlParam(paramsXml);
httpClient.setHttps(true);
httpClient.post();
//因为数据太多,为了保证数据安全性,所有有选择地返回数据
//加返回的数据封装到map中
String content = httpClient.getContent();
Map<String, String> txRetVal = WXPayUtil.xmlToMap(content);
Map<String, Object> retVal = new HashMap<>();
String qrCodeUrl = txRetVal.get("code_url");
retVal.put("qrCodeUrl",qrCodeUrl);
retVal.put("orderNo",orderNo);
retVal.put("totalFee",order.getTotalFee());
retVal.put("courseId",order.getCourseId());
return retVal;
}
5.扫码支付完成需跳转到支付结果页面,也就是查询支付订单,显示支付成功,并根据业务逻辑显示需要显示的信息,最后跟新订单状态。。。。代码比较简单,我就直接贴在下面
//4.查询支付订单
@GetMapping("queryPayState/{orderNo}")
public RetVal queryPayState(@PathVariable String orderNo) throws Exception {
Map<String, String> txRetMap = orderService.queryPayState(orderNo);
//更新订单状态
if(txRetMap.get("trade_state").equals("SUCCESS")){
orderService.updateOrderState(txRetMap);
return RetVal.success().message("支付成功");
}else{
return RetVal.error().message("支付失败");
}
}
service层
@Override
public Map<String, String> queryPayState(String orderNo) throws Exception{
//把传递的参数封装成一个map结构
Map<String, String> requestParams = new HashMap<>();
//公众账号ID appid
requestParams.put("appid",WX_PAY_APP_ID);
//商户号 mch_id
requestParams.put("mch_id",WX_PAY_MCH_ID);
//随机字符串 nonce_str
requestParams.put("nonce_str", WXPayUtil.generateNonceStr());
//商户订单号 out_trade_no
requestParams.put("out_trade_no",orderNo);
//把map接口的参数转换成xml并且签名
String paramsXml = WXPayUtil.generateSignedXml(requestParams, WX_PAY_XML_KEY);
//调用微信下单API
HttpClient httpClient = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
httpClient.setXmlParam(paramsXml);
httpClient.setHttps(true);
httpClient.post();
String content = httpClient.getContent();
Map<String, String> txRetVal = WXPayUtil.xmlToMap(content);
return txRetVal;
}
@Override
public void updateOrderState(Map<String, String> txRetMap) {
//b.修改订单表里面的状态
QueryWrapper<EduOrder> wrapper = new QueryWrapper<>();
String orderNo = txRetMap.get("out_trade_no");
wrapper.eq("order_no", orderNo);
EduOrder order = baseMapper.selectOne(wrapper);
order.setStatus(1);
baseMapper.updateById(order);
//c.往支付记录表里面添加一条记录
QueryWrapper<EduPayLog> logWrapper = new QueryWrapper<>();
logWrapper.eq("order_no", orderNo);
EduPayLog existLog = payLogService.getOne(logWrapper);
if(existLog==null){
EduPayLog payLog = new EduPayLog();
payLog.setOrderNo(orderNo);
payLog.setPayTime(new Date());
payLog.setTotalFee(order.getTotalFee());
payLog.setTransactionId(txRetMap.get("transaction_id"));
payLog.setTradeState(txRetMap.get("trade_state"));
payLogService.save(payLog);
}
}