开发背景
- 最近在学习java,所以从网上看了一些别人的代码,再加入了自己的一些理解,主要是担心之后会忘记,所以写下一篇东西记录一下思路。
一、 获取acess_token以及jsapiTicket
- 新建一个类TokenThread,实现线程的Runnable接口,代码如下:
TokenThread
package util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import model.AccessToken;
import model.JsapiTicket;
/**
* Created by xu on 2017/7/10.
*/
public class TokenThread implements Runnable {
public static String appId = "xxx";
public static String appSecret= "xxx";
public static AccessToken accessToken = null;
public static JsapiTicket jsapiTicket = null;
public final static String js_api_ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";
@Override
public void run() {
while (true) {
try {
accessToken = this.getAccessToken();
jsapiTicket = this.getJsapiTicket();
//获取到accessToken后,休眠7000秒,保证不会重复的获取,超过了每天的最大次数
if (null != accessToken) {
System.out.println(accessToken.getAccessToken());
System.out.println(jsapiTicket.getJsapiTicket());
Thread.sleep(7000 * 1000); //获取到access_token 休眠7000秒
} else {
Thread.sleep(1000 * 3); //获取的access_token为空 休眠3秒
}
} catch (Exception e) {
System.out.println("发生异常:" + e.getMessage());
e.printStackTrace();
try {
Thread.sleep(1000 * 10); //发生异常休眠1秒
} catch (Exception e1) {
}
}
}
}
/**
* 获取access_token
* @return
*/
private AccessToken getAccessToken(){
NetWorkHelper netHelper = new NetWorkHelper();
String Url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",this.appId,this.appSecret);
String result = netHelper.getHttpsResponse(Url,"");
System.out.println(result);
//response.getWriter().println(result);
JSONObject json = JSONObject.parseObject(result);
System.out.println(json);
AccessToken token = new AccessToken();
token.setAccessToken(json.getString("access_token"));
token.setExpiresin(json.getInteger("expires_in"));
return token;
}
/**
* 获取jsapi_ticket
* @return
*/
private JsapiTicket getJsapiTicket(){
NetWorkHelper netHelper = new NetWorkHelper();
String Url = js_api_ticket_url.replace("ACCESS_TOKEN",this.getAccessToken().getAccessToken());
String result = netHelper.getHttpsResponse(Url,"");
System.out.println(result);
JSONObject json = JSONObject.parseObject(result);
System.out.println(json);
JsapiTicket jsapiTicket = new JsapiTicket();
jsapiTicket.setJsapiTicket(json.getString("ticket"));
jsapiTicket.setExpiresin(json.getInteger("expires_in"));
return jsapiTicket;
}
}
这里用到了两个工具类NetWorkHelper,发起网络请求网上有封装好的,我做一下搬运工:
NetWorkHelper
package util;
import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Created by xu on 2017/7/10.
*/
public class NetWorkHelper {
public String getHttpsResponse(String hsUrl,String requestMethod) {
URL url;
InputStream is = null;
String resultData = "";
try {
url = new URL(hsUrl);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
TrustManager[] tm = {xtm};
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tm, null);
con.setSSLSocketFactory(ctx.getSocketFactory());
con.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
con.setDoInput(true); //允许输入流,即允许下载
//在android中必须将此项设置为false
con.setDoOutput(false); //允许输出流,即允许上传
con.setUseCaches(false); //不使用缓冲
if(null!=requestMethod && !requestMethod.equals("")) {
con.setRequestMethod(requestMethod); //使用指定的方式
}
else{
con.setRequestMethod("GET"); //使用get请求
}
is = con.getInputStream(); //获取输入流,此时才真正建立链接
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bufferReader = new BufferedReader(isr);
String inputLine = "";
while ((inputLine = bufferReader.readLine()) != null) {
resultData += inputLine + "\n";
}
System.out.println(resultData);
Certificate[] certs = con.getServerCertificates();
int certNum = 1;
for (Certificate cert : certs) {
X509Certificate xcert = (X509Certificate) cert;
}
} catch (Exception e) {
e.printStackTrace();
}
return resultData;
}
X509TrustManager xtm = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
};
}
上面还引入了阿里巴巴的json解析包import com.alibaba.fastjson.JSONObject;自行上网搜索就好。
上面的获取accessToken的过程中,new了一个AccessToken和JsapiTicket对象,我把她们放进了一个model类里。
AccessToken
package model;
/**
* Created by xu on 2017/7/10.
*/
public class AccessToken {
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresin() {
return expiresin;
}
public void setExpiresin(int expiresin) {
this.expiresin = expiresin;
}
private String accessToken;
private int expiresin;
}
JsapiTicket
package model;
/**
* Created by xu on 2017/7/12.
*/
public class JsapiTicket {
private String jsapiTicket;
private int expiresin;
public String getJsapiTicket() {
return jsapiTicket;
}
public void setJsapiTicket(String jsapiTicket) {
this.jsapiTicket = jsapiTicket;
}
public int getExpiresin() {
return expiresin;
}
public void setExpiresin(int expiresin) {
this.expiresin = expiresin;
}
}
新建一个HttpServlet,AccessTokenServlet,用来执行获取,初始化的过程中执行,这里需要配置web.xml
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>wechatServlet</servlet-name>
<servlet-class>com.wecahtServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>wechatServlet</servlet-name>
<url-pattern>/wechat</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>GetConfigServlet</servlet-name>
<servlet-class>com.GetConfigServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetConfigServlet</servlet-name>
<url-pattern>/getConfig</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ReturnRobotServlet</servlet-name>
<servlet-class>com.ReturnRobotServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ReturnRobotServlet</servlet-name>
<url-pattern>/doReturn</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>initAccessTokenServlet</servlet-name>
<servlet-class>
com.AccessTokenServlet
</servlet-class>
<init-param>
<param-name>appid</param-name>
<param-value>xxxx</param-value>
</init-param>
<init-param>
<param-name>appsecret</param-name>
<param-value>xxxx</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<welcome-file-list>
<welcome-file>returnRobot.jsp</welcome-file>
</welcome-file-list>
</web-app>
AccessTokenServlet
package com;
import util.TokenThread;
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 java.io.IOException;
/**
* Created by xu on 2017/7/10.
*/
@WebServlet(name = "AccessTokenServlet")
public class AccessTokenServlet extends HttpServlet {
public void init() throws ServletException {
TokenThread.appId = getInitParameter("appid"); //获取servlet初始参数appid和appsecret
TokenThread.appSecret = getInitParameter("appsecret");
System.out.println("appid:"+TokenThread.appId);
System.out.println("appSecret:"+TokenThread.appSecret);
new Thread(new TokenThread()).start(); //启动进程
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
二、获取jssdk配置
- 创建一个GetConfigServlet用以页面获取jssdk的配置信息
GetConfigServlet
package com;
import com.alibaba.fastjson.JSON;
import util.Sign;
import util.TokenThread;
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 java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* Created by xu on 2017/7/12.
*/
@WebServlet(name = "GetConfigServlet")
public class GetConfigServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String url = request.getParameter("url");
String jsapi_tickec = TokenThread.jsapiTicket.getJsapiTicket();
Map<String, String> jssdk = Sign.main(jsapi_tickec,url);
String str = JSON.toJSONString(jssdk);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
try {
out = response.getWriter();
out.write(str);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get config test success");
}
}
上文中引用了sign工具类:
Sign
package util;
import java.util.UUID;
import java.util.Map;
import java.util.HashMap;
import java.util.Formatter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;
public class Sign {
public static Map<String, String> main(String jsapiTicket,String posturl) {
String jsapi_ticket = jsapiTicket;
// 注意 URL 一定要动态获取,不能 hardcode
String url = posturl;
Map<String, String> ret = sign(jsapi_ticket, url);
// for (Map.Entry entry : ret.entrySet()) {
// System.out.println(entry.getKey() + ", " + entry.getValue());
// }
return ret;
};
public static Map<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + 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();
}
ret.put("url", url);
ret.put("appId", TokenThread.appId);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
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;
}
private static String create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
前段js:
$(document).ready(function () {
//获取配置信息
$.ajax({
url : "http://120.77.43.103/wechat/getConfig",
type : 'post',
dataType : 'json',
contentType : "application/x-www-form-urlencoded; charset=utf-8",
data : {
'url' : location.href.split('#')[0]
},
success : function(data) {
console.log(data);
wx.config({
debug : true,
appId : data.appId,
timestamp : data.timestamp,
nonceStr : data.nonceStr,
signature : data.signature,
jsApiList : [ 'checkJsApi', 'onMenuShareTimeline',
'onMenuShareAppMessage', 'onMenuShareQQ',
'onMenuShareWeibo', 'hideMenuItems',
'showMenuItems', 'hideAllNonBaseMenuItem',
'showAllNonBaseMenuItem', 'translateVoice',
'startRecord', 'stopRecord', 'onRecordEnd',
'playVoice', 'pauseVoice', 'stopVoice',
'uploadVoice', 'downloadVoice', 'chooseImage',
'previewImage', 'uploadImage', 'downloadImage',
'getNetworkType', 'openLocation', 'getLocation',
'hideOptionMenu', 'showOptionMenu', 'closeWindow',
'scanQRCode', 'chooseWXPay',
'openProductSpecificView', 'addCard', 'chooseCard',
'openCard' ]
});
},
error: function (xhr, type) {
showAlert("getJSSDKSignature出错");
},
});
checkUserDeposit();
});
function checkUserDeposit() {
wx.ready(function () {
scanQRCode();
});
}
function scanQRCode() {
wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
//var result = "linuxserl.honeybot.cn:5120/download/?id=bind@104@10V1BLH100040478054";
//var result = "CODE_128,10V1BLH100261";
var postCode = "";
var robotCodeType = 0;
if (result.indexOf(",") > -1) {
//条形码
var codes = result.split(',');
if (codes != null && codes.length > 1) {
postCode = codes[1];
robotCodeType = 1;
}
} else {
//二维码
var reg = /@(.*?)@/;
var codes = reg.exec(result);
if (codes.length > 1) {
postCode = codes[1];
robotCodeType = 0;
}
}
showConfirm("是否确认退还?",
function () {
returnRobot(robotCodeType, postCode);
});
}
});
}
function returnRobot(robotCodeType, robotCodeValue) {
var dialogLoading = null;
var postData = {
robot_code:
{
robot_code_type: robotCodeType,
robot_code_value: robotCodeValue
}
}
$.ajax({
type: 'POST',
cache: false,
url: "http://120.77.43.103/wechat/doReturn",
data: "json_body=" + JSON.stringify(postData),
dataType: 'json',
beforeSend: function (XHR) {
dialogLoading = showLoading();
},
success: function (data) {
if (data.result_code == 0) {
setTimeout(function() {
showAlert("申请退还机器人成功,请点击确定支付租金", function () {
goTo(config.page_url.return_robot_wait_confrm);
});
}, 500);
} else {
setTimeout(function () {
showAlert(data.result_message);
}, 500);
}
},
error: function (xhr, type) {
showAlert('error')
},
complete: function (xhr, type) {
dialogLoading.hide();
}
});
}
wx.error(function (res) {
showAlert("微信接口出错");
});
三、额外的一些签名,验证配置
wecahtServlet
package com;
import com.sun.tools.classfile.Signature;
import util.CheckUtil;
import util.Sign;
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 java.io.IOException;
/**
* Created by xu on 2017/7/10.
*/
@WebServlet(name = "wecahtServlet")
public class wecahtServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if( CheckUtil.checkSignature(signature,timestamp,nonce))
{
response.getWriter().println(echostr);
}
}
}
工具类CheckUtil
package util;
import java.util.Arrays;
/**
* Created by xu on 2017/7/10.
*/
public class CheckUtil
{
private static final String token = "test";
public static boolean checkSignature(String signature,String timestamp,String nonce)
{
String[] arr = new String[]{token,timestamp,nonce};
//排序
Arrays.sort(arr);
//生成字符串
StringBuffer content = new StringBuffer();
for (int i=0;i<arr.length;i++)
{
content.append(arr[i]);
}
//sha1加密
String temp = Decript.SHA1(content.toString());
//校验签名
return temp.equals(signature);
}
}
sha1
package util;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by xu on 2017/7/10.
*/
public class Decript {
public static String SHA1(String decript) {
try {
MessageDigest digest = MessageDigest
.getInstance("SHA-1");
digest.update(decript.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 "";
}
}
引用JdbcUtils jdbc连接工具类
package util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcUtils
{
private static String url="jdbc:mysql://xxx.xxx.xxx/weixin?useUnicode=true&characterEncoding=utf-8";
private static String user="xxx";
private static String password="xxx";
private JdbcUtils()
{
}
static
{
try
{
Class.forName("com.mysql.jdbc.Driver");
}
catch(ClassNotFoundException e)
{
throw new ExceptionInInitializerError(e);
}
}
public static Connection getConnection() throws SQLException
{
return DriverManager.getConnection(url, user, password);
}
public static void free(ResultSet resultset,Statement st,Connection conn)
{
//6.释放资源
try{
if(resultset!=null)
resultset.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
try
{
if(st!=null)
st.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
if(conn!=null)
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}