微信jsapi 調用分享接口(完整版)

1.測試環境

申請測試賬號

地址: https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

填寫內容:

    ①:接口配置信息

        url:配置http://+域名或者http://+外網ip也可以

        token:自定義(任意)

        js安全域名(要和url的中的域名)

  提交配置信息時微信會先進行驗證所以你需要在能訪問的url對應的服務上面進行驗證代碼如下:  能夠打印出System.out.println("echostr:"+echostr);的值驗證成功.

微信會通過你配置的url+代碼中(/) 在你提交接口配置信息時,微信服務會請求到前面敘述的那個路徑,來驗證成功即能打印出echostr值(關鍵的一步,如果驗證不通過,後續開發沒辦法進行)

/**
* 微信消息接收和token驗證
*
* @param reqDate
* @param request
* @param response
* @throws IOException
value的值你可以自定義,但是要保證和url的一致性
*/
@RequestMapping(value = {"/"}, method = {RequestMethod.POST, RequestMethod.GET})
public void get(@RequestBody(required = false) String reqDate, HttpServletRequest request,
                HttpServletResponse response) throws Exception {
    boolean isGet = request.getMethod().toLowerCase().equals("get");
    PrintWriter print;
    if (isGet) {
        // 微信加密簽名
        String signature = request.getParameter("signature");
        // 時間戳
        String timestamp = request.getParameter("timestamp");
        // 隨機數
        String nonce = request.getParameter("nonce");
        // 隨機字符串
        String echostr = request.getParameter("echostr");
        // 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
        if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {
            try {
                print = response.getWriter();
                print.write(echostr);
                print.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("echostr:"+echostr);
    }
}
public class CheckoutUtil {
    private static String token = "weixin"; //與在後臺配置的Token一樣
    /**
     * 驗證簽名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 將token、timestamp、nonce三個參數進行字典序排序
        // Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;
        try {
            md = MessageDigest.getInstance("SHA-1");
            // 將三個參數字符串拼接成一個字符串進行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 將sha1加密後的字符串可與signature對比,標識該請求來源於微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }
    /**
     * 將字節數組轉換爲十六進制字符串
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }


    /**
     * 將字節轉換爲十六進制字符串
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];
        String s = new String(tempArr);
        return s;
    }
    public static void sort(String a[]) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }
}

 

②:JS接口安全域名(注意:是域名不是url不要攜帶 http://,直接填寫域名否側報錯:invalid url domain)

2.關注測試號二維碼(不重要)

url/token/js域名配置都成功之後就可以開始開發了

 

3.前端頁面代碼如下:

$.ajax({
    type: "POST",
    url: 'http://www.innshine.com/wechat/token',
    // contentType: "application/json; charset=utf-8",
    dataType: "JSON",
    data:{"url":location.href.split('#')[0]},//url一定要是當前的頁面的路徑而且出去#後面的(微信規定),後臺加需要url
    success: function (res) {
        console.log('res', res)
        wx.config({
            debug: true, // 開啓調試模式,調用的所有api的返回值會在客戶端alert出來,若要查看傳入的參數,可以在pc端打開,參數信息會通過log打出,僅在pc端時纔會打印。
            appId: 'wxae743829eed54eaa', // 必填,公衆號的唯一標識
            timestamp: res.timestamp, // 必填,生成簽名的時間戳
            nonceStr: res.noncestr, // 必填,生成簽名的隨機串
            signature: res.signature,// 必填,簽名
            jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'] // 必填,需要使用的JS接口列表
        });

        wx.ready(function () {   //需在用戶可能點擊分享按鈕前就先調用
            wx.updateAppMessageShareData({
                title: 'test', // 分享標題
                desc: 'test列表', // 分享描述
                link: 'http://www.innshine.com/wechat/index.html', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公衆號JS安全域名一致
                imgUrl: 'http://www.innshine.com/wechat/images/down.jpg', // 分享圖標
            }, function (res) {
                console.info("success")
            });
            

            wx.updateTimelineShareData({
                title: 'test', // 分享標題
                link: 'http://www.innshine.com/wechat/index.html', // 分享鏈接,該鏈接域名或路徑必須與當前頁面對應的公衆號JS安全域名一致
                imgUrl: 'http://www.innshine.com/wechat/images/down.jpg', // 分享圖標
            }, function (res) {
                console.info("success")
            });
           



        });
        wx.error(function (res) {
            //打印錯誤消息。及把 debug:false,設置爲debug:ture就可以直接在網頁上看到彈出的錯誤提示
            alert("錯誤error" + JSON.stringify(res));
        });
    }
})

4.後端代碼:

controller

@Autowired
WxJsApiServer wxJsApiServer;
@Autowired
Properties properties;


@RequestMapping("token")
public  Map<String, String> getJsapiTicket(String url)throws DigestException {
     String token = wxJsApiServer.getAccessTokenByAppIdAndSecret(properties.getAPPID(),properties.getAPPSECRET());
     String ticket = wxJsApiServer.getJsApiTicketByToken(token);
     return  getSign(url,ticket);
}


//url:去掉不包含#之後的路徑
public  Map<String, String> getSign(String url,String ticket ) throws DigestException {
//注意哥哥蠶食都是小寫的不要有大寫(微信加密參數規則要求)
   HashMap<String,String> map = new HashMap<String,String>();
   map.put("jsapi_ticket",ticket);
   map.put("noncestr",SHA1.generateNonceStr());
   map.put("timestamp",String.valueOf(SHA1.getCurrentTimestamp()));//注意:一定要重視這一點參加加密的時間戳是秒級的值 不要使用毫秒值
   map.put("url",url);
   //生成signature
   String signature=SHA1.getSha1Encode(map);
   map.put("signature",signature);
   logger.info("signature:{}",signature);
   return map;
}

properties:參數實體類

@Component
@Data
public class Properties {
/**
* 獲取token接口
*/
@Value("${wx.token}")
private String GetPageAccessTokenUrl;
/**
* 獲取ticket接口
*/
@Value("${wx.ticket}")
private String GetJsapiTicketUrl;
/**
* 公衆號標識
*/
@Value("${wx.appid}")
private String APPID;
/**
* 公衆號驗證所需參數(必須)
*/
@Value("${wx.secret}")
private String APPSECRET;
}

server

@Autowired
Properties properties;
@Override
public String getAccessTokenByAppIdAndSecret(String APPID, String SECRET) {
   String wxUrl = properties.getGetPageAccessTokenUrl().replace("APPID", properties.getAPPID()).replace("SECRET", properties.getAPPSECRET());
    HttpClient client = null;
    String accessToken = null;
    try {
        client = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(wxUrl);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String response = client.execute(httpget, responseHandler);
        JSONObject OpenidJSONO = JSONObject.parseObject(response);
        if (OpenidJSONO.get("access_token")==null){
            return "FALSE";
        }
        accessToken = String.valueOf(OpenidJSONO.get("access_token"));
        //緩存
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //關閉連接
        client.getConnectionManager().shutdown();
    }
    return accessToken;
}
@Override
public String getJsApiTicketByToken(String accessToken) {
    String requestUrl = properties.getGetJsapiTicketUrl().replace("ACCESS_TOKEN", accessToken);
    HttpClient client = null;
    String ticket = null;
    try {
        client = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(requestUrl);
        ResponseHandler<String> responseHandler = new BasicResponseHandler();
        String response = client.execute(httpget, responseHandler);
        JSONObject OpenidJSONO = JSONObject.parseObject(response);
        if (OpenidJSONO.get("ticket") == null) {
            return "FALSE";
        }
        ticket = String.valueOf(OpenidJSONO.get("ticket"));
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        client.getConnectionManager().shutdown();
    }
    return ticket;
}

sha1加密

public class    SHA1 {
    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();
    /**
     * Takes the raw bytes from the digest and formats them correct.
     *
     * @param bytes the raw bytes from the digest.
     * @return the formatted bytes.
     */
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        // 把密文轉換成十六進制的字符串形式
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
//            Formatter formatter = new Formatter();
//            for (byte b : bytes)
//            {
//                formatter.format("%02x", b);
//            }
//            String result = formatter.toString();
//            formatter.close();
//            return result;
    }
    public static String encode(String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            messageDigest.update(str.getBytes("UTF-8"));
            byte[]  bytes= messageDigest.digest();
            int len = bytes.length;
            StringBuilder buf = new StringBuilder(len * 2);
            // 把密文轉換成十六進制的字符串形式
            for (int j = 0; j < len; j++) {
                buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0xf]);
                buf.append(HEX_DIGITS[bytes[j] & 0xf]);
            }
            return buf.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static String getSha1(String str){
        if(str == null || str.length()==0){
            return null;
        }
        char hexDigits[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(str.getBytes("UTF-8"));
            byte[] md = mdTemp.digest();
            int j = md.length;
            char buf[] = new char[j*2];
            int k = 0;
            for(int i=0;i<j;i++){
                byte byte0 = md[i];
                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
                buf[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(buf);
        } catch (Exception e) {
            return null;
        }
    }


    /**
     * 獲取隨機字符串 Nonce Str
     *
     * @return String 隨機字符串
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
    /**
     * 獲取當前時間戳,單位秒
     * @return
     */
    public static long getCurrentTimestamp() {
        return System.currentTimeMillis()/1000;
    }
    /**
     * 獲取當前時間戳,單位毫秒
     * @return
     */
    public static long getCurrentTimestampMs() {
        return System.currentTimeMillis();
    }
    /**
     * SHA1 安全加密算法
     *
     * @return
     * @throws DigestException
     */
    public static String getSha1Encode(Map<String, String> map)  {
        String encode = encode(getOrderByLexicographic(map));
        return encode;
    }




    public static String getOrderByLexicographic(Map<String, String> map) {
        return splitParams(lexicographicOrder(getParamsName(map)), map);
    }
    /**
     * 拼接參數
     *
     * @param paramNames
     * @param maps
     * @return
     */
    public static String splitParams(List<String> paramNames, Map<String, String> maps) {
        StringBuilder params = new StringBuilder();
        for (String paramName : paramNames) {
            params.append(paramName);
            for (Map.Entry<String, String> entry : maps.entrySet()) {
                if (paramName.equals(entry.getKey())) {
                    params.append("=" + String.valueOf(entry.getValue()) + "&");
                }
            }
        }
        params.deleteCharAt(params.length() - 1);
        return params.toString();
    }
    /**
     * 參數按字典順序排序
     *
     * @param paramNames 參數集合
     * @return 返回排序集合
     */
    public static List<String> lexicographicOrder(List<String> paramNames) {
        Collections.sort(paramNames);
        return paramNames;
    }
    /**
     * 獲取參數名稱 key
     *
     * @param maps
     * @return
     */
    public static List<String> getParamsName(Map<String, String> maps) {
        List<String> paramNames = new ArrayList<String>();
        for (Map.Entry<String, String> entry : maps.entrySet()) {
            paramNames.add(entry.getKey());
        }
        return paramNames;
    }

httputile:

public class HttpUtils {
    /**
     * get請求,參數拼接在地址上
     * @param url 請求地址加參數
     * @return 響應
     */
    public static String get(String url,String AccessToken)
    {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        url = url.replaceAll(" ","%20");
        HttpGet get = new HttpGet(url);
        if(AccessToken != null && !AccessToken.equals("")){
            get.addHeader("Authorization",AccessToken);
        }
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(get);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * get請求,參數放在map裏
     * @param url 請求地址
     * @param map 參數map
     * @return 響應
     */
    public static String getMap(String url,String AccessToken,Map<String,String> map)
    {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();
        for(Map.Entry<String,String> entry : map.entrySet())
        {
            pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
        }
        CloseableHttpResponse response = null;
        try {
            URIBuilder builder = new URIBuilder(url);
            builder.setParameters(pairs);
            HttpGet get = new HttpGet(builder.build());
            if(AccessToken != null && !AccessToken.equals("")){
                get.addHeader("Authorization",AccessToken);
            }
            response = httpClient.execute(get);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * 發送post請求,參數用map接收
     * @param url 地址
     * @param map 參數
     * @return 返回值
     */
    public static  String postMap(String url,Map<String,String> map) {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost post = new HttpPost(url);
        post.addHeader("Content-Type", "application/json");
        List<NameValuePair> pairs = new ArrayList<NameValuePair>();
        if (map != null){
            for(Map.Entry<String,String> entry : map.entrySet())
            {
                pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
            }
        }
        CloseableHttpResponse response = null;
        try {
            post.setEntity(new UrlEncodedFormEntity(pairs,"UTF-8"));
            response = httpClient.execute(post);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * 發送post請求,參數用map<String object>接收
     * @param url
     * @param map
     * @param encoding
     * @return
     */
    public static String mapPost(String url, Map<String,Object> map, String encoding){
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = null;
        String result = null;
        try{
             httpClient = HttpClients.createDefault();
            httpPost = new HttpPost(url);
            //設置參數
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            Iterator iterator = map.entrySet().iterator();
            while(iterator.hasNext()){
            Map.Entry<String,String> elem = (Map.Entry<String, String>) iterator.next();
            list.add(new BasicNameValuePair(elem.getKey(),String.valueOf(elem.getValue())));
            }
            if(list.size() > 0){
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,encoding);
            httpPost.setEntity(entity);
            }
            HttpResponse response = httpClient.execute(httpPost);
            if(response != null){
            HttpEntity resEntity = response.getEntity();
            if(resEntity != null){
            result = EntityUtils.toString(resEntity,encoding);
            }
            }
            }catch(Exception ex){
            ex.printStackTrace();
            }
            System.out.println(result);
        return result;
    }
    /**
     * post請求,參數爲json字符串
     * @param url 請求地址
     * @param jsonString json字符串
     * @return 響應
     */
    public static String postJson(String url,String jsonString,String AccessToken)
    {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost post = new HttpPost(url);
        post.addHeader("Content-Type", "application/json");
        if(AccessToken != null && !AccessToken.equals("")){
            post.addHeader("Authorization",AccessToken);
        }
        CloseableHttpResponse response = null;
        try {
            if(jsonString != null && !jsonString.equals("")){
                post.setEntity(new ByteArrayEntity(jsonString.getBytes("UTF-8")));
            }
            response = httpClient.execute(post);
            if(response != null && response.getStatusLine().getStatusCode() == 200)
            {
                HttpEntity entity = response.getEntity();
                result = entityToString(entity);
            }
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                httpClient.close();
                if(response != null)
                {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    private static String entityToString(HttpEntity entity) throws IOException {
        String result = null;
        if(entity != null)
        {
            long lenth = entity.getContentLength();
            if(lenth != -1 && lenth < 2048)
            {
                result = EntityUtils.toString(entity,"UTF-8");
            }else {
                InputStreamReader reader1 = new InputStreamReader(entity.getContent(), "UTF-8");
                CharArrayBuffer buffer = new CharArrayBuffer(2048);
                char[] tmp = new char[1024];
                int l;
                while((l = reader1.read(tmp)) != -1) {
                    buffer.append(tmp, 0, l);
                }
                result = buffer.toString();
            }
        }
        return result;
    }


}

正式環境開發:

        登錄公衆號平臺:

                配置兩處:

                    1.導航"基礎配置"中配置url/token,配置要求和測試配置一樣.

                    2.再在"基礎配置"的"ip白名單"添加項目所要部署到的服務器的ip.

                    3.導航"公衆號設置"中再點擊"功能設置"然後配置"js安全域配置,注意此時需要下載一個文件MP_verify_gt5yNwRcoQWm4SIk.txt,文件可在彈出窗口中的提示出獲取,文件下載以後*(springboot項目爲例)放在static目錄下,然後通過上面配置的url+文件名,頁面響應一串字符串即代表成功.

 

正是開發代碼和測試代碼一樣.

 

微信 JS 接口簽名校驗工具: https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

 

nginx配置

  安裝和配置過程可以自己百度:

注意點給大家說一下:nginx.conf文件

server {
       listen       8089;//只是服務器開放的端口並不是項目端口號,但是卻要和項目的端口號保持一致.默認是80端口
       server_name  www.innshines.com;//你自己的域名
       location /wxshare {
           # root   html;
           # index  index.html index.htm;
            proxy_pass   http://127.0.0.1:8089;//項目部署所在的服務器的本地ip,端口記得要開放而且要在防火牆的白名單中放行端口
        }
    }

 

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