开发步骤
1.准备应用开发服务器,获取访问地址,开发者中心服务器配置须用到。
2.通过测试号申请系统,可通过微信扫描二维码快速申请一个接口测试号,可查看接口权限表
3.填写应用服务器配置提交后,微信端需要验证是否和服务器接入成功。
if (RequestUtil.isGet()) {
// 微信加密签名
String signature = request.getParameter("signature");
// 随机字符串
String echostr = request.getParameter("echostr");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样
返回echostr,表示接入成功,否则接入失败
if (StringUtils.isBlank(signature)) {
out.print("wechat param not found");
} else if (SignUtil.checkSignature(signature,timestamp,
nonce)) {
out.print(echostr);
}
out.close();
out = null;
}
public static boolean checkSignature(String signature, String
timestamp, String nonce) {
ResourceBundle resource = ResourceBundle.getBundle("config");
String token = resource.getString("wx.token");
String[] arr = new String[]{token, timestamp, nonce};
// 将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
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;
// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return tmpStr != null && tmpStr.equals(signature.toUpperCase());
}
4.配置公众号菜单
自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现 出来。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的 效果。
自定义菜单格式如下(测试服务号):
{
"button": [
{
"name": "课程中心",
"sub_button": [
{
"type": "view",
"name": "我的课程",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myCourse",
"sub_button": [ ]
},
{
"type": "view",
"name": "可选课程",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=selectCourse",
"sub_button": [ ]
}
]
},
{
"name": "个人中心",
"sub_button": [
{
"type": "view",
"name": "我的考试",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myExam",
"sub_button": [ ]
},
{
"type": "view",
"name": "我的问卷",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myQuestionnaire",
"sub_button": [ ]
},
{
"type": "view",
"name": "我的评估",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myOem",
"sub_button": [ ]
},
{
"type": "view",
"name": "我的资讯",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myNews",
"sub_button": [ ]
},
{
"type": "view",
"name": "我的档案",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myPortfolio",
"sub_button": [ ]
}
]
},
{
"name": "其他",
"sub_button": [
{
"type": "view",
"name": "ELP微平台",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=wxElnIndex",
"sub_button": [ ]
},
{
"type": "view",
"name": "个人名片",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=myCard",
"sub_button": [ ]
},
{
"type": "view",
"name": "在线反馈",
"url": "http://v4.21tb.com/wx/checkLogin.do?
functionName=feedback",
"sub_button": [ ]
},
{
"type": "view",
"name": "退出",
"url": "http://v4.21tb.com/wx/loginOut.do?
functionName=checkLogin",
"sub_button": [ ]
}
]
}
]
}
手机端菜单显示如下:
5.应用与微信对接,事件处理
服务端接收逻辑:
/**
* /wx/wechat/index.do
*
* Date: 2/18/14
* Time: 12:07 AM
*/
public class WeChatAction extends BaseAction<IndexModel> {
public String index() throws IOException {
String corpCode = request.getParameter("corpCode");
if(StringUtils.isNotBlank(corpCode)){
ExecutionContext.setCorpCode(corpCode);
}
if (RequestUtil.isGet()) {
// 微信加密签名
String signature = request.getParameter("signature");
// 随机字符串
String echostr = request.getParameter("echostr");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 通过检验signature对请求进行校验,若校验成功则原样
返回echostr,表示接入成功,否则接入失败
if (StringUtils.isBlank(signature)) {
out.print("wechat param not found");
} else if (SignUtil.checkSignature(signature,
timestamp, nonce)) {
out.print(echostr);
}
out.close();
out = null;
} else if (RequestUtil.isPost()) {
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 调用核心业务类接收消息、处理消息
String respMessage =CoreService.processRequest(request,
response);
// 响应消息
PrintWriter out = response.getWriter();
out.print(respMessage);
out.close();
}
return null;
}
}
public class CoreService {
/**
* 处理微信发来的请求
*
* @param request
* @return
*/
public static String processRequest(HttpServletRequestrequest,
HttpServletResponse response) {
String respMessage = null;
try {
// 默认返回的文本消息内容
StringBuilder respContent = new StringBuilder();
// xml请求解析
Map<String, String> requestMap =MessageUtil.
parseXml(request);
// 发送方帐号(open_id)
String fromUserName = requestMap.get("FromUserName");
// 公众帐号
String toUserName = requestMap.get("ToUserName");
// 消息类型
String msgType = requestMap.get("MsgType");
String content = requestMap.get("Content");
String eventKey = requestMap.get("EventKey");
// 回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_
TEXT);
textMessage.setFuncFlag(0);
// 文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_
TEXT)) {
if (content.equalsIgnoreCase("授权")
|| content.equalsIgnoreCase("登录")
|| content.equalsIgnoreCase("登陆")
|| content.equalsIgnoreCase("\"登录\"")
|| content.equalsIgnoreCase("dl")) {
respContent.append(loginMsg(request,
fromUserName));
} else {
//respContent.append("您发送的是文本消息!");
}
}
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE
_IMAGE)){
//respContent.append("您发送的是图片消息!");
}
// 地理位置消息
else if(msgType.equals(MessageUtil.REQ_MESSAGE_TYPE
_LOCATION)) {
//respContent.append("您发送的是地理位置消息!");
}
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE
_LINK)){
//respContent.append("您发送的是链接消息!");
}
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE
_VOICE)){
//respContent.append("您发送的是音频消息!");
}
// 事件推送
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE
_EVENT)){
// 事件类型
String eventType = requestMap.get("Event");
// 订阅
if (eventType.equals(MessageUtil.EVENT_TYPE_
SUBSCRIBE)) {
respContent.append(subscribeMsg(request
,fromUserName));
}
//取消订阅
else if (eventType.equals(MessageUtil.EVENT_TYPE_
UNSUBSCRIBE)) {
//取消订阅后用户再收不到公众号发送的消息,因
此不需要回复消息,取消授权关系
ApplicationContext app = new
ClassPathXmlApplicationContext(new
String[] {"classpath:applicationContext.xml"
,"classpath:spring-localCache.xml"});
JedisCommands jedis = app.getBean("jedisSession"
, JedisCommands.class);
Map<String,String> object=
jedis.hgetAll(fromUserName);
if(MapUtils.isNotEmpty(object)){
ExecutionContext.setCorpCode(object.get(
ELNConfigure.CORP_CODE));
UserService userService=app.getBean(
"userService",UserService.class);
userService.cancelBindWCharId(
fromUserName,object.get(ELNConfigure.
CORP_CODE));
}else{
String serverName = request.getServerName();
String baseDomain = CustomDomainUtil.
getBaseDomain(serverName);
String cookieDomain = "." + baseDomain;
CookieUtil.setCookie(response,ELNConfigure
.WX_ELN_SESSION_ID, null,ELNConfigure.
COOKIE_PATH, "0", cookieDomain);
CookieUtil.setCookie(response,ELNConfigure
.CORP_CODE,null,ELNConfigure.
COOKIE_PATH, "0", cookieDomain);
CookieUtil.setCookie(response, "_wcharId"
, null,ELNConfigure.COOKIE_PATH,
"0", cookieDomain);
}
ExecutionContext.setCorpCode(null);
}
// 自定义菜单点击事件
else
if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)){
if (eventKey.equalsIgnoreCase("LOGIN")) {
respContent.append(loginMsg(request, fromUserName));
}
// else {
// respContent.append("您发来的是点击菜单事件");
// }
else if(eventKey.equalsIgnoreCase("send_news")){
NewsMessage newsMessage = new NewsMessage();
newsMessage.setToUserName(fromUserName);
newsMessage.setFromUserName(toUserName);
newsMessage.setCreateTime(new Date()
.getTime());
newsMessage.setMsgType(MessageUtil.RESP_
MESSAGE_TYPE_NEWS);
newsMessage.setArticleCount(2);
List<Article> articles = new
ArrayList<Article>();
Article article = new Article();
article.setTitle("文章1");
article.setDescription("挺好的一篇文章");
article.setPicUrl("http://yufa.21tb.com/
wx/images/course/els_course_cover_default
.png");
article.setUrl("");
articles.add(article);
Article article1 = new Article();
article1.setTitle("文章2");
article1.setDescription("挺好的一篇文章");
article1.setPicUrl("http://yufa.21tb.com/
wx/images/course/els_course_cover_default.
png");
article1.setUrl("");
articles.add(article1);
newsMessage.setArticles(articles);
respMessage=MessageUtil.
newsMessageToXml(newsMessage);
return respMessage;
}
}
} else {
respContent.append("请求处理异常,请稍候尝试!");
}
textMessage.setContent(respContent.toString());
respMessage = MessageUtil.textMessageToXml(textMessage);
} catch (Exception e) {
e.printStackTrace();
}
return respMessage;
}
}
6.实现自己的服务业务