开发步骤

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.实现自己的服务业务