Java企业微信开发_07_JSSDK多图上传

简介: 一、本节要点 1.1可信域名  所有的JS接口只能在企业微信应用的可信域名下调用(包括子域名),可在企业微信的管理后台“我的应用”里设置应用可信域名。这个域名必须要通过ICP备案,不然jssdk会配置失败   1.2JS-SDK使用权限签名算法 1.2.1 签名生成规则如下: (1)参与签名的字段包括:           noncestr(随机字符串),          有效的jsapi_ticket,           timestamp(时间戳),           url(当前网页的URL,不包含#及其后面部分) 。

一、本节要点

1.1可信域名

 所有的JS接口只能在企业微信应用的可信域名下调用(包括子域名),可在企业微信的管理后台“我的应用”里设置应用可信域名。这个域名必须要通过ICP备案,不然jssdk会配置失败

 

1.2JS-SDK使用权限签名算法

1.2.1 签名生成规则如下:

(1)参与签名的字段包括:

          noncestr(随机字符串),

         有效的jsapi_ticket,

          timestamp(时间戳),

          url(当前网页的URL,不包含#及其后面部分) 。

(2)对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式 (即 key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。

(3)对string1进行sha1签名,得到signature:

1.2.2示例:

(1)待签名参数:

      noncestr=Wm3WZYTPz0wzccnW

      jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg

      timestamp=1414587457

      url=http://mp.weixin.qq.com

(2)字典序

string1=jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com

(3)sha1加密

signature=sha1(string1)

 

1.2.3代码示例:

 1     /**
 2      * 3.获取微信的JSSDK配置信息
 3      * @param request
 4      * @return
 5      */
 6     public static Map<String, Object> getWxConfig(HttpServletRequest request) {
 7         Map<String, Object> ret = new HashMap<String, Object>();
 8         //1.准备好参与签名的字段
 9 
10         String nonceStr = UUID.randomUUID().toString(); // 必填,生成签名的随机串
11         //System.out.println("nonceStr:"+nonceStr);
12         String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
13         String jsapi_ticket =getJsapiTicket(accessToken);// 必填,生成签名的H5应用调用企业微信JS接口的临时票据
14         //System.out.println("jsapi_ticket:"+jsapi_ticket);
15         String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳
16         //System.out.println("timestamp:"+timestamp);
17         String url=request.getRequestURL().toString();
18         //System.out.println("url:"+url);
19         
20         //2.字典序           ,注意这里参数名必须全部小写,且必须有序
21         String sign = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonceStr+ "&timestamp=" + timestamp + "&url=" + url;
22 
23         //3.sha1签名
24         String signature = "";
25         try {
26             MessageDigest crypt = MessageDigest.getInstance("SHA-1");
27             crypt.reset();
28             crypt.update(sign.getBytes("UTF-8"));
29             signature = byteToHex(crypt.digest());
30             //System.out.println("signature:"+signature);
31         } catch (NoSuchAlgorithmException e) {
32             e.printStackTrace();
33         } catch (UnsupportedEncodingException e) {
34             e.printStackTrace();
35         }
36         ret.put("appId", WeiXinParamesUtil.corpId);
37         ret.put("timestamp", timestamp);
38         ret.put("nonceStr", nonceStr);
39         ret.put("signature", signature);
40         return ret;
41     }
42 
43 
44     /**
45      * 方法名:byteToHex</br>
46      * 详述:字符串加密辅助方法 </br>
47      * 开发人员:souvc  </br>
48      * 创建时间:2016-1-5  </br>
49      * @param hash
50      * @return 说明返回值含义
51      * @throws 说明发生此异常的条件
52      */
53     private static String byteToHex(final byte[] hash) {
54         Formatter formatter = new Formatter();
55         for (byte b : hash) {
56             formatter.format("%02x", b);
57         }
58         String result = formatter.toString();
59         formatter.close();
60         return result;
61 
62     }
63     
64     
65     
66     private static String getExt(String contentType){
67         if("image/jpeg".equals(contentType)){
68             return ".jpg";
69         }else if("image/png".equals(contentType)){
70             return ".png";
71         }else if("image/gif".equals(contentType)){
72             return ".gif";
73         }
74         
75         return null;
76     }
View Code

 

二、代码实现

2.1 配置可信域名

在登录企业微信后台,配置应用:企业应用->自建应用->选择你的应用->网页授权及JS-SDK->输入你的域名。

这样安全域名就配置好了。

 

 

2.2 JSSDK的前端页面—JSSDKUploadPics.jsp

此页面完整代码:

<%@ page language="java" import="java.util.*"
    contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@page language="java" import="com.ray.util.WeiXinUtil"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<title>上传报销单</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<meta name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="js/jquery-3.2.1.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<style type="text/css">
html {
    -ms-text-size-adjust: 100%;
    -webkit-text-size-adjust: 100%;
    -webkit-user-select: none;
    user-select: none;
}

body {
    line-height: 1.6;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    background-color: #f1f0f6;
}

* {
    margin: 0;
    padding: 0;
}

button {
    font-family: inherit;
    font-size: 100%;
    margin: 0;
    *font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

ul, ol {
    padding-left: 0;
    list-style-type: none;
}

a {
    text-decoration: none;
}

.label_box {
    background-color: #ffffff;
}

.label_item {
    padding-left: 15px;
}

.label_inner {
    padding-top: 10px;
    padding-bottom: 10px;
    min-height: 24px;
    position: relative;
}

.label_inner:before {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    height: 1px;
    border-top: 1px solid #ededed;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    top: auto;
    bottom: -2px;
}

.lbox_close {
    position: relative;
}

.lbox_close:before {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    height: 1px;
    border-top: 1px solid #ededed;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
}

.lbox_close:after {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    height: 1px;
    border-top: 1px solid #ededed;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
    top: auto;
    bottom: -2px;
}

.lbox_close .label_item:last-child .label_inner:before {
    display: none;
}

.btn {
    display: block;
    margin-left: auto;
    margin-right: auto;
    padding-left: 14px;
    padding-right: 14px;
    font-size: 18px;
    text-align: center;
    text-decoration: none;
    overflow: visible;
    /*.btn_h(@btnHeight);*/
    height: 42px;
    border-radius: 5px;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    box-sizing: border-box;
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    color: #ffffff;
    line-height: 42px;
    -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
}

.btn.btn_inline {
    display: inline-block;
}

.btn_primary {
    background-color: #437DBA;
}

.btn_primary:not (.btn_disabled ):visited {
    color: #ffffff;
}

.btn_primary:not (.btn_disabled ):active {
    color: rgba(255, 255, 255, 0.9);
    background-color: #3b78b9;
}

button.btn {
    width: 100%;
    border: 0;
    outline: 0;
    -webkit-appearance: none;
}

button.btn:focus {
    outline: 0;
}

.wxapi_container {
    font-size: 16px;
}

h1 {
    font-size: 14px;
    font-weight: 400;
    line-height: 2em;
    padding-left: 15px;
    color: #8d8c92;
}

.desc {
    font-size: 14px;
    font-weight: 400;
    line-height: 2em;
    color: #8d8c92;
}

.wxapi_index_item a {
    display: block;
    color: #3e3e3e;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

.wxapi_form {
    background-color: #ffffff;
    padding: 0 15px;
    margin-top: 30px;
    padding-bottom: 15px;
}

h3 {
    padding-top: 16px;
    margin-top: 25px;
    font-size: 16px;
    font-weight: 400;
    color: #3e3e3e;
    position: relative;
}

h3:first-child {
    padding-top: 15px;
}

h3:before {
    content: " ";
    position: absolute;
    left: 0;
    top: 0;
    width: 200%;
    height: 1px;
    border-top: 1px solid #ededed;
    -webkit-transform-origin: 0 0;
    transform-origin: 0 0;
    -webkit-transform: scale(0.5);
    transform: scale(0.5);
}

.btn {
    margin-bottom: 15px;
}
</style>


</head>
<body>
    <%
        Map<String, Object> res = new HashMap<String, Object>();
        res = WeiXinUtil.getWxConfig(request);
        request.setAttribute("appId", res.get("appId"));
        request.setAttribute("timestamp", res.get("timestamp"));
        request.setAttribute("nonceStr", res.get("nonceStr"));
        request.setAttribute("signature", res.get("signature"));
    %>

<body>
    <div class="wxapi_container">

        <form action="" method="POST"></form>



        <div class="lbox_close wxapi_form">
            <h3 id="menu-basic">基础接口</h3>
            <span class="desc">判断当前客户端是否支持指定JS接口</span>
            <button class="btn btn_primary" id="checkJsApi">checkJsApi</button>

            <span class="desc">上传图片接口</span>
            <button class="btn btn_primary" id="uploadImage">uploadImage</button>
            <span class="desc">下载图片接口</span>
            <button class="btn btn_primary" id="downloadImage">downloadImage</button>


            <span class="desc">调起微信扫一扫接口</span>
            <button class="btn btn_primary" id="scanQRCode1">scanQRCode(直接返回结果)</button>

            <span class="desc">测试按钮</span>
            <button class="btn btn_primary" id="ceshi">ceshi</button>

        </div>
    </div>

    <script>
        /*
         * 注意:
         * 所有的JS接口只能在应用配置的安全域名下面使用。   
         *
         */
        wx.config({
            beta : true,
            debug : true,
            appId : '${appId}',
            timestamp : '${timestamp}',
            nonceStr : '${nonceStr }',
            signature : '${signature}',

            jsApiList : [ 'checkJsApi', 'chooseImage', 'previewImage',
                    'uploadImage', 'downloadImage', 'scanQRCode', ]
        });

        //通过ready接口处理成功验证
        wx.ready(function() {
            // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
            $("#ceshi").click(function() {
                alert("ceshi11111111");
            });

        });

        // 1 判断当前版本是否支持指定 JS 接口,支持批量判断
        $("#checkJsApi").click(function() {
            wx.checkJsApi({
                jsApiList : [ 'getNetworkType', 'previewImage' ],
                success : function(res) {
                    alert(JSON.stringify(res));
                }
            });
        });

        //2.拍照或从手机相册中选图接口
        var images = {
            localId : [],
            serverId : []
        };
        $("#uploadImage").click(function() {
            wx.chooseImage({
                success : function(res) {
                    images.localId = res.localIds;
                    alert('已选择 ' + res.localIds.length + ' 张图片');

                    uploadImg();
                }
            });
        });

        // 5.3 上传图片
        function uploadImg() {
            if (images.localId.length == 0) {
                alert('请先使用 chooseImage 接口选择图片');
                return;
            }
            var i = 0, length = images.localId.length;
            images.serverId = [];

            function upload() {
                wx
                        .uploadImage({
                            localId : images.localId[i],
                            success : function(res) {
                                i++;
                                alert('已上传:' + i + '/' + length);
                                images.serverId.push(res.serverId);
                                //将serverId上传至服务器
                                alert("ajax请求即将执行--");

                                $
                                        .ajax({
                                            type : "POST",
                                            url : "http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/uploadExpenseAccaoutServlet",
                                            data : {
                                                serverId : res.serverId
                                            },
                                            dataType : "text",
                                            success : function(data) {
                                                alert(data);
                                            }

                                        });

                                if (i < length) {
                                    upload();
                                }
                            },
                            fail : function(res) {
                                alert(JSON.stringify(res));
                            }
                        });
            }
            upload();
        };

        //点击扫描按钮,扫描二维码并返回结果
        document.querySelector('#scanQRCode1').onclick = function() {
            wx
                    .scanQRCode({
                        desc : 'scanQRCode desc',
                        needResult : 1,
                        success : function(res) {
                            //扫码后获取结果参数:htpp://xxx.com/c/?6123,截取到url中的防伪码后,赋值给Input
                            var result = res.resultStr;
                            alert(result);

                            $
                                    .ajax({
                                        type : "POST",
                                        url : "http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/qrservlet",
                                        data : {
                                            result : res.resultStr
                                        },
                                        dataType : "text",
                                        success : function(data) {
                                            alert(data);
                                        }

                                    });

                        }
                    });
        };
    </script>


</body>
</html>
View Code

 

 此页面主要包括:

(1)引入JS文件:

在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js

<script src="js/jquery-3.2.1.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
View Code

 

(2)调用后台WeiXinUtil.getWxConfig(HttpServletRequest request)方法,获取企业微信的JSSDK配置信息

    <%
        Map<String, Object> res = new HashMap<String, Object>();
        res = WeiXinUtil.getWxConfig(request);
        request.setAttribute("appId", res.get("appId"));
        request.setAttribute("timestamp", res.get("timestamp"));
        request.setAttribute("nonceStr", res.get("nonceStr"));
        request.setAttribute("signature", res.get("signature"));
    %>
View Code

 

(3)通过config接口注入权限验证配置

wx.config({
            beta : true,
            debug : true,
            appId : '${appId}',
            timestamp : '${timestamp}',
            nonceStr : '${nonceStr }',
            signature : '${signature}',

            jsApiList : [ 'checkJsApi', 'chooseImage', 'previewImage',
                    'uploadImage', 'downloadImage', 'scanQRCode', ]
        });
View Code

 

(4)选择图片与图片上传,以及通过ajax调用后台servlet

    //2.拍照或从手机相册中选图接口
        var images = {
            localId : [],
            serverId : []
        };
        $("#uploadImage").click(function() {
            wx.chooseImage({
                success : function(res) {
                    images.localId = res.localIds;
                    alert('已选择 ' + res.localIds.length + ' 张图片');

                    uploadImg();
                }
            });
        });

        // 5.3 上传图片
        function uploadImg() {
            if (images.localId.length == 0) {
                alert('请先使用 chooseImage 接口选择图片');
                return;
            }
            var i = 0, length = images.localId.length;
            images.serverId = [];

            function upload() {
                wx
                        .uploadImage({
                            localId : images.localId[i],
                            success : function(res) {
                                i++;
                                alert('已上传:' + i + '/' + length);
                                images.serverId.push(res.serverId);
                                //将serverId上传至服务器
                                alert("ajax请求即将执行--");

                                $
                                        .ajax({
                                            type : "POST",
                                            url : "http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/uploadExpenseAccaoutServlet",
                                            data : {
                                                serverId : res.serverId
                                            },
                                            dataType : "text",
                                            success : function(data) {
                                                alert(data);
                                            }

                                        });

                                if (i < length) {
                                    upload();
                                }
                            },
                            fail : function(res) {
                                alert(JSON.stringify(res));
                            }
                        });
            }
            upload();
        };
View Code

 

 

 2.3 获取企业微信JSSDK配置信息—WeiXinUtil.java

此类完整代码:

package com.ray.util;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ray.pojo.AccessToken;




import net.sf.json.JSONException;
import net.sf.json.JSONObject;

public class WeiXinUtil {

    private static Logger log = LoggerFactory.getLogger(WeiXinUtil.class);  
    //微信的请求url
    //获取access_token的接口地址(GET) 限200(次/天)  
    public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";  
    //获取jsapi_ticket的接口地址(GET) 限200(次/天)  
    public final static String jsapi_ticket_url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESSTOKEN";  



    /**
     * 1.发起https请求并获取结果 
     *  
     * @param requestUrl 请求地址 
     * @param requestMethod 请求方式(GET、POST) 
     * @param outputStr 提交的数据 
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值) 
     */  
    public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {  
        JSONObject jsonObject = null;  
        StringBuffer buffer = new StringBuffer();  
        try {  
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化  
            TrustManager[] tm = { new MyX509TrustManager() };  
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
            sslContext.init(null, tm, new java.security.SecureRandom());  
            // 从上述SSLContext对象中得到SSLSocketFactory对象  
            SSLSocketFactory ssf = sslContext.getSocketFactory();  

            URL url = new URL(requestUrl);  
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
            httpUrlConn.setSSLSocketFactory(ssf);  

            httpUrlConn.setDoOutput(true);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  
            // 设置请求方式(GET/POST)  
            httpUrlConn.setRequestMethod(requestMethod);  

            if ("GET".equalsIgnoreCase(requestMethod))  
                httpUrlConn.connect();  

            // 当有数据需要提交时  
            if (null != outputStr) {  
                OutputStream outputStream = httpUrlConn.getOutputStream();  
                // 注意编码格式,防止中文乱码  
                outputStream.write(outputStr.getBytes("UTF-8"));  
                outputStream.close();  
            }  

            // 将返回的输入流转换成字符串  
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  
            jsonObject = JSONObject.fromObject(buffer.toString());  
        } catch (ConnectException ce) {  
            log.error("Weixin server connection timed out.");  
        } catch (Exception e) {  
            log.error("https request error:{}", e);  
        }  
        return jsonObject;  
    }  

   /**
     * 2.发送https请求之获取临时素材 
     * @param requestUrl
     * @param savePath  文件的保存路径,此时还缺一个扩展名
     * @return
     * @throws Exception
     */
    public static File getFile(String requestUrl,String savePath) throws Exception {  
        //String path=System.getProperty("user.dir")+"/img//1.png";
    
        
            // 创建SSLContext对象,并使用我们指定的信任管理器初始化  
            TrustManager[] tm = { new MyX509TrustManager() };  
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");  
            sslContext.init(null, tm, new java.security.SecureRandom());  
            // 从上述SSLContext对象中得到SSLSocketFactory对象  
            SSLSocketFactory ssf = sslContext.getSocketFactory();  

            URL url = new URL(requestUrl);  
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();  
            httpUrlConn.setSSLSocketFactory(ssf);  

            httpUrlConn.setDoOutput(true);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  
            // 设置请求方式(GET/POST)  
            httpUrlConn.setRequestMethod("GET");  

            httpUrlConn.connect();  

            //获取文件扩展名
            String ext=getExt(httpUrlConn.getContentType());
            savePath=savePath+ext;
            System.out.println("savePath"+savePath);
            //下载文件到f文件
            File file = new File(savePath);

            
            // 获取微信返回的输入流
            InputStream in = httpUrlConn.getInputStream(); 
            
            //输出流,将微信返回的输入流内容写到文件中
            FileOutputStream out = new FileOutputStream(file);
             
            int length=100*1024;
            byte[] byteBuffer = new byte[length]; //存储文件内容
            
            int byteread =0;
            int bytesum=0;
            
            while (( byteread=in.read(byteBuffer)) != -1) {  
                bytesum += byteread; //字节数 文件大小 
                out.write(byteBuffer,0,byteread);  
                
            }  
            System.out.println("bytesum: "+bytesum);
            
            in.close();  
            // 释放资源  
            out.close();  
            in = null;  
            out=null;
            
            httpUrlConn.disconnect();  

            
            return file;
    }  
    
    

    /**
     * @desc :2.微信上传素材的请求方法
     *  
     * @param requestUrl  微信上传临时素材的接口url
     * @param file    要上传的文件
     * @return String  上传成功后,微信服务器返回的消息
     */
    public static String httpRequest(String requestUrl, File file) {  
        StringBuffer buffer = new StringBuffer();  

        try{
            //1.建立连接
            URL url = new URL(requestUrl);
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();  //打开链接

            //1.1输入输出设置
            httpUrlConn.setDoInput(true);
            httpUrlConn.setDoOutput(true);
            httpUrlConn.setUseCaches(false); // post方式不能使用缓存
            //1.2设置请求头信息
            httpUrlConn.setRequestProperty("Connection", "Keep-Alive");
            httpUrlConn.setRequestProperty("Charset", "UTF-8");
            //1.3设置边界
            String BOUNDARY = "----------" + System.currentTimeMillis();
            httpUrlConn.setRequestProperty("Content-Type","multipart/form-data; boundary="+ BOUNDARY);

            // 请求正文信息
            // 第一部分:
            //2.将文件头输出到微信服务器
            StringBuilder sb = new StringBuilder();
            sb.append("--"); // 必须多两道线
            sb.append(BOUNDARY);
            sb.append("\r\n");
            sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + file.length()
            + "\";filename=\""+ file.getName() + "\"\r\n");
            sb.append("Content-Type:application/octet-stream\r\n\r\n");
            byte[] head = sb.toString().getBytes("utf-8");
            // 获得输出流
            OutputStream outputStream = new DataOutputStream(httpUrlConn.getOutputStream());
            // 将表头写入输出流中:输出表头
            outputStream.write(head);

            //3.将文件正文部分输出到微信服务器
            // 把文件以流文件的方式 写入到微信服务器中
            DataInputStream in = new DataInputStream(new FileInputStream(file));
            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = in.read(bufferOut)) != -1) {
                outputStream.write(bufferOut, 0, bytes);
            }
            in.close();
            //4.将结尾部分输出到微信服务器
            byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
            outputStream.write(foot);
            outputStream.flush();
            outputStream.close();


            //5.将微信服务器返回的输入流转换成字符串  
            InputStream inputStream = httpUrlConn.getInputStream();  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  
            }  

            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  


        } catch (IOException e) {
            System.out.println("发送POST请求出现异常!" + e);
            e.printStackTrace();
        } 
        return buffer.toString();
    }

    /** 
     * 2.发起http请求获取返回结果 
     *  
     * @param requestUrl 请求地址 
     * @return 
     */  
    public static String httpRequest(String requestUrl) {  
        StringBuffer buffer = new StringBuffer();  
        try {  
            URL url = new URL(requestUrl);  
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();  

            httpUrlConn.setDoOutput(false);  
            httpUrlConn.setDoInput(true);  
            httpUrlConn.setUseCaches(false);  

            httpUrlConn.setRequestMethod("GET");  
            httpUrlConn.connect();  

            // 将返回的输入流转换成字符串  
            InputStream inputStream = httpUrlConn.getInputStream();  
            //InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");  
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);  
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);  

            String str = null;  
            while ((str = bufferedReader.readLine()) != null) {  
                buffer.append(str);  

            }  
            bufferedReader.close();  
            inputStreamReader.close();  
            // 释放资源  
            inputStream.close();  
            inputStream = null;  
            httpUrlConn.disconnect();  

        } catch (Exception e) {  
        }  
        return buffer.toString();  
    }  


    /** 
     * 3.获取access_token 
     *  
     * @param appid 凭证 
     * @param appsecret 密钥 
     * @return 
     */  
    public static AccessToken getAccessToken(String appid, String appsecret) {  
        AccessToken accessToken = null;  

        String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);  
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  
        // 如果请求成功  
        if (null != jsonObject) {  
            try {  
                accessToken = new AccessToken();  
                accessToken.setToken(jsonObject.getString("access_token"));  
                accessToken.setExpiresIn(jsonObject.getInt("expires_in"));  
            } catch (JSONException e) {  
                accessToken = null;  
                // 获取token失败  
                log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
        return accessToken;  
    }  

    /**
     * 4. 获取JsapiTicket
     * @param accessToken
     * @return
     */
    public static String getJsapiTicket(String accessToken){


        String requestUrl = jsapi_ticket_url.replace("ACCESSTOKEN", accessToken);  
        JSONObject jsonObject = httpRequest(requestUrl, "GET", null);  

        String  jsapi_ticket="";
        // 如果请求成功  
        if (null != jsonObject) {  
            try {  
                jsapi_ticket=jsonObject.getString("ticket");  

            } catch (JSONException e) {  

                // 获取token失败  
                log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
        return jsapi_ticket;  
    }

    /**
     * 3.获取企业微信的JSSDK配置信息
     * @param request
     * @return
     */
    public static Map<String, Object> getWxConfig(HttpServletRequest request) {
        Map<String, Object> ret = new HashMap<String, Object>();
        //1.准备好参与签名的字段

        String nonceStr = UUID.randomUUID().toString(); // 必填,生成签名的随机串
        //System.out.println("nonceStr:"+nonceStr);
        String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        String jsapi_ticket =getJsapiTicket(accessToken);// 必填,生成签名的H5应用调用企业微信JS接口的临时票据
        //System.out.println("jsapi_ticket:"+jsapi_ticket);
        String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳
        //System.out.println("timestamp:"+timestamp);
        String url=request.getRequestURL().toString();
        //System.out.println("url:"+url);
        
        //2.字典序           ,注意这里参数名必须全部小写,且必须有序
        String sign = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonceStr+ "&timestamp=" + timestamp + "&url=" + url;

        //3.sha1签名
        String signature = "";
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(sign.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
            //System.out.println("signature:"+signature);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        ret.put("appId", WeiXinParamesUtil.corpId);
        ret.put("timestamp", timestamp);
        ret.put("nonceStr", nonceStr);
        ret.put("signature", signature);
        return ret;
    }


    /**
     * 方法名:byteToHex</br>
     * 详述:字符串加密辅助方法 </br>
     * 开发人员:souvc  </br>
     * 创建时间:2016-1-5  </br>
     * @param hash
     * @return 说明返回值含义
     * @throws 说明发生此异常的条件
     */
    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 getExt(String contentType){
        if("image/jpeg".equals(contentType)){
            return ".jpg";
        }else if("image/png".equals(contentType)){
            return ".png";
        }else if("image/gif".equals(contentType)){
            return ".gif";
        }
        
        return null;
    }
}
View Code

 

获取获取企业微信JSSDK配置信息的方法为:

public static Map<String, Object> getWxConfig(HttpServletRequest request) 

 

2.4创建跳转菜单按钮

完整代码:

MenuService.java

package com.ray.service;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.ray.pojo.menu.Button;
import com.ray.pojo.menu.CommonButton;
import com.ray.pojo.menu.ComplexButton;
import com.ray.pojo.menu.Menu;
import com.ray.pojo.menu.ViewButton;
import com.ray.util.WeiXinUtil;

import net.sf.json.JSONObject;


public class MenuService {
    private static Logger log = LoggerFactory.getLogger(MenuService.class);  
    // 菜单创建(POST) 限100(次/天)  
    public static String create_menu_url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN&agentid=AGENTID";  

    /** 
     * 1.创建菜单 
     *  
     * @param menu 菜单实例 
     * @param accessToken 有效的access_token 
     * @return 0表示成功,其他值表示失败 
     */  
    public void createMenu(String accessToken,Menu menu,int agentId) {  

        //1.获取json字符串:将Menu对象转换为json字符串
        Gson gson = new Gson(); 
        String jsonMenu =gson.toJson(menu);      //使用gson.toJson(user)即可将user对象顺序转成json
        System.out.println("jsonMenu:"+jsonMenu);


        //2.获取请求的url  
        create_menu_url = create_menu_url.replace("ACCESS_TOKEN", accessToken)
                .replace("AGENTID", String.valueOf(agentId));  

        //3.调用接口,发送请求,创建菜单  
        JSONObject jsonObject = WeiXinUtil.httpRequest(create_menu_url, "POST", jsonMenu);  
        System.out.println("jsonObject:"+jsonObject.toString());

        //4.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInt("errcode")) {  
                log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
 
    }  

    /** 
     * 2.组装菜单数据 
     *  
     * @return 
     */  
    public  Menu getMenu() {  
    /*    ViewButton btn11 = new ViewButton();  
        btn11.setName("添加报销单");  
        btn11.setType("view");  
        btn11.setUrl("http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/uploadExpenseAccaout.jsp");  
*/
        ViewButton btn11 = new ViewButton();  
        btn11.setName("JSSDK多图上传");  
        btn11.setType("view");  
        btn11.setUrl("http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/JSSDKUploadPics.jsp");  

        ViewButton btn21 = new ViewButton();  
        btn21.setName("JSSDK测试(全)");  
        btn21.setType("view");  
        btn21.setUrl("http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/jsapiTicktAll.jsp");  

        ViewButton btn22 = new ViewButton();  
        btn22.setName("PC端网页授权");  
        btn22.setType("view");  
        btn22.setUrl("https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww92f5da92bb24696e&agentid=1000002&redirect_uri=http%3A%2F%2F5nffqn.natappfree.cc%2FWeiXin_QiYe_Demo%2Fwebauthorization.jsp&state=state");  

        
        
        CommonButton btn12 = new CommonButton();  
        btn12.setName("扫一扫");  
        btn12.setType("click");  
        btn12.setKey("12");  

        
        
        CommonButton btn13 = new CommonButton();  
        btn13.setName("翻译功能");  
        btn13.setType("click");  
        btn13.setKey("13");  

        ViewButton btn14 = new ViewButton();  
        btn14.setName("上传图片");  
        btn14.setType("view");  
        btn14.setUrl("http://5nffqn.natappfree.cc/WeiXin_SanFenBaiXue/uploadimg.jsp");  



        ViewButton btn15 = new ViewButton();  
        btn15.setName("上传图片2");  
        btn15.setType("view");  
        btn15.setUrl("http://5nffqn.natappfree.cc/WeiXin_SanFenBaiXue/index2.jsp");  

    
    

        

        CommonButton btn23 = new CommonButton();  
        btn23.setName("美女电台");  
        btn23.setType("click");  
        btn23.setKey("23");  

        CommonButton btn24 = new CommonButton();  
        btn24.setName("人脸识别");  
        btn24.setType("click");  
        btn24.setKey("24");  

        CommonButton btn25 = new CommonButton();  
        btn25.setName("聊天唠嗑");  
        btn25.setType("click");  
        btn25.setKey("25");  

        CommonButton btn31 = new CommonButton();  
        btn31.setName("Q友圈");  
        btn31.setType("click");  
        btn31.setKey("31");  

        CommonButton btn33 = new CommonButton();  
        btn33.setName("幽默笑话");  
        btn33.setType("click");  
        btn33.setKey("33");  

        CommonButton btn34 = new CommonButton();  
        btn34.setName("用户反馈");  
        btn34.setType("click");  
        btn34.setKey("34");  

        CommonButton btn35 = new CommonButton();  
        btn35.setName("关于我们");  
        btn35.setType("click");  
        btn35.setKey("35");  

        ViewButton btn32 = new ViewButton();  
        btn32.setName("周边搜索");  
        btn32.setType("view");  
        btn32.setUrl("http://liufeng.gotoip2.com/xiaoqrobot/help.jsp");  

        ComplexButton mainBtn1 = new ComplexButton();  
        mainBtn1.setName("正在做功能");  
        mainBtn1.setSub_button(new Button[] { btn11, btn12, btn13, btn14, btn15 });  

        ComplexButton mainBtn2 = new ComplexButton();  
        mainBtn2.setName("测试");  
        mainBtn2.setSub_button(new Button[] { btn21, btn22, btn23, btn24, btn25 });  

        ComplexButton mainBtn3 = new ComplexButton();  
        mainBtn3.setName("更多");  
        mainBtn3.setSub_button(new Button[] { btn31, btn33, btn34, btn35, btn32 });  

        /** 
         * 这是企业号目前的菜单结构,每个一级菜单都有二级菜单项<br> 
         *  
         * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> 
         * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> 
         * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); 
         */  
        Menu menu = new Menu();  
        menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });  

        return menu;  
    }  

}
View Code

MenuTest.java

package com.ray.test;

import org.junit.Test;

import com.ray.pojo.menu.Menu;
import com.ray.service.MenuService;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.WeiXinUtil;

public class MenuTest {
    
  @Test    
  public void testCreateMenu(){
      //1.组装菜单
      MenuService ms=new MenuService();
      Menu menu=ms.getMenu();
      
      //2.获取access_token:根据企业id和应用密钥获取access_token
      String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
      System.out.println("accessToken:"+accessToken);
      
      //3.创建菜单
      ms.createMenu( accessToken, menu, WeiXinParamesUtil.agentId);
      
     
    
  }
  
  
  
  
}
View Code

 

创建跳转菜单按钮,点击后,跳转到 JSSDKUploadPics.jsp页面

(1)在MenuService.java中添加一个跳转按钮。

    ViewButton btn11 = new ViewButton();  
        btn11.setName("JSSDK多图上传");  
        btn11.setType("view");  
        btn11.setUrl("http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/JSSDKUploadPics.jsp");  
View Code

(2)运行MenuTest类中的testCreateMenu,来创建菜单。

 

2.5 总结一下JSSDK完整过程

这样JSSDK完整过程如下:

(1)点击菜单按钮跳转到JSSDKUploadPics.jsp页面

(2)调用后台方法获取微信配置信息

(3)通过config接口注入(2)中获取的权限验证配置

(4)弹出JSSDK配置成功的提示框

(5)选择图片并上传到微信服务器

(6)上传图片到微信服务器后,将微信服务器返回的图片的serverID(即mediaId)通过ajax方式传到后台servlet

(7)在servlet中,根据接收的serverID,进行获取临时素材并存到本地的操作(这一步请见下一节)

 

 

至此JSSDK的配置已经成功,我们可以调用微信JSSDK提供的众多接口了。

相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
目录
相关文章
|
14天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
14天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
14天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。
|
2天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
3天前
|
数据采集 存储 人工智能
【Python+微信】【企业微信开发入坑指北】4. 企业微信接入GPT,只需一个URL,自动获取文章总结
【Python+微信】【企业微信开发入坑指北】4. 企业微信接入GPT,只需一个URL,自动获取文章总结
13 0
|
3天前
|
人工智能 机器人 API
【Python+微信】【企业微信开发入坑指北】3. 如何利用企业微信API给微信群推送消息
【Python+微信】【企业微信开发入坑指北】3. 如何利用企业微信API给微信群推送消息
6 0
|
3天前
|
缓存 人工智能 API
【Python+微信】【企业微信开发入坑指北】2. 如何利用企业微信API主动给用户发应用消息
【Python+微信】【企业微信开发入坑指北】2. 如何利用企业微信API主动给用户发应用消息
7 0
|
7天前
|
IDE Java 数据库连接
使用 Java 进行桌面应用开发
【4月更文挑战第19天】Java 是一款广泛应用于企业级、网络和桌面应用开发的编程语言。其跨平台特性使Java程序能在不同操作系统上运行,而JDK提供了开发所需工具和库。使用Swing等GUI库构建用户界面,结合JDBC进行数据库操作,Socket实现网络通信。虽然面临性能和用户体验的挑战,但通过优化和选用合适的IDE,Java仍能开发出高效稳定的桌面应用。
|
8天前
|
前端开发 Java Go
开发语言详解(python、java、Go(Golong)。。。。)
开发语言详解(python、java、Go(Golong)。。。。)
|
8天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
147 10

热门文章

最新文章