闲暇时间对这两天的工作做一个总结,也是一个备忘录
一、个人测试公众号开通
访问http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login,用自己的微信号登录,注册一个测试公众号(拥有所有权限)。
二、个人本地项目内网穿透映射 ,推荐使 用natapp,https://natapp.cn/
备注: 官网新手文档(https://natapp.cn/article/natapp_newbie)
新手注 端口号不要改 默认80
tomcat 用户<Context path="" docBase="wxProject" debug="0" reloadable="true"/> 配置默认打开项目
三、项目代码及配置
域名为内网穿透映射的域名 wxServlet 代码如下
package com.wx.web.servlet;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns="/WxServlet")
public class WxServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 5826089535002664715L;
/**
* Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)
*/
private final String TOKEN = "wxzyh";
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("开始校验签名");
/**
* 接收微信服务器发送请求时传递过来的4个参数
*/
String signature = request.getParameter("signature");// 微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
String timestamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce");// 随机数
String echostr = request.getParameter("echostr");// 随机字符串
// 排序
String sortString = sort(TOKEN, timestamp, nonce);
// 加密
String mySignature = sha1(sortString);
// 校验签名
if (mySignature != null && mySignature != ""
&& mySignature.equals(signature)) {
System.out.println("签名校验通过。");
// 如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。
// response.getWriter().println(echostr);
response.getWriter().write(echostr);
} else {
System.out.println("签名校验失败.");
}
}
/**
* 排序方法
*
* @param token
* @param timestamp
* @param nonce
* @return
*/
public String sort(String token, String timestamp, String nonce) {
String[] strArray = { token, timestamp, nonce };
Arrays.sort(strArray);
StringBuilder sb = new StringBuilder();
for (String str : strArray) {
sb.append(str);
}
return sb.toString();
}
/**
* 将字符串进行sha1加密
*
* @param str
* 需要加密的字符串
* @return 加密后的内容
*/
public String sha1(String str) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(str.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
token 超时处理,servlet init 线程处理,每隔(7000*1000)重新获取 相关代码如下
package com.wx.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wx.web.common.ConfigUtil;
import com.wx.web.util.NetWorkHelper;
@WebServlet(
name = "InitTokenServlet",
urlPatterns = {"/InitTokenServlet"},
loadOnStartup = 1
)
public class InitTokenServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 6331264937014187299L;
@Override
public void init() throws ServletException {
System.out.println("启动WebServlet");
super.init();
final String appId = ConfigUtil.APPID;
final String appSecret = ConfigUtil.APP_SECRET;
new Thread(new Runnable(){
@Override
public void run() {
while(true){
try {
String token = getAccessToken(appId, appSecret);
if(token!=null){
ConfigUtil.ACCESS_TOKEN = token;
getTicket(token);
Thread.sleep(7000*1000);
}else{
Thread.sleep(1000*3);
}
} catch (Exception e) {
System.out.println("发生异常:"+e.getMessage());
e.printStackTrace();
try {
Thread.sleep(1000*1);
} catch (Exception e2) {
// TODO: handle exception
}
}
}
}
}).start();
}
private String getAccessToken(String appId,String appSecret){
NetWorkHelper netHelper = new NetWorkHelper();
String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
String result = netHelper.getHttpsResponse(url, "");
System.out.println("获取到的access_token="+result);
JSONObject json = JSON.parseObject(result);
String accesstoken = json.getString("access_token");
return accesstoken;
}
private void getTicket(String token){
NetWorkHelper netHelper = new NetWorkHelper();
String url = String.format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi", token);
String result = netHelper.getHttpsResponse(url, "");
System.out.println("获取到的ticket="+result);
JSONObject json = JSON.parseObject(result);
String ticket = json.getString("ticket");
ConfigUtil.JSAPI_TICKET = ticket;
}
}
package com.wx.web.common;
public class ConfigUtil {
public static final String APPID = "xxxxxxxxx";
public static final String APP_SECRET = "xxxxxxxxxxxxxxxx";
public static final String GRANT_TYPE = "client_credential";
public static final String JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
public static final String JSAPI_TICKET_TYPE = "jsapi";
public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
public static String ACCESS_TOKEN = "";
public static String JSAPI_TICKET = "";
}
给页面提供参数的servlet JSON 返回
package com.wx.web.servlet;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.alibaba.fastjson.JSONObject;
import com.wx.web.common.ConfigUtil;
@WebServlet(urlPatterns="/WxConfigServlet")
public class WxConfigServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = -8577082499121279011L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String url = req.getParameter("url");
Map<String,Object> data = new HashMap<String, Object>();
String nonce_str = createNoncestr();
String timestamp = createTimestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + ConfigUtil.JSAPI_TICKET +
"&noncestr=" + nonce_str +
"×tamp=" + timestamp +
"&url=" + url;
System.out.println(string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
data.put("url", url);
data.put("jsapi_ticket", ConfigUtil.JSAPI_TICKET);
data.put("nonceStr", nonce_str);
data.put("timestamp", timestamp);
data.put("signature", signature);
data.put("appId", ConfigUtil.APPID);
// ConfigUtil.NONCESTR =
// super.doPost(req, resp);
resp.setContentType("application/json; charset=utf-8");
resp.setCharacterEncoding("UTF-8");
String userJson = JSONObject.toJSONString(data);
OutputStream out = resp.getOutputStream();
out.write(userJson.getBytes("UTF-8"));
out.flush();
}
protected String createNoncestr() {
return UUID.randomUUID().toString();
}
protected String createTimestamp() {
return Long.toString(System.currentTimeMillis()/1000);
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
}
页面获取
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
<title>线下转账</title>
<link rel="stylesheet" type="text/css" href="../css/aui/aui.css" />
<!--<link rel="stylesheet" type="text/css" href="../css/style.css" />-->
<style>
.txt_money {
color: #e74c3c;
font-weight: bold;
padding: 0 4px;
}
select.sj_select {
font-size: 12px !important;
padding: 6px 0 6px 15px !important;
color: #666 !important;
}
.txt_money {
color: #e74c3c;
font-weight: bold;
padding: 0 4px;
}
.ptb {
padding: 2px 12px !important;
}
.zzxx .aui-list-item-input{color:#CC4D03}
</style>
</head>
<body>
</body>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js" type="text/javascript" ></script>
<script>
wxConfig();
/**
* 微信配置接口
* @returns
*/
function wxConfig(){
var url = window.location.href;
$.post('/wxZyh/WxConfigServlet', { url: url }, function(ret){
var appId = ret.appId;
var timestamp = ret.timestamp;
var nonceStr = ret.nonceStr;
var signature = ret.signature;
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature,// 必填
jsApiList: ['chooseImage','previewImage','uploadImage','downloadImage','getLocalImgData'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
});
}
</script>
</html>