JSSDK使用步骤
1:绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。如果你使用了支付类接口,请确保支付目录在该安全域名下,否则将无法完成支付。
备注:登录后可在“开发者中心”查看对应的接口权限。(注意:一个公众号只能设置三个域名,设置好了每个月只有三次修改的机会,而且还需要审核,所以慎重。重点是微信接口只能在这三个域名下测试,本地无法测试)
2:引入JS文件
在需要调用JS接口的页面引入如下JS文件,(支持https):/open/js/jweixin-1.0.
请注意,如果你的页面启用了https,务必引入/open/js/jweixin-1.0. ,否则将无法在iOS9.0以上系统中成功使用JSSDK
如需使用摇一摇周边功能,请引入 jweixin-1.1.
备注:支持使用 AMD/CMD 标准模块加载方法加载
3.把ID和密码存到,方便以后替换
#超级合伙人联盟服务号
WEIXIN_APPID=xxxxxx
WEIXIN_APP_SECRET=xxxxxx
OSS_ACCESS_ID=xxxxx
OSS_ACCESS_KEY=xxxxx
OSS_URL=/
4.JS-SDK使用权限签名算法(获取jsapi_ticket)
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .;
public class WeiXinUtil {
private static final Log logger = ();
/**
*
* @param httpSession
* @param request
* @param actionContext
* @param from 第一次分享出去后 后面微信会自己拼接 from 和 isappinstalled(这是个坑人的点)
* @param isappinstalled
* @throws Exception
*/
public static void getToken(HttpSession httpSession, HttpServletRequest request, ActionContext actionContext, String from,
String isappinstalled) throws Exception {
String access_token = null;
if (null == ("access_token")) {
// 第一步获取token存入全局缓存,
String result1 = ("/cgi-bin/token?grant_type=client_credential&appWEIXIN_APPID") + "&secret=" + ("WEIXIN_APP_SECRET"));
obj1 = new JSONObject(result1);
access_token = ("access_token").toString();
("access_token", access_token);
} else {
access_token = ("access_token").toString();
}
String jsapi_ticket = null;
if (null == ("jsapi_ticket")) {
// 第二步根据token得到jsapi_ticket存入全局缓存
String result2 = ("/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi");
JSONObject obj2 = new JSONObject(result2);
jsapi_ticket = ("ticket").toString();
("jsapi_ticket", jsapi_ticket);
} else {
jsapi_ticket = ("jsapi_ticket").toString();
}
// 获取请求的地址
StringBuffer url = ();
String contextUrl = (() - ().length(), ()).toString();
String httpUrl = contextUrl + ();
if (from != null && isappinstalled != null) {
httpUrl = httpUrl + "?from=" + from + "&isappinstalled=" + isappinstalled;
}
// 签名算法
Map<String, String> map = (jsapi_ticket, httpUrl);
("appId", ("WEIXIN_APPID"));
("timestamp", ("timestamp"));
("nonceStr", ("nonceStr"));
("signature", ("signature"));
("newDate", new Date().getTime());
}
public static String getOnlyToken(HttpSession httpSession) throws Exception {
String access_token = null;
if (null == ("access_token")) {
// 第一步获取token存入全局缓存,
String result1 = ("/cgi-bin/token?grant_type=client_credential&appWEIXIN_APPID") + "&secret=" + ("WEIXIN_APP_SECRET"));
obj1 = new JSONObject(result1);
access_token = ("access_token").toString();
("access_token", access_token);
} else {
access_token = ("access_token").toString();
}
return access_token;
}
/**
* 从微信上获取图片并且上传到OSS服务器上
* @param httpSession
* @param serverId
* @return
* @throws Exception
*/
public static String downloadPicAndUploadOSS(HttpSession httpSession, String serverId) throws Exception {
String token = getOnlyToken(httpSession);
String downloadUrl = "/cgi-bin/media/get?access_token="+token+"&media_/").getPath();
String filePath = url+"";
File file = new File(filePath);
if (!().exists()) {
().mkdirs();
}
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
buffer = new byte[2048];
int length = (buffer);
while (length != -1) {
(buffer, 0, length);
length = (buffer);
}
();
();
byte[] imageToArray = imageToArray(filePath);
String stockImage = (imageToArray, "", "_stock");
("stock_image_url====>" + stockImage);
return stockImage;
}
public static byte[] imageToArray(String filePath) throws FileNotFoundException, IOException {
byte[] data = null;
FileImageInputStream input = null;
try {
input = new FileImageInputStream(new File(filePath));
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int numBytesRead = 0;
while ((numBytesRead = (buf)) != -1) {
(buf, 0, numBytesRead);
}
data = ();
();
();
}
catch (FileNotFoundException ex1) {
();
}
catch (IOException ex1) {
();
}
return data;
}
}
相关工具类
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class HttpClientUtil {
private static final Log logger = ();
/**
* http get 方式交互
*/
public static String getHTTP(String URL) {
String responseMsg = "";
// 构造HTTPClient的实例
HttpClient httpClient = new HttpClient();
GetMethod getmethod = new GetMethod(URL);
// 使用系统系统的默认的恢复策略
().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
try {
// ִ执行 HTTPClient方法,调用HTTP接口
(getmethod);
// 读取返回的内容
byte[] responseBody = ();
// 处理返回内容
responseMsg = new String(responseBody);
// 返回结果显示
// ("HTTP GET 方式执行结果:"+responseMsg);
} catch (HttpException e) {
();
} catch (IOException e) {
();
} finally {
// 释放操作
();
}
return responseMsg;
}
public static String getHTTP_New(String URL) {
String responseMsg = "";
HttpClient httpClient = new HttpClient();
// 创建GET方法的实例
GetMethod getMethod = new GetMethod(URL);
// 此处可以在getMethod上添加请求参数
try {
// 执行getMethod
int statusCode = (getMethod);
if (statusCode != HttpStatus.SC_OK) {
("Method failed: " + ());
}
// 读取内容
byte[] responseBody = ();
// 处理内容
responseMsg = new String(responseBody);
} catch (HttpException e) {
// 发生致命的异常,可能是协议不对或者返回的内容有问题
("Please check your provided http address!");
();
} catch (IOException e) {
// 发生网络异常
();
} finally {
// 释放连接
();
}
return responseMsg;
}
// HTTP 通过POST方式交互
/**
* http post 方式交互
*/
public static String postHTTP(String URL, String uid, String pwd, String tos, String content, String otime) {
String ResultStrMsg = "";
// 1.构造HttpClient的实例
HttpClient httpClient = new HttpClient();
().setContentCharset("GB2312");
PostMethod method = new PostMethod(URL);
// 把参数值放入到PostMethod对象中
// 方式一
NameValuePair[] dataparam = { new NameValuePair("id", uid), new NameValuePair("pwd", pwd),
new NameValuePair("to", tos), new NameValuePair("content", content), new NameValuePair("time", otime) };
(dataparam);
// 方式二
// ("", "");
// ("", "");
try {
// 执行接口方法,调用接口方法
(method);
// 读取返回的值ֵ
ResultStrMsg = ().trim();
// ("HTTP POST 方式执行结果:"+ResultStrMsg);
} catch (HttpException e) {
// TODO Auto-generated catch block
();
} catch (IOException e) {
// TODO Auto-generated catch block
();
} finally {
();
}
return ResultStrMsg;
}
public static String postHTTP_new(String URL, String uid, String pwd, String tos, String content, String otime) {
String ResultStrMsg = "";
// 1.构造HttpClient的实例
HttpClient httpClient = new HttpClient();
().setContentCharset("GB2312");
PostMethod method = new PostMethod(URL);
// 把参数值放入到PostMethod对象中
// 方式一
NameValuePair[] dataparam = { new NameValuePair("account", uid), new NameValuePair("pswd", pwd),
new NameValuePair("mobile", tos), new NameValuePair("msg", content), new NameValuePair("needstatus", otime) };
(dataparam);
// 方式二
// ("", "");
// ("", "");
try {
// 执行接口方法,调用接口方法
(method);
// 读取返回的值ֵ
ResultStrMsg = ().trim();
// ("HTTP POST 方式执行结果:"+ResultStrMsg);
} catch (HttpException e) {
// TODO Auto-generated catch block
();
} catch (IOException e) {
// TODO Auto-generated catch block
();
} finally {
();
}
return ResultStrMsg;
}
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 = ("SSL", "SunJSSE");
(null, tm, new ());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = ();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) ();
(ssf);
(true);
(true);
(false);
// 设置请求方式(GET/POST)
(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = ();
// 注意编码格式,防止中文乱码
(("UTF-8"));
();
}
// 将返回的输入流转换成字符串
InputStream inputStream = ();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = ()) != null) {
(str);
}
();
();
// 释放资源
();
inputStream = null;
();
jsonObject = (());
} catch (ConnectException ce) {
("Weixin server connection timed out.");
} catch (Exception e) {
("https request error:{}", e);
}
return jsonObject;
}
}
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* 微信分享接口的SHA1签名
* @author Administrator
*
*/
public class Sign {
public static void main(String[] args) {
String jsapi_ticket = "jsapi_ticket";
// 注意 URL 一定要动态获取,不能 hardcode
String url = "";
Map<String, String> ret = sign(jsapi_ticket, url);
for ( entry : ()) {
(() + ", " + ());
}
};
public static Map<String, String> sign(String jsapi_ticket, String url) {
Map<String, String> ret = new HashMap<String, String>();
String nonce_str = create_nonce_str();
String timestamp = create_timestamp();
String string1;
String signature = "";
//注意这里参数名必须全部小写,且必须有序
string1 = "jsapi_ticket=" + jsapi_ticket +
"&noncestr=" + nonce_str +
"×tamp=" + timestamp +
"&url=" + url;
try
{
MessageDigest crypt = ("SHA-1");
();
(("UTF-8"));
signature = byteToHex(());
}
catch (NoSuchAlgorithmException e)
{
();
}
catch (UnsupportedEncodingException e)
{
();
}
("url", url);
("jsapi_ticket", jsapi_ticket);
("nonceStr", nonce_str);
("timestamp", timestamp);
("signature", signature);
return ret;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
("%02x", b);
}
String result = ();
();
return result;
}
private static String create_nonce_str() {
return ().toString();
}
private static String create_timestamp() {
return (() / 1000);
}
}
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
public class OSSUploadUtil {
private static String[] types = new String[] { ".bmp", ".png", ".gif", ".jpeg", ".pjpeg", ".jpg" };
public static String imageFileUpload(byte[] fileByte, String user_avatar, String suffix) throws Exception {
String fileType = ".jpg";
for (int i = 0; i < ; i++) {
if (types[i].equalsIgnoreCase(user_avatar.substring(user_avatar.lastIndexOf(".")))) {
if (types[i].endsWith(".gif"))
fileType = ".gif";
if (types[i].endsWith(".png"))
fileType = ".png";
}
}
String fileName = (() + (new Random(999999).nextLong())) + suffix + fileType;
try {
InputStream input = new ByteArrayInputStream(fileByte);
String bucketName = "whkzdd";
// 使用默认的OSS服务器地址创建OSSClient对象。
OSSClient client = new OSSClient(("OSS_ACCESS_ID"), ("OSS_ACCESS_KEY"));
ensureBucket(client, bucketName);
ObjectMetadata objectMeta = new ObjectMetadata();
();
(bucketName, fileName, input, objectMeta);
String saveUrl = ("OSS_URL") + fileName;
return saveUrl;
} catch (Exception e) {
();
return null;
}
}
public static void ensureBucket(OSSClient client, String bucketName)throws OSSException, ClientException {
try {
// 创建bucket
(bucketName);
(bucketName, );
} catch (ServiceException e) {
if (!OSSErrorCode.BUCKES_ALREADY_EXISTS.equals(())) {
// 如果Bucket已经存在,则忽略
throw e;
}
}
}
}
5.后台action(请求使用微信接口的页面,我们需要的主要是这几个参数appId,timestamp,nonceStr,signature,newDate)
// 个人信息
@Action("userInfo")
public String userInfo() {
FuUser fuUser = (FuUser) ().getSession().getAttribute("fuUser");
().put("fuUser", fuUser);
try {
((), (), (),
from, isappinstalled);
} catch (Exception e) {
();
}
return SUCCESS;
}
6.前台分享接口和上传图片接口
<div class="userTx">
<a href="javascript:void();" >
<c:if test="${empty }">
<img src="../images_yqb/"/>
</c:if>
<c:if test="${!empty }">
<img src="${}"/>
</c:if>
</a>
</div>
<input type="hidden"/>
<input type="hidden" value="${appId}"/>
<input type="hidden" value="${timestamp}"/>
<input type="hidden" value="${nonceStr}"/>
<input type="hidden" value="${signature}"/>
</body>
</html>
<script src="/open/js/jweixin-1.0."></script>
<link href="${ctx}/js/uploadify-v2.1.4/" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="${ctx}/js/uploadify-v2.1.4/"></script>
<script type="text/javascript" src="${ctx}/js/uploadify-v2.1.4/.v2.1."></script>
<script language="javascript" type="text/javascript">
//通过config接口注入权限验证配置
var appId=$("#appId").val();
var timestamp=$("#timestamp").val();
var nonceStr=$("#nonceStr").val();
var signature=$("#signature").val();
({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature,// 必填,签名,见附录1
jsApiList: ['checkJsApi','onMenuShareTimeline','onMenuShareAppMessage','chooseImage', 'uploadImage'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
(function(){
//判断当前客户端版本是否支持指定JS接口
({
jsApiList: ['chooseImage', 'uploadImage'], // 需要检测的JS接口列表,所有JS接口列表见附录2,
success: function(res) {
// 以键值对的形式返回,可用的api值true,不可用为false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
if(!res["checkResult"]["chooseImage"]) {
alert("当前客户端不支持上传图片");
}
}
});
//获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
({
title: '10元抢iPhone6s猜股市涨跌', // 分享标题
desc: '', // 分享描述
link: 'https:///user_options/', // 分享链接
imgUrl: 'https:///images_czt/', // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
//获取“分享给朋友”按钮点击状态及自定义分享内容接口
({
title: '10元抢iPhone6s猜股市涨跌', // 分享标题
desc: '', // 分享描述
link: 'https:///user_options/', // 分享链接
imgUrl: 'https:///images_czt/', // 分享图标
type: '', // 分享类型,music、video或link,不填默认为link
dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
});
//图片div点击事件
$("#imgUpload").click(function() {
({
count: 1, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
var localIds = ; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
if(localIds == null || localIds == ""){
alert("请选择头像图片!");
return null;
}
$("#imgUpload").find("img").attr("src", localIds);
$.post("${ctx}/wxyqb/", {"srcId": ()}, function(d) {});
({
localId: (), // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: 1, // 默认为1,显示进度提示
success: function (res) {
var serverId = ; // 返回图片的服务器端ID
$("#serverId").val(serverId);
$.post('${ctx}/wxyqb/',
{"serverId" : serverId, "userId" : ${}}, function(d){
if(d == 1){
alert("头像上传失败!")
return false;
}
if(d == 2){
alert("设置成功!");
= "${ctx}/wxyqb/";
}
});
},
fail: function (res) {
alert(res);
}
});
}
});
});
</script>
6.对图片处理的action
//把图片ID放到session
@Action("setImageSrcId")
public String setImageSrcId() {
if (srcId != null && !"".equals(srcId)) {
().getSession().setAttribute("srcId", srcId);
}
return null;
}
// 保存用户头像
@Action("saveUserAvatar")
public String saveUserAvatar() {
try {
if (serverId == null || "".equals(serverId)) {
write("1"); // 上传图片失败
return null;
}
FuUser fuUser = (userId);
String userAvatar = ((), serverId);
(userAvatar);
(fuUser);
().getSession().setAttribute("srcId", null);
().getSession().setAttribute("fuUser", fuUser);//刷新用户session,显示最新的图片
write("2");
} catch (Exception e) {
();
}
return null;
}
微信JSSDK还有个最坑爹的地方就是,一旦那个页面用到了微信接口,那么你请求到那个页面的地址就不能用get方式传参,否则就调用不了它的接口。另外因为必须在绑定的域名下使用接口,所以不能在本地调式,也给开发带了很大的麻烦。