Java企业微信开发_08_JSSDK多图上传
Posted shirayner
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java企业微信开发_08_JSSDK多图上传相关的知识,希望对你有一定的参考价值。
一、本节要点
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×tamp=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+ "×tamp=" + 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 }
二、代码实现
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>
此页面主要包括:
(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>
(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")); %>
(3)通过config接口注入权限验证配置
wx.config({ beta : true, debug : true, appId : \'${appId}\', timestamp : \'${timestamp}\', nonceStr : \'${nonceStr }\', signature : \'${signature}\', jsApiList : [ \'checkJsApi\', \'chooseImage\', \'previewImage\', \'uploadImage\', \'downloadImage\', \'scanQRCode\', ] });
(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(); };
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"); h以上是关于Java企业微信开发_08_JSSDK多图上传的主要内容,如果未能解决你的问题,请参考以下文章