您的位置:首页 > 移动开发 > 微信开发

微信测试号中被动消息回复的测试

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放在之前回复图片的位置,然后用测试号测试结果。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  微信