微信开发-发送给朋友,分享到朋友圈开发

微信分享功能开发

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

一.服务器端程序

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;
/**
 * 
 * 
 *

Project:mryl_phone_v2

* *

Package:com.wiimedia.controller

* *

Description:微信分享Controller

* *

Company:Wiimedia

* *@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; } } } /** * *

Project:mryl_phone_v2

* *

:mryl_phone_v2

* *

Description:更新和获取ticket的方法,因为用的solr所以更新和新增是一样的ID无则添加,有责更新

* *

Company:Wiimedia

* *@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)); } /** * *

Project:mryl_phone_v2

* *

:mryl_phone_v2

* *

Description:根据标签,时间戳,密匙,URL进行签名

* *

Company:Wiimedia

* *@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 {
    /**
     * 
     *

Project:mryl_phone_v2

* *

:mryl_phone_v2

* *

Description:生成随即字符串

* *

Company:Wiimedia

* *@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;

/**
     * 
     *

Project:mryl_phone_v2

* *

:mryl_phone_v2

* *

Description:公众平台接口工具类

* *

Company:Wiimedia

* *@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,



能力有限,希望有问题及时邮箱或留言,谢谢.

Email:[email protected]

你可能感兴趣的:(接口调用)