微信测试号中被动消息回复的测试
2018-03-23 14:30
363 查看
微信测试号中被动消息回复的测试
这里只贴相关的代码,具体的操作步骤(注册微信订阅号、测试号等)不再提及。测试号的路径配置
这是使用的是花生壳的内网穿透,至于具体使用请参照花生壳官网说明。
图片中的url是用来接收微信测试接口配置的验证,即像截图中说明:要验证token,token的值可以随意设置,和自己代码中的值保持一致即可,下面是代码中相关的接收方法,需要注意的是微信这个接口验证使用的是get方式。
private static String TOKEN = "czyTest"; /** * 确认请求来自微信服务器,用于微信配置认证 */ @RequestMapping(value = "/wxCore", method = RequestMethod.GET) public void core(HttpServletRequest request, HttpServletResponse response) { PrintWriter out = null; String signature = request.getParameter("signature"); String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String echostr = request.getParameter("echostr"); String reSignature = null; try { String[] str = {TOKEN, timestamp, nonce}; Arrays.sort(str); String bigStr = str[0] + str[1] + str[2]; reSignature = new SHA1().getDigestOfString(bigStr.getBytes()) .toLowerCase(); if (null != reSignature && reSignature.equals(signature)) { //请求来自微信 response.setContentType("text/html"); response.setCharacterEncoding("UTF-8"); out = response.getWriter(); out.write(echostr); out.flush(); LOGGER.info("返回字符串:" + echostr); } else { LOGGER.info("error request! the request is not from weixin server"); } out.close(); } catch (Exception e) { LOGGER.error(e.getMessage()); } }
接收用户输入的消息,并解析
由微信开发文档可知,用户消息主要分为:文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息和链接消息,且数据格式为XML格式,具体文档参见微信公众平台技术文档—接收普通消息首先,先写一个解析xml数据的类:
/** * 解析微信发来的xml数据请求,并将结果以Map格式返回 */ public static Map<String, String> parseXml(HttpServletRequest request) throws Exception { 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(); // 遍历所有子节点,将内容封装至map中 for (Element e : elementList) { System.out.println(e.getName() + "|" + e.getText()); map.put(e.getName(), e.getText()); } // 释放资源 inputStream.close(); return map; }
之后可以根据解析出的内容,判断用户发送的消息类型,并返回相关数据,在此之前先写好相关的返回信息,本文就只写文本回复和图片回复,因为微信接收的也是xml格式,因此要将消息封装为xml;
返回文本消息:
/** * 构造文本消息 * * @param map 封装了解析结果的Map * @param content 文本消息内容 * @return 文本消息XML字符串 */ private static String buildTextMessage(Map<String, String> map, String content) { //发送方帐号 String fromUserName = map.get("FromUserName"); //接收方微信号 String toUserName = map.get("ToUserName"); String time = new Date().getTime(); /** * 文本消息的XML数据格式 * <xml> * <ToUserName><![CDATA[ToUser]]></ToUserName> * <FromUserName><![CDATA[FromUser]]></FromUserName> * <CreateTime><![CDATA[Text]]></CreateTime> * <Content><![CDATA[文本消息]]></Content> * <MsgId>12345</MsgId> * </xml> */ return String.format( "<xml>" + "<ToUserName><![CDATA[%s]]></ToUserName>" + "<FromUserName><![CDATA[%s]]></FromUserName>" + 4000 "<CreateTime>%s</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[%s]]></Content>" + "</xml>", fromUserName, toUserName, time, content); }
回复图片消息:
/** * 构造图片消息 * * @param map 封装了解析结果的Map * @param mediaId 通过素材管理接口上传多媒体文件得到的id * @return 图片消息XML字符串 */ private static String buildImageMessage(Map<String, String> map, String mediaId) { //发送方帐号 String fromUserName = map.get("FromUserName"); //接收方微信号 String toUserName = map.get("ToUserName"); String time = String.valueOf(new Date().getTime()); /** * 图片消息XML数据格式 * * <xml> * <ToUserName><![CDATA[toUser]]></ToUserName> * <FromUserName><![CDATA[fromUser]]></FromUserName> * <CreateTime>12345678</CreateTime> * <MsgType><![CDATA[image]]></MsgType> * <Image></Image><MediaId><![CDATA[media_id]]></MediaId></Image> * </xml> */ return String.format( "<xml>" + "<ToUserName><![CDATA[%s]]></ToUserName>" + "<FromUserName><![CDATA[%s]]></FromUserName>" + "<CreateTime>%s</CreateTime>" + "<MsgType><![CDATA[image]]></MsgType>" + "<Image>" + " <MediaId><![CDATA[%s]]></MediaId>" + "</Image>" + "</xml>", fromUserName, toUserName, time, mediaId); }
处理用户发来请求的类型等:
/** * 接收到消息后处理回复 * 返回封装好的xml格式数据给用户 */ private static String handleMessage(Map<String, String> map) { //响应消息 String responseMessage = ""; //消息内容 String content = map.get("Content"); //消息类型 String msgType = map.get("MsgType").toString().toLowerCase(); if (msgType.equals("text")) { switch (content) { case "文本": String msgText = "这是一个文本回复的测试。"; responseMessage = buildTextMessage(map, msgText); break; case "图片": //通过素材管理接口上传图片得到的media_id String imgMediaId = "525GIsWEmMjBmeMLdVEFGxzI5tdp6ZP6uKBtnGhTFt3WaBJF76RZOEoJB7i7icRk"; responseMessage = buildImageMessage(map, imgMediaId); break; default: String text = "( ′◔ ‸◔`)!"; responseMessage = buildTextMessage(map, text); break; } } else if (msgType.equals("image")) { String msgText = "你输入的是一张图片。"; responseMessage = buildTextMessage(map, msgText); } //返回响应消息 return responseMessage; }
之后是微信端的数据接入和返回的请求处理,在验证token的时候微信发送的是get请求,而处理用户输入信息的则是post请求:
@RequestMapping(value = "/wxCore", method = RequestMethod.POST) public void wxCore(HttpServletRequest request, HttpServletResponse response) throws IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); // 将请求、响应的编码均设置为UTF-8(防止中文乱码) String responseMessage; try { System.out.println("请求进入"); //解析微信发来的请求,将解析后的结果封装成Map返回 Map<String, String> map = parseXml(request); System.out.println("开始构造响应消息"); responseMessage = handleMessage(map); System.out.println(responseMessage); if (responseMessage.equals("")) { responseMessage = "未正确响应"; } } catch (Exception e) { e.printStackTrace(); System.out.println("发生异常:" + e.getMessage()); responseMessage = "未正确响应"; } //发送响应消息 response.getWriter().println(responseMessage); }
新增素材获取media_id
因为返回图片、图文、音频等消息均需要一个media_id,所以在这里写一个上传素材获取media_id的例子,上传的时候需要获取用户的access_token。在这里写了一个工具类,发送请求获取access_token和上传文件获取media_id。package com.util; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.*; /** * Created by czy on 2018/3/23. */ public class WxApiUtil { // 素材上传(POST)https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE private static final String UPLOAD_MEDIA = "https://api.weixin.qq.com/cgi-bin/media/upload"; /** * 微信服务器素材上传 * * @param file 表单名称media * @param token access_token * @param type type只支持四种类型素材(video/image/voice/thumb) */ public static JSONObject uploadMedia(File file, String token, String type) { if (file == null || token == null || type == null) { return null; } if (!file.exists()) { System.out.println("上传文件不存在,请检查!"); return null; } String url = UPLOAD_MEDIA; JSONObject jsonObject = null; PostMethod post = new PostMethod(url); post.setRequestHeader("Connection", "Keep-Alive"); post.setRequestHeader("Cache-Control", "no-cache"); FilePart media; HttpClient httpClient = new HttpClient(); //信任任何类型的证书 Protocol myhttps = new Protocol("https", new SSLProtocolSocketFactory(), 443); Protocol.registerProtocol("https", myhttps); try { media = new FilePart("media", file); Part[] parts = new Part[]{new StringPart("access_token", token), new StringPart("type", type), media}; MultipartRequestEntity entity = new MultipartRequestEntity(parts, post.ge c164 tParams()); post.setRequestEntity(entity); int status = httpClient.executeMethod(post); if (status == HttpStatus.SC_OK) { String text = post.getResponseBodyAsString(); jsonObject = JSONObject.parseObject(text); } else { System.out.println("upload Media failure status is:" + status); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (HttpException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return jsonObject; } /** * 正常的HTTP请求,用以请求微信接口,获取access_token * @param url 请求的路径 * @param paras 请求的参数,主要是appID和appsecret * @return 返回String类型的数据 */ public static String normalGet(String url, String paras) throws Exception { String resp = ""; HttpClient client = new HttpClient(); client.setTimeout(1000 * 60); GetMethod method = new GetMethod(url); method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); method.setQueryString(paras); client.executeMethod(method); if (method.getStatusCode() == 200) { resp = method.getResponseBodyAsString(); } else { throw new Exception("http statusCode:" + String.valueOf(method.getStatusCode()) + "\n" + method.getStatusText() + "\n" + "url:" + method.getURI()); } return resp; } public static Map<String, Object> getAccessToken(String appId, String appSecret) { /** * 接口地址为https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET,其中grant_type固定写为client_credential即可。 */ String url = String.format("https://api.weixin.qq.com/cgi-bin/token?"); String params = "grant_type=client_credential&appid=" + appId + "&secret=" + appSecret; //此请求为https的get请求,返回的数据格式为{"access_token":"ACCESS_TOKEN","expires_in":7200} try { String access_token = normalGet(url, params); Map<String, Object> stringObjectMap = parseJSON2Map(access_token); System.out.println("获取到的access_token=" + stringObjectMap.toString()); return stringObjectMap; } catch (Exception e) { e.printStackTrace(); return null; } } /** * json字符串解析成map * * @param jsonStr * @return */ public static Map<String, Object> parseJSON2Map(String jsonStr) { Map<String, Object> map = new HashMap<String, Object>(); //最外层解析 JSONObject json = JSONObject.parseObject(jsonStr); for (Object k : json.keySet()) { Object v = json.get(k); //如果内层还是数组的话,继续解析 if (v instanceof JSONArray) { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); Iterator<Object> it = ((JSONArray) v).iterator(); while (it.hasNext()) { JSONObject json2 = (JSONObject) it.next(); list.add(parseJSON2Map(json2.toString())); } map.put(k.toString(), list); } else { map.put(k.toString(), v); } } return map; } }
上传的一个测试:
package com; import com.alibaba.fastjson.JSONObject; import com.util.AccessToken; import com.util.WxApiUtil; import java.io.File; import java.util.Map; /** * Created by czy on 2018/3/23. */ public class Test { public static void main(String[] args) { String appid = "wx1f311ff23bd4f4f6"; String appkey = "3d79a65c5f739046c79f8ac805c38ca0"; Map<String, Object> accessToken = WxApiUtil.getAccessToken(appid, appkey); String access_token = (String) accessToken.get("access_token"); File file = new File("D:\\1.jpg"); JSONObject image = WxApiUtil.uploadMedia(file, access_token, "image"); System.out.println(image.toJSONString()); } }
输出的结果为:
{"media_id":"525GIsWEmMjBmeMLdVEFGxzI5tdp6ZP6uKBtnGhTFt3WaBJF76RZOEoJB7i7icRk","created_at":1521786195,"type":"image"}
可以将这个id放在之前回复图片的位置,然后用测试号测试结果。
相关文章推荐
- 公众平台测试帐号开发全流程第6篇-接收和被动回复消息
- 微信客服消息实现被动回复
- 微信开发怎么被动发送图文消息用户输入信息之后回复
- 微信消息管理之被动回复用户消息
- 微信订阅号消息回复测试
- 夺命雷公狗---微信开发06----接收并被动回复语音消息
- 关于 微信发送被动回复音乐消息 用户接收不到的问题
- 微信开发五 被动回复用户消息
- 微信被动回复用户消息
- 微信服务号被动回复消息:该公众号提供的服务出现故障,请稍后再试
- 微信被动回复用户消息-文本消息-springmvc环境下自动生成xml
- 微信测试号开发之六 图灵自动回复文本消息
- 微信被动回复用户消息功能——关注、取消
- 微信测试号开发之六 图灵自动回复文本消息
- 微信消息管理之被动回复用户消息
- 微信被动回复用户消息-文本消息-填坑
- 微信开发被动回复消息:该公众号暂时无法提供服务,请稍后再试
- 微信自动回复消息,批量发送消息,收到消息处理
- python实现微信消息群发和微信自动回复
- 微信测试号开发之三 接收处理消息并响应