热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

微信分享功能开发用了一天时间,把微信发送给朋友和分享到朋友圈功能开发出来,在这里给大家分享一下,避免大家走弯路。一.服务器端程序packagecom.wiimedia.control

微信分享功能开发

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

一.服务器端程序

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 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 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 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:358106209@qq.com


推荐阅读
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
author-avatar
蓝染
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有