在偶然间,需要做一个公众账号分享的功能,细一想~ 奈何宝宝不会呀,听都没听过肿么破,当时就心累了。
言归正传,由于我所有的开发代码均是在又各位前辈在度娘中留下的辛勤汗水,再由于自己本身就渣,属于能够通过查找资料的方式完成代码就谢天谢地那种类型,所以呢以下所有内容均属于从度娘中获取,只是把自己做过的,寻找过的资料做一个整理
首先下载官方的示例代码:http://demo.open.weixin.qq.com/jssdk/sample.zip
此代码包括:jweixin-1.js、demo.js、style.css、jssdk.html。以上代码略加修改即可以用,下面是具体的实现方法四步曲:
步骤一:绑定域名,先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”;
步骤二:引入JS文件,在需要调用JS接口的页面引入JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js;
步骤三:通过config接口注入权限验证配置,所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用);
步骤四:通过ready接口处理成功验证。
因此,这里最重要的一步是步骤三,获取config配置的签名signature ,如下:
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '', // 必填,公众号的唯一标识 timestamp: , // 必填,生成签名的时间戳 nonceStr: '', // 必填,生成签名的随机串 signature: '',// 必填,签名,见附录1 jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 });
在开发之前肯定是需要几个从公众平台账号中拿到的开发者id,如不知道是什么,找领导要不给就干嘛~~ 好了,由于此处也是领导给的APPID编号这些,所以具体我也不清楚怎么来的。。。。 百度上应该可以找到吧~
(一)实体类 TokenJson
**
* @author Allen
* @version 1.0
* 创建时间:2016年4月12日 下午4:54:58
*/
public class TokenJson {
private String access_token;
private int expires_in;
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public int getExpires_in() {
return expires_in;
}
public void setExpires_in(int expires_in) {
this.expires_in = expires_in;
}
}
/**
* @author Allen
* @version 1.0
* 创建时间:2016年4月12日 下午5:03:14
*/
public class TicketJson {
private int errcode;
private String errmsg;
private String ticket;
private String expires_in;
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getExpires_in() {
return expires_in;
}
public void setExpires_in(String expires_in) {
this.expires_in = expires_in;
}
}
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
/**
* @author Allen
* @version 1.0 创建时间:2016年4月12日 下午4:30:23
*/
public class HttpGetRequest {
/**
* Get Request
*
* @return
* @throws Exception
*/
public static String doGet(String url) throws Exception {
URL localURL = new URL(url);
URLConnection connection = localURL.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
httpURLConnection.setRequestProperty("Accept-Charset", "utf-8");
httpURLConnection.setRequestProperty("Content-Type",
"application/text");
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader reader = null;
StringBuffer resultBuffer = new StringBuffer();
String tempLine = null;
if (httpURLConnection.getResponseCode() >= 300) {
throw new Exception(
"HTTP Request is not success, Response code is "
+ httpURLConnection.getResponseCode());
}
try {
inputStream = httpURLConnection.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
reader = new BufferedReader(inputStreamReader);
while ((tempLine = reader.readLine()) != null) {
resultBuffer.append(tempLine);
}
} finally {
if (reader != null) {
reader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
}
return resultBuffer.toString();
}
}
/**
* 发起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) {
Logger.getAnonymousLogger().info("Weixin server connection timed out.");
} catch (Exception e) {
Logger.getAnonymousLogger().info("信任管理器请求时..."+e);
}
return jsonObject;
}
MyX509TrustManager 这个不用纠结是什么,它是用于验证SSL的一个自定义Class,此方法不可直接用,需要做一些相应更改,如HTTPS验证方式,SSL证书等等,自我调整应该即可。。。。 (自白:没有通过此方法实现HTTPS,而是使用了
HttpGetRequest
)WxParams 实体类 用于记录从weixin官网得到的token与ticket
/**
* @author Allen
* @version 1.0
* 创建时间:2016年4月13日 下午3:53:57
*/
public class WxParams {
public static String token;
public static String tokenTime;
public static String tokenExpires;
public static String ticket;
public static String ticketTime;
public static String ticketExpires;
}
Sign 用于整理整合得到的值 (虽然我不懂,哈哈哈~~)
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class Sign {
public static Map sign(String jsapi_ticket, String url) {
Map ret = new HashMap();
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;
// System.out.println(string1);
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(string1.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
ret.put("url", url);
ret.put("jsapi_ticket", jsapi_ticket);
ret.put("nonceStr", nonce_str);
ret.put("timestamp", timestamp);
ret.put("signature", signature);
return ret;
}
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 create_nonce_str() {
return UUID.randomUUID().toString();
}
private static String create_timestamp() {
return Long.toString(System.currentTimeMillis() / 1000);
}
}
import java.util.Map;
import net.sf.json.JSONObject;
import wrt.book.Json.TicketJson;
import wrt.book.Json.TokenJson;
/**
* @author Allen
* @version 1.0
* 创建时间:2016年4月12日 下午4:28:41
*/
public class WxUtil {
//此处的appid与wx.config 参数appId一致 微信公众账号提供给开发者的信息,以下同理
public static String APPID = "wxb5571f0bxxxxxxxxx";
//同上
public static String SECRET = "c73435d332dxxxxxxxxxxx";
private static TokenJson getAccess_token(){
String url = String.format("https://api.weixin.qq.com/xxxxxxxxxxxxxxxxxxxx",APPID,SECRET);
try {
String result = HttpGetRequest.doGet(url);
System.out.println("微信服务器获取token:"+result);
JSONObject rqJsonObject = JSONObject.fromObject(result);
TokenJson tokenJson = (TokenJson) JSONObject.toBean(rqJsonObject,TokenJson.class);
return tokenJson;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
private static TicketJson getTicket(String token){
String url = String.format("http://api.weixin.qq.com/xxxxxxxxxxxxxxxxxxxxxxxx",token);
try {
String result = HttpGetRequest.doGet(url);
System.out.println("微信服务器获取Ticket:"+result);
JSONObject rqJsonObject = JSONObject.fromObject(result);
TicketJson ticket = (TicketJson) JSONObject.toBean(rqJsonObject,TicketJson.class);
return ticket;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
/**
* 获取js sdk 认证信息
* @author
* @date 创建时间 2016年7月28日 上午11:25:01
* @param url
* @return
*/
public static Map getSign(String url){
//处理token失效的问题
try {
long tokenTimeLong = Long.parseLong(WxParams.tokenTime);
long tokenExpiresLong = Long.parseLong(WxParams.tokenExpires);
//时间差
long differ = (System.currentTimeMillis() - tokenTimeLong) /1000;
if (WxParams.token == null || differ > (tokenExpiresLong - 1800)) {
System.out.println("token为null,或者超时,重新获取");
TokenJson tokenJson = getAccess_token();
if (tokenJson != null) {
WxParams.token = tokenJson.getAccess_token();
WxParams.tokenTime = System.currentTimeMillis()+"";
WxParams.tokenExpires = tokenJson.getExpires_in()+"";
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
TokenJson tokenJson = getAccess_token();
if (tokenJson != null) {
WxParams.token = tokenJson.getAccess_token();
WxParams.tokenTime = System.currentTimeMillis()+"";
WxParams.tokenExpires = tokenJson.getExpires_in()+"";
}
}
//处理ticket失效的问题
try {
long ticketTimeLong = Long.parseLong(WxParams.ticketTime);
long ticketExpiresLong = Long.parseLong(WxParams.ticketExpires);
//时间差
long differ = (System.currentTimeMillis() - ticketTimeLong) /1000;
if (WxParams.ticket == null || differ > (ticketExpiresLong - 1800)) {
System.out.println("ticket为null,或者超时,重新获取");
TicketJson ticketJson = getTicket(WxParams.token);
if (ticketJson != null) {
WxParams.ticket = ticketJson.getTicket();
WxParams.ticketTime = System.currentTimeMillis()+"";
WxParams.ticketExpires = ticketJson.getExpires_in()+"";
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
TicketJson ticketJson = getTicket(WxParams.token);
if (ticketJson != null) {
WxParams.ticket = ticketJson.getTicket();
WxParams.ticketTime = System.currentTimeMillis()+"";
WxParams.ticketExpires = ticketJson.getExpires_in()+"";
}
}
Map ret = Sign.sign(WxParams.ticket, url);
System.out.println("计算出的签名-----------------------");
for (Map.Entry entry : ret.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
System.out.println("-----------------------");
return ret;
}
}
index.jsp 通过<%%> 嵌入
<%
//签名
String url = request.getScheme()+"://";
url+=request.getHeader("host");
url+=request.getRequestURI();
if(request.getQueryString()!=null){
url+="?"+request.getQueryString();
}
Map sign = WxUtil.getSign(url);
String timestamp = sign.get("timestamp");
String nonceStr = sign.get("nonceStr");
String jsapi_ticket = sign.get("jsapi_ticket");
String signature = sign.get("signature");
//String url = sign.get("url");
%>
以上是全部代码,基本稍加更改则可直接使用。
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
验证失败调用
wx.error(function(res){
// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});
同时,测试时,必须部署到微信公众平台账号中,因为它会检测当前传入的HTTP地址是否与备案的相同,如若不同则会一直报异常,切记切记。。。
无奈本屌只会用,不懂其原理,惭愧惭愧,不过能解决的就是好的不是嘛~ 最后附上相关资料信息
微信开发:JS-SDK之分享接口的实现
微信开发(六)微信分享接入
wx.onMenuShareTimeline使用注意事项
感谢那些为此默默付出的大神们~~ 咱们谢谢他们哒,同时新手勿喷勿喷诺~