零、 微信⼩程序开发流程
1. ⼩程序内调⽤登录接⼝,获取到⽤户的openid,api参⻅公共api【⼩程序登录API
】
2. 商户server调⽤⽀付统⼀下单,api参⻅公共api【统⼀下单API
】
3. 商户server调⽤再次签名,api参⻅公共api【再次签名
】
4. 商户server接收⽀付通知,api参⻅公共api【⽀付结果通知API
】
5. 商户server查询⽀付结果,api参⻅公共api【查询订单API
】
⼀、 调⽤⼩程序登录API
创建spring boot项⽬,依赖web、lombox
定义好常量类,包含⼩程序appid/secret和商户号mch_id和mch_key
public class WechatConstant {
public final static String MCH_ID = "test"; // 写⾃⼰的mch_id
public final static String MCH_KEY = "⾃⼰设置的key"; // 写⾃⼰的MCH_KEY
public final static String APPID = "test"; // 写⾃⼰的APPID
public final static String SECRET = "test"; // 写⾃⼰的SECRET
}
在pom.xml引⼊httpclient的依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
创建基于httpclient的http请求⼯具类HttpRequestUtils
public class HttpRequestUtils {
/**
* 向指定URL发送GET⽅法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
System.out.println(urlNameString);
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通⽤的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT
5.1;SV1)");
// 建⽴实际的连接
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输⼊流来读取URL的响应
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使⽤finally块来关闭输⼊流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST⽅法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通⽤的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT
5.1;SV1)");
// 发送POST请求必须设置如下两⾏
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输⼊流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使⽤finally块来关闭输出流、输⼊流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/**
* post请求并得到返回结果
*
* @param requestUrl
* @param requestMethod
* @param output
* @return
*/
public static String httpsRequest(String requestUrl, String requestMethod, String output) {
try {
URL url = new URL(requestUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod(requestMethod);
if (null != output) {
OutputStream outputStream = connection.getOutputStream();
outputStream.write(output.getBytes("UTF-8"));
outputStream.close();
}
// 从输⼊流读取返回内容
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
connection.disconnect();
return buffer.toString();
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
}
⼩程序端可通过wx.login()这个API去获取⼀个code
login: function(e) {
console.log('login start')
wx.login({
success: function(info) {
console.log('login: ' + info.code)
wx.request({
method: 'post',
url: 'http://andyzheng.utools.club/wxPay/login/' + info.code,
success: function(res) {
console.log(res.data)
app.globalData.userInfo.openId = res.data.openid
}
})
}
})
}
后端请求微信⼩程序登录API,得到openId
@PostMapping(value = "/login/{code}")
@ResponseBody
public String login(@PathVariable String code) {
String url = String.format("https://api.weixin.qq.com/sns/jscode2session?
appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
WechatConstant.APPID, WechatConstant.SECRET, code);
String result = HttpRequestUtils.sendGet(url, null);
log.info(result);
return result;
}
⼆、 调⽤⽀付API前的准备
继承配置类
@Slf4j
public class MyWXPayConfig extends WXPayConfig {
@Override
String getAppID() {
return WechatConstant.APPID;
}
@Override
String getMchID() {
return WechatConstant.MCH_ID;
}
@Override
String getKey() {
return WechatConstant.MCH_KEY;
}
@Override
InputStream getCertStream() {
return null;
}
@Override
IWXPayDomain getWXPayDomain() {
return new IWXPayDomain() {
@Override
public void report(String domain, long elapsedTimeMillis, Exception ex) {
log.info("report");
}
@Override
public DomainInfo getDomain(WXPayConfig config) {
return new IWXPayDomain.DomainInfo(WXPayConstants.DOMAIN_API, true);
}
};
}
}
三、 请求⼩程序⽀付
pay: function(e) {
// var openId = 'ohq2Z5YmV0lyLRCYbEKV-q6TOyUA'
var openId = app.globalData.userInfo.openId
wx.request({
url: 'http://andyzheng.utools.club/wxPay/pay/' + openId,
// url: 'http://andyzheng.utools.club:8080/wxPay/pay/' + openId,
method: 'post',
success: function(res) {
wx.requestPayment({
'timeStamp': res.data.timeStamp,
'nonceStr': res.data.nonceStr,
'package': res.data.package,
'signType': res.data.signType,
'paySign': res.data.paySign,
'success': function (payRes) {
// debugger
console.log('success' + payRes.errMsg)
},
'fail': function (payRes) {
//debugger
console.log('fail' + payRes.errMsg)
}
})
}
})
}
四、 后端接收⽀付请求,并返回签名
Controller接收⽀付请求
/**
* ⽀付
* @param request
* @param openId
* @return
* @throws Exception
*/
@PostMapping("/pay/{openId}")
@ResponseBody
public Map<String, String> pay(HttpServletRequest request, @PathVariable String openId) throws Exception {
// 获取请求ip地址
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.indexOf(",") != -1) {
String[] ips = ip.split(",");
ip = ips[0].trim();
}
return wxPayService.wxPay(openId, ip);
}
Service实现请求⽀付API(1. ⽣成商户订单)
// 1. 拼接统⼀下单地址参数
Map<String, String> paraMap = new HashMap<String, String>();
paraMap.put("body", "实训邦课程优惠购买"); // 商家名称-销售商品类⽬、String(128)
paraMap.put("openid", openId); // openId,通过登录获取
paraMap.put("out_trade_no", UUID.randomUUID().toString().replaceAll("-", ""));// 订单号,每次都不同
paraMap.put("spbill_create_ip", ipAddress);
paraMap.put("total_fee", "1"); // ⽀付⾦额,单位分,即0.01元
paraMap.put("trade_type", "JSAPI"); // ⽀付类型
log.info("paraMap为:" + paraMap);
log.info("================ 分隔线 ==============");
Service实现请求⽀付API(2. 调⽤⽀付统⼀下单API)
// 2. 通过MyWXPayConfig创建WXPay对象,⽤于⽀付请求
final String SUCCESS_NOTIFY = "http://andyzheng.utools.club/wxPay/success";
boolean useSandbox = false; // 是否使⽤沙盒环境⽀付API,是的话不会真正扣钱
WXPayConfig config = new MyWXPayConfig();
WXPay wxPay = new WXPay(config, SUCCESS_NOTIFY, false, useSandbox);
// 3. fillRequestData会将上述参数⽤key=value形式和mchKey⼀起加密为sign,验证地址:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=20_1
Map<String, String> map = wxPay.unifiedOrder(wxPay.fillRequestData(paraMap), 15000, 15000);
Service实现请求⽀付API(3. 得到prepay_id后,返回组合数据和再次签名的结果到前端⼩程序)
评论0
最新资源