微信开发 一 接入篇

本例中有些引用的类与方法不做过多介绍,之后会提供完整源码下载,请自行查看。

本篇根据开发者文档-接入指南编写。请对照查看,一些传入与返回参数就不过多介绍。地址为:https://mp.weixin.qq.com/wiki/17/2d4265491f12608cd170a95559800f2d.html

服务器配置

获取开发者信息

这里写图片描述

在项目中配置信息

这里写图片描述

服务器配置信息

这里写图片描述
Token : 必须与代码中配置相同,如本处都为: wechat。
EncodingAESKey : 必须与代码中配置相同。
注意:微信公众服务地址必须以http://或https://开头,分别支持80端口和443端口。微信公众号接口只支持80接口。而Linux 80端口被系统默认。所以必须将80端口请求重定向到8080。具体配置如下:

iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

验证服务器地址的有效性

编写服务器主路径

该路径与服务器配置信息中URL中配置路径相同。GET请求携带四个参数:

参数描述
signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp时间戳
nonce随机数
echostr随机字符串
@Controller
@RequestMapping("/core")
public class WeChatCoreController {

    private static final Logger logger = Logger.getLogger(WeChatCoreController.class);

    @Resource   
    private WeChatCoreService weChatCoreService;

    @RequestMapping("/start")
    public void start(HttpServletRequest request, HttpServletResponse response) {
        logger.info("===========startWeChat============");
        try {
            // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
            request.setCharacterEncoding("UTF-8");
            response.setCharacterEncoding("UTF-8");

            PrintWriter out = response.getWriter();
            String method = request.getMethod();
            if(method.equals("GET")) {
                String signature = request.getParameter("signature");           // 微信加密签名
                String timestamp = request.getParameter("timestamp");           // 时间戳
                String nonce = request.getParameter("nonce");                   // 随机数
                String echostr = request.getParameter("echostr");               // 随机字符串
                System.out.println("确认配置>>>>>>>>>signature="+signature+"  ,timestamp="+timestamp);
                if(signature != null && timestamp != null) {
                    // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
                    if (weChatCoreService.checkSignature(signature, timestamp, nonce)) {
                        out.print(echostr);
                    }
                }
            } else if(method.equals("POST")) {
                System.out.println("=================New Message==================");
                String respMessage = weChatCoreService.processRequest(request);
                out.print(respMessage);
            }
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
验证有效性

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。

加密/校验流程如下:
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

public boolean checkSignature(String signature, String timestamp, String nonce) {
        logger.info("==========checkSignature==========");

        String[] arr = new String[] { WeChatCertificate.WECHAT_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 = StringUtil.byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

业务逻辑

此后用户每次向公众号发送消息、或者产生自定义菜单点击事件时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,然后开发者可以依据自身业务逻辑进行响应,例如回复消息等。

用户向公众号发送消息时,公众号方收到的消息发送者是一个OpenID,是使用用户微信号加密后的结果,每个用户对每个公众号有一个唯一的OpenID。

本方法中有些调用类与方法将之后章节中介绍说明

/**
     * 处理用户发送的消息
     */
    public String processRequest(HttpServletRequest request) {
        logger.info("==========processRequest==========");
        String respMessage = null;
        try {
            Map< String, String> requestMap = new HashMap< String, String>();

            //安全模式,消息包为纯密文,需要开发者加密和解密,安全系数高  注:java.security.InvalidKeyException:illegal Key Size 请参考Remark文件 第二条
            WXBizMsgCrypt pc = new WXBizMsgCrypt(WeChatCertificate.WECHAT_TOKEN, WeChatCertificate.WECHAT_ENCODINGAESKEY, WeChatCertificate.WECHAT_APPID);
            String encrypt_type =request.getParameter("encrypt_type");  
            if (encrypt_type == null || encrypt_type.equals("raw")) {       //不用加密  
                requestMap = XMLUtil.parseXml(request);                     // xml请求解析
            } else {                                                        //需走加解密流程
                String msgSignature = request.getParameter("msg_signature");// 微信加密签名     
                String timeStamp = request.getParameter("timestamp");       // 时间戳      
                String nonce = request.getParameter("nonce");               // 随机数  
                String encryptMsg = StringUtil.inputStream2String(request.getInputStream()); //密文   
                String data = pc.decryptMsg(msgSignature, timeStamp, nonce, encryptMsg); 
                requestMap = XMLUtil.parseXml(data);                        // xml请求解析
            }

            String msgType = requestMap.get("MsgType");         // 消息类型
            String xmlStr = requestMap.get("wechatXML");        // 用户传来的xml
            System.out.println("Receive information>>>"+xmlStr);
            logger.info("Receive information:>>>"+xmlStr);

            switch(msgType) {
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_IMAGE      : respMessage = ImageRespMsg.test(xmlStr); break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_VOICE      : respMessage = VoiceRespMsg.test(xmlStr); break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_VIDEO      : respMessage = VideoRespMsg.test(xmlStr); break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_SHORTVIDEO : respMessage = VideoRespMsg.test(xmlStr); break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_LINK       : respMessage = TextRespMsg.test(xmlStr);  break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_LOCATION   : respMessage = TextRespMsg.test(xmlStr);  break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_TEXT : {
                    String content = requestMap.get("Content");
                    switch(content) {
                        case "news" : 
                            respMessage = NewsRespMsg.test(xmlStr);
                            break;
                        case "music" : 
                            respMessage = MusicRespMsg.test(xmlStr);
                            break;
                        default : respMessage = TextRespMsg.test(xmlStr);
                    }
                }   break;
                case WeChatEntitiesType.REQ_MESSAGE_TYPE_EVENT      : {
                    String event = requestMap.get("Event");
                    String wechatXML = requestMap.get("wechatXML");
                    switch(event) {
                        case WeChatEntitiesType.EVENT_TYPE_CLICK : 
                            MenuClickEvent.requestMessage(wechatXML);
                            break;
                        case WeChatEntitiesType.EVENT_TYPE_VIEW : 
                            MenuViewEvent.requestMessage(wechatXML);
                    }
                    respMessage = TextRespMsg.test(xmlStr); 
                }   break;
                default :  respMessage = TextRespMsg.test(xmlStr);
            }
            //对返回消息进行加密。注:微信测试号不支持加密模式。测试需注释加解密过程
//          respMessage = pc.encryptMsg(respMessage, System.currentTimeMillis()+"", "xxxxxx");

            System.out.println("returned messages>>>"+respMessage);
            logger.info("returned messages:>>>"+respMessage);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return respMessage;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值