java springMVC 开发微信公众号

微信开发总结

(1)首先是要通过signature对请求进行校验,才有资格成为开发者

(2)然后access_token是公众号的全局唯一票据,只要拿着这个票据就可以对你的微信公众号做一些操作

(3)接受用户发来的请求有它的格式,根据这个格式去解析和获取我们想要的数据,然后就可以进行我们要做的业务

(4)返回给用户的响应,也有它对应的格式,根据格式去回应就可以了

(5)想要进行菜单的开发,就要去申请,并且交钱,所有这方面还是挺麻烦的

(6)菜单的开发,是向微信服务器放送请求,然后带上access_token(票据),它就知道要对哪个微信公众号,进行怎样的操作。

 

 

 

代码分析  首先Controller

 

@Controller

@RequestMapping("/weixin")

public class WeiXinController {

 

    @RequestMapping(value="/api",method = RequestMethod.GET)

    @ResponseBody

    public String xxtInterface(WeChat wc){

        System.out.println("/api");

        String signature = wc.getSignature(); // 微信加密签名

        String timestamp = wc.getTimestamp(); // 时间戳

        String nonce = wc.getNonce();// 随机数

        String echostr = wc.getEchostr();// 随机字符串

 

        // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败

        if (SignUtil.checkSignature(signature, timestamp, nonce)) {

            return echostr;

        } else {

            System.out.println("不是微信服务器发来的请求,请小心!");

            return null;

        }

    }

 

    @RequestMapping(value="/api",method = RequestMethod.POST)

    @ResponseBody

    public void getWeiXinMessage(HttpServletRequest request, HttpServletResponse response) throws Exception

    {

        // 将请求、响应的编码均设置为UTF-8(防止中文乱码)

        request.setCharacterEncoding("UTF-8");  //微信服务器POST消息时用的是UTF-8编码,在接收时也要用同样的编码,否则中文会乱码;

        response.setCharacterEncoding("UTF-8"); //在响应消息(回复消息给用户)时,也将编码方式设置为UTF-8,原理同上;

 

        //初始化配置文件

        String respMessage = CoreService.processRequest(request);//调用CoreService类的processRequest方法接收、处理消息,并得到处理结果;

        // 响应消息

        //调用response.getWriter().write()方法将消息的处理结果返回给用户

        PrintWriter printWriter=response.getWriter();

        printWriter.write(respMessage);

        printWriter.close();

        //return respMessage;

    }

}

 

(1)因为微信的开发接口只对应一个URL,所以要通过getpost请求区分,它到底想拉还是推。

(2)我这里get请求通过signature对请求进行校验,然后我就有资格开发微信公众号了(*^__^*) 

(3)post请求就是处理我要在微信上开发的业务,自动回复,推送图文消息,关注后发送消息提醒,点击按钮触发什么时间等等的业务,都在POST这个请求里去做。

(4)因为我不想我的控制层太多代码,显得臃肿,所有要把做的东西放到service(服务层)去做。PS:正常开发也要这样做,这是一个程序猿的自我修养。

 

 

 

CoreService (服务层)

    public static String processRequest(HttpServletRequest request) throws UnsupportedEncodingException {

        request.setCharacterEncoding("UTF-8");

        String respMessage = null;

        try {

            // 默认返回的文本消息内容

            String respContent = "请求处理异常,请稍候尝试!";

            // xml请求解析

            // 调用消息工具类MessageUtil解析微信发来的xml格式的消息,解析的结果放在HashMap里;

            Map<String, String> requestMap = MessageUtil.parseXml(request);

            // HashMap中取出消息中的字段;

            // 发送方帐号(open_id

            String fromUserName = requestMap.get("FromUserName");

            // 公众帐号

            String toUserName = requestMap.get("ToUserName");

            // 消息类型

            String msgType = requestMap.get("MsgType");

            // 消息内容

            String content = requestMap.get("Content");

            // HashMap中取出消息中的字段;

            logger.info("fromUserName is:" + fromUserName + " toUserName is:" + toUserName + " msgType is:" + msgType);

 

            // 文本消息

            if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {

                //根据关键字获取自动回复的内容

                respContent = TulingApiProcess.getTulingResult(content, fromUserName, toUserName);

                return respContent;

            } else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {// 事件推送

                String eventType = requestMap.get("Event");// 事件类型

                if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {// 订阅

                    respContent = "欢迎关注[You are my sunshine]";

                    return MessageResponse.getTextMessage(fromUserName, toUserName, respContent);

                } else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {// 自定义菜单点击事件

                    String eventKey = requestMap.get("EventKey");// 事件KEY值,与创建自定义菜单时指定的KEY值对应

                    logger.info("eventKey is:" + eventKey);

                    return MenuClickService.getClickResponse(eventKey, fromUserName, toUserName);

                }

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

        return respMessage;

    }

 

}

 

(1)好吧,这里的代码会很乱,因为所有的业务都在这里做了~

(2)首先获取微信发来的msgType 知道它到底想做什么,或者说知道它发送什么过来,然后我们就执行怎样的操作 

msgType  常用的有:text(文本),event(推送,关注就是一个推送,CLICK(自定义菜单的触发)

(3)因为微信传过来的是XML格式的数据,所以我要把它转成Map格式的数据(为了数据好取一点)

 Map<String, String> requestMap = MessageUtil.parseXml(request);

(4)然后就根据msgType去执行相应的操作就可以了

 

 

 

将要返回的小心进行封装,并转成xml格式字符串返回去

public class MessageResponse {

/**

 * 回复文本消息

 */

public static String getTextMessage(String fromUserName , String toUserName , String respContent) {

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);

textMessage.setContent(respContent);

System.out.println("这是getTextMessage:");

System.out.println(MessageUtil.textMessageToXml(textMessage));

return MessageUtil.textMessageToXml(textMessage);

}

/**

 * 创建图文消息

 */

public static String getNewsMessage(String fromUserName , String toUserName , List<Article> articleList) {

NewsMessage newsMessage = new NewsMessage();

newsMessage.setToUserName(fromUserName);

newsMessage.setFromUserName(toUserName);

newsMessage.setCreateTime(new Date().getTime());

newsMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);

newsMessage.setFuncFlag(0);

// 设置图文消息个数

newsMessage.setArticleCount(articleList.size());

// 设置图文消息包含的图文集合

newsMessage.setArticles(articleList);

// 将图文消息对象转换成xml字符串

return MessageUtil.newsMessageToXml(newsMessage);

}

}

 

 

把实体转成XML格式的字符串

 public class MessageUtil {

/** 

     * 返回消息类型:文本 

     */  

    public static final String RESP_MESSAGE_TYPE_TEXT = "text";  

  

    /** 

     * 返回消息类型:音乐 

     */  

    public static final String RESP_MESSAGE_TYPE_MUSIC = "music";  

  

    /** 

     * 返回消息类型:图文 

     */  

    public static final String RESP_MESSAGE_TYPE_NEWS = "news";  

  

    /** 

     * 请求消息类型:文本 

     */  

    public static final String REQ_MESSAGE_TYPE_TEXT = "text";  

  

    /** 

     * 请求消息类型:图片 

     */  

    public static final String REQ_MESSAGE_TYPE_IMAGE = "image";  

  

    /** 

     * 请求消息类型:链接 

     */  

    public static final String REQ_MESSAGE_TYPE_LINK = "link";  

  

    /** 

     * 请求消息类型:地理位置 

     */  

    public static final String REQ_MESSAGE_TYPE_LOCATION = "location";  

  

    /** 

     * 请求消息类型:音频 

     */  

    public static final String REQ_MESSAGE_TYPE_VOICE = "voice";  

  

    /** 

     * 请求消息类型:推送 

     */  

    public static final String REQ_MESSAGE_TYPE_EVENT = "event";  

  

    /** 

     * 事件类型:subscribe(订阅

     */  

    public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";  

  

    /** 

     * 事件类型:unsubscribe(取消订阅

     */  

    public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";  

  

    /** 

     * 事件类型:CLICK(自定义菜单点击事件

     */  

    public static final String EVENT_TYPE_CLICK = "CLICK";  

  

    /** 

     * 解析微信发来的请求(XML) 

     * @param request

     * @return 

     * @throws Exception 

     */  

    @SuppressWarnings("unchecked")  

    public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {

        // 将解析结果存储在HashMap中  

        Map<String, String> map = new HashMap<String, String>();  

        // request中取得输入流  

        InputStream inputStream = request.getInputStream();  

        // 读取输入流  

        SAXReader reader = new SAXReader();

        Document document = reader.read(inputStream);

        // 得到xml根元素  

        Element root = document.getRootElement();

        // 得到根元素的所有子节点  

        List<Element> elementList = root.elements();  

        // 遍历所有子节点  

        for (Element e : elementList)  

            map.put(e.getName(), e.getText());  

        // 释放资源  

        inputStream.close();  

        inputStream = null;  

        return map;  

    }  

 

    /**

     * 文本消息对象转换成xml

     * @param textMessage 文本消息对象

     * @return xml

     */

    public static String textMessageToXml(TextMessage textMessage) {

        xstream.alias("xml", textMessage.getClass());

        return xstream.toXML(textMessage);

    }

  

    /** 

     * 音乐消息对象转换成xml 

     * @param musicMessage 音乐消息对象

     * @return xml 

     */  

   /* public static String musicMessageToXml(MusicMessage musicMessage) {  

        xstream.alias("xml", musicMessage.getClass());  

        return xstream.toXML(musicMessage);  

    }  */

  

    /**

     * 图文消息对象转换成xml

     * @param newsMessage 图文消息对象

     * @return xml

     */

    public static String newsMessageToXml(NewsMessage newsMessage) {

        xstream.alias("xml", newsMessage.getClass());

        xstream.alias("item", new Article().getClass());

        return xstream.toXML(newsMessage);

    }

 

    public static String LinkMessageToXml(LinkMessage linkMessage){

        xstream.alias("xml",linkMessage.getClass());

        return xstream.toXML(linkMessage);

    }

    /**

     * 扩展xstream,使其支持CDATA

     *

     */

    private static XStream xstream = new XStream(new XppDriver() {

        public HierarchicalStreamWriter createWriter(Writer out) {

            return new PrettyPrintWriter(out) {

                // 对所有xml节点的转换都增加CDATA标记

                boolean cdata = true;

                @SuppressWarnings("unchecked")

                public void startNode(String name, Class clazz) {

                    super.startNode(name, clazz);

//                 super.startNode(name);

                }

 

                protected void writeText(QuickWriter writer, String text) {

                    if (cdata) {

                        writer.write("<![CDATA[");

                        writer.write(text);

                        writer.write("]]>");

                    } else {

                        writer.write(text);

                    }

                }

            };

        }

    });

}

 

 

(1)主要的是这个转换

//把类名转成 <xml></xml>       

 xstream.alias("xml", textMessage.getClass());

//里面的属性就转成对应的xml        

return xstream.toXML(textMessage);

    

 

 

 


你可能感兴趣的:(JAVA微信公众号,springMVC微信公众号)