eclipse+tomcat+微信开发者工具
spring,spring-mvc
//获取用户openid
getWXOpenId: function () {
var that = this;
wx.login({
//获取code
success: function (res) {
var code = res.code; //返回code
var appId = '填入appid';
var secret = '填入sercret';
wx.request({
url: 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appId + '&secret=' + secret + '&js_code=' + code + '&grant_type=authorization_code',
data: {},
header: {
'content-type': 'json'
},
success: function (res) {
var openid = res.data.openid //返回openid
that.setData({
openId: openid
});
that.buyGoods(openid);
}
})
}
});
},
//发送信息到后台
buyGoods: function (openId) {
var that = this;
var courseName = 0;
//后台服务地址
var address = "后台接口路径";
wx.request({
url: address,
data: {
openId: openId,
courseName: courseName
},
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
method: "POST",
success: function (res) {
console.log(res);
that.doWxPay(res.data);
},
fail: function (err) {
wx.showToast({
icon: "none",
title: '服务器异常,清稍候再试'
})
},
});
},
doWxPay(param) {
console.log(param);
//小程序发起微信支付
wx.requestPayment({
timeStamp: param.data.timeStamp,//记住,这边的timeStamp一定要是字符串类型的,不然会报错
nonceStr: param.data.nonceStr,
package: param.data.package,
signType: 'MD5',
paySign: param.data.paySign,
success: function (event) {
// success
console.log(event);
wx.showToast({
title: '支付成功',
icon: 'success',
duration: 2000
});
},
fail: function (error) {
// fail
console.log("支付失败")
console.log(error)
},
complete: function () {
// complete
console.log("pay complete")
}
});
},
有很多是用不到的,可以自己去掉
4.0.0
com.jt
pay
0.0.1-SNAPSHOT
war
org.springframework
spring-webmvc
4.3.9.RELEASE
mysql
mysql-connector-java
5.1.40
com.alibaba
druid
1.0.29
org.mybatis
mybatis
3.2.8
org.mybatis
mybatis-spring
1.3.1
org.springframework
spring-jdbc
4.3.9.RELEASE
com.fasterxml.jackson.core
jackson-databind
2.8.5
junit
junit
4.12
jstl
jstl
1.2
org.apache.shiro
shiro-spring
1.3.2
commons-httpclient
commons-httpclient
3.1
org.apache.httpcomponents
httpclient
4.5.2
package com.jt.sys.controller;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.commons.httpclient.HttpException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.DigestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import com.jt.common.vo.HttpRequest;
import com.jt.common.vo.HttpUtil;
import com.jt.common.vo.JsonResult;
@RequestMapping("/")
@Controller
public class PageController {
@RequestMapping("test")
public String test(){
return "test";
}
@RequestMapping("buyStepOne")
@ResponseBody
public JsonResult buyStepOne(String openId,String courseName) throws UnsupportedEncodingException {
String appId = "appid";
String mch_id = "商户id";
String notify_url = "支付成功后台回调地址";
String trade_type = "JSAPI";
//签名类型
String SIGNTYPE = "MD5";
//第一次发起支付请求的接口地址
String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//key为商户平台设置的密钥key
String WXKeHukey = "商户平台密钥";
//生成的随机字符串
String nonce_str = getRandomString(32);
//商品名称
String body = new String(courseName.getBytes("ISO-8859-1"),"UTF-8");
//本机的ip地址
String spbill_create_ip = "ip地址";
//商户订单号(先用时间代替)
Date date = new Date();
String orderNo = date.getTime()+"";
String money = "1";//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
Map packageParams = new HashMap();
//小程序ID,微信分配的小程序ID
packageParams.put("appid", appId);
//商户号,微信支付分配的商户号
packageParams.put("mch_id", mch_id);
//随机字符串,长度要求在32位以内。
packageParams.put("nonce_str", nonce_str);
//商品简单描述
packageParams.put("body", body);
//商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
packageParams.put("out_trade_no", orderNo);//商户订单号
//订单总金额,单位为分
packageParams.put("total_fee", money);
//终端IP,支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
packageParams.put("spbill_create_ip", spbill_create_ip);
//异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
packageParams.put("notify_url", notify_url);
//交易类型(JSAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付,不同trade_type决定了调起支付的方式,请根据支付产品正确上传)
packageParams.put("trade_type", trade_type);
//用户标识,trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。
packageParams.put("openid", openId);
// 除去数组中的空值和签名参数
packageParams = paraFilter(packageParams);
String prestr = createLinkString(packageParams); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
//MD5运算生成签名,这里是第一次签名,用于调用统一下单接口,key为商户平台设置的密钥key
String mysign = sign(prestr, WXKeHukey, "utf-8").toUpperCase();
System.out.println("=======================第一次签名:" + mysign + "=====================");
//拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去
String xml = "" + "" + appId + " "
+ ""
+ "" + mch_id + " "
+ "" + nonce_str + " "
+ "" + notify_url + " "
+ "" + openId + " "
+ "" + orderNo + " "
+ "" + spbill_create_ip + " "
+ "" + money + " "
+ "" + trade_type + " "
+ "" + mysign + " "
+ " ";
System.out.println("调试模式_统一下单接口 请求XML数据:" + xml);
//调用统一下单接口,并接受返回的结果
String result = httpRequest(pay_url, "POST", xml);
System.out.println("调试模式_统一下单接口 返回XML数据:" + result);
// 将解析结果存储在HashMap中
// Map map = doXMLParse(result);
// String return_code = (String) map.get("return_code");//返回状态码
//解析结果,将结果存在map中
Map map = doXMLToMap(result);
String return_code = (String) map.get("return_code");
//返回给移动端需要的参数
Map response = new HashMap();
if(return_code == "SUCCESS" || return_code.equals(return_code)){
// 业务结果
String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
response.put("nonceStr", nonce_str);
response.put("package", "prepay_id=" + prepay_id);
Long timeStamp = System.currentTimeMillis() / 1000;
response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
String stringSignTemp = "appId=" + appId + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=" + SIGNTYPE + "&timeStamp=" + timeStamp;
//再次签名,这个签名用于小程序端调用wx.requesetPayment方法
String paySign = sign(stringSignTemp, WXKeHukey, "utf-8").toUpperCase();
System.out.println("=======================第二次签名:" + paySign + "=====================");
response.put("paySign", paySign);
response.put("appid", appId);
}
return new JsonResult(response);
}
/**
* 解析xml,取出其中的result_code,和prepay_id
*/
public HashMap doXMLToMap(String results) {
HashMap result = new HashMap();
String return_code = results.substring(results.indexOf(" "));
result.put("return_code", return_code);
if(return_code.equals("SUCCESS")) {
String prepay_id = results.substring(results.indexOf(" "));
result.put("prepay_id", prepay_id);
}
return result;
}
/**
*
* @param requestUrl请求地址
* @param requestMethod请求方法
* @param outputStr参数
*/
public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {
// 创建SSLContext
StringBuffer buffer = null;
try {
URL url = new URL(requestUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
// 往服务器端写内容
if (null != outputStr) {
OutputStream os = conn.getOutputStream();
os.write(outputStr.getBytes("utf-8"));
os.close();
}
// 读取服务器端返回的内容
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
buffer = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
buffer.append(line);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return buffer.toString();
}
/**
* 除去数组中的空值和签名参数
*
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map paraFilter(Map sArray) {
Map result = new HashMap();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
*
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map params) {
List keys = new ArrayList(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
/**
* 签名字符串
* @param text需要签名的字符串
* @param key 密钥
* @param input_charset编码格式
* @return 签名结果
*/
public static String sign(String text, String key, String input_charset) {
text = text + "&key=" + key;
return DigestUtils.md5DigestAsHex(getContentBytes(text, input_charset));
}
/**
* @param content
* @param charset
* @return
* @throws SignatureException
* @throws UnsupportedEncodingException
*/
public static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
/**
* 支付成功后回调方法
* @return
*/
@RequestMapping("buySteptwo")
@ResponseBody
public JsonResult buySteptwo() {
Map params = getParamsMap();
try {
//读取参数
InputStream inputStream ;
StringBuffer sb = new StringBuffer();
inputStream = getRequest().getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
//解析xml成map
Map m = new HashMap();
m = XMLUtil.doXMLParse(sb.toString());
//过滤空 设置 TreeMap
SortedMap
https://download.csdn.net/download/qq_40488121/11704169
上线阶段出现了问题,因为微信不希望开发者将appid和密钥存储在前台,所以直接调用微信的接口获取appid是不行的,只能通过后台来获取,这样的话应该是前台一步到位发一次请求就好了,但是我比较懒,就直接把请求微信的接口直接改到后台,直接后台获取openid后放回,其他都不用变
public void getOpenId() {
Map<String, Object> params = getParamsMap();
String code = params.get("code").toString();
String secret = "ede5a99e35a0c99a1ea61df19a1aeb72";
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
String openid = HttpUtil.doGet(url);
renderText(openid);
}