微信开发学习总结(三)——消息管理(1)

版权声明:本文为博主原创文章,请尊重原创,未经博主允许禁止转载,保留追究权 https://blog.csdn.net/qq_29914837/article/details/82903594

上一节内容:
微信开发学习总结(二)——微信开发环境准备(2)
https://blog.csdn.net/qq_29914837/article/details/82896861


接收普通消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

请注意:
1、关于重试的消息排重,推荐使用msgid排重。
2、微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见“发送消息-被动回复消息”。
3、如果开发者需要对用户消息在5秒内立即做出回应,即使用“发送消息-被动回复消息”接口向用户被动回复消息时,可以在公众平台官网的开发者中心处设置消息加密。开启加密后,用户发来的消息和开发者回复的消息都会被加密(但开发者通过客服接口等API调用形式向用户发送消息,则不受影响)。关于消息加解密的详细说明,请见“发送消息-被动回复消息加解密说明”。

一、文本消息推送XML数据包结构

<xml>  <ToUserName>< ![CDATA[toUser] ]></ToUserName>  <FromUserName>< ![CDATA[fromUser] ]></FromUserName>  <CreateTime>1348831860</CreateTime>  <MsgType>< ![CDATA[text] ]></MsgType>  <Content>< ![CDATA[this is a test] ]></Content>  <MsgId>1234567890123456</MsgId>  </xml>
参数 描述
ToUserName 开发者微信号
FromUserName 发送方帐号(一个OpenID)
CreateTime 消息创建时间 (整型)
MsgType text
Content 文本消息内容
MsgId 消息id,64位整型

二、接收微信服务器发送的消息并做出响应

通过下面代码来实现接收微信服务器发送的消息并做出响应的功能。

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上(也就是我们在服务器配置的URL)。

①WeiXinCheck.java(工具类,包含各种常用方法)

package weixin.util;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import net.sf.json.JSONObject;
import weixin.entity.accesstoken.AccessToken;

/**
 * @所属类别:工具类
 * @用途:微信开发校验方法、sha1加密算法等
 * @author yilei
 * @version:1.0
 */
public class WeiXinCheck {

	/**
	 * @method 将token、timestamp、nonce三个参数进行字典序排序
	 * @param token
	 * @param timestamp
	 * @param nonce
	 * @return 排序后的字符串
	 */
	public static String sort(String token, String timestamp, String nonce) {
		String[] strArray = { token, timestamp, nonce };
		Arrays.sort(strArray);
		StringBuilder sb = new StringBuilder();
		for (String str : strArray) {
			sb.append(str);
		}
		return sb.toString();
	}

	/**
	 * @method 将三个参数字符串拼接成一个字符串进行sha1加密
	 * @param str,需要加密的字符串(排序后的字符串)
	 * @return 加密后的内容
	 */
	public static String sha1(String str) {
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-1");
			digest.update(str.getBytes());
			byte messageDigest[] = digest.digest();
			// Create Hex String
			StringBuffer hexString = new StringBuffer();
			// 字节数组转换为 十六进制 数
			for (int i = 0; i < messageDigest.length; i++) {
				String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexString.append(0);
				}
				hexString.append(shaHex);
			}
			return hexString.toString();

		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * @method 开发者获得加密后的字符串可与signature对比
	 * @param str ,需要加密的字符串(排序后的字符串)
	 * @return 加密后的内容
	 */
	public static boolean equalSignature(String str, String signature) {
		boolean falg = false;
		if (str != null && str != "") {
			if (str.equals(signature)) {
				falg = true;
			}
		}
		return falg;

	}

	/**
	 * 发起Http请求, 通过GET方式访问网络用到的方法
	 * @param url,请求的URL地址
	 * @return 响应后的字符串
	 */
	public static JSONObject doGetStr(String url){
		DefaultHttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(url);
		JSONObject jsonObject = null;
		try {
			HttpResponse response =  httpClient.execute(httpGet);
			HttpEntity entity = response.getEntity();
			if(entity!=null){
				String result=EntityUtils.toString(entity);
				jsonObject = JSONObject.fromObject(result);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return jsonObject;
	}
	
	/**
	 * 发起Http请求, 通过POST方式访问网络用到的方法
	 * @param url,请求的URL地址
	 * @return 响应后的字符串
	 */
	public static JSONObject doPostStr(String url,String outstr){
		DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);
        JSONObject jsonObject = null;
		try {
			httpPost.setEntity(new StringEntity(outstr, "UTF-8"));
			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			String result=EntityUtils.toString(entity,"UTF-8");
			jsonObject = JSONObject.fromObject(result);
		
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		return jsonObject;
		
	}

	/**
	 * 获取access_token
	 * @return AccessToken对象
	 */
	public static AccessToken getAccessToken() {
		AccessToken accessToken = new AccessToken();
		String url = WeiXin.ACCESS_TOKEN_URL.replace("APPID", WeiXin.APPID).replace("APPSECRET", WeiXin.APPSECRET);
		JSONObject jsonObject = WeiXinCheck.doGetStr(url);
		if (jsonObject != null) {
			accessToken.setAccessToken(jsonObject.getString("access_token"));
			accessToken.setExpiresin(jsonObject.getInt("expires_in"));
		}
		return accessToken;
	}
	
    /**
     * 解析微信发来的请求(XML)并且转换为Map
     * @param request
     * @return map
     * @throws Exception
     */
	public static Map<String,String> parseXml(HttpServletRequest request) throws Exception {
        // 将解析结果存储在HashMap中
        Map<String,String> map = new HashMap();
        // 从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) {
            System.out.println(e.getName() + "|" + e.getText());
            map.put(e.getName(), e.getText());
        }

        // 释放资源
        inputStream.close();
        return map;
    }
	
    // 根据消息类型 构造返回消息
    public static String buildXml(Map<String,String> map) {
        String result;
        String msgType = map.get("MsgType").toString();
        if(msgType.toUpperCase().equals("TEXT")){//文本消息
            result = buildTextMessage(map, "欢迎猪牧狼马蜂YY,消息类型:文本消息");
        }else{
            String fromUserName = map.get("FromUserName");
            // 开发者微信号
            String toUserName = map.get("ToUserName");
            result = String
                    .format(
                            "<xml>" +
                                    "<ToUserName><![CDATA[%s]]></ToUserName>" +
                                    "<FromUserName><![CDATA[%s]]></FromUserName>" +
                                    "<CreateTime>%s</CreateTime>" +
                                    "<MsgType><![CDATA[text]]></MsgType>" +
                                    "<Content><![CDATA[%s]]></Content>" +
                            "</xml>",
                            fromUserName, toUserName, getCreateTime(),
                            "请回复如下关键词:\n文本\n图片\n语音\n视频\n音乐\n图文");
        }

        return result;
    }

    /**
     * 构造文本消息
     * @param map
     * @param content
     * @return
     */
    private static String buildTextMessage(Map<String,String> map, String content) {
        //发送方帐号
        String fromUserName = map.get("FromUserName");
        // 开发者微信号
        String toUserName = map.get("ToUserName");
        return String.format(
                "<xml>" +
                        "<ToUserName><![CDATA[%s]]></ToUserName>" +
                        "<FromUserName><![CDATA[%s]]></FromUserName>" +
                        "<CreateTime>%s</CreateTime>" +
                        "<MsgType><![CDATA[text]]></MsgType>" +
                        "<Content><![CDATA[%s]]></Content>" + "</xml>",
                fromUserName, toUserName, getCreateTime(), content);
    }
    
    /**
     * 格式化日期格式
     * @return 格式化的日期
     */
    public static String getCreateTime() {
        Date dt = new Date();// 如果不需要格式,可直接用dt,dt就是当前系统时间
        DateFormat df = new SimpleDateFormat("yyyyMMddhhmm");// 设置显示格式
        String nowTime = df.format(dt);
        long dd = (long) 0;
        try {
            dd = df.parse(nowTime).getTime();
        } catch (Exception e) {

        }
        return String.valueOf(dd);
    }
	
}

②MainApplication.java (微信开发接口入口)

package weixin;

import java.io.IOException;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import weixin.util.WeiXin;
import weixin.util.WeiXinCheck;
/**
 * @所属类别:servlet类
 * @用途:微信开发接口入口
 * @author yilei
 * @version:1.0
 */
public class MainApplication extends HttpServlet{

	/**
	 * 开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上(校验签名是否通过,通过才可以进行微信开发其他操作)
	 * @param request
	 * @param response
	 * @throws IOException 
	 */
	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		 // TODO Auto-generated method stub
		 System.out.println("开始校验签名");
		 //接收微信服务器发送请求时传递过来的4个参数
		 String signature = request.getParameter("signature");//微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
		 String timestamp = request.getParameter("timestamp");//时间戳
		 String nonce = request.getParameter("nonce");//随机数
		 String echostr = request.getParameter("echostr");//随机字符串
		 //排序
		 String sortString = WeiXinCheck.sort(WeiXin.TOKEN, timestamp, nonce);
		 //sha1加密
		 String mySignature = WeiXinCheck.sha1(sortString);
		 //校验签名
		 if (WeiXinCheck.equalSignature(mySignature, signature)) {
	            System.out.println("签名校验通过。");
	            //如果检验成功输出echostr,微信服务器接收到此输出,才会确认检验完成。
	            //response.getWriter().println(echostr);
	            response.getWriter().println(echostr);
	        } else {
	            System.out.println("签名校验失败.");
	        }
	}
	
	/**
	 * 处理微信服务器发来的消息
	 */
    @Override
	public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        // TODO 接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息
        // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        System.out.println("微信的post请求进入了本地服务器了");
        String result = "";
        try {
            Map<String,String> map = WeiXinCheck.parseXml(request);
            System.out.println("微信公众号要开始发送消息");
            result = WeiXinCheck.buildXml(map);
            System.out.println(result);
            if(result.equals("")){
                result = "未正确响应";
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("发生异常:"+ e.getMessage());
        }
        response.getWriter().println(result);
    }
	
}

启动服务器,具体步骤参考前面几节课程

然后,关注微信测试公众号
在这里插入图片描述

在这里插入图片描述

微信开发学习总结(三)——消息管理(1)——项目源码
下载地址:
https://download.csdn.net/download/qq_29914837/10696854


下一节内容:
微信开发学习总结(三)——消息管理(2)
https://blog.csdn.net/qq_29914837/article/details/82904454


猜你喜欢

转载自blog.csdn.net/qq_29914837/article/details/82903594