微信分享带图文(JAVA)

一、绑定JS安全域名,引入分享所需的JS文件

 绑定js安全域有认证过的微信公众号,然后再“公众号设置”的“功能设置”里填写“JS接口安全域名”,填写前必须在对应的域名服务器的根目录(可访问目录)放置官方txt的文件。配置前最好看一遍官方文档

<script type="text/javascript" src="https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script type="text/javascript" src="${theme_dir}/wx/js/share.js"></script>

这里我把其余的操作放入了share.js。

二、参数获取

根据官方文档可知:

Java实现分享pdf至微信 java 微信分享_JSON

 我们需要的参数:appId,timestamp,nonceStr,signature,jsApiList

Java实现分享pdf至微信 java 微信分享_JSON_02

appId可以直接在公众号的基本配置里面找到;

jsApiList即为调用的微信公众号的接口。需要注意的是:

wx.onMenuShareTimeline(分享到朋友圈)、wx.onMenuShareAppMessage(分享给朋友)、

wx.onMenuShareQQ(分享给好友)、wx.onMenuShareQZone(分享到QQ空间) 这四个接口即将废弃。

客户端6.7.2及JSSDK 1.4.0以上版本支持的 :

wx.updateAppMessageShareData(分享给好友或朋友)、wx.updateTimelineShareData(分享到朋友圈或QQ空间)

这两个接口用来代替。(但是我这只能用旧的,而且手机端不生效,求大神解决)

timestamp、nonceStr和signature都是后台生成的这里有官方的代码Java的只需要把sign.java放入即可《下载链接

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

这是sign.java的部分代码,里面有上面三个参数的生成策略,需要传入参数jsapi_ticket和url,url就是要分享网站的网址,一般是前台传入的当前网址,jsapi_ticket就是需要通过

https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+newToken+"&type=jsapi

 这个网址请求得到,这里需要获得access_token,而access_token需要通过

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret

这个网址请求得到,这里需要获得appid和secret,这两个参数都可以从微信公众号的基本配置里看到,secret需要开启一下。

参数都有了就可以在分享请求时发送给参数给接口完成分享请求。

特别注意:

这里请求获取的的access_token和jsapi_ticket都有时间限制,一般来说为2个小时,而且请求也是有次数限制的(2000次),所以说在一般情况下,要对请求到的access_token和jsapi_ticket进行储存,分享前对储存的值得有效时间进行判断,有效期内便可以直接取用。

Controller:

private static final Logger LOGGER = Logger.getLogger(TokenAction.class);
	@Resource
	private TokenStoreService tokenStoreService;
	
	private String url;
	    //获取ticket
		@Action("/wx/open/userQudao/signature")
	    public void signature() throws Exception{
			String newToken;
			String newTicket;
			//计算access_token
			TokenStore tokenStore=tokenStoreService.getTokenBybindingId(EnumToken.TOKEN.value());//获取数据库存储的token
			if(tokenStore!=null){
				Date d=tokenStore.getAddTime();//获取上次token添加时间
				Long expiresIn=Long.parseLong(tokenStore.getExpiresIn());//获取有效时间
				Long timeDifference = DateUtil.timeDifference(d);//计算时间差
				if(expiresIn/60-timeDifference<10){
					//如果有效时间超过有效时间(-10min误差)则重新获取并更新数据库
					LOGGER.info("重新获取token并更新数据库");
					newToken = tokenStoreService.getTokenUpdateSql(Global.getValue("wx_appId"),Global.getValue("wx_appSecret"),tokenStore);
				}else{
					newToken = tokenStore.getOauthToken();
					LOGGER.info("获取数据库的token,不执行更新");
				}
			}else{
				//获取token并写入数据库
				LOGGER.info("执行Token添加");
				newToken = tokenStoreService.getTokenUpdateSql(Global.getValue("wx_appId"),Global.getValue("wx_appSecret"),tokenStore);
			}
	        //根据token获取ticket
			TokenStore ticketStore=tokenStoreService.getTokenBybindingId(EnumToken.TICKET.value());//获取数据库存储的ticket
			if(ticketStore!=null){
				Date d=ticketStore.getAddTime();//获取上次ticket添加时间
				Long expiresIn=Long.parseLong(ticketStore.getExpiresIn());//获取有效时间
				Long timeDifference = DateUtil.timeDifference(d);//计算时间差
				if(expiresIn/60-timeDifference<10){
					//如果有效时间超过有效时间(-10min误差)则重新获取并更新数据库
					LOGGER.info("重新获取ticket并更新数据库");
					newTicket = tokenStoreService.getTicketUpdateSql(ticketStore,newToken);
				}else{
					newTicket = ticketStore.getOauthToken();
					LOGGER.info("获取数据库的ticket,不执行更新");
				}
			}else{
				newTicket = tokenStoreService.getTicketUpdateSql(ticketStore,newToken);
				LOGGER.info("执行Ticket添加");
			}
            
            //调用微信公众号官方方法生成所需信息
	        Map<String, String> sign = Sign.sign(newTicket.toString(), this.getUrl());
	        //发送json
	        sign.put("appId", EnumToken.APPID.value());
	        printWebJson(JSON.toJSONString(sign));
	        LOGGER.info("json.为:"+JSON.toJSONString(sign));
	    }
		public String getUrl() {
			return url;
		}
		public void setUrl(String url) {
			this.url = url;
		}

service

/**
	 * 获取token并更新数据库(超时或者不存在时) 
	 */
	public String getTokenUpdateSql(String appId, String appSecret,TokenStore tokenStore) {
		//获取token
    	String getTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret;
	 	JSONObject newTokenStr = HttpUtil.doGet(getTokenUrl);
	 	JSONObject newTokenJson = JSONObject.parseObject(newTokenStr.toJSONString());
        String newToken = newTokenJson.getString("access_token");
        String expiresIn=newTokenJson.getString("expires_in");
        //写入数据库
        TokenStore tokenStore2=new TokenStore();
        tokenStore2.setBindingId(EnumToken.TOKEN.value());
        tokenStore2.setAddTime(new Date());
        tokenStore2.setExpiresIn(expiresIn);
        tokenStore2.setOauthToken(newToken);
        if(tokenStore!=null) {
        	tokenStore2.setId(tokenStore.getId());
			this.refreshToken(tokenStore2);
			//System.out.println("执行了Token修改");
		} else {
			this.save(tokenStore2);
			//System.out.println("执行了Token添加");
		}
    	return newToken;
	}
	/**
	 * 获取ticket并更新数据库(超时或者不存在时) 
	 */
	public String getTicketUpdateSql(TokenStore ticketStore,String newToken) {
		//获取token
        String jsapiUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+newToken+"&type=jsapi";
        JSONObject  newTicketStr = HttpUtil.doGet(jsapiUrl);
        JSONObject newTicketJson = JSONObject.parseObject(newTicketStr.toJSONString());
        String newTicket = newTicketJson.getString("ticket");
        String expiresIn = newTicketJson.getString("expires_in");
        //写入数据库
        TokenStore ticketStore2=new TokenStore();
        ticketStore2.setBindingId(EnumToken.TICKET.value());
        ticketStore2.setAddTime(new Date());
        ticketStore2.setExpiresIn(expiresIn);
        ticketStore2.setOauthToken(newTicket);
        if(ticketStore!=null) {
        	ticketStore2.setId(ticketStore.getId());
			this.refreshToken(ticketStore2);
			//System.out.println("执行了Ticket修改");
		} else {
			this.save(ticketStore2);
			//System.out.println("执行了Ticket添加");
		}
    	return newTicket;
	}

 share.js

$(function(){
    var imgUrl = '';  //分享的图片/小图标
    var lineLink = window.location.href;    //当前 页面 地址
    var descContent = '';   //分享简介  小的 图文里面 的 文字部分
    var shareTitle = '';  //标题  这里为 文章标题
    var appid = '';
    $.ajax({
        type : 'POST',
        url :  "", //请求控制器地址
        dataType : "json",
        data:{
            url:window.location.href
        },
        success : function(response){
            var appId = response.appid;     //微信公众号 appid  以下看后端备注
            var timestamp = response.timestamp;
            var noncestr = response.nonceStr;
            var signature = response.signature;
            console.log(response);
            wx.config({
                debug: false,//开启调试模式,调用的所有api的返回值会在客户端alert出来,所有的接口信息会在Console里显示
                appId: appId,//微信id
                timestamp: timestamp,//时间戳
                nonceStr: noncestr,//随机字符串
                signature: signature,//签名
                jsApiList: [
                    'checkJsApi',
                    'onMenuShareAppMessage',
                    'onMenuShareTimeline',
                    'onMenuShareQQ',
                    'updateAppMessageShareData',
                    'updateTimelineShareData'
                ]//使用到的接口
            });
            wx.ready(function() {
                // 判断当前客户端版本是否支持指定JS接口
                wx.checkJsApi({
                  jsApiList: [
                      'onMenuShareAppMessage',
                      'onMenuShareTimeline',
                      'updateAppMessageShareData',
                      'updateTimelineShareData',
                   ], // 需要检测的JS接口列表,所有JS接口列表见附录2,
                  success: function(res) {
            	  console.log(JSON.stringify(res));
                  // 以键值对的形式返回,可用的api值true,不可用为false
                  // 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
                  }
                });
                // 新
                // 自定义“分享给朋友”及“分享到QQ”按钮的分享内容(1.4.0)
                wx.updateAppMessageShareData({
                    title: shareTitle, // 分享标题
                    link: lineLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: imgUrl, // 分享图标
                    desc: descContent, // 分享描述
                    success: function (res) {
                        // 用户确认分享后执行的回调函数
                        //	alert("Xxinok"+JSON.stringify(res));
                        },
                        cancel: function (res) {
                        // 用户取消分享后执行的回调函数
                        	//	alert("X分享取消 "+JSON.stringify(res));
                        },
                        fail: function (res) {
                        	//   alert("X分享失败 "+JSON.stringify(res));
                        }
                });
                // 自定义“分享到朋友圈”及“分享到QQ空间”按钮的分享内容(1.4.0)
                wx.updateTimelineShareData({
                    title: shareTitle, // 分享标题
                    desc: descContent, // 分享描述
                    link: lineLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: imgUrl, // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl:'' , // 如果type是music或video,则要提供数据链接,默认为空
                    success: function (res) {
                        // 用户确认分享后执行的回调函数
                        },
                        cancel: function (res) {
                        // 用户取消分享后执行的回调函数
                        },
                        fail: function (res) {
                        	
                        }
                });
                
                // 旧
                // 自定义“分享给朋友”
                wx.onMenuShareAppMessage({
                    title: shareTitle, // 分享标题
                    link: lineLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: imgUrl, // 分享图标
                    desc: descContent, // 分享描述
                    success: function (res) {
                    // 用户确认分享后执行的回调函数
                    },
                    cancel: function () {
                    // 用户取消分享后执行的回调函数
                    },
                    fail: function () {
                    }
                });
                // 自定义“分享到朋友圈”
                wx.onMenuShareTimeline({
                    title: shareTitle, // 分享标题
                    desc: descContent, // 分享描述
                    link: lineLink, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
                    imgUrl: imgUrl, // 分享图标
                    type: '', // 分享类型,music、video或link,不填默认为link
                    dataUrl:'' , // 如果type是music或video,则要提供数据链接,默认为空
                    success: function (res) {
                    // 用户确认分享后执行的回调函数
                    	//alert("ok"+JSON.stringify(res));
                    },
                    cancel: function (res) {
                    // 用户取消分享后执行的回调函数
                    	//alert("分享取消 "+JSON.stringify(res));
                    },
                    fail: function (res) {
                    }
                });
                //-------------分享到QQ
                wx.onMenuShareQQ({
                 title: shareTitle, // 分享标题
                 desc: descContent, // 分享描述
                 link: lineLink, // 分享链接
                 imgUrl: imgUrl, // 分享图标
                 success: function (res) {
                     // 用户确认分享后执行的回调函数
                     },
                     cancel: function (res) {
                     // 用户取消分享后执行的回调函数
                     },
                     fail: function (res) {
                     }
                });
                //-------------分享到QQ空间
                wx.onMenuShareQZone({
                 title: shareTitle, // 分享标题
                 desc: descContent, // 分享描述
                 link: lineLink, // 分享链接
                 imgUrl: imgUrl, // 分享图标
                 success: function () { 
                 // 用户确认分享后执行的回调函数
                 },
                 cancel: function () { 
                 // 用户取消分享后执行的回调函数
                 }
                });
            });
        },
        error:function(response){
        	 //alert(response.errMsg)
        }
    });

})