微信支付开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html
咱们这次采用的是Native支付
Native支付使用场景:用户打开"微信扫一扫“,扫描商户的二维码后完成支付
微信提供的api如下,咋们这次只使用统一下单的api。
首先你得准备如下商号配置:
weixin:
appid: wx8397f8696b538317 #微信公众账号或开放平台APP的唯一标识
partner: 1473426802 #财付通平台的商户账号
partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb #财付通平台的商户密钥
notifyurl: http://www.itcast.cn #回调地址
写入application.yml文件
server:
port: 8040
#微信支付信息配置: 这里请填写自己的id....
weixin:
appid: wx8397f8696b538317 #微信公众账号或开放平台APP的唯一标识
partner: 1473426802 #财付通平台的商户账号
partnerkey: T6m9iK73b0kn9g5v426MKfHQH7X8rKwb #财付通平台的商户密钥
notifyurl: http://www.itcast.cn #回调地址
pom文件如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
<!-- 微信支付依赖!xml————map相互转换 -->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!-- HttpClient工具包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!-- 其它需要的依赖配置...父工程 statrt-web.... -->
<!-- 二维码 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.0</version>
</dependency>
HttpClient工具类
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
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() {
// 信任所有
@Override
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;
}
}
PayController
import com.github.wxpay.sdk.WXPayUtil;
import com.sws.weixin.services.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/weixin")
public class PayController {
@Autowired
private PayService payService;
@GetMapping("/pay")
public Object pay(String out_trade_no, String total_fee) throws Exception {
//调用:统一下单!
Map<String, String> pay = payService.pay("5000", "1");
return pay;
}
//回调函数
//必须得是post 的方式,这里查看yml: http://wsm.free.idcfengye.com/weixin/notifyurl /weixin/notifyurl 绑定的回调就是这个方法!
@PostMapping("/notifyurl")
public String notifyurl(HttpServletRequest request) {
System.out.println("支付后回调---------------------------");
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
is = request.getInputStream();
baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
baos.write(bytes, 0, len);
}
String str = new String(baos.toByteArray(), "UTF-8");
System.out.println(str);
//响应数据,如果不写, 商户就不会接受微信的回调,微信就会24小时内频繁进行响应...
Map respMap = new HashMap();
respMap.put("return_code", "SUCCESS");
respMap.put("return_msg", "OK");
return WXPayUtil.mapToXml(respMap);
//处理异常,最终关闭资源!
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return "";
}
}
接口
public interface PayService {
public Map<String, String> pay(String out_trade_no, String total_fee) throws Exception;
}
实现接口
import com.github.wxpay.sdk.WXPayUtil;
import com.sws.weixin.util.HttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class PayServiceimpl implements PayService{
//从yml 中读取对应的... yml配置属性!
@Value("${weixin.appid}")
private String appid;
@Value("${weixin.partner}")
private String partner;
@Value("${weixin.partnerkey}")
private String partnerkey;
@Value("${weixin.notifyurl}")
private String notifyurl;
//唯一订单号 交易金额单位: 分
@Override
public Map<String, String> pay(String out_trade_no, String total_fee) throws Exception{
//设置统一下单: 请求参数;
Map<String, String> param = new HashMap<>();
param.put("appid", appid); //应用ID
param.put("mch_id", partner); //商户ID号
param.put("nonce_str", WXPayUtil.generateNonceStr()); //随机数
param.put("body", "My商场"); //订单描述
param.put("out_trade_no", out_trade_no); //商户订单号: 这是唯一的,会在微信存储!
param.put("total_fee", total_fee); //交易金额:
param.put("spbill_create_ip", "127.0.0.1"); //终端IP
param.put("notify_url", notifyurl); //回调地址: 是后面需要进行商户暴漏的回调接口!
param.put("trade_type", "NATIVE"); //交易类型,NATIVE
String xml = WXPayUtil.generateSignedXml(param, partnerkey); //将map 转换成 xml 并传入签名
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //统一下单的: api!
//获取HttpClient 请求对象!
HttpClient httpClient = new HttpClient(url);
//传入参数,执行请求post
httpClient.setXmlParam(xml);
httpClient.setHttps(true);
httpClient.post();
//获取返回结果! 打印!
String content = httpClient.getContent();
System.out.println(content);
//将返回xml 转换成Map 方便展示输出!
Map<String, String> stringStringMap = WXPayUtil.xmlToMap(content);
//输出: 订单号 金额 支付url(将这个绑定至上面的,二维码中扫码就可以,看到信息进行支付了!!)
Map<String, String> result = new HashMap<>();
result.put("out_trade_no", out_trade_no);
result.put("total_fee", total_fee);
result.put("code_url", stringStringMap.get("code_url"));
//打印!
System.out.println(stringStringMap.get("code_url"));
return result;
}
}
启动项目访问:http://localhost:8040/weixin/pay
code_url中的值为支付地址:weixin://wxpay/bizpayurl?pr=xxxxxxxx
将地址,采用前端js转换成二维码即可。
<html>
<head>
<title>二维码入门小demo</title>
<!--1.引入js 2. 创建一个img标签 用来存储显示二维码的图片 3.创建js对象 4.设置js对象的配置项-->
<script src="https://www.jq22.com/demo/erweima20161214/dist/umd/qrious.js"> </script>
</head>
<body>
<img id="myqrious" >
</body>
<script>
var qrious = new QRious({
element:document.getElementById("myqrious"),// 指定的是图片所在的DOM对象
size:250, //指定图片的像素大小
level:'H', //指定二维码的容错级别(H:可以恢复30%的数据)
value:'weixin://wxpay/bizpayurl?pr=xxxxxxxx'
//指定二维码图片代表的真正的值
})
</script>
</html>