1.测试环境

申请测试账号

地址: https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index

填写内容:

①:接口配置信息

url:配置http://+域名或者http://+外网ip也可以

token:自定义(任意)

js安全域名(要和url的中的域名)

提交配置信息时微信会先进行验证所以你需要在能访问的url对应的服务上面进行验证代码如下:  能够打印出System.out.println("echostr:"+echostr);的值验证成功.

微信会通过你配置的url+代码中(/) 在你提交接口配置信息时,微信服务会请求到前面叙述的那个路径,来验证成功即能打印出echostr值(关键的一步,如果验证不通过,后续开发没办法进行)

/**
* 微信消息接收和token验证
*
* @param reqDate
* @param request
* @param response
* @throws IOException
value的值你可以自定义,但是要保证和url的一致性
*/
@RequestMapping(value = {"/"}, method = {RequestMethod.POST, RequestMethod.GET})
public void get(@RequestBody(required = false) String reqDate, HttpServletRequest request,HttpServletResponse response) throws Exception {boolean isGet = request.getMethod().toLowerCase().equals("get");PrintWriter print;if (isGet) {// 微信加密签名String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败if (signature != null && CheckoutUtil.checkSignature(signature, timestamp, nonce)) {try {print = response.getWriter();print.write(echostr);print.flush();} catch (IOException e) {e.printStackTrace();}}System.out.println("echostr:"+echostr);}
}
public class CheckoutUtil {private static String token = "weixin"; //与在后台配置的Token一样/*** 验证签名** @param signature* @param timestamp* @param nonce* @return*/public static boolean checkSignature(String signature, String timestamp, String nonce) {String[] arr = new String[] { token, timestamp, nonce };// 将token、timestamp、nonce三个参数进行字典序排序// Arrays.sort(arr);sort(arr);StringBuilder content = new StringBuilder();for (int i = 0; i < arr.length; i++) {content.append(arr[i]);}MessageDigest md = null;String tmpStr = null;try {md = MessageDigest.getInstance("SHA-1");// 将三个参数字符串拼接成一个字符串进行sha1加密byte[] digest = md.digest(content.toString().getBytes());tmpStr = byteToStr(digest);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}content = null;// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;}/*** 将字节数组转换为十六进制字符串** @param byteArray* @return*/private static String byteToStr(byte[] byteArray) {String strDigest = "";for (int i = 0; i < byteArray.length; i++) {strDigest += byteToHexStr(byteArray[i]);}return strDigest;}/*** 将字节转换为十六进制字符串*/private static String byteToHexStr(byte mByte) {char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };char[] tempArr = new char[2];tempArr[0] = Digit[(mByte >>> 4) & 0X0F];tempArr[1] = Digit[mByte & 0X0F];String s = new String(tempArr);return s;}public static void sort(String a[]) {for (int i = 0; i < a.length - 1; i++) {for (int j = i + 1; j < a.length; j++) {if (a[j].compareTo(a[i]) < 0) {String temp = a[i];a[i] = a[j];a[j] = temp;}}}}
}

②:JS接口安全域名(注意:是域名不是url不要携带 http://,直接填写域名否侧报错:invalid url domain)

2.关注测试号二维码(不重要)

url/token/js域名配置都成功之后就可以开始开发了

3.前端页面代码如下:

$.ajax({type: "POST",url: 'http://www.innshine.com/wechat/token',// contentType: "application/json; charset=utf-8",dataType: "JSON",data:{"url":location.href.split('#')[0]},//url一定要是当前的页面的路径而且出去#后面的(微信规定),后台加需要urlsuccess: function (res) {console.log('res', res)wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId: 'wxae743829eed54eaa', // 必填,公众号的唯一标识timestamp: res.timestamp, // 必填,生成签名的时间戳nonceStr: res.noncestr, // 必填,生成签名的随机串signature: res.signature,// 必填,签名jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'] // 必填,需要使用的JS接口列表});wx.ready(function () {   //需在用户可能点击分享按钮前就先调用wx.updateAppMessageShareData({title: 'test', // 分享标题desc: 'test列表', // 分享描述link: 'http://www.innshine.com/wechat/index.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: 'http://www.innshine.com/wechat/images/down.jpg', // 分享图标}, function (res) {console.info("success")});wx.updateTimelineShareData({title: 'test', // 分享标题link: 'http://www.innshine.com/wechat/index.html', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: 'http://www.innshine.com/wechat/images/down.jpg', // 分享图标}, function (res) {console.info("success")});});wx.error(function (res) {//打印错误消息。及把 debug:false,设置为debug:ture就可以直接在网页上看到弹出的错误提示alert("错误error" + JSON.stringify(res));});}
})

4.后端代码:

controller

@Autowired
WxJsApiServer wxJsApiServer;
@Autowired
Properties properties;@RequestMapping("token")
public  Map<String, String> getJsapiTicket(String url)throws DigestException {String token = wxJsApiServer.getAccessTokenByAppIdAndSecret(properties.getAPPID(),properties.getAPPSECRET());String ticket = wxJsApiServer.getJsApiTicketByToken(token);return  getSign(url,ticket);
}//url:去掉不包含#之后的路径
public  Map<String, String> getSign(String url,String ticket ) throws DigestException {
//注意哥哥蚕食都是小写的不要有大写(微信加密参数规则要求)HashMap<String,String> map = new HashMap<String,String>();map.put("jsapi_ticket",ticket);map.put("noncestr",SHA1.generateNonceStr());map.put("timestamp",String.valueOf(SHA1.getCurrentTimestamp()));//注意:一定要重视这一点参加加密的时间戳是秒级的值 不要使用毫秒值map.put("url",url);//生成signatureString signature=SHA1.getSha1Encode(map);map.put("signature",signature);logger.info("signature:{}",signature);return map;
}

properties:参数实体类

@Component
@Data
public class Properties {
/**
* 获取token接口
*/
@Value("${wx.token}")
private String GetPageAccessTokenUrl;
/**
* 获取ticket接口
*/
@Value("${wx.ticket}")
private String GetJsapiTicketUrl;
/**
* 公众号标识
*/
@Value("${wx.appid}")
private String APPID;
/**
* 公众号验证所需参数(必须)
*/
@Value("${wx.secret}")
private String APPSECRET;
}

server

@Autowired
Properties properties;
@Override
public String getAccessTokenByAppIdAndSecret(String APPID, String SECRET) {String wxUrl = properties.getGetPageAccessTokenUrl().replace("APPID", properties.getAPPID()).replace("SECRET", properties.getAPPSECRET());HttpClient client = null;String accessToken = null;try {client = new DefaultHttpClient();HttpGet httpget = new HttpGet(wxUrl);ResponseHandler<String> responseHandler = new BasicResponseHandler();String response = client.execute(httpget, responseHandler);JSONObject OpenidJSONO = JSONObject.parseObject(response);if (OpenidJSONO.get("access_token")==null){return "FALSE";}accessToken = String.valueOf(OpenidJSONO.get("access_token"));//缓存} catch (Exception e) {e.printStackTrace();} finally {//关闭连接client.getConnectionManager().shutdown();}return accessToken;
}
@Override
public String getJsApiTicketByToken(String accessToken) {String requestUrl = properties.getGetJsapiTicketUrl().replace("ACCESS_TOKEN", accessToken);HttpClient client = null;String ticket = null;try {client = new DefaultHttpClient();HttpGet httpget = new HttpGet(requestUrl);ResponseHandler<String> responseHandler = new BasicResponseHandler();String response = client.execute(httpget, responseHandler);JSONObject OpenidJSONO = JSONObject.parseObject(response);if (OpenidJSONO.get("ticket") == null) {return "FALSE";}ticket = String.valueOf(OpenidJSONO.get("ticket"));} catch (Exception e) {e.printStackTrace();} finally {client.getConnectionManager().shutdown();}return ticket;
}

sha1加密

public class    SHA1 {private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5','6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";private static final Random RANDOM = new SecureRandom();/*** Takes the raw bytes from the digest and formats them correct.** @param bytes the raw bytes from the digest.* @return the formatted bytes.*/private static String getFormattedText(byte[] bytes) {int len = bytes.length;StringBuilder buf = new StringBuilder(len * 2);// 把密文转换成十六进制的字符串形式for (int j = 0; j < len; j++) {buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);buf.append(HEX_DIGITS[bytes[j] & 0x0f]);}return buf.toString();
//            Formatter formatter = new Formatter();
//            for (byte b : bytes)
//            {
//                formatter.format("%02x", b);
//            }
//            String result = formatter.toString();
//            formatter.close();
//            return result;}public static String encode(String str) {if (str == null) {return null;}try {MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");messageDigest.update(str.getBytes("UTF-8"));byte[]  bytes= messageDigest.digest();int len = bytes.length;StringBuilder buf = new StringBuilder(len * 2);// 把密文转换成十六进制的字符串形式for (int j = 0; j < len; j++) {buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0xf]);buf.append(HEX_DIGITS[bytes[j] & 0xf]);}return buf.toString();} catch (Exception e) {throw new RuntimeException(e);}}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;}}/*** 获取随机字符串 Nonce Str** @return String 随机字符串*/public static String generateNonceStr() {char[] nonceChars = new char[32];for (int index = 0; index < nonceChars.length; ++index) {nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));}return new String(nonceChars);}/*** 获取当前时间戳,单位秒* @return*/public static long getCurrentTimestamp() {return System.currentTimeMillis()/1000;}/*** 获取当前时间戳,单位毫秒* @return*/public static long getCurrentTimestampMs() {return System.currentTimeMillis();}/*** SHA1 安全加密算法** @return* @throws DigestException*/public static String getSha1Encode(Map<String, String> map)  {String encode = encode(getOrderByLexicographic(map));return encode;}public static String getOrderByLexicographic(Map<String, String> map) {return splitParams(lexicographicOrder(getParamsName(map)), map);}/*** 拼接参数** @param paramNames* @param maps* @return*/public static String splitParams(List<String> paramNames, Map<String, String> maps) {StringBuilder params = new StringBuilder();for (String paramName : paramNames) {params.append(paramName);for (Map.Entry<String, String> entry : maps.entrySet()) {if (paramName.equals(entry.getKey())) {params.append("=" + String.valueOf(entry.getValue()) + "&");}}}params.deleteCharAt(params.length() - 1);return params.toString();}/*** 参数按字典顺序排序** @param paramNames 参数集合* @return 返回排序集合*/public static List<String> lexicographicOrder(List<String> paramNames) {Collections.sort(paramNames);return paramNames;}/*** 获取参数名称 key** @param maps* @return*/public static List<String> getParamsName(Map<String, String> maps) {List<String> paramNames = new ArrayList<String>();for (Map.Entry<String, String> entry : maps.entrySet()) {paramNames.add(entry.getKey());}return paramNames;}

httputile:

public class HttpUtils {/*** get请求,参数拼接在地址上* @param url 请求地址加参数* @return 响应*/public static String get(String url,String AccessToken){String result = null;CloseableHttpClient httpClient = HttpClients.createDefault();url = url.replaceAll(" ","%20");HttpGet get = new HttpGet(url);if(AccessToken != null && !AccessToken.equals("")){get.addHeader("Authorization",AccessToken);}CloseableHttpResponse response = null;try {response = httpClient.execute(get);if(response != null && response.getStatusLine().getStatusCode() == 200){HttpEntity entity = response.getEntity();result = entityToString(entity);}return result;} catch (IOException e) {e.printStackTrace();}finally {try {httpClient.close();if(response != null){response.close();}} catch (IOException e) {e.printStackTrace();}}return null;}/*** get请求,参数放在map里* @param url 请求地址* @param map 参数map* @return 响应*/public static String getMap(String url,String AccessToken,Map<String,String> map){String result = null;CloseableHttpClient httpClient = HttpClients.createDefault();List<NameValuePair> pairs = new ArrayList<NameValuePair>();for(Map.Entry<String,String> entry : map.entrySet()){pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));}CloseableHttpResponse response = null;try {URIBuilder builder = new URIBuilder(url);builder.setParameters(pairs);HttpGet get = new HttpGet(builder.build());if(AccessToken != null && !AccessToken.equals("")){get.addHeader("Authorization",AccessToken);}response = httpClient.execute(get);if(response != null && response.getStatusLine().getStatusCode() == 200){HttpEntity entity = response.getEntity();result = entityToString(entity);}return result;} catch (URISyntaxException e) {e.printStackTrace();} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {httpClient.close();if(response != null){response.close();}} catch (IOException e) {e.printStackTrace();}}return null;}/*** 发送post请求,参数用map接收* @param url 地址* @param map 参数* @return 返回值*/public static  String postMap(String url,Map<String,String> map) {String result = null;CloseableHttpClient httpClient = HttpClients.createDefault();HttpPost post = new HttpPost(url);post.addHeader("Content-Type", "application/json");List<NameValuePair> pairs = new ArrayList<NameValuePair>();if (map != null){for(Map.Entry<String,String> entry : map.entrySet()){pairs.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));}}CloseableHttpResponse response = null;try {post.setEntity(new UrlEncodedFormEntity(pairs,"UTF-8"));response = httpClient.execute(post);if(response != null && response.getStatusLine().getStatusCode() == 200){HttpEntity entity = response.getEntity();result = entityToString(entity);}return result;} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {httpClient.close();if(response != null){response.close();}} catch (IOException e) {e.printStackTrace();}}return null;}/*** 发送post请求,参数用map<String object>接收* @param url* @param map* @param encoding* @return*/public static String mapPost(String url, Map<String,Object> map, String encoding){CloseableHttpClient httpClient = null;HttpPost httpPost = null;String result = null;try{httpClient = HttpClients.createDefault();httpPost = new HttpPost(url);//设置参数List<NameValuePair> list = new ArrayList<NameValuePair>();Iterator iterator = map.entrySet().iterator();while(iterator.hasNext()){Map.Entry<String,String> elem = (Map.Entry<String, String>) iterator.next();list.add(new BasicNameValuePair(elem.getKey(),String.valueOf(elem.getValue())));}if(list.size() > 0){UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,encoding);httpPost.setEntity(entity);}HttpResponse response = httpClient.execute(httpPost);if(response != null){HttpEntity resEntity = response.getEntity();if(resEntity != null){result = EntityUtils.toString(resEntity,encoding);}}}catch(Exception ex){ex.printStackTrace();}System.out.println(result);return result;}/*** post请求,参数为json字符串* @param url 请求地址* @param jsonString json字符串* @return 响应*/public static String postJson(String url,String jsonString,String AccessToken){String result = null;CloseableHttpClient httpClient = HttpClients.createDefault();HttpPost post = new HttpPost(url);post.addHeader("Content-Type", "application/json");if(AccessToken != null && !AccessToken.equals("")){post.addHeader("Authorization",AccessToken);}CloseableHttpResponse response = null;try {if(jsonString != null && !jsonString.equals("")){post.setEntity(new ByteArrayEntity(jsonString.getBytes("UTF-8")));}response = httpClient.execute(post);if(response != null && response.getStatusLine().getStatusCode() == 200){HttpEntity entity = response.getEntity();result = entityToString(entity);}return result;} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {try {httpClient.close();if(response != null){response.close();}} catch (IOException e) {e.printStackTrace();}}return null;}private static String entityToString(HttpEntity entity) throws IOException {String result = null;if(entity != null){long lenth = entity.getContentLength();if(lenth != -1 && lenth < 2048){result = EntityUtils.toString(entity,"UTF-8");}else {InputStreamReader reader1 = new InputStreamReader(entity.getContent(), "UTF-8");CharArrayBuffer buffer = new CharArrayBuffer(2048);char[] tmp = new char[1024];int l;while((l = reader1.read(tmp)) != -1) {buffer.append(tmp, 0, l);}result = buffer.toString();}}return result;}}

正式环境开发:

登录公众号平台:

配置两处:

1.导航"基础配置"中配置url/token,配置要求和测试配置一样.

2.再在"基础配置"的"ip白名单"添加项目所要部署到的服务器的ip.

3.导航"公众号设置"中再点击"功能设置"然后配置"js安全域配置,注意此时需要下载一个文件MP_verify_gt5yNwRcoQWm4SIk.txt,文件可在弹出窗口中的提示出获取,文件下载以后*(springboot项目为例)放在static目录下,然后通过上面配置的url+文件名,页面响应一串字符串即代表成功.

正是开发代码和测试代码一样.

微信 JS 接口签名校验工具: https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

nginx配置

安装和配置过程可以自己百度:

注意点给大家说一下:nginx.conf文件

server {listen       8089;//只是服务器开放的端口并不是项目端口号,但是却要和项目的端口号保持一致.默认是80端口server_name  www.innshines.com;//你自己的域名location /wxshare {# root   html;# index  index.html index.htm;proxy_pass   http://127.0.0.1:8089;//项目部署所在的服务器的本地ip,端口记得要开放而且要在防火墙的白名单中放行端口}}

微信jsapi 调用分享接口(完整版)相关推荐

  1. html5 调用微信分享,HTML5教程之微信调用分享接口

    1.前端用的angular1框架,首先需要在index页面引入微信接口文件: 2.在myApp.run文件中写微信分享函数,注意该函数需要将当前页面的url获取并解析,然后发给后端来生成对应签名,直接 ...

  2. 微信端H5页面调用分享接口

    最近公司做了一个给学生投票的H5页面,主要是在微信端使用,需要添加微信分享功能: 本文章主要是记录调用微信分享接口需要注意的事项: 1.前端用的angular1框架,首先需要在index页面引入微信接 ...

  3. 微信朋友圈分享接口使用总结

    微信朋友圈分享接口是非常细节的,而且不好调试,所以在此总结一下,以帮助大家 首先应该遵循微信开发者文档介绍,用接口调试工具将你需要的接口的权限确定一下(这里得去申请接口权限)?然后将这个网址用手机端微 ...

  4. 微信JSSDK自定义分享接口的策略调整--纪念我们被坑过的五一

    引言 五一假期已过半,再睡一个懒觉,就要开始新的一天工作,想想都有点小激动呢~~~~~~ 问题现象 1.微信公众号自定义分享无法显示自定义的数据,朋友圈也是如此,但是(重点来了,拿好小板凳!),qq和 ...

  5. 小程序微信支付申请与配置完整版操作流程

    小程序微信支付申请与配置完整版操作流程 一. 申请小程序微信支付 微信支付申请分为两种情况: 情况一,申请新的微信支付商户号: 情况二,绑定已有微信支付商户号 注意:申请微信支付的小程序账户需要进行微 ...

  6. 微信表情的字符编号完整版【图文并茂哦!】

    [图文并茂哦!] Emoji表情的分类(微信表情的字符编号完整版) Emoji表情有很多种版本,包括Unified.FreeEIM.DoCoMo.KDDI.Softbank和Google,而且不同版本 ...

  7. 月结流程概述(加作者微信索取无水印PDF完整版)

    http://blog.sina.com.cn/s/blog_eb52f4660102wl7c.html 1.1    月结流程概述(加作者微信索取无水印PDF完整版) 下表为典型的制造业期末财务结算 ...

  8. Vue开发微信公众号调用微信JS-SDK的分享接口(实现微信公众号分享功能)

    描述 使用微信提供的分享功能,其实就是JSSDK使用,使用它提供的接口功能. 可以先看下微信公众号开发文档,上面介绍的很详细.提供了那些功能,怎么去使用. https://developers.wei ...

  9. 微信小程序分享接口卡片图片尺寸比例

    调用微信小程序分享需要button标签 <button open-type="share">test</button> 然后在js的page里加一个函数 o ...

最新文章

  1. 基于adaboost的人脸检测方法
  2. 转向AIOps之前,你应该做好哪些准备?
  3. 快速排序,冒泡排序时间复杂度推导
  4. PHP用CURL伪造IP和来源
  5. java序列化的方法_【Java常见序列化与反序列方法总结】
  6. mac11.14 mysql_mysql 5.7 11 章 数据类型(1)
  7. 树莓派教程 - 1.6 树莓派GPIO库wiringPi 外接USB串口ttyUSB ch340 cp2102
  8. mockito简单教程
  9. I210网卡LINUX的mac,intel(R)I211网卡刷I210简易教程
  10. 有关气象数据资料下载网址
  11. linux su root 限制,Linux禁止普通用户su至root
  12. leetcode每日一题-字符串中的第一个唯一字符
  13. c语言随机数字密码生成器,随机数生成器(浮点数整型数)
  14. 466. 回文日期 Java题解 (模拟)
  15. 汉芯门主角制造另外一个汉芯?
  16. 在Deepin 15.11系统中遇到微信版本过低不能登录的解决方法
  17. 光线:提高照片的艺术感
  18. 我xp电脑桌面没有计算机图标不见了,XP电脑开机后桌面图标打开方式全部不见的恢复方法...
  19. 电子器件系列25:74HC138译码器
  20. 怎么用clear case?

热门文章

  1. Reqtify需求追踪中遇到SCADE ALM GateWay问题
  2. java通过麒麟实现开机自启动,京东四面:说说Tomcat 在 SpringBoot 中是如何启动的!...
  3. 切换成root用户失败
  4. 迈思德网关成功与TLINK物联网平台对接
  5. 苹果手机的处理器全都是64位的吗?
  6. 80后制作密室手游 登索尼平台获得千万风投
  7. ubuntu服务器lxde桌面,UBUNTU最小化搭建LXDE桌面环境
  8. 浅浅浅学 Spring 基基基础
  9. 神漏洞!一张高清照片,破解三星Galaxy S8虹膜识别
  10. 增加最少的边使有向图变为强连通图