站内搜索

java开发微信分享到朋友圈功能

微信分享功能开发

用了一天时间,把微信发送给朋友和分享到朋友圈功能开发出来,在这里给大家分享一下,避免大家走弯路。

一、服务器端程序

package com.wiimedia.controller;  import java.io.IOException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Arrays;import java.util.Date; import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping; import com.google.gson.Gson;import com.wiimedia.model.Ticket;import com.wiimedia.service.ArticleSolrService;import com.wiimedia.service.TicketRepository;import com.wiimedia.service.TicketRepositorySolr;import com.wiimedia.utils.GetRandomStr;import com.wiimedia.utils.SignatureBean;import com.wiimedia.utils.weixin.WeixinUtil;/** *  *  *<p>Project:mryl_phone_v2</p>  *  *<p>Package:com.wiimedia.controller</p>  *  *<p>Description:微信分享Controller</p> * *<p>Company:Wiimedia</p> * *@Athor:SongJia * *@Date:2016-7-15 上午09:34:10 * */ @Controller@RequestMapping("/WeixinshareController/Api/Inteface")public class WeixinshareController { @Autowired private TicketRepositorySolr ticketRepositorySolr;  @RequestMapping("/getSignature") public String getSignature( HttpServletRequest request,   HttpServletResponse response) throws IOException, ParseException{  //获取签名页面链接  String url = request.getParameter("url");  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  //从数据库中获取标签,并检查标签是否过期  Ticket oldticket = ticketRepositorySolr.getTicketById("20160114wiimediamrylsong1152");  if(oldticket==null){//第一次访问,标签不存在。   executeTicket(response,"1",url,format);   return null;  }else{//标签存在,判断标签是否超时   String oldAcquiretime = oldticket.getAcquiretime();   long difference=format.parse(format.format(new Date())).getTime()-format.parse(oldAcquiretime).getTime();   if(difference>7100000){//标签超时,重新到微信服务器请求标签超时时间为7200秒(7200000毫秒)    executeTicket(response,"2",url,format);    return null;    }else{//标签未超时    /**      * 注意事项                * 1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。     * 2.签名用的url必须是调用JS接口页面的完整URL。           * 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。      *      ****根据第1点要求   signature 配置的时候很容易出错,需要把生成 Ticket的 noncestr和 timestamp传给客户端***     */    String signature = signature(oldticket.getTicket(),oldticket.getTimestamp(),oldticket.getNoncestr(),url);    SignatureBean signatureBean = new SignatureBean();    signatureBean.setNoncestr(oldticket.getNoncestr());    signatureBean.setSignature(signature);    signatureBean.setTimestamp(oldticket.getTimestamp());    signatureBean.setUrl(url);    response.setContentType("text/html;charset=UTF-8");    response.getWriter().print(new Gson().toJson(signatureBean));    return null;    }   }   } /**  *   *<p>Project:mryl_phone_v2</p>   *   *<p>:mryl_phone_v2</p>   *   *<p>Description:更新和获取ticket的方法,因为用的solr所以更新和新增是一样的ID无则添加,有责更新</p>  *  *<p>Company:Wiimedia</p>  *  *@Athor:SongJia  *  *@Date:2016-7-15 上午09:45:00   *  */ public void executeTicket(HttpServletResponse response,String flag,String url,SimpleDateFormat format) throws IOException{   //获取签名随即字符串  GetRandomStr randomStr = new GetRandomStr();  String noncestr = randomStr.getRandomString(15);  //获取签名时间戳  String timestamp = Long.toString(System.currentTimeMillis());  //请求accessToken  String accessTokenUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=您的APPID&secret=您的密匙";  String tokenJson = WeixinUtil.httpRequest(accessTokenUrl, "GET", null);  Gson gson = new Gson();  ShareAccess_Token token = gson.fromJson(tokenJson, ShareAccess_Token.class);  String to= token.getAccess_token();  //获取标签  String urlTicket ="https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="+to+"&type=jsapi";  String ticketJson = WeixinUtil.httpRequest(urlTicket, "GET", null);  Ticket ticket = gson.fromJson(ticketJson, Ticket.class);  String t = ticket.getTicket();  //String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");  //我的Ticket ID是写死的  String acquiretime = format.format(new Date());  ticket.setTid("20160114wiimediamrylsong1152");  ticket.setAcquiretime(acquiretime);  ticket.setTimestamp(timestamp);  ticket.setNoncestr(noncestr);  //因为用的SOLR所以更新和添加的方法是一样的,可以根据自己具体需求进行修改,本文不再贴出代码.  if(flag.equals("2")){   ticketRepositorySolr.addTicketToSolr(ticket);   }else{   ticketRepositorySolr.addTicketToSolr(ticket);  }  /**    * 注意事项              * 1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。   * 2.签名用的url必须是调用JS接口页面的完整URL。         * 3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。    *    *根据第1点要求   signature 配置的时候很容易出错,需要把生成 Ticket的 noncestr和 timestamp传给客户端*   */  String signature = signature(t,timestamp,noncestr,url);  SignatureBean signatureBean = new SignatureBean();  signatureBean.setNoncestr(noncestr);  signatureBean.setSignature(signature);  signatureBean.setTimestamp(timestamp);  signatureBean.setUrl(url);  response.setContentType("text/html;charset=UTF-8");  response.getWriter().print(new Gson().toJson(signatureBean)); }  /**  *   *<p>Project:mryl_phone_v2</p>   *   *<p>:mryl_phone_v2</p>   *   *<p>Description:根据标签,时间戳,密匙,URL进行签名</p>  *  *<p>Company:Wiimedia</p>  *  *@Athor:SongJia  *  *@Date:2016-7-15 上午09:37:13   *  */ private String signature(String jsapi_ticket, String timestamp, String noncestr, String url) {  jsapi_ticket = "jsapi_ticket=" + jsapi_ticket;  timestamp = "timestamp=" + timestamp;  noncestr = "noncestr=" + noncestr;  url = "url=" + url;  String[] arr = new String[] { jsapi_ticket, timestamp, noncestr, url };  // 将token、timestamp、nonce,url参数进行字典序排序  Arrays.sort(arr);  StringBuilder content = new StringBuilder();  for (int i = 0; i < arr.length; i++) {   content.append(arr[i]);   if (i != arr.length - 1) {    content.append("&");   }  }  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;  return tmpStr; } /**  * 将字节转换为十六进制字符串  *   * @param mByte  * @return  */ 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; } /**  * 将字节数组转换为十六进制字符串  *   * @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; }   class ShareAccess_Token{  private String access_token;  private String expires_in;  public String getAccess_token() {   return access_token;  }  public void setAccess_token(String accessToken) {   access_token = accessToken;  }  public String getExpires_in() {   return expires_in;  }  public void setExpires_in(String expiresIn) {   expires_in = expiresIn;  }  }}

二、客户端代码.

<script type="text/javascript">   var url = window.location.href;   var articleId = "";   var shareTitle="明日医疗资讯";   var shareImgUrl="";   var userinfo = localStorage.getItem("_userinfo");   var timestamp;   var noncestr;   var signature;   //获取签名    $.ajax({      type: "GET",      url: "WeixinshareController/Api/Inteface/getSignature",      //data:{timestamp:timestamp,noncestr:noncestr,url:url},      data:{url:url},      success: function(data){        var objData=JSON.parse(data);         timestamp=objData.timestamp;         noncestr=objData.noncestr;         signature=objData.signature;         console.log(objData);         wxShare();      }     });   function wxShare(){   wx.config({    debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。    appId: '您的appid', // 和获取Ticke的必须一样------必填,公众号的唯一标识    timestamp:timestamp, // 必填,生成签名的时间戳    nonceStr: noncestr, // 必填,生成签名的随机串    signature: signature,// 必填,签名,见附录1    jsApiList: [    'onMenuShareAppMessage'    ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2   });   }   wx.ready(function(){     //config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,     //config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关     //接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。     //----------“分享给朋友”    wx.onMenuShareAppMessage({     title: "明日医疗资讯", // 分享标题     desc: shareTitle, // 分享描述     link: url, // 分享链接     imgUrl: shareImgUrl, // 分享图标     type: '', // 分享类型,music、video或link,不填默认为link     dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空     success: function () {       // 用户确认分享后执行的回调函数、     },     cancel: function () {       // 用户取消分享后执行的回调函数     }    });    //------------"分享到朋友圈"    wx.onMenuShareTimeline({     title: '明日医疗资讯', // 分享标题     link: '', // 分享链接     imgUrl: shareImgUrl, // 分享图标     success: function () {       // 用户确认分享后执行的回调函数     },     cancel: function () {       // 用户取消分享后执行的回调函数     }    });    //-------------分享到QQ    wx.onMenuShareQQ({     title: '明日医疗资讯', // 分享标题     desc: shareTitle, // 分享描述     link: '', // 分享链接     imgUrl: shareImgUrl, // 分享图标     success: function () {       // 用户确认分享后执行的回调函数     },     cancel: function () {       // 用户取消分享后执行的回调函数     }    });    //-------------分享到QQ空间    wx.onMenuShareQZone({     title: '明日医疗资讯', // 分享标题     desc: shareTitle, // 分享描述     link: '', // 分享链接     imgUrl: shareImgUrl, // 分享图标     success: function () {       // 用户确认分享后执行的回调函数     },     cancel: function () {       // 用户取消分享后执行的回调函数     }    });    });

三、服务器需要的工具类和Model

① Ticket

package com.wiimedia.model;  public class Ticket{ private String tid; private String ticket;  private String errcode; private String errmsg;  private String expires_in; private String acquiretime; private String noncestr; private String timestamp;  public Ticket(String tid, String ticket, String errcode, String errmsg,   String expiresIn, String acquiretime, String noncestr,   String timestamp) {  super();  this.tid = tid;  this.ticket = ticket;  this.errcode = errcode;  this.errmsg = errmsg;  expires_in = expiresIn;  this.acquiretime = acquiretime;  this.noncestr = noncestr;  this.timestamp = timestamp; } public String getTid() {  return tid; } public void setTid(String tid) {  this.tid = tid; } public String getTicket() {  return ticket; } public void setTicket(String ticket) {  this.ticket = ticket; } public String getErrcode() {  return errcode; } public void setErrcode(String errcode) {  this.errcode = errcode; } public String getErrmsg() {  return errmsg; } public void setErrmsg(String errmsg) {  this.errmsg = errmsg; } public String getExpires_in() {  return expires_in; } public void setExpires_in(String expiresIn) {  expires_in = expiresIn; } public String getAcquiretime() {  return acquiretime; } public void setAcquiretime(String acquiretime) {  this.acquiretime = acquiretime; } public String getNoncestr() {  return noncestr; } public void setNoncestr(String noncestr) {  this.noncestr = noncestr; } public String getTimestamp() {  return timestamp; } public void setTimestamp(String timestamp) {  this.timestamp = timestamp; }  }

② 添加到数据库的业务根据自己需要进行实现.
③ GetRandomStr

package com.wiimedia.utils; import java.util.Random; public class GetRandomStr { /**  *   *<p>Project:mryl_phone_v2</p>   *   *<p>:mryl_phone_v2</p>   *   *<p>Description:生成随即字符串 </p>  *  *<p>Company:Wiimedia</p>  *  *@Athor:SongJia  *  *@Date:2016-7-14 上午11:14:46   *  */ public String getRandomString(int length) {  String base = "abcdefghijklmnopqrstuvwxyz0123456789";   Random random = new Random();   StringBuffer sb = new StringBuffer();   for (int i = 0; i < length; i++) {    int number = random.nextInt(base.length());    sb.append(base.charAt(number));   }   return sb.toString();   }}

④ SignatureBean

package com.wiimedia.utils; public class SignatureBean { private String noncestr; private String url; private String timestamp; private String signature; public String getNoncestr() {  return noncestr; } public void setNoncestr(String noncestr) {  this.noncestr = noncestr; } public String getUrl() {  return url; } public void setUrl(String url) {  this.url = url; } public String getTimestamp() {  return timestamp; } public void setTimestamp(String timestamp) {  this.timestamp = timestamp; } public String getSignature() {  return signature; } public void setSignature(String signature) {  this.signature = signature; } }

⑤ WeixinUtil

package com.wiimedia.utils.weixin;import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.ConnectException;import java.net.URL; import javax.net.ssl.HttpsURLConnection;import javax.net.ssl.SSLContext;import javax.net.ssl.SSLSocketFactory;import javax.net.ssl.TrustManager; /**  *   *<p>Project:mryl_phone_v2</p>   *   *<p>:mryl_phone_v2</p>   *   *<p>Description:公众平台接口工具类</p>  *  *<p>Company:Wiimedia</p>  *  *@Athor:SongJia  *  *@Date:2016-7-15 上午09:37:13   *  */public class WeixinUtil {  /**   * 发起https请求并获取结果   *   * @param requestUrl 请求地址   * @param requestMethod 请求方式(GET、POST)   * @param outputStr 提交的数据   * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)   */ public static String httpRequest(String requestUrl, String requestMethod, String outputStr) {    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();    return buffer.toString();   } catch (ConnectException ce) {    ce.printStackTrace();   } catch (Exception e) {    e.printStackTrace();  }   return "";  }}

四、至此,分享功能已经开发完成,但是,在生成signature的时候会遇到很多问题,这里提供一些wx.config失败的排错方法。

① 确认自己的生成的signature是否正确
在微信提供的http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign进行校验

② wx.config中使用的noncestr, timestamp与用以签名中的对应noncestr, timestamp是否一致一致…如上面(一.服务器代码)
(有可能因为JS页面加载顺序问题,服务器生成的signature,noncestr,timestamp在wx.config中没有获取到)。

③ 确认url是页面完整的url,包括GET参数部分
需要去掉#后面的部分

④ config 中的 appid 与用来获取 jsapi_ticket 的 appid 是否一致

⑤ 报错{errmsg:config:ok}是debug的正常返回把调试模式关掉就OK
wx.config debug: false,

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。

更多java开发微信分享到朋友圈功能相关文章请关注PHP中文网!

  • 上一篇:C#微信公众号开发
  • 下一篇:js微信分享API