生成二维码和微信支付
- 1.流程分析
- 1.2微信支付概述
- 1.2.1账号分析
- 步骤二:微信认证,公众号认证后才可申请微信支付
- 步骤三:申请微信支付
- 步骤四:商户账号审核
- 步骤五:在线签署协议
- 1.2.2支付接口和SDK(了解)
- 在测试项目完成操作:test-wxpay
- 步骤一:添加依赖
- 步骤二:编写配置类,实现WXPayConfig接口
- 步骤三:测试类
- 3. 查询订单
- 4.JS版二维码:QRCode.js
- 拷贝qrcode.min.js
- 编写wxpay.html
- 5.支付页面
- 创建页面
- 后端实现
- 工具类
1.流程分析
1.2微信支付概述
1.2.1账号分析
- 步骤一:注册公众号,根据自身主体类型注册对应的公众号
- 只能申请服务号,订阅号没有办法申请支付
https://kf.qq.com/product/weixinmp.html#hid=87
步骤二:微信认证,公众号认证后才可申请微信支付
步骤三:申请微信支付
- 登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
步骤四:商户账号审核
- 审核通过之后会往您填写的邮箱里发一封邮件是关于微信支付商户的帐号信息,同时您对公账户上也会收到几毛钱的汇款,需要您查看下具体的金额然后登录微信支付商户平台进行验证
步骤五:在线签署协议
- 本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。
- 步骤六:完成上述步骤,你可以得到调用API用到的账号和密钥
- appid:微信公众账号或开放平台APP的唯一标识
- mch_id:商户号
- key:商户密钥
1.2.2支付接口和SDK(了解)
微信支付帮助文档地址:
微信支付https://pay.weixin.qq.com/wiki/doc/api/index.html
- 手动调用,常见的接口(了解)
在测试项目完成操作:test-wxpay
步骤一:添加依赖
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
步骤二:编写配置类,实现WXPayConfig接口
package com.czxy.test.pay;
import com.github.wxpay.sdk.WXPayConfig;
import java.io.InputStream;
/**
* Created by wangshuaihao
*/
public class MyWXPayConfig implements WXPayConfig {
/**
* 应用ID:微信开放平台审核通过的应用APPID
* @return
*/
@Override
public String getAppID() {
return "wx8397f8696b538317";
}
/**
* 商户号:微信支付分配的商户号
* @return
*/
@Override
public String getMchID() {
return "1473426802";
}
/**
* 秘钥,用于生成签名(sign)
* @return
*/
@Override
public String getKey() {
return "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb";
}
@Override
public InputStream getCertStream() {
return null;
}
/**
* 连接超时时间,单位是毫秒
* @return
*/
@Override
public int getHttpConnectTimeoutMs() {
return 0;
}
/**
* 读超时时间,单位是毫秒
* @return
*/
@Override
public int getHttpReadTimeoutMs() {
return 0;
}
}
步骤三:测试类
package com.czxy.test.pay;
import com.github.wxpay.sdk.WXPay;
import java.util.HashMap;
import java.util.Map;
/**
* Created by wangshuaihao
*/
public class TestPayUnifiedOrder {
public static void main(String[] args) throws Exception {
WXPay wxPay = new WXPay(new MyWXPayConfig());
Map<String,String> map=new HashMap();
map.put("body","畅购"); //商品描述
map.put("out_trade_no","20200401001"); //订单号
map.put("total_fee","1"); //金额
map.put("spbill_create_ip","127.0.0.1"); //终端IP
map.put("notify_url","http://www.baidu.com");//回调地址
//JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付
map.put("trade_type","NATIVE"); //交易类型
Map<String, String> result = wxPay.unifiedOrder( map );
System.out.println("支付结果:" + result.get("code_url"));
System.out.println("返回状态码:" + result.get("return_code"));
System.out.println("返回信息:" + result.get("return_msg"));
System.out.println("业务结果:" + result.get("result_code"));
System.out.println(result);
}
}
3. 查询订单
public class TestPayOrderQuery {
public static void main(String[] args) throws Exception {
WXPay wxPay=new WXPay(new MyWXPayConfig());
Map<String,String>map=new HashMap<>();
map.put("out_trade_no","20200401991"); //订单号
Map<String,String>result =wxPay.orderQuery(map);
//发送请求
System.out.println("返回状态码:" + result.get("return_code"));
System.out.println("返回信息:" + result.get("return_msg"));
System.out.println("业务结果:" + result.get("result_code"));
System.out.println("交易状态:" + result.get("trade_state"));
/*
SUCCESS—支付成功
REFUND—转入退款
NOTPAY—未支付
CLOSED—已关闭
REVOKED—已撤销(刷卡支付)
USERPAYING--用户支付中
PAYERROR--支付失败
*/
System.out.println("交易状态:" + result.get("trade_state"));
System.out.println("交易状态描述:" + result.get("trade_state_desc"));
System.out.println(result);
}
4.JS版二维码:QRCode.js
- QRCode.js 是一个用于生成二维码的 JavaScript 库。主要是通过获取 DOM 的标签,再通过 HTML5 Canvas 绘制而成,不依赖任何库。
拷贝qrcode.min.js
编写wxpay.html
<html lang="en">
<head>
<title>二维码入门案例</title>
</head>
<body>
<div id='qrcode'></div>
</body>
</html>
<!-- 代码需要 -->
<script src="/js/qrcode.min.js" ></script>
<script type="text/javascript">
let qrcode = new QRCode(document.getElementById("qrcode"), {
width : 200,
height : 200
});
qrcode.makeCode("weixin://wxpay/bizpayurl?pr=Mfqcl2R");
</script>
5.支付页面
创建页面
<template>
<div>
<!-- 顶部导航 start -->
<TopNav></TopNav>
<!-- 顶部导航 end -->
<div style="clear:both;"></div>
<!-- 页面头部 start -->
<div class="header w990 bc mt15">
<div class="logo w990">
<h2 class="fl"><a href="index.html"><img src="images/logo.png" alt="畅购商城"></a></h2>
<div class="flow fr flow3">
<ul>
<li>1.我的购物车</li>
<li>2.填写核对订单信息</li>
<li class="cur">3.成功提交订单</li>
</ul>
</div>
</div>
</div>
<!-- 页面头部 end -->
<div style="clear:both;"></div>
<!-- 主体部分 start -->
<div class="success w990 bc mt15">
<div class="success_hd">
<h2>订单提交成功</h2>
</div>
<div class="success_bd">
<p><span></span>订单提交成功,我们将及时为您处理</p>
<div id='qrcode' style="width:190px;margin: 0 auto"></div>
<p>{{$route.query.sn}}</p>
<p class="message">完成支付后,你可以 <a href="">查看订单状态</a> <a href="">继续购物</a> <a href="">问题反馈</a></p>
</div>
</div>
<!-- 主体部分 end -->
<div style="clear:both;"></div>
<!-- 底部版权 start -->
<Footer></Footer>
<!-- 底部版权 end -->
</div>
</template>
<script>
import TopNav from '@/components/TopNav'
import Footer from '@/components/Footer'
export default {
head: {
title: '订单详情',
link: [
{rel:'stylesheet',href: '/style/fillin.css'},
{rel:'stylesheet',href: '/style/base.css'},
{rel:'stylesheet',href: '/style/global.css'},
{rel:'stylesheet',href: '/style/success.css'},
],
script:[
{type:'text/javascript',src:'/js/qrcode.min.js'}
]
},
components: {
TopNav,
Footer,
},
data() {
return {
payRequest:{
sn:''
}
}
},
methods: {
async payFn(){
let {data} =await this.$request.pay(this.payRequest)
if(data.code == 20000){
//获得支付路径
this.wxurl=data.other.wxurl
//创建二维码构建器,new QRCode(位置,参数)
let qrcode = new QRCode(document.getElementById("qrcode"), { width : 200, height : 200});
qrcode.makeCode("weixin://wxpay/bizpayurl?pr=pybkohMzz");
}else{
alert(data.message)
}
}
},
mounted() {
this.payRequest.sn = this.$route.query.sn
this.payFn()
},
}
</script>
<style>
#qrcode img {
background-color: #fff;
padding: 6px;
}
</style>
后端实现
- PayRequest
@Data
public class PayRequest {
private Long sn;
}
- PayProperties
package com.czxy.changgou4.config;
import com.github.wxpay.sdk.WXPayConfig;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.io.InputStream;
@Data
@ConfigurationProperties(prefix = "sc.pay")
public class PayProperties implements WXPayConfig {
private String appID; // 公众账号ID
private String mchID; // 商户号
private String key; // 生成签名的密钥
private int httpConnectTimeoutMs; // 连接超时时间
private int httpReadTimeoutMs; // 读取超时时间
private String notifyUrl;
@Override
public InputStream getCertStream() {
//加载证书,需要通过账号中心生成
return null;
}
}
工具类
- PayHelper
package com.czxy.changgou4.utils;
import com.czxy.changgou4.config.PayProperties;
import com.github.wxpay.sdk.WXPay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
@EnableConfigurationProperties(PayProperties.class)
public class PayHelper {
private WXPay wxPay;
private PayProperties payProperties;
@Bean
public WXPay wxPay(PayProperties payProperties){
if(wxPay == null){
wxPay = new WXPay(payProperties);
this.payProperties = payProperties;
}
return wxPay;
}
private static final Logger logger = LoggerFactory.getLogger(PayHelper.class);
public PayHelper() {
}
public PayHelper(PayProperties payProperties) {
wxPay = new WXPay(payProperties);
}
public String createPayUrl(Long sn) {
String key = "pay.url." + sn;
try {
Map<String, String> data = new HashMap<>();
// 商品描述
data.put("body", "商城测试");
// 订单号
data.put("out_trade_no", sn.toString());
//货币
data.put("fee_type", "CNY");
//金额,单位是分
data.put("total_fee", "1");
//调用微信支付的终端IP(商城的IP)
data.put("spbill_create_ip", "127.0.0.1");
//回调地址
data.put("notify_url", payProperties.getNotifyUrl());
// 交易类型为扫码支付
data.put("trade_type", "NATIVE");
//商品id,使用假数据
data.put("product_id", "1234567");
Map<String, String> result = this.wxPay.unifiedOrder(data);
if ("SUCCESS".equals(result.get("return_code"))) {
if("SUCCESS".equals(result.get("result_code"))){
String url = result.get("code_url");
return url;
} else {
logger.error("创建预交易订单失败,错误信息:{}", result.get("err_code_des"));
return null;
}
} else {
logger.error("创建预交易订单失败,错误信息:{}", result.get("return_msg"));
return null;
}
} catch (Exception e) {
logger.error("创建预交易订单异常", e);
return null;
}
}
/**
* 查询订单状态
* 交易状态参考:(trade_state)
SUCCESS—支付成功
REFUND—转入退款
NOTPAY—未支付
CLOSED—已关闭
REVOKED—已撤销(付款码支付)
USERPAYING--用户支付中(付款码支付)
PAYERROR--支付失败(其他原因,如银行返回失败)
* @param sn
* @return
*/
public PayState queryOrder(Long sn) {
Map<String, String> data = new HashMap<>();
// 订单号
data.put("out_trade_no", sn.toString());
try {
Map<String, String> result = this.wxPay.orderQuery(data);
if("SUCCESS".equals(result.get("return_code"))){
if("SUCCESS".equals(result.get("result_code"))) {
String tradeState = result.get("trade_state");
if ("SUCCESS".equals(tradeState)) {
return PayState.SUCCESS;
}
if ("NOTPAY".equals(tradeState)) {
return PayState.NOT_PAY;
}
if ("CLOSED".equals(tradeState)) {
return PayState.CLOSED;
}
}
}
return PayState.PAY_ERROR;
} catch (Exception e) {
logger.error("查询订单状态异常", e);
return PayState.PAY_ERROR;
}
}
}
- PayState
package com.czxy.changgou4.utils;
import lombok.Getter;
@Getter
public enum PayState {
NOT_PAY(0,"未支付"),SUCCESS(1,"支付成功"),CLOSED(2,"已关闭"),PAY_ERROR(3,"支付失败");
PayState(int code,String desc) {
this.code = code;
this.desc = desc;
}
private int code; //自定义编码
private String desc; //描述信息
/**
success("成功"),error("失败");
private String flag="默认值";
public String getFlag(){
return flag;
}
private PayState(String flag){
this.flag = flag;
}
**/
}
- 编写controller
package com.czxy.changgou4.controller;
import com.czxy.changgou4.service.PayService;
import com.czxy.changgou4.vo.BaseResult;
import com.czxy.changgou4.vo.PayRequest;
import com.github.wxpay.sdk.WXPayUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
@RestController
@RequestMapping("/pay")
public class PayController {
@Resource
private PayService payService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@PostMapping
public BaseResult pay(@RequestBody PayRequest payRequest){
//获得支付路径
String wxurl = payService.pay(payRequest);
if (wxurl !=null){
//返回信息
return BaseResult.ok("获得支付链接成功").append("wxurl",wxurl);
}else {
return BaseResult.error("支付失败请重试");
}
}
@PostMapping("/callback")
public void callback(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
System.out.println("回调.........");
try {
String xmlStr = IOUtils.toString(httpServletRequest.getInputStream(), "UTF-8");
Map<String, String> map = WXPayUtil.xmlToMap(xmlStr);
if ("SUCCESS".equals(map.get("return_code"))){
httpServletResponse.setContentType("text/xml");
String data="<xml> <return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
httpServletResponse.getWriter().println(data);
}else {
httpServletResponse.setContentType("text/xml");
String data="<xml> <return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>";
httpServletResponse.getWriter().println(data);
}
} catch (Exception e) {
httpServletResponse.setContentType("text/xml");
String data="<xml> <return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[ERROR]]></return_msg></xml>";
httpServletResponse.getWriter().println(data);
}
}
}
- 编写实现类
package com.czxy.changgou4.service.impl;
import com.czxy.changgou4.service.PayService;
import com.czxy.changgou4.utils.PayHelper;
import com.czxy.changgou4.vo.PayRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
@Service
@Transactional
public class PayServiceImpl implements PayService {
@Resource
private PayHelper payHelper;
@Override
public String pay(PayRequest payRequest) {
//获得支付连接
String sn = payHelper.createPayUrl(payRequest.getSn());
return sn;
}
}