调用微信JS-SDK自定义分享以及其他接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zzxzzxhao/article/details/78315314

微信里第三方网页分享是默认没有图标还有简介之类的内容,如果我们想实现自定义分享效果,必须得调用微信官方的js-sdk,之前有网站提供这些服务,现在微信封死了,只能通过这种方式来实现。现在介绍如何实现。


前期准备

(1)已经通过实名验证的微信公众号
这个不需要过多介绍吧。。。

(2)通过备案的域名
域名、服务器这些也不过多介绍,网上很多教程;
如果想本地测试的话,个人使用过花生壳内网穿透这个软件,蛮好的,价格也便宜。至于Nginx。。。好像墙越来越高了,尝试使用未能成功。。。
①JS接口安全域名
感觉这个蛮重要的,主要很多人设置错误,导致后面验证无法通过,所以还是写一下
公众号设置-功能设置这里可以设置,具体要求,点开设置里面都有,按照要求来即可,安全域名设置以后,后面调用的时候,一定要把安全域名写全!!不然会自定义分享失败!

(3)查看AppId,AppSecret

(4)推荐使用官方自带工具:微信开发者工具,用于本地调试。
下载地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140
好处:
1.使用自己的微信号来调试微信网页授权
2.调试、检验页面的 JS-SDK 相关功能与权限,模拟大部分 SDK 的输入和输出
3.使用基于 weinre 的移动调试功能,支持 X5 Blink 内核的远程调试
4.利用集成的 Chrome DevTools 协助开发
(需要注意的是,有时候在微信开发者工具上能成功调用js-sdk,但是实机测试不行,这类情况一般是调用参数出错,我的话就是上面提到的域名设置出错,其他的还没发现)


具体代码实现:

(1)引入JS文件
这里需要注意是http还是https,如果生产环境是https,务必前缀是https,都则会出现mix content这样的错误,导致引入失败。

<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
现行版本是1.2,可以查看官方文档更新。

(2)通过config接口注入权限验证配置
官方说明:

js代码实现:
//微信校检
	var url=location.href.split('?').toString();
	$.ajax({
		url:appIndex.(微信验证地址),
		type:"post",
		data:{"url":url},
		dataType:"json",
		success:function(res){
			 wx.config({
	                debug: false,////生产环境需要关闭debug模式
	                appId: res.appid,//appId通过微信服务号后台查看
	                timestamp: res.timestamp,//生成签名的时间戳
	                nonceStr: res.nonceStr,//生成签名的随机字符串
	                signature: res.signature,//签名
	                jsApiList: [//需要调用的JS接口列表
	                    'checkJsApi',//判断当前客户端版本是否支持指定JS接口
	                    'onMenuShareTimeline',//分享给好友
	                    'onMenuShareAppMessage',//分享到朋友圈
	                    'closeWindow',//窗口关闭
	                ]
	            });
		}
	});

(3)通过ready接口处理成功验证
官方说明:

js代码实现:
//config参数加载完成以后进行
wx.ready(function(){
	//分享到朋友圈
	wx.onMenuShareTimeline({
	    title: '标题', // 分享标题
	    link: 'http://www.***/Live/mobile/mobileindex.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
	    imgUrl: 'http://www.***/views/images/livepic.jpg', // 分享图标
	    success: function () { 
	    },
	    cancel: function () { 
	        // 用户取消分享后执行的回调函数
	    }
	});
	
	//分享给朋友
	wx.onMenuShareAppMessage({
	    title: '标题', // 分享标题
	    desc: '描述', // 分享描述
	    link: 'http://www.***/CR/Live/mobile/mobileindex.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致
	    imgUrl: 'http://www.***/views/images/livepic.jpg', // 分享图标
	    type: '', // 分享类型,music、video或link,不填默认为link
	    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
	    success: function () { 
	    },
	    cancel: function () { 
	        // 用户取消分享后执行的回调函数
	    }
	});
});
(注意: 我上面的所有链接地址,都是我安全域名下的文件路径,建议带上http://,不带好像会出问题)

(4)Java代码
我的工程是ssm框架的,不过代码不复杂
package com.zzx.Weixin.Util.action;

import java.io.IOException;
import java.security.MessageDigest;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.zzx.Weixin.Util.service.WeixinService;
import com.zzx.pojo.AccessToken;
import com.zzx.pojo.JsapiTicket;
import com.zzx.sys.control.JsonObject;
import com.zzx.sys.control.JsonUtil;
import com.zzx.sys.control.Result;
import com.zzx.sys.control.util.HttpUtils;

import net.sf.json.JSONObject;

/**
* @author 郑志欣
* @date 2017年10月7日
* 微信工具类,主要为微信校检信息服务
*/
@Controller
public class WeixinController {
	@Autowired
	private WeixinService wxservice;
	
	private static final String APPID="YOURAPPID";
	
	private static final String APPSECRET="YOURAPPSECRET";
	
	private static final String ACCESS_TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

	private static final String JSAPI_URL="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi";

	//微信参数
	private static String accessToken;
	private static String jsApiTicket;
	
	
	@RequestMapping("微信验证地址")
	public void getWechatParam(HttpServletRequest request, HttpServletResponse response){
		Result result =new Result();
		String rpr=request.getParameter("url");
		String url;
		String[] strs = rpr.split(",");
		if(strs.length==1) {
			url=strs[0];
		}else {
			url=strs[0]+"?"+strs[1]+"&"+strs[2];
		}
		long nowTime=System.currentTimeMillis();
		
		//获取数据库保存的access_token
		AccessToken token=wxservice.getAccessToken();
		accessToken=token.getToken();
		long tokenTime=token.getExpiresIn();
		
		//判断数据库中是否存在access_token或者是否过期
		if(StringUtils.isBlank(accessToken)||nowTime-tokenTime>0) {
			AccessToken tokenInfo=getAccessToken();
			if(tokenInfo!=null) {
				long getTokenTime=tokenInfo.getExpiresIn();
				long expiretime=nowTime+(getTokenTime*1000);
				String getToken=tokenInfo.getToken();
				
				//把accesstoken保存到数据库
				wxservice.setAccessToken(getToken,expiretime);
				accessToken=tokenInfo.getToken();
			}
		}
		
		//获取数据库中的JsapiTicket
		JsapiTicket ticket=wxservice.getJsapiTicket();
		jsApiTicket=ticket.getTicket();
		long ticketTime=ticket.getExpiresIn();
		
		//判断数据库中是否存在jsapi_ticket或者是否过期
		if(StringUtils.isBlank(jsApiTicket)||nowTime-ticketTime>0) {
			JsapiTicket ticketInfo=getJsapi_ticket();
			if(ticketInfo!=null) {
				long getTicketTime=ticketInfo.getExpiresIn();
				long expiretime=nowTime+(getTicketTime*1000);
				String getTicket=ticketInfo.getTicket();
				
				//把jsapi_ticket保存到数据库中
				wxservice.setJsapiTicket(getTicket,expiretime);
				jsApiTicket=ticketInfo.getTicket();
			}
		}
		
		//生成微信权限验证的参数
		String nonceStr = createNonceStr();
        String timestamp = createTimestamp();
        String string1;
        
        //注意这里参数名必须全部小写,且必须有序
        string1 = "jsapi_ticket=" + jsApiTicket +
                "&noncestr=" + nonceStr +
                "×tamp=" + timestamp +
                "&url=" + url;
        
        //sha1加密
        String signature=getSha1(string1);
        
        result.getData().put("url",url);
        result.getData().put("jsapi_ticket",jsApiTicket);
        result.getData().put("nonceStr",nonceStr);
        result.getData().put("timestamp",timestamp);
        result.getData().put("signature",signature);
        result.getData().put("appid",APPID);
        
        JsonUtil.output(response, result);
	}
	
	/**
	 * get请求
	 * @param url
	 * @return
	 */
	public static JSONObject doGetStr(String url) {
		CloseableHttpClient httpClient=HttpClients.createDefault();
		HttpGet httpGet=new HttpGet(url);
		JSONObject jsonObject=null;
		try {
			HttpResponse response=httpClient.execute(httpGet);
			HttpEntity entity=response.getEntity();
			
			if(entity !=null) {
				String result=EntityUtils.toString(entity,"UTF-8");
				jsonObject=JSONObject.fromObject(result);
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return jsonObject;
	}
	
	/**
	 * 获取access_token
	 * @return token
	 */
	public static AccessToken getAccessToken() {
		AccessToken token=new AccessToken();
		String url=ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET",APPSECRET);
		JSONObject jsonObject=doGetStr(url);
		if(jsonObject!=null) {
			token.setToken(jsonObject.getString("access_token"));
			token.setExpiresIn(jsonObject.getInt("expires_in"));
		}
		
		return token;
	}
	
	/**
	 * 获取jsapi_ticket
	 * @return 
	 */
	public static JsapiTicket getJsapi_ticket() {
		JsapiTicket jsapi=new JsapiTicket();
		String url=JSAPI_URL.replace("ACCESS_TOKEN",accessToken);
		JSONObject jsonObject=doGetStr(url);
		if(jsonObject!=null) {
			jsapi.setExpiresIn(jsonObject.getInt("expires_in"));
			jsapi.setTicket(jsonObject.getString("ticket"));
		}
		return jsapi;
	}
	
	//生成随机字符串
    private static String createNonceStr() {
        return UUID.randomUUID().toString();
    }
    //生成时间戳
    private static String createTimestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
    //sha1加密方法
  	public static String getSha1(String str) {
  		if(str==null||str.length()==0) {
  			return null;
  		}
  		char hexDigits[]= {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
  		
  		try {
  			MessageDigest mdTemp=MessageDigest.getInstance("SHA1");
  			mdTemp.update(str.getBytes("UTF-8"));
  			
  			byte[] md=mdTemp.digest();
  			int j=md.length;
  			char buf[]=new char[j*2];
  			int k=0;
  			for (int i = 0; i < j; i++) {
  				byte byte0=md[i];
  				buf[k++]=hexDigits[byte0>>>4 & 0xf];
  				buf[k++]=hexDigits[byte0 & 0xf];
  			}
  			return new String(buf);
  		} catch (Exception e) {
  			return null;
  		}
  	}
}

里面的JsonUtil和Result是我的两个工具类,就是使用hasmap存放数据。这里说一下,access_token和JsapiTicket每天调用次数有限,所以最好保存下来,至于你怎么保存,看你的需求,反正我是直接存放到数据库里,后面的service层和dao层代码不贴了,大概都会

后面就可以进行测试了。。。

猜你喜欢

转载自blog.csdn.net/zzxzzxhao/article/details/78315314