一、本节要点

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代码示例:

     /**
* 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;
}

二、代码实现

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");
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;
}
}

获取获取企业微信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;
} }

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); } }

创建跳转菜单按钮,点击后,跳转到 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");

(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提供的众多接口了。

Java企业微信开发_07_JSSDK多图上传的更多相关文章

  1. Java企业微信开发_07_素材管理之上传本地临时素材文件

    一.本节要点 1.临时素材有效期 media_id是可复用的,同一个media_id可用于消息的多次发送(3天内有效) 2.上传文件时的http请求里都有啥 具体原理可参看: 为什么上传文件的表单需要 ...

  2. Java企业微信开发_06_素材管理之上传本地临时素材文件至微信服务器

    一.本节要点 1.临时素材有效期 media_id是可复用的,同一个media_id可用于消息的多次发送(3天内有效) 2.上传文件时的http请求里都有啥 具体原理可参看: 为什么上传文件的表单需要 ...

  3. Java企业微信开发_09_身份验证之移动端网页授权(有完整项目源码)

    注: 源码已上传github: https://github.com/shirayner/WeiXin_QiYe_Demo 一.本节要点 1.1 授权回调域(可信域名) 在开始使用网页授权之前,需要先 ...

  4. Java企业微信开发_03_通讯录同步

    一.本节要点 1.获取通讯录密钥 获取方式: 登录企业微信—>管理工具—>通讯录同步助手—>开启“API接口同步”  ; 开启后,即可看到通讯录密钥,也可设置通讯录API的权限:读取 ...

  5. Java企业微信开发_05_消息推送之发送消息(主动)

    一.本节要点 1.发送消息与被动回复消息 (1)流程不同:发送消息是第三方服务器主动通知微信服务器向用户发消息.而被动回复消息是 用户发送消息之后,微信服务器将消息传递给 第三方服务器,第三方服务器接 ...

  6. Java企业微信开发_05_消息推送之被动回复消息

    一.本节要点 1.消息的加解密 微信加解密包 下载地址:http://qydev.weixin.qq.com/java.zip      ,此包中封装好了AES加解密方法,直接调用方法即可. 其中,解 ...

  7. Java企业微信开发_04_消息推送之发送消息(主动)

    源码请见: Java企业微信开发_00_源码及资源汇总贴 一.本节要点 1.发送消息与被动回复消息 (1)流程不同:发送消息是第三方服务器主动通知微信服务器向用户发消息.而被动回复消息是 用户发送消息 ...

  8. Java企业微信开发_03_自定义菜单

    一.本节要点 1.菜单相关实体类的封装 参考官方文档中的请求包的内容,对菜单相关实体类进行封装. 这里需要格外注意的是,企业微信中请求包的数据是Json字符串格式的,而不是xml格式.关于json序列 ...

  9. Java企业微信开发_02_通讯录同步

    一.本节要点 1.获取通讯录密钥 获取方式: 登录企业微信—>管理工具—>通讯录同步助手—>开启“API接口同步”  ; 开启后,即可看到通讯录密钥,也可设置通讯录API的权限:读取 ...

随机推荐

  1. yum 无法安装mysql

    昨晚帮盆友搭建服务器时,一直出现yum mysql 无法安装.报错信息如下: Transaction Check Error:  file /etc/my.cnf from install of my ...

  2. Rancher探秘一:初识Rancher

    前言:最近公司需要导入k8s管理,看了一些rancher相关内容,在此做一记录,rancher系列会根据进展不定期更新. Rancher是什么? Rancher是一个开源的企业级容器管理平台.通过Ra ...

  3. 看了就很快学会jQuery

    一.jQuery简介与第一个jQuery程序 1.1.jQuery简介 1.2.jQuery特点 1.3.jQuery版本 1.4.获得jQuery库 1.5.第一个jQuery程序 二.jQuery ...

  4. lucas定理证明

    Lucas 定理(证明) A.B是非负整数,p是质数.AB写成p进制:A=a[n]a[n-1]...a[0],B=b[n]b[n-1]...b[0]. 则组合数C(A,B)与C(a[n],b[n])* ...

  5. 使用Zxing.net实现asp.net mvc二维码功能

    新建一个html辅助类 public static class HtmlHelperExtensions { , , ) { var barcodeWriter = new BarcodeWriter ...

  6. hdu 5969 最大的位或

    最大的位或 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  7. vim对光标所在的数字进行增减

    真是vim会在不经意间给你惊喜...... 现在发现把光标移到某数字的上方,c-a是加1, c-x是减1 当时真有点众里寻他千百度的感觉

  8. 九度OJ 1342:寻找最长合法括号序列II (DP)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:898 解决:366 题目描述: 假如给你一个由'('和')'组成的一个随机的括号序列,当然,这个括号序列肯定不能保证是左右括号匹配的,所以给 ...

  9. oschina git服务, 如何生成并部署ssh key

    1.如何生成ssh公钥 你可以按如下命令来生成 sshkey: ssh-keygen -t rsa -C "xxxxx@xxxxx.com" # Generating public ...

  10. as2解析json

    as2写的json解析,带容错,如果要做格式检查,得自己修改了,直接贴代码 //--------------------------------------------------json解析---- ...