微信jsApiSdk對接

博主使用jfinal框架

微信開發文檔

https://mp.weixin.qq.com/wiki/11/74ad127cc054f6b80759c40f77ec03db.html

對接過程:
    1.在公衆號上面填寫好域名指向、獲取功能權限
    2.看開發文檔、獲取簽名算法、獲取前端接口。
    3.獲取access_token、jsapi_ticket
    4.驗證
出現的問題:
    簽名不一致、
    最後發現是寫入txt文件的時候加了"\n\s";
建議:
    從:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign
    這個驗籤中string1 與你打印出來一至的話
    就是可能是timestamp、noncestr、jsapi_ticket出問題
    如果是外寫jsapi_ticket更要注意。
其他問題想看文檔的:
    附錄5-常見錯誤及解決方法

簽名算法用官網的例子 Sign類:

import java.util.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.UnsupportedEncodingException;

public class Sign {
    public static void main(String[] args) {
        String jsapi_ticket = "jsapi_ticket";

        // 注意 URL 一定要動態獲取,不能 hardcode
        String url = "http://example.com";
        Map<String, String> ret = sign(jsapi_ticket, url);
        for (Map.Entry entry : ret.entrySet()) {
            System.out.println(entry.getKey() + ", " + entry.getValue());
        }
    }
    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 (int)(System.currentTimeMillis() / 1000)+"";
    }
}

寫個週期任務 Task
由於微信的限制訪問次數

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by cwq on 2017/3/4.
 * jdk 1.8
 */
public class Task {
    private Runnable runnable = new Runnable() {
        public void run() {
            System.out.println("默認一個小時一次執行任務 !!");
        }
    };//執行線程
    private long initialDelay = 0;//初始化延時
    private long period = 1;//兩次開始執行最小間隔時間
    private TimeUnit unit = TimeUnit.HOURS;//計時單位

    public Runnable getRunnable() {
        return runnable;
    }

    public void setRunnable(Runnable runnable) {
        this.runnable = runnable;
    }

    public long getInitialDelay() {
        return initialDelay;
    }

    public void setInitialDelay(long initialDelay) {
        this.initialDelay = initialDelay;
    }

    public long getPeriod() {
        return period;
    }

    public void setPeriod(long period) {
        this.period = period;
    }

    public TimeUnit getUnit() {
        return unit;
    }

    public void setUnit(TimeUnit unit) {
        this.unit = unit;
    }

    public void run() {
        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        service.scheduleAtFixedRate(runnable, initialDelay, period, unit);
    }

調用類

package com.se.activities.utils.wechatjs.task;

import com.se.activities.utils.WechatConfig;
import com.se.activities.utils.wechatjs.FileOperation;
import com.se.sdk.oauth.util.HttpKit;
import com.se.utils.PropertyUtil;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

/**
 * Created by cwq on 2017/3/4.
 * jdk 1.8
 */
public class WeChatJsApiTask {
    private final static Logger logger = LoggerFactory.getLogger(WeChatJsApiTask.class);//日誌
    private static String getJsApiAccessToken = "https://api.weixin.qq.com/cgi-bin/token?" +
            "grant_type=client_credential&appid=APPID&secret=APPSECRET";//參考以下文檔獲取access_token(有效期7200秒,開發者必須在自己的服務全局緩存access_token)
    private static String getJsApiTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" +
            "access_token=ACCESS_TOKEN&type=jsapi";
    private static String appId = "xxx";//  公衆號的唯一標識
    private static String appSecret = "xxx";//公衆號的appsecret
    public static String activitiesPicDir = "";//博主使用存文件的方式存tick 文件物理路徑


    private Runnable runnable = new Runnable() {
        public void run() {
            getTick();
        }
    };//執行線程

    //更新微信的 js_ticket
    private void getTick(){
        String url = getJsApiAccessToken.replace("APPID", appId).replace("APPSECRET", appSecret);
        String res = HttpKit.get(url);

        String access_token = "0";
        try {
            JSONObject jsonObject = new JSONObject(res);
//            {"access_token":"ACCESS_TOKEN","expires_in":7200}
//            {"errcode":40013,"errmsg":"invalid appid"}
            if(jsonObject.get("access_token")!=null) access_token = jsonObject.getString("access_token");
            if(jsonObject.get("access_token")==null) {
                System.out.println("@WeChatJsApiTask 取access_token失敗:["+res+"]");
            }
            if(!access_token.equals("0")){
                url = getJsApiTicket.replace("ACCESS_TOKEN", access_token);
                res = HttpKit.get(url);
//                System.out.println(res);
                jsonObject = new JSONObject(res);
                if(jsonObject.getString("errmsg").equals("ok")){
                    String ticket = jsonObject.getString("ticket");
                    File file = new File(activitiesPicDir+ File.separatorChar+"JsApiTask.txt");
                    FileOperation.createFile(file);
                    FileOperation.writeTxtFile(ticket,file);
                    System.out.println("@WeChatJsApiTask 取js_ticket:["+ticket+"]");
                }else{
                    System.out.println("@WeChatJsApiTask 取ticket失敗:["+res+"]");
                }
            }
            /*
            {"errcode":0,"errmsg":"ok",
            "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
            "expires_in":7200
            }
            */
        } catch (JSONException e) {
            logger.error("轉換jsonObject有錯,或者不在參數", e);
        }
    }

    public void run() {
        Task task = new Task();
        task.setRunnable(runnable);
        task.run();
        System.out.println("執行週期性任務任務>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        System.out.println("微信JS-SDK憑證更新>>>>>>>");
        System.out.println("初始化延時>>>>>>>>>>>>>>>" + task.getInitialDelay());
        System.out.println("兩次開始執行最小間隔時間>>>" + task.getPeriod());
        System.out.println("計時單位>>>>>>>>>>>>>>>>>" + task.getUnit());
        System.out.println("執行週期性任務任務<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    }
}

寫入文件用到的類

package com.se.activities.utils.wechatjs;

import java.io.*;

/**
 * Created by cwq on 2017/3/4.
 * jdk 1.8
 */
public class FileOperation {

    /**
     * 創建文件
     *
     * @param fileName
     * @return
     */
    public static boolean createFile(File fileName) {
        boolean flag = false;
        try {
            if (!fileName.exists()) {
                fileName.createNewFile();
                flag = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }
    /**
     * 讀TXT文件內容
     *
     * @param fileName
     * @return
     */
    public static String readTxtFile(File fileName){
        String result = "";
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        try {
            fileReader = new FileReader(fileName);
            bufferedReader = new BufferedReader(fileReader);
            try {
                String read = "";
                while ((read = bufferedReader.readLine()) != null) {
                    result = result + read;//可憐的博主在這裏+了"/n/s" 然後簽名一直都不成功
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
                if (fileReader != null) {
                    fileReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 
     * @param content
     * @param fileName
     * @return
     * @throws Exception
     */
    public static boolean writeTxtFile(String content, File fileName){
        RandomAccessFile mm = null;
        boolean flag = false;
        FileOutputStream o = null;
        try {
            o = new FileOutputStream(fileName);
            o.write(content.getBytes("utf-8"));
            o.close();
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (mm != null) {
                    mm.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }
}

控制器加簽名 返回


 HttpServletRequest req = getRequest();
            String httpUrl = req.getScheme() + "://" + req.getServerName() + req.getContextPath()
                    + req.getServletPath() + "?" + req.getQueryString();
            httpUrl = httpUrl.split("#")[0];
            Map<String, String> JsApiSign = createJsApiSign(URLDecoder.decode(httpUrl));
            setAttr("JsApiSign", JsApiSign);
            Map<String, String> JsApi = createJsApiSign(httpUrl);
            JsApi.put("imgUrl", index_child + "/dow_app_icon.svg");
            setAttr("JsApi", JsApi);

創建簽名

   private Map<String, String> createJsApiSign(String url) {
        String jsapi_ticket = FileOperation.readTxtFile(new File(activitiesPicDir + File.separatorChar + "JsApiTask.txt"));
        System.out.println("@handle createJsApiSign[jsapi_ticket:" + jsapi_ticket + "]");
        Map<String, String> ret = Sign.sign(jsapi_ticket, url);
        ret.put("appId", appId);
        return ret;
    }

jsp調用文件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<c:if test="${JsApiSign!=null}">
    <%--<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>--%>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
    <script>
        wx.config({
            debug: false, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
            appId: '${JsApiSign.appId}', // 必填,公衆號的唯一標識
            timestamp:${JsApiSign.timestamp}, // 必填,生成簽名的時間戳
            nonceStr: '${JsApiSign.nonceStr}', // 必填,生成簽名的隨機串
            signature: '${JsApiSign.signature}',// 必填,簽名,見附錄1
            jsApiList: ["onMenuShareTimeline", "onMenuShareAppMessage"] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
        });

        var link = "${JsApiSign.url}";
        if (link.indexOf("is_share") == -1) link = link + "&is_share=1";
        wx.ready(function () {
            wx.onMenuShareTimeline({
                title: '', // 分享標題
                link: link, // 分享鏈接
                imgUrl: '${JsApi.imgUrl}', // 分享圖標
                success: function () {
                    // 用戶確認分享後執行的回調函數
                    weChatShare(1);//import的時候 頁面回調的方法
                },
                cancel: function () {
                    // 用戶取消分享後執行的回調函數
                }
            });
            wx.onMenuShareAppMessage({
                title: '', // 分享標題
                desc: '', // 分享描述
                link: link, // 分享鏈接
                imgUrl: '${JsApi.imgUrl}', // 分享圖標
                type: '', // 分享類型,music、video或link,不填默認爲link
                dataUrl: '', // 如果type是music或video,則要提供數據鏈接,默認爲空
                success: function () {
                    weChatShare(2);
                },
                cancel: function () {
                }
            });
        });

    </script>
</c:if>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章