开发步骤

1.准备应用开发服务器,获取访问地址,开发者中心服务器配置须用到。

2.通过测试号申请系统,可通过微信扫描二维码快速申请一个接口测试号,可查看接口权限表

3.配置公众号菜单

  • 自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。

  • 一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。

  • 创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现 出来。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的 效果。

自定义菜单格式如下(测试服务号):

 "menu": {
        "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": [ ]
                    }
                ]
            }
        ]
    }

手机端菜单显示如下:

4.应用与微信对接

服务端接收逻辑:

 /**
 * /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(HttpServletRequest request,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;
    }

}

5.实现自己的服务业务