java開發微信分享到朋友圈功能
阿新 • • 發佈:2019-01-27
微信分享功能開發
用了一天時間,把微信傳送給朋友和分享到朋友圈功能開發出來,在這裡給大家分享一下,避免大家走彎路。
一、伺服器端程式
二、客戶端程式碼.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();
}
}
④ SignatureBeanpackage 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;
}
}
⑤ WeixinUtilpackage 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,
以上就是本文的全部內容,希望對大家的學習有所幫助
喜歡我的文章的,可以關注微信公眾號“測試專案開發”,需要什麼內容可以在裡面提,我看到後會給大家解答。