java版本微信jssdk、微信验证签名demo(Servlet)
开发背景
- 最近在学习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";@Overridepublic 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() {@Overridepublic boolean verify(String arg0, SSLSession arg1) {return true;}});con.setDoInput(true); //允许输入流,即允许下载//在android中必须将此项设置为falsecon.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() {@Overridepublic X509Certificate[] getAcceptedIssuers() {// TODO Auto-generated method stubreturn null;}@Overridepublic void checkServerTrusted(X509Certificate[] arg0, String arg1)throws CertificateException {// TODO Auto-generated method stub}@Overridepublic 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和appsecretTokenThread.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 一定要动态获取,不能 hardcodeString 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 StringStringBuffer 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 blocke.printStackTrace();}finally{try{if(st!=null)st.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{if(conn!=null)try {conn.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}
}
完整项目地址:https://github.com/345632699/...
java版本微信jssdk、微信验证签名demo(Servlet)相关推荐
- ##iOS中的微信支付 支付验证签名失败
iOS中的微信支付 支付验证签名失败 今天要在项目中添加微信支付,iOS端的所有东西都已经按照文档搞好了,可就是跳转到微信的时候显示"支付验证签名失败",可是安卓端的都没有问题,就 ...
- 视频教程-微信公众号实战(Java版本,带前后台)-微信开发
微信公众号实战(Java版本,带前后台) 2018年5月创办 威海科进网络科技有限公司,这里的视频主要是为了做个记录,方便员工提升自己的水平 陈健 ¥29.00 立即订阅 扫码下载「CSDN程序员学院 ...
- 微信js扫一扫,扫条形码去掉code_128。在vue中封装全局对象的方法,封装微信js-sdk权限验证的方法
微信公众号在调用扫一扫功能时,一维码(条形码)在直接返回结果时会在结果前带上EAN_8, EAN_13, CODE_25, CODE_39, CODE_128, UPC_A, UPC_E wx.sca ...
- php 微信支付md5签名,微信支付回调验证签名处理
微信支付回调验证签名:一定要验证签名,可能不造成伪造数据,或者数据库造到灌水: /** * 微信支付回调类 * @name callbackaction.class.php * @author yan ...
- 微信JSSDK invalid signature签名错误的解决方法
导致签名错误的原因: 微信文档给出以下原因. invalid signature签名错误:建议按如下顺序检查: 确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cg ...
- 微信jssdk ajax 获取签名,【Golang版】微信access_token、jsapi_ticket、signature签名算法生成示例,开箱即用...
# WXToken 项目地址:[https://github.com/henson/WXToken](https://github.com/henson/WXToken) 因为手上有一个项目需要用到微 ...
- ios不行安卓可以 微信签名_微信支付-支付验证签名失败(iOS)
在项目中添加微信支付,iOS端的所有东西都已经按照文档搞好了,可就是跳转到微信的时候显示"支付验证签名失败",可是安卓端的都没有问题,就很郁闷了. 后来在对文档的时候发现... 6 ...
- 微信支付 支付验证签名失败
公众号支付,WeixinJSBridge.invoke()方法,返回错误:支付验证签名失败 检查后台签名参数.支付密钥均正确,却还是错误,最后询问微信支付技术才解决,问题所在就是微信给的java sd ...
- 对hash签名失败_vue项目中微信jssdk在ios签名失败
一.问题描述 1. vue项目中微信jssdk签名时,在安卓和ios是有差异的,签名时使用的url=window.location.href.split('#')[0],此时在安卓没问题,在ios会导 ...
最新文章
- 基于Spring AOP的JDK动态代理和CGLIB代理
- vs shortcut
- System.arraycopy用法
- Andriod UI设计之度量单位说明(DIP,DP,PX,SP)
- Javascript特效:利用封装动画函数模拟关闭安全管家弹窗
- NVMe驱动解析-DMA传输
- js拆分百分数_计算百分比Javascript
- 自己做的js甘特图插件
- matlab绘图 作业,实验作业2 - -MATLAB作图
- Spring bean解析 - refresh
- 谈谈Android 6.0 的动态权限管理
- 教师如何创建在线查分系统
- PHP 将xml文件解析为数组
- SecureCRT的下载安装
- 第一篇Blog:电动汽车与燃料电池汽车
- Linux下安装rar解压
- Docker镜像与仓库(四)
- 在easydl平台上传已经标注好的数据,怎么按照要求进行json和图片格式配置。是用labellmg图片标注工具生成的xml文件。
- STM32F103C8 TIM1 CHN PWM输出代码
- 论文写作 3: 慎用的单词与短语