一、申请微信公众号
获取公众号的appid ,先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
二、获取填写网页授权页面
三、引入JS文件
在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js
请注意,如果你的页面启用了https,务必引入 https://res.wx.qq.com/open/js/jweixin-1.0.0.js ,否则将无法在iOS9.0以上系统中成功使用JSSDK
四、通过config接口注入权限验证配置
所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复)。
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名,见附录1
jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});
步骤五:通过ready接口处理成功验证
wx.ready(function(){
// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,
所以如果需要在页面加载时就
调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});
六、调用jssdk时需要获取jssdk的临时调用凭证。
jsapi_ticket的有效期为7200秒,通过access_token(有效期为7200秒)来获取。因此jsapi_ticket和access_token需缓存在服务器中。本例使用redis缓存。
七、调用微信分享接口的例子
1、wxshare.js文件内容
function getRandom(){//生成签名的随机串
var random = "";
for (var i = 1; i <= 32; i++) {
var n = Math.floor(Math.random() * 16.0).toString(16);
random += n;
if ((i == 8) || (i == 12) || (i == 16) || (i == 20)) random += "";
}
return random;
}
//微信接口配置
var wxShare={
isReady:false,//是否初始化完成
access_token:"",//公众号token,令牌
ticket:"",//调用jssdk的临时凭证
readySuccessCall:[],//微信初始化成功后的执行事务
appName:"saasCollection",//项目名称
config:{
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来。
appId: "", // 必填,公众号的唯一标识
timestamp: Math.ceil(new Date().getTime()/1000).toString(), // 必填,生成签名的时间戳
nonceStr: getRandom(), // 必填,生成签名的随机串
signature: "",// 必填,签名,见附录1
jsApiList: ['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
},
init:function(){//初始化
if(!wx){
zfalert("系统提示","微信接口调用失败",false);
return false;
}
var that=this;//保存作用域
this.wx_get_appid(function(data){//获取appid
if(data.appId){
// Cookie.Set("appId",data.appId,3600);
that.config.appId=data.appId;
}
that.wx_get_access_token(function(data){//获取token,通过token获取jsapi_ticket
if(data.access_token){
// Cookie.Set("access_token",data.access_token,3600);
that.access_token=data.access_token;
}
that.wx_get_ticket(function(data){//获取jsapi_ticket
if(data.ticket){
// Cookie.Set("ticket",data.ticket,3600);
that.ticket=data.ticket;
}
that.wx_get_sign(function(data){//根据noncestr, jsapi_ticket, timestamp, url获取签名
that.config.signature=data.signature;
that.initWx(function(){//初始化微信接口
});
});
});
});
});
},
wx_get_appid:function(call){ //获取微信公众号的appid
this.appId=Cookie.Get("appId");//从cookie中获取appId
if(!this.appId){
$.get(getRootPath()+"/api/wxApi/getAppId.WX?time="+new Date(),{},function(data){
call && call(data);
},"json");//请求后台获取access_token
return ;
}
call && call({});
},
wx_get_access_token:function(call){ //获取公众号访问令牌
this.access_token=Cookie.Get("access_token");//从Cookie中获取
if(!this.access_token){//Cookie中
$.get(getRootPath()+"/api/wxApi/getWxToken.WX?time="+new Date(),{},function(data){
call && call(data);
},"json");//请求后台获取access_token
return ;
}
call && call({});
},
wx_get_ticket:function(call){ //获取票据使用ajax的get请求获取签名
this.ticket=Cookie.Get("ticket");
if(! this.ticket){
$.get(getRootPath()+"/api/wxApi/getJsApiTicket.WX?time="+new Date(),{},
function(data){
call && call(data);
},"json");//请求获取调用jssdk的临时单据
return;
}
call && call({});
},
wx_get_sign:function(call){ //获取签名
while(!this.config.appId || !this.ticket){
this.init();
}
$.post(getRootPath()+"/api/wxApi/getSign.WX",{//通过ajax请求后台获取签名
"noncestr":this.config.nonceStr,
"ticket":this.ticket,
"timestamp":this.config.timestamp,
"url":location.href.split('#')[0]
},function(data){
call && call(data);
},"json");//请求获取调用jssdk的临时单据
},
initWx:function(call,errorCall){//初始化微信接口
var that=this;
wx.config(this.config);//初始化微信配置
this.isReady=true;
wx.ready(function(){
this.isReady=true;
if(that.readySuccessCall.length>0){
$.each(that.readySuccessCall,function(i,n){
n();
})
}
call && call();
});
wx.error(function(res){
this.isReady=false;
errorCall && errorCall();
});
}
}
//初始化
wxShare.init();
2、初始化config后调用分享接口的shareopt.js中的代码
$(function(){
wxShare.shareApi=function(shareList){
if(wxShare.isReady){//判断微信config是否被初始化
if(shareList.onMenuShareTimeline){//分享到朋友圈
var timelineParameter=shareList.onMenuShareTimeline;//获取传入的参数
wx.onMenuShareTimeline({//调用微信接口
title: timelineParameter.title, // 分享标题
link: timelineParameter.link, // 分享链接
imgUrl: timelineParameter.imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
timelineParameter.success && timelineParameter.success();
},
cancel: function () {
// 用户取消分享后执行的回调函数
timelineParameter.cancel && timelineParameter.cancel();
}
});
} if(shareList.onMenuShareAppMessage){//分享给朋友
var appMessageParameter=shareList.onMenuShareAppMessage;//获取传入的参数
wx.onMenuShareAppMessage({
title:appMessageParameter.title, // 分享标题
desc: appMessageParameter.desc, // 分享描述
link: appMessageParameter.link, // 分享链接
imgUrl: appMessageParameter.imgUrl, // 分享图标
type: appMessageParameter.type, // 分享类型,music、video或link,
//不填默认为link
dataUrl: appMessageParameter.dataUrl, // 如果type是music或video,
//则要提供数据链接,默认为空
success: function () {
// 用户确认分享后执行的回调函数
appMessageParameter.success && appMessageParameter.success();
},
cancel: function () {
// 用户取消分享后执行的回调函数
appMessageParameter.cancel && appMessageParameter.cancel();
}
});
} if(shareList.onMenuShareQQ){//分享给qq
var shareQQParameter=shareList.onMenuShareQQ;//获取传入的参数
wx.onMenuShareQQ({
title: shareQQParameter.title, // 分享标题
desc: shareQQParameter.desc, // 分享描述
link: shareQQParameter.link, // 分享链接
imgUrl: shareQQParameter.imgUrl, // 分享图标
success: function () {
// 用户确认分享后执行的回调函数
},
cancel: function () {
// 用户取消分享后执行的回调函数
}
});
}
}else{
//初始化
wxShare.init();
wxShare.isReady=true;
console.log("系统提示,微信分享接口调用失败");
}
}
//成功初始化后执行api 分享事务
wxShare.readySuccessCall.push(function(){
var title = "分享接口测试标题",
link = window.location.href,
imgUrl = getRootPath()+"/images/front/bg/wxlog.jpg",//分享接口显示的图片
desc = "分享接口测试",
success = function(){
alert("系统提示","分享成功",false);
},
cancel = function(){
alert("系统提示","分享取消分享",false);
};
var inp_title=$("input[name='title']").val();
if(inp_title){
title=inp_title ;
}
var inp_imgUrl=$("input[name='imgUrl']").val();
if(inp_imgUrl){
imgUrl=inp_imgUrl;
}
var inp_desc=$("input[name='desc']").val();
if(inp_desc){
desc=inp_desc;
}
wxShare.shareApi({
onMenuShareTimeline : {//分享到朋友圈
title: title, // 分享标题
link: link, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
success();
},
cancel: function () {
cancel();
}
},
onMenuShareAppMessage:{//分享给朋友
title: title, // 分享标题
desc: desc, // 分享描述
link: link, // 分享链接
imgUrl: imgUrl, // 分享图标
type: "link", // 分享类型,music、video或link,不填默认为link
dataUrl: "", // 如果type是music或video,则要提供数据链接,默认为空
success: function () {
success();
},
cancel: function () {
cancel();
}
},
onMenuShareQQ:{//分享给qq
title: title, // 分享标题
desc: desc, // 分享描述
link: link, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
success();
},
cancel: function () {
cancel();
}
},
onMenuShareWeibo:{
title: title, // 分享标题
desc: desc, // 分享描述
link: link, // 分享链接
imgUrl: imgUrl, // 分享图标
success: function () {
success();
},
cancel: function () {
cancel();
}
}
});
});
});
八、java代码实现部分及工具类
import java.io.IOException;
/**
* HttpClient工具类
*
* @author shi
*/
public class HttpClientUtil {
public static String get(String url) throws IOException{
String returnVal="";
// 定义httpClient的实例
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet=new HttpGet(url);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();//设置请求和传输超时时间
httpGet.setConfig(requestConfig);
try {
CloseableHttpResponse response2 = httpclient.execute(httpGet);//执行请求
RmProjectHelper.logError("response2:", response2);
HttpEntity entity2 = (HttpEntity) response2.getEntity();
if(entity2!=null){
returnVal = EntityUtils.toString(entity2, "UTF-8");
}else{
returnVal = null;
}
} catch (ClientProtocolException e) {
RmProjectHelper.logError("retVal", e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
RmProjectHelper.logError("retVal", e.getMessage());
}finally{
if(httpclient!=null){
httpclient.close();
}
}
return returnVal;
}
public static Map<String, Object> parseJSON2Map(String bizData) {
Map<String, Object> ret = new HashMap<String, Object>();
try{
JSONObject bizDataJson = JSONObject.parseObject(bizData);
for(Object key:bizDataJson.keySet()){
Object value = bizDataJson.get(key);
if(value instanceof JSONArray){
List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
Iterator<Object> it = ((JSONArray) value).iterator();
while(it.hasNext()){
JSONObject json2 = (JSONObject)it.next();
list.add(parseJSON2Map(json2.toString()));
}
ret.put(String.valueOf(key),list);
}else{
ret.put(String.valueOf(key), String.valueOf(value));
}
}
}catch(Exception e){
RmProjectHelper.logError("系统异常", e);
}
return ret;
}
/**
* 使用post 提交到url
*
* @param url 目标url
* @param postDataXML 表体数据
* @throws Exception
*/
public static String post(String url, String postDataXML)
throws Exception {
// 定义httpClient的实例
CloseableHttpClient httpclient = HttpClients.createDefault();
String retVal;
try {
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();//设置请求和传输超时时间
httpPost.setConfig(requestConfig);
StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
CloseableHttpResponse response2 = httpclient.execute(httpPost);
try {
RmProjectHelper.logError("系统调试",response2.getStatusLine());
HttpEntity entity2 = (HttpEntity) response2.getEntity();
if(entity2!=null){
retVal = EntityUtils.toString(entity2, "UTF-8");
}else{
retVal = null;
}
// do something useful with the response body
// and ensure it is fully consumed
EntityUtils.consume( entity2);
return retVal;
} finally {
response2.close();
}
} finally {
httpclient.close();
}
}
}
4、wxshare.js中ajax请求获取appi、access_token、jsapi_ticket和sign签名请求的实现
import java.io.IOException;
@Controller
@RequestMapping(value="/api/wxApi")
public class WxApi {
/**
* 微信公共服务
*/
@Autowired
private WxService wxService;
/**
* 获取
* @param model
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value="/getAppId"+ISystemConstant.SUFFIX_WX,produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Map<String,Object> getAppId(Model model, HttpServletRequest request){
Map<String,Object> result=new HashMap<String,Object>();
String appId="1233456";//获取微信公众号的appid,根据自己具体业务写
result.put("appId", appId);
return result;
}
/**
* 获取token
* {
* "expires_in": "7200",
* "access_token": "TmKDWukZhk_2SVVLIuSMieu57J9i9CyDHBu01rLBjnfcOxeqLnpkLt。。。
* @param model
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value="/getWxToken"+ISystemConstant.SUFFIX_WX,produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Map<String,Object> getWxToken(Model model, HttpServletRequest request){
Map<String,Object> result=new HashMap<String,Object>();
// String uri="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +appID+
// "&secret="+appsecret;
String token=wxService.getToken();
result.put("access_token", token);
return result;
}
/**
* 获取调用jssdk的临时票据
* @param model
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value="/getJsApiTicket"+ISystemConstant.SUFFIX_WX,produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Map<String,Object> getJsApiTicket(Model model, HttpServletRequest request) throws IOException{
Map<String,Object> result=new HashMap<String,Object>();
// String uri="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" +appID+
// "&secret="+appsecret;
String jsApiTicket=wxService.getJsApiTicket();
result.put("ticket", jsApiTicket);
return result;
}
/**
* 获取签名
* @param model
* @param request
* @return
* @throws IOException
*/
@RequestMapping(value="/getSign"+ISystemConstant.SUFFIX_WX,produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Map<String,Object> getSign(Model model, HttpServletRequest request){
Map<String,Object> result=new HashMap<String,Object>();
String noncestr=request.getParameter("noncestr");
String jsapi_ticket=request.getParameter("ticket");
String timestamp=request.getParameter("timestamp");
String url=request.getParameter("url");
String sign=wxService.getSign(noncestr, jsapi_ticket, timestamp, url);
result.put("signature", sign);
return result;
}
}
5、WxService 具体代码,在service中根据httpclient工具类发送请求获取access_token 和 jsapi_ticket,将access_token 和 jsapi_ticket存入redis中
注:使用jedis,具体jedis在这不在贴出代码。
import java.io.IOException;
@Service
//默认将类中的所有public函数纳入事务管理
@Transactional(readOnly = true)
/**
* 微信接口服务
*/
public class WxService {
/**
* 获取调用jsApi的签名
* @param noncestr:随机数
* @param jsapi_ticket:临时票据
* @param timestamp:时间戳
* @param url:请求url
* @return
*/
public String getSign(String noncestr,String jsapi_ticket,String timestamp,String url ){
if(StringHelper.isEmpty(noncestr)){
throw new PjException("随机数不可为空");
}
if(StringHelper.isEmpty(jsapi_ticket)){
throw new PjException("调用微信的要获取的凭证失败");
}
if(StringHelper.isEmpty(timestamp)){
throw new PjException("时间戳不可为空");
}
if(StringHelper.isEmpty(url)){
throw new PjException("要分享的连接不可为空");
}
String sign="";
Map<String,String> signMap=new HashMap<String,String>();
signMap.put("noncestr", noncestr);
signMap.put("jsapi_ticket", jsapi_ticket);
signMap.put("timestamp", timestamp);
signMap.put("url", url);
sign= SignUtil.getSignature(signMap);
return sign;
}
/**
* 获取微信公众号的token
* @return
*/
public String getToken(){
Jedis jedis = null;
String accessToken="";
try {
jedis = RedisCacheService.getJedis();//获取redis连接
accessToken =jedis.get("ACCESS_TOKEN");//获取redis中的access_token
if(StringHelper.isEmpty(accessToken)){//redis中没有,去请求微信服务器
String appid="appid";//微信公众号的appid,登录微信公众号查看,填入自己微信公众号的实际appid
String appsecret="appsecret";//填入自己公众号对应的appsecret
String url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";//获取公共号token的url
StringBuilder sb=new StringBuilder();
sb.append(url);
sb.append("&appid=");
sb.append(appid);
sb.append("&secret=");
sb.append(appsecret);
url=sb.toString();
String returnVal=HttpClientUtil.get(url);//发送请求获取访问token
if(!StringHelper.isEmpty(returnVal)){
Map<String,Object> result=HttpClientUtil.parseJSON2Map(returnVal);
accessToken=(String)result.get("access_token");
jedis.setex("ACCESS_TOKEN", 7000, accessToken);//将access_token放入redis中默认7000秒后失效获取新的access_token
return accessToken;
}else{
throw new PjException("没有获取到返回值");
}
}
return accessToken;
} catch (Exception e) {
RmProjectHelper.logError("获取微信token", e.getMessage());
}finally{
RedisCacheService.returnResource(jedis);
}
return accessToken;
}
/**
* 获取调用jsapi的ticket临时凭证
* @return
*/
public String getJsApiTicket(){
Jedis jedis = null;
String jsApiTicket="";
try {
jedis = RedisCacheService.getJedis();
jsApiTicket =jedis.get("jsapi_ticket");
if(StringHelper.isEmpty(jsApiTicket)){
// https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
jsApiTicket =jedis.get("jsapi_ticket");
if(!StringHelper.isEmpty(jsApiTicket)){//再次判断是否为空,获取jsApiTicket返回
return jsApiTicket;
}
String ticketUrl="https://api.weixin.qq.com/cgi-bin/ticket/getticket";
String access_token=getToken();
StringBuilder sb=new StringBuilder();
sb.append(ticketUrl);
sb.append("?access_token=");
sb.append(access_token);
sb.append("&type=jsapi");
String returnVal=HttpClientUtil.get(sb.toString());
if(!StringHelper.isEmpty(returnVal)){
Map<String,Object> result=HttpClientUtil.parseJSON2Map(returnVal);
jsApiTicket=(String)result.get("ticket");
jedis.setex("jsapi_ticket", ISystemConstant.TOKE_OUT_TIME, jsApiTicket);
return jsApiTicket;
}else{
throw new PjException("请求获取jsApiTicket失败!");
}
}
}catch (Exception e) {
RmProjectHelper.logError("获取调用jsapi的ticket临时凭证 ", e.getMessage());
}finally{
RedisCacheService.returnResource(jedis);
}
return jsApiTicket;
}
}
九、json解析工具类下载地址http://download.csdn.net/detail/shiyuqiong/9560191