微信接口的JAVA简单封装

微信接口这块的东西不是弄起来不算特别难,封装好了基本都能复用,不过没做过微信开发的同学第一次整起来还是显得有些蛋疼的。

正好最近有弄微信的项目,把里头基础接口方面代码的封装记录一下,主要是jssdk方面和微信接口授权方面的java代码。

一、access_token和ticket

微信里面有两个access_token,一个是网页授权的access_token,这个是独立的token,第二个是其他接口调用的时候需要使用。这两个token都是需要进行全局缓存然后7200秒更新一次的。这里先说第二个token。

获取并缓存token和ticket的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public static Map<String,String> GetWxAccess() {
long timestamp = System.currentTimeMillis() / 1000;
String ACCESS_TOKEN = "";
String ticket = "";
WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
ServletContext sc = webApplicationContext.getServletContext();
//获取缓存
String at = "";
if(sc.getAttribute("ACCESS_TOKEN")!=null){
at = (String) sc.getAttribute("ACCESS_TOKEN");
}
long at_alive = 0;
if(sc.getAttribute("AT_ALIVE")!=null){
at_alive = (Long) sc.getAttribute("AT_ALIVE");
}
boolean time = (timestamp-at_alive)<7000;
//at有效
if(at!=null&&!"".equals(at)&&time){
ACCESS_TOKEN = at;
ticket = (String) sc.getAttribute("ticket");
}else{
//at无效
String ACCESS_TOKEN_RSP = HttpRequest.sendGet("https://api.weixin.qq.com/cgi-bin/token", "grant_type=client_credential&appid="+appid+"&secret="+secret);
JSONObject jb3 = JSONObject.fromObject(ACCESS_TOKEN_RSP);
Map map3 = (Map)jb3;
ACCESS_TOKEN = (String) map3.get("access_token");
String jsapi_ticket_RSP = HttpRequest.sendGet("https://api.weixin.qq.com/cgi-bin/ticket/getticket", "access_token="+ACCESS_TOKEN+"&type=jsapi");
JSONObject jb4 = JSONObject.fromObject(jsapi_ticket_RSP);
Map map4 = (Map)jb4;
ticket = (String) map4.get("ticket");
sc.setAttribute("ACCESS_TOKEN",ACCESS_TOKEN );
sc.setAttribute("ticket",ticket );
sc.setAttribute("AT_ALIVE", timestamp);
}
Map<String, String> res =new HashMap<String, String>();
res.put("ACCESS_TOKEN", ACCESS_TOKEN);
res.put("ticket", ticket);
return res;
}
public static String GetAccessToken(){
Map<String, String> map = GetWxAccess();
return map.get("ACCESS_TOKEN");
}
public static String GetTicket(){
Map<String, String> map = GetWxAccess();
return map.get("ticket");
}

二、jssdk

jssdk主要是后台计算signature然后在前端js中进行配置config。
我习惯前端使用ajax获取config如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
(function() {
if(window.location.host.indexOf("localhost")>=0) return;
$.ajax({
url:"../wxAuth/getconfig",
method:"get",
data:{url:window.location.host+window.location.pathname+window.location.search},
success:function(data){
var wxconfig= new WXConfig();
wxconfig.appId=data.appId;
wxconfig.timestamp=data.timestamp;
wxconfig.nonceStr=data.nonceStr;
wxconfig.signature=data.signature;
SetWXConfig(wxconfig);
}
})
})();
var WXConfig=function(){
this.appId=null;
this.timestamp=null;
this.nonceStr=null;
this.signature=null;
};
var SetWXConfig= function(wxconfig){
wx.config({
debug: false,
appId: wxconfig.appId,
timestamp: wxconfig.timestamp,
nonceStr: wxconfig.nonceStr,
signature: wxconfig.signature,
jsApiList: [
'chooseImage',
'uploadImage',
'downloadImage',
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone'
]
});
}

页面加载时自动请求获取config,在success方法中配置wx.config。

这样做个人觉得在通用性方面好一点,因为微信token只能全局缓存一个,所有如果公众号下面有多个项目,可以起一个单独的项目做这些事,其他项目只用在需要的时候去获取就ok了,从而避免token的冲突。

对应的后台部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@ResponseBody
@RequestMapping("getconfig")
public JSONObject GetConfig(String url){
JSONObject json = new JSONObject();
long timestamp = System.currentTimeMillis() / 1000;
String noncestr = UUID.randomUUID().toString();
String signature = "";
String ACCESS_TOKEN = WXPushService.GetAccessToken();
String ticket = WXPushService.GetTicket();
String str = "jsapi_ticket="+ticket+"&noncestr="+noncestr+"&timestamp="+timestamp+"&url=http://"+url;
signature = SHA1.getSHA1(str);
json.put("appId", appid);
json.put("timestamp", timestamp);
json.put("nonceStr", noncestr);
json.put("signature", signature);
return json;
}

三、网页授权

网页授权部分东西不算很多,有一个特殊的access_token需要缓存,目前项目中我把网页授权部分放在了拦截器中,代码集成的不多,全写在一坨离了,逻辑也略微蛋疼,凑合着看

the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//检查session
if(AuthService.checkLogin(request)){
return AuthService.checkAuth();//检查内部的访问权限
}else {
String code = request.getParameter("code");
String state = request.getParameter("state");
if(code!=null &&!"".equals(code)){//如果code不为空,表示当前已重定向获取了code,可以用code去换取openid
//get open id
String s=HttpRequest.GetRequest("https://api.weixin.qq.com/sns/oauth2/access\_token?appid="+SystemProperties.appid+"&secret="+SystemProperties.secret+"&code="+code+"&grant_type=authorization_code");
JSONObject jb = JSONObject.fromObject(s);
Map map = (Map)jb;
String token = (String) map.get("access_token");
String openid = (String) map.get("openid");
SysUser user=service.GetUserByOpenId(openid);//在数据库中查找用户
if(user!=null && user.getId()>0){
AuthService.SetSession(request, user);
return AuthService.checkAuth();
}else {//用户不存在,表示是新用户,需要获取用户信息保存数据库
if(state.equals("full")){//如果是获取的full完整用户信息,表示是新用户
String s2 = HttpRequest.GetRequest("https://api.weixin.qq.com/sns/userinfo?access_token="+token+"&openid="+openid+"&lang=zh_CN");
JSONObject jb2 = JSONObject.fromObject(s2);
Map map2 = (Map)jb2;
SysUser newUser = new SysUser();
///构造用户
///....
///....
///
userService.AddNewUser(newUser);
AuthService.SetSession(request, newUser);
return AuthService.checkAuth();
}else{//如果是不是获取的full完整用户信息,则当前请求的是base接口,前面也没有在数据库中找到相应用户,则需要去请求full接口,获取完整用户信息
String query=request.getQueryString();
query= query.replaceAll("(&*)code=.*(?=&)", "");
query = query.replaceAll("(&*)state=.*(?=$)", "");
if("".equals(query.trim())){
query=null;
}
String retrunUrl = request.getRequestURL()+(query==null?"":"?"+query);
response.sendRedirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid="+SystemProperties.appid+"&redirect_uri="+URLEncoder.encode(retrunUrl,"UTF-8")+"&response_type=code&scope=snsapi_userinfo&state=full#wechat_redirect");
}
}
}else {//code为空,重定向微信authorize,获取code
//1 redirect get code
String query=request.getQueryString();
String retrunUrl = request.getRequestURL()+(query==null?"":"?"+query);
response.sendRedirect("https://open.weixin.qq.com/connect/oauth2/authorize?appid="+SystemProperties.appid+"&redirect_uri="+URLEncoder.encode(retrunUrl,"UTF-8")+"&response_type=code&scope=snsapi_base&state=base#wechat_redirect");
}
return false;
}

具体可以查看 微信公众平台