java版本微信jssdk、微信验证签名demo(Servlet)

开发背景

  1. 最近在学习java,所以从网上看了一些别人的代码,再加入了自己的一些理解,主要是担心之后会忘记,所以写下一篇东西记录一下思路。
一、 获取acess_token以及jsapiTicket
  1. 新建一个类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配置
  1. 创建一个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 +
                "&timestamp=" + 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();
                    }
            }
        }
    }
}

完整项目地址:https://github.com/345632699/...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值