当用户购买成功一样产品,为了使用户能够二次消费,可以在订单详细页面加一个红包按钮,当用户点击之后,可以分享特定的内容(一个title、一段描述、一条超连接、一张图片)给朋友或者分享到朋友圈,当用户点击之后进入一个输入手机号码(即登录账号或绑定的手机号码)的页面,提交之后随机抽取代金券。如果你吃过“美团外卖”,对于这个流程可能就很清晰了。
如下图流程步骤:
我是利用spring封装简单的任务调度器,1个小时自动调用微信jsapi_ticket接口,获取微信使用JS-SDK使用的权限问题的。首先,为了获取jsapi_ticket需要access_token公众号的全局唯一票据。第二步,根据access_token获取jsapi_ticket。第三步,缓存获取的jsapi_ticket参数。
需要的参数:
请求连接(GET):https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
公众号AppID(应用ID):wx****************
公众号AppSecret(应用密钥):2b****************************e0
需要的参数:
请求连接(GET):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
微信全局票据凭证(access_token):********…
设置一个静态的字符串,运用spring任务调度器,每隔一个小时改变该字符串的值。
以上三个步骤集成在一个方法里,代码如下:
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import com.qq.weixin.constant.Constant;
import com.qq.weixin.publics.WXUtils;
public class JsapiTicketTimeTask {
public static String jsapi_ticket = "";
/**
*
* @method getTicket
* @描述: TODO(每隔一个小时调用一次微信获取jsapi的接口的任务调用器,在spring配置里面调用)
* @参数
* @返回类型:void
* @添加时间 2015-9-1下午04:22:16
* @作者:Mr.zhou
*/
public void getTicket() {
//调用微信接口获取access_token凭证
//Constant.ACCESS_TOKEN = https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
String tokenUrl = Constant.ACCESS_TOKEN.replace("APPID", Constant.APPID).replace("APPSECRET", Constant.APPSECRET);
String tokenStr = WXUtils.httpsRequest(tokenUrl, "GET", null);
try {
JSONObject tokenJson = new JSONObject(tokenStr);
String access_token = (String) tokenJson.get("access_token");
if(access_token != null && !"".equals(access_token)){
//如果可以获取access_token,即可以调用jsapi_tiket的凭证了
String ticketUrl = Constant.JSAPI_TICKET.replace("ACCESS_TOKEN", access_token); //Constant.JSAPI_TICKET = https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
String ticketStr = WXUtils.httpsRequest(ticketUrl, "GET", null);
JSONObject ticketJson = new JSONObject(ticketStr);
String errmsg = (String) ticketJson.get("errmsg");
//如果调用成功,返回ok
if("ok".equals(errmsg)){
jsapi_ticket = (String) ticketJson.get("ticket");
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
WXUtils.httpsRequest方法:
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 java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
//http请求
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr){
try {
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
return buffer.toString();
} catch (ConnectException ce) {
System.out.println("连接超时:{}");
} catch (Exception e) {
System.out.println("https请求异常:{}");
}
return null;
}
spring XML任务调度器代码:
<bean id="jsapiTask" class="cn.ly.web.quartz.JsapiTicketTimeTask">bean>
<bean id="timerTask"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref="jsapiTask">property>
<property name="targetMethod" value="getTicket">property>
bean>
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="delay" value="1000">property>
<property name="period" value="3600000">property>
<property name="timerTask" ref="timerTask">property>
bean>
<bean class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTask" />
list>
property>
bean>
在需要调用微信转发图文消息的订单详细页面,首先需要引入微信的js文件(http://res.wx.qq.com/open/js/jweixin-1.0.0.js),然后加载该页面的时候需要进行ajax与服务器端进行参数的交互,根据获取的参数,调用微信的权限接口验证是否能够使用微信的接口功能。
<script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js">script>
<script type="text/javascript">
$(function(){
ajaxConfig();
});
function ajaxConfig(){
$.ajax({
type:"post",
dataType: "json",
data: {
url : location.href.split('#')[0]
},
url: "ajax_order/testConfig",
success: function(obj){
if(obj.result == "success"){
//微信注入权限接口
wx.config({
debug: false,
appId: obj.appId,
timestamp: obj.timestamp,
nonceStr: obj.nonceStr,
signature: obj.signature,
jsApiList: [
'onMenuShareTimeline', //分享到朋友圈
'onMenuShareAppMessage' //分享给朋友
]
});
}else{
alert("加载数据错误");
}
},
error:function(){
alert("系统请求异常!");
}
});
}
script>
ajax_order/testConfig方法:
import java.util.Date;
import java.util.Map;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.opensymphony.xwork2.ActionSupport;
import com.qq.weixin.constant.Constant;
import com.qq.weixin.publics.Sign;
@Component
@Scope("prototype")
public class ShareAction extends ActionSupport{
private String timestamp,nonceStr,signature,appId=Constant.APPID; //签名需要的参数
private String url; //JS-SDK授权的url
private String result;
/**
*
* @method testConfig
* @描述: TODO(微信config接口注入权限)
* @参数@return
* @返回类型:String
* @添加时间 2015-9-2下午02:35:54
* @作者:Mr.zhou
*/
public String testConfig(){
//JsapiTicketTimeTask.jsapi_ticket 是通过spring调度器每1个小时与微信端进行通信,获取jsapi_ticket凭证
String jsapi_ticket = JsapiTicketTimeTask.jsapi_ticket;
if("".equals(jsapi_ticket)){
result = "error";
return SUCCESS;
}
//进行数据的加密(url,jsapi_ticket,nonceStr,timestamp)等参数进行SHA1加密
Map ret = Sign.sign(jsapi_ticket, url);
timestamp = ret.get("timestamp");
nonceStr = ret.get("nonceStr");
signature = ret.get("signature");
result = "success";
return SUCCESS;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getNonceStr() {
return nonceStr;
}
public void setNonceStr(String nonceStr) {
this.nonceStr = nonceStr;
}
public String getSignature() {
return signature;
}
public void setSignature(String signature) {
this.signature = signature;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setResult(String result) {
this.result = result;
}
public String getResult() {
return result;
}
}
}
Sign方法请点击下载,官方例子
在上面的config权限注入成功之后,就可以调用微信的分享接口,把设定的内容分享给朋友或者朋友圈了。当然,如果内容是动态获取的,那么你就可以在调用当前接口的时候,ajax获取一些动态的信息,然后在调用分享接口。当前我是以静态的分享案例为例子。
注意:下面的wx.**方法,都是上面jsApiList包含的方法名称哦。比如你需要调用微信的导航接口,就需要在jsApiList列表里面添加‘openLocation’这个方法了。
$(function(){
//当用户点击一个id为testBtn的按钮的时候激活事件
$("#testBtn").click(function(){
wx.onMenuShareAppMessage({
title: '互联网之子',
desc: '在长大的过程中,我才慢慢发现,我身边的所有事,别人跟我说的所有事,那些所谓本来如此,注定如此的事,它们其实没有非得如此,事情是可以改变的。更重要的是,有些事既然错了,那就该做出改变。',
link: 'http://movie.douban.com/subject/25785114/',
imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
trigger: function (res) {
// 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
alert('用户点击发送给朋友');
},
success: function (res) {
alert('已分享');
},
cancel: function (res) {
alert('已取消');
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
alert('已注册获取“发送给朋友”状态事件');
wx.onMenuShareTimeline({
title: '互联网之子',
link: 'http://movie.douban.com/subject/25785114/',
imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg',
trigger: function (res) {
// 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,因为客户端分享操作是一个同步操作,这时候使用ajax的回包会还没有返回
alert('用户点击分享到朋友圈');
},
success: function (res) {
alert('已分享');
},
cancel: function (res) {
alert('已取消');
},
fail: function (res) {
alert(JSON.stringify(res));
}
});
alert('已注册获取“分享到朋友圈”状态事件');
});
});
当你熟悉了以上的大致流程之后,你就可以调用一些微信JS-SDK的功能了,比如导航当前与目标位置,转发消息到朋友圈或者QQ空间等等。如果博客写得不好,还请大家多多包涵。= =!
微信2017年4月25日起,分享的链接一定要与公众号JS设置的安全域名一致哦。例如安全域名是www.abc.com 那么www.abc.com/123是成功的,但是www.def.com/123就不成功了。