微信开发-实现jsapi ticket

来源:互联网 发布:淘宝上便宜的羊毛被 编辑:程序博客网 时间:2024/05/18 01:34

 由于微信的对access_token 和 jssdk-ticket 都有有效期限制,在页面中调用jssdk函数时需要校验,实现思路如下:

1 在程序里用定时器或者开启线程每7000s计算一次access_token和jssdk-ticket;

2 将access_token 和jssdk-ticket 通过静态变量 static 存在内存中。

3 在action中,设置成员变量 signature,将获取静态变量jssdk-ticket值计算后赋予signature,通过get set 方式将成员变量的值传给jsp页面

4 在jsp页面中通过el表达式获取signature值,noncestr、timestamp,url等值。


程序jsp+action实现

1 编写initservlet类启动线程,在web.xml文件中配置servlet 实现程序启动时即运行servlet.

InitServlet.java

/** * Created by lr on 2015/6/11 */public class InitServlet extends HttpServlet {       public void init() throws ServletException {           new Thread(new TokenThread()).start();       }}

web.xml文件

<servlet>       <servlet-name>initServlet</servlet-name>       <servlet-class>cn.cp.wxphone.servlet.InitServlet</servlet-class>           <!-- 程序启动时开始执行 -->         <load-on-startup>0</load-on-startup></servlet>

TokenThread.java

2 在线程中将token、ticket存为静态变量,并实现定时计算。
package cn.cp.wxphone.Thread;import cn.cp.wxphone.manager.JsApiTicketManager;import cn.cp.wxphone.manager.TokenManager;import cn.cp.wxphone.pojo.Token;import cn.cp.wxphone.tag.AppTag;/** * Created by lr on 2015/6/11. */    public class TokenThread implements Runnable {        public static Token accessToken = null;        public static String jsApiTicket=null;        public void run() {            while (true) {                try {                    accessToken = TokenManager.getToken(AppTag.AppID,AppTag.AppSecret );                    jsApiTicket = JsApiTicketManager.getTicket().getJsi_Ticket();                        if (null != accessToken) {                        System.out.println("获取access_token成功,有效时长{}秒 token:{}" + "," + accessToken.getExpiresIn() + "," + accessToken.getAccessToken());                        // 休眠7000秒                        Thread.sleep((accessToken.getExpiresIn() - 200) * 1000);                        //  Thread.sleep(30*1000);                    } else {                        // 如果access_token为null,60秒后再获取                        Thread.sleep(60 * 1000);                    }                } catch (InterruptedException e) {                    try {                        Thread.sleep(60 * 1000);                    } catch (InterruptedException e1) {                        System.out.println("{}" + "," + e1);                    }                        System.out.println("{}" + "," + e);                }            }        }    }


appid和appsecret 在apptag类中定义为静态常量 public static final String APPID ="XXXXXX";


3 在action中获取静态变量ticket,并计算signatrue 。

action类  MarketAction.java

package cn.cp.wxphone.action;import cn.cp.wxphone.Thread.TokenThread;import cn.cp.wxphone.manager.JsApiTicketManager;import java.util.HashMap;import java.util.Map;/** * Created by lr on 2015/6/15. */public class MarketAction extends BaseAction {    //微信验证使用的变量 url,signature,AppId等    Map<String, String> entity = new HashMap<String, String>();    public String add() throws Exception {        JsApiTicketManager jsM = new JsApiTicketManager();        String url = "http://cpchat.cpgroup.cn/wxproject/marketAction_add.action";        System.out.println("获取thread中jsApiTicket" + TokenThread.jsApiTicket);        entity = jsM.sign(TokenThread.jsApiTicket, url);        return "success";    }    public Map<String, String> getEntity() {        return entity;    }    public void setEntity(Map<String, String> entity) {        this.entity = entity;    }}

JsApiTicketManager.java 实现计算ticket 和signature,生成随机字符串。

package cn.cp.wxphone.manager;import cn.cp.wxphone.pojo.JsiTicket;import cn.cp.wxphone.pojo.Token;import cn.cp.wxphone.tag.AppTag;import net.sf.json.JSONException;import net.sf.json.JSONObject;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;/** * Created by lr on 2015/6/17. */public class JsApiTicketManager {    private static final String jsiticket_url="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";    public static void main(String[] args){        JsApiTicketManager manager = new JsApiTicketManager();        JsiTicket ticket = manager.getTicket();        System.out.println("jsiTicket"+ticket.getJsi_Ticket());        String url ="http://cpchat.cpgroup.cn/wxproject/marketAction_add";        Map<String,String> resmap = new HashMap<String,String>();        resmap = manager.sign(ticket.getJsi_Ticket(),url);        for (Map.Entry entry : resmap.entrySet()){            System.out.println("KEY:"+entry.getKey()+"VALUE:"+entry.getValue() );        }    }   // 获取jsapi_ticket    public static JsiTicket getTicket() {         JsiTicket ticket =null;        TokenManager tokenManager = new TokenManager();        Token token = tokenManager.getToken(AppTag.AppID, AppTag.AppSecret);        String url =jsiticket_url.replace("ACCESS_TOKEN",token.getAccessToken());        // 请求获取ticket        JSONObject jsonObject= tokenManager.httpsRequest(url,"GET",null);        if(null!=jsonObject){            try {                ticket = new JsiTicket();                ticket.setJsi_Ticket(jsonObject.getString("ticket"));                ticket.setExpiresIn(jsonObject.getInt("expires_in"));            } catch (JSONException e) {                ticket = null;                // 获取ticket失败                System.out.println("获取ticket失败 errcode:{} errmsg:{}"+","+jsonObject.getInt("errcode")+","+jsonObject.getString("errmsg"));            }        }        return ticket;    }   //获取计算后的signature,及其它字段 noncestr,timestamp,jsapi_ticket    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("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);    }    }

url地址与自定义菜单中view类型button定义的url 一致。

4 jsp页面中获取action中的值

<%@ page contentType="text/html; charset=utf-8" language="java"%><!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.1 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><%@taglib prefix="s" uri="/struts-tags" %><html><head lang="en">    <meta charset="UTF-8">    <title>微信JS-SDK Demo</title>    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">    <link rel="stylesheet" href="css/style.css"></head><body ontouchstart=""><div class="wxapi_container">    <div class="lbox_close wxapi_form">        <h3 id="menu-location">地理位置接口</h3>        <span class="desc">使用微信内置地图查看位置接口</span>        <button class="btn btn_primary" id="openLocation">openLocation</button>        <span class="desc">获取地理位置接口</span>        <button class="btn btn_primary" id="getLocation">getLocation</button>    </div></div></body><script src="boot/js/jweixin-1.0.0.js"></script><script>    wx.config({        debug: true,        appId: 'wx4bffdab5471c8016',        timestamp: '${entity.timestamp}',        nonceStr: '${entity.nonceStr}',        signature: '${entity.signature}',        jsApiList: [            'chooseImage',            'previewImage',            'uploadImage',            'downloadImage',            'openLocation',            'getLocation'        ]    });</script></html>

 在使用el表达式时,出现了一些问题

如果是传数字类型 如 string tempStr=”123“ 时可写为 ${tempStr},但是当传字符时 应写为‘${tempStr}',要加‘单引号,调试时,因为这个问题浪费了很多时间。

之前一直搞不清楚jstl,el ,struct标签区别,及使用这里总结下

1) jsp页面中就支持EL表达式,在html中和javascript中均可通过${entity.name}的方式获取action中map类型的数据。

2)在jsp+struct2  的环境时,html中标签可使用struct标签来替代 text,button 等标签,能够简化textfield,select类型标签的取数。

3)jstl标签是el表达式的扩展,在有些日期类型的控件中,转换日期类型的数据比较方便。




0 0
原创粉丝点击