微信开发与代码的编写(二)
时间:2023-01-27 01:00:00
编写微信开发和代码(2)
接收和回复普通消息
介绍微信公众平台消息管理接口
要接收和回复微信公众号的普通消息,首先要熟悉微信公众平台API中消息接口部分,点此进入,点击后将进入到【消息管理】部分,如下图所示:
我们只需要关注上图中普通消息的接收和回复"接收消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-接收普通消息-"和"发送消息-被动回复消息"
消息接收
先说接收消息, 当普通微信用户向公众账户发送信息时,微信服务器将首先收到用户发送的信息,然后根据指定的用户信息XML格式组装数据,最后POST消息的XML数据包由开发人员填写URL上。
目前收到的普通消息有以下类型:
1 文本消息
2 图片消息
3 语音消息
4 视频消息
5 小视频消息
6 地理位置信息
7 链接消息
每种新闻类型都有其指定的类型XML这据格式,这数据格式xml格式请查看官方文档,具体格式定义和属性说明。格式简单,基本共同属性包括ToUserName、FromUserName、CreateTime、MsgType、MsgId,而且每种类型都有自己特殊的属性。
接收信息的过程实际上是获取信息的过程post请求的这个xml,然后对这个xml分析过程。post请求的入口仍然是前面提到的微信公众号的地址。整个公众号的所有请求都将采用此入口,但接入时是get在其他情况下,请求是post请求。
消息回复
微信服务器将用户信息发送到公共账户的开发者服务器地址后,将等待开发者服务器回复响应信息。如果微信服务器在5秒内无法收到响应,则会断开连接,并重新启动请求,共重试三次。
如果服务器不能保证在5秒内处理和回复,必须做出以下回复,使微信服务器不会进行任何处理,也不会启动重试(在这种情况下,可以使用客户服务信息接口进行异步回复),否则会有严重的错误提示。详见下面的说明:
1.(推荐方式)直接回复success 2.直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段内容为空)
一旦遇到以下情况,微信会在微信官方账号会话中向用户发布系统提示微信官方账号暂时无法提供服务,请稍后再试:
1.开发人员在5秒内没有回复任何内容 2.开发人员回复异常数据,如JSON数据等
另外,请注意,回复图片等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。
目前,消息回复支持文本、图片、图片、语音、视频和音乐的回复。每种类型的消息都有特定的信息XML数据格式。这些回复信息xml请参考官方文件,具体格式定义和属性说明。格式简单,包括基本共有属性ToUserName、FromUserName、CreateTime、MsgType,而且每种类型都有自己特殊的属性。
接收和回复微信公众号的普通消息
接收消息
收到消息和被动回复消息是不分离的,这是一个互动场景,一般是公共账户通过分析收到的消息,会给出相应的回复。
正如我之前所说,接收信息的过程实际上是通过获取微信服务器post请求发送给我们的微信官方账号服务器xml数据,然后我们的微信官方账号服务器对此进行了处理xml分析处理过程。便于分析XML我们借助数据dom4j,dom4j非常优秀JavaXML API,它具有性能优异、功能强大、使用方便的特点,用于读写XML文件的。微信服务器发来的微信服务器xml请求数据,我们写一个parseXml处理方法,parseXml该方法的代码如下:
/** * 分析微信发来的请求(XML) * * @param request 包装请求信息HttpServletRequest对象 * @return map 解析结果 * @throws Exception */ public static Map parseXml(HttpServletRequest request) throws Exception { // 存储分析结果HashMap中 Map map = new HashMap(); // 从request获取输入流 InputStream inputStream = request.getInputStream(); // 读取输入流 SAXReader reader = new SAXReader(); Document document = reader.read(inputStream); // 得到xml根元素 Element root = document.getRootElement(); // 所有获得根元素的子节点 List elementList = root.elements(); // 遍历所有子节点 for (Element e : elementList) { System.out.println(e.getName() "|" e.getText()); map.put(e.getName(), e.getText()); } // 释放资源 inputStream.close(); inputStream = null; return map; }
然后在处理微信请求的入口处servlet的doPost方法中调用parseXml调用代码如下:
/** * 处理微信服务器发来的消息 */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO 由微信服务器转发的用户发送给公众账户的接收、处理和响应信息 // 将请求和响应的代码设置为UTF-8(防止中文乱码) request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); System.out.println("请求进入"); String responseMessage; try { //分析微信发来的请求,将分析结果封装成Map返回 Map map = MessageHandlerUtil.parseXml(request); System.out.println("开始构建响应信息"); responseMessage = MessageHandlerUtil.buildResponseMessage(map); System.out.println(responseMessage); if(responseMessage.equals("")){ responseMessage ="未正确响应"; } } catch (Exception e) { e.printStackTrace(); System.out.println("发生异常:" e.getMessage()); responseMessage ="未正确响应"; } //发送响应信息 response.getWriter().println(responseMessage); }
这样,我们就完成了新闻的接收。新闻接收后,我们将根据新闻类型进行响应,并根据新闻类型构建一种返回新闻的方法。代码如下:
/** * 根据消息类型结构返回消息 * @param map 包装分析结果Map * @return responseMessage(响应信息) */ public static String buildResponseMessage(Map map) { //响应消息 String responseMessage = ""; ///获取消息类型 String msgType = map.get("MsgType").toString(); System.out.println("MsgType:" msgType); //消息类型
MessageType messageEnumType = MessageType.valueOf(MessageType.class, msgType.toUpperCase());
switch (messageEnumType) {
case TEXT:
//处理文本消息
responseMessage = handleTextMessage(map);
break;
case IMAGE:
//处理图片消息
responseMessage = handleImageMessage(map);
break;
case VOICE:
//处理语音消息
responseMessage = handleVoiceMessage(map);
break;
case VIDEO:
//处理视频消息
responseMessage = handleVideoMessage(map);
break;
case SHORTVIDEO:
//处理小视频消息
responseMessage = handleSmallVideoMessage(map);
break;
case LOCATION:
//处理位置消息
responseMessage = handleLocationMessage(map);
break;
case LINK:
//处理链接消息
responseMessage = handleLinkMessage(map);
break;
case EVENT:
//处理事件消息,用户在关注与取消关注公众号时,微信会向我们的公众号服务器发送事件消息,开发者接收到事件消息后就可以给用户下发欢迎消息
responseMessage = handleEventMessage(map);
default:
break;
}
//返回响应消息
return responseMessage;
}
这样我们就完成了根据消息类型进行响应了,在处理微信请求的入口servlet的doPost方法中调用buildResponseMessage方法即可,doPost方法的完整代码在上面已经贴出来了.buildResponseMessage方法中使用到了一个MessageType类,这是一个消息类型枚举类,MessageType类的代码如下:
/**
* 接收到的消息类型
*/
public enum MessageType {
TEXT,//文本消息
IMAGE,//图片消息
VOICE,//语音消息
VIDEO,//视频消息
SHORTVIDEO,//小视频消息
LOCATION,//地理位置消息
LINK,//链接消息
EVENT//事件消息
}
回复消息
下面我基于这样一个业务场景来演示构造回复的消息,接收到文本消息"文本",回复文本消息;接收到“图片”,回复图片消息;接收到“语音”,回复语音消息;接收到“视频”,回复视频消息;接收到“音乐”,回复音乐消息;接收到“图文”,回复图文消息。下面具体说明各种消息的构建,只贴出核心代码,一些辅助代码类请自行下载项目代码参考.
回复文本消息
接收的文本消息的XML数据格式如下:
1348831860
1234567890123456
回复的文本消息的XML数据格式如下:
消息创建时间(整形)
其中接收消息格式中的ToUserName便是回复消息的FromUserName,接收消息格式中的FromUserName便是回复消息的ToUserName。CreateTime为消息发送的时间戳。MsgType为消息类型,文本为text。Content为消息内容。具体每一种类型消息的回复,就是构造此种类型的xml格式内容,格式大同小异,只是音乐、视频、语音、图文格式相对于文本消息构造的xml内容稍微复杂一点。
写一个构建文本消息的方法,代码如下:
/**
* 构造文本消息
* @param map 封装了解析结果的Map
* @param content 文本消息内容
* @return 文本消息XML字符串
*/
private static String buildTextMessage(Map map, String content) {
//发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
/**
* 文本消息XML数据格式
*
1348831860
1234567890123456
*/
return String.format(
"" +
" " +
" " +
"%s " +
" " +
" " +
" ",
fromUserName, toUserName, getMessageCreateTime(), content);
}
回复图片消息
写一个构建图片消息的方法,代码如下:
/**
* 构造图片消息
* @param map 封装了解析结果的Map
* @param mediaId 通过素材管理接口上传多媒体文件得到的id
* @return 图片消息XML字符串
*/
private static String buildImageMessage(Map map, String mediaId) {
//发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
/**
* 图片消息XML数据格式
*
12345678
*/
return String.format(
"" +
" " +
" " +
"%s " +
" " +
"" +
" " +
" " +
" ",
fromUserName, toUserName, getMessageCreateTime(), mediaId);
}
回复音乐消息
写一个构建音乐消息的方法,代码如下:
/**
* 构造音乐消息
* @param map 封装了解析结果的Map
* @param music 封装好的音乐消息内容
* @return 音乐消息XML字符串
*/
private static String buildMusicMessage(Map map, Music music) {
//发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
/**
* 音乐消息XML数据格式
*
12345678
*/
return String.format(
"" +
" " +
" " +
"%s " +
" " +
"" +
" " +
" " +
" " +
" " +
" " +
" ",
fromUserName, toUserName, getMessageCreateTime(), music.title, music.description, music.musicUrl, music.hqMusicUrl);
}
回复视频消息
写一个构建视频消息的方法,代码如下:
/**
* 构造视频消息
* @param map 封装了解析结果的Map
* @param video 封装好的视频消息内容
* @return 视频消息XML字符串
*/
private static String buildVideoMessage(Map map, Video video) {
//发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
/**
* 音乐消息XML数据格式
*
12345678
*/
return String.format(
"" +
" " +
" " +
"%s " +
" " +
"" +
" ",
fromUserName, toUserName, getMessageCreateTime(), video.mediaId, video.title, video.description);
}
回复语音消息
写一个构建语音消息的方法,代码如下:
/**
* 构造语音消息
* @param map 封装了解析结果的Map
* @param mediaId 通过素材管理接口上传多媒体文件得到的id
* @return 语音消息XML字符串
*/
private static String buildVoiceMessage(Map map, String mediaId) {
//发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
/**
* 语音消息XML数据格式
*
12345678
*/
return String.format(
"" +
" " +
" " +
"%s " +
" " +
"" +
" " +
" " +
" ",
fromUserName, toUserName, getMessageCreateTime(), mediaId);
}
回复图文消息
写一个构建图文消息的方法,代码如下:
/**
* 构造图文消息
* @param map 封装了解析结果的Map
* @return 图文消息XML字符串
*/
private static String buildNewsMessage(Map map) {
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
NewsItem item = new NewsItem();
item.Title = "微信开发学习总结(一)——微信开发环境搭建";
item.Description = "工欲善其事,必先利其器。要做微信公众号开发,那么要先准备好两样必不可少的东西:\n" +
"\n" +
" 1、要有一个用来测试的公众号。\n" +
"\n" +
" 2、用来调式代码的开发环境";
item.PicUrl = "http://images2015.cnblogs.com/blog/289233/201601/289233-20160121164317343-2145023644.png";
item.Url = "http://www.cnblogs.com/xdp-gacl/p/5149171.html";
String itemContent1 = buildSingleItem(item);
NewsItem item2 = new NewsItem();
item2.Title = "微信开发学习总结(二)——微信开发入门";
item2.Description = "微信服务器就相当于一个转发服务器,终端(手机、Pad等)发起请求至微信服务器,微信服务器然后将请求转发给我们的应用服务器。应用服务器处理完毕后,将响应数据回发给微信服务器,微信服务器再将具体响应信息回复到微信App终端。";
item2.PicUrl = "";
item2.Url = "http://www.cnblogs.com/xdp-gacl/p/5151857.html";
String itemContent2 = buildSingleItem(item2);
String content = String.format("\n" +
" \n" +
" \n" +
"%s \n" +
" \n" +
"%s \n" +
"\n" + "%s" +
" \n" +
" ", fromUserName, toUserName, getMessageCreateTime(), 2, itemContent1 + itemContent2);
return content;
}
/**
* 生成图文消息的一条记录
*
* @param item
* @return
*/
private static String buildSingleItem(NewsItem item) {
String itemContent = String.format("- \n" +
"
\n" +
" \n" +
" \n" +
" \n" +
" ", item.Title, item.Description, item.PicUrl, item.Url);
return itemContent;
}
根据上述提到的消息回复业务场景,我们可以写一个handleTextMessage方法来作为构造各种回复消息的处理入口,代码如下:
/**
* 接收到文本消息后处理
* @param map 封装了解析结果的Map
* @return
*/
private static String handleTextMessage(Map map) {
//响应消息
String responseMessage;
// 消息内容
String content = map.get("Content");
switch (content) {
case "文本":
String msgText = "孤傲苍狼又要开始写博客总结了,欢迎朋友们访问我在博客园上面写的博客\n" +
"孤傲苍狼的博客";
responseMessage = buildTextMessage(map, msgText);
break;
case "图片":
//通过素材管理接口上传图片时得到的media_id
String imgMediaId = "dSQCiEHYB-pgi7ib5KpeoFlqpg09J31H28rex6xKgwWrln3HY0BTsoxnRV-xC_SQ";
responseMessage = buildImageMessage(map, imgMediaId);
break;
case "语音":
//通过素材管理接口上传语音文件时得到的media_id
String voiceMediaId = "h3ul0TnwaRPut6Tl1Xlf0kk_9aUqtQvfM5Oq21unoWqJrwks505pkMGMbHnCHBBZ";
responseMessage = buildVoiceMessage(map,voiceMediaId);
break;
case "图文":
responseMessage = buildNewsMessage(map);
break;
case "音乐":
Music music = new Music();
music.title = "赵丽颖、许志安 - 乱世俱灭";
music.description = "电视剧《蜀山战纪》插曲";
music.musicUrl = "http://gacl.ngrok.natapp.cn/music/music.mp3";
music.hqMusicUrl = "http://gacl.ngrok.natapp.cn/music/music.mp3";
responseMessage = buildMusicMessage(map, music);
break;
case "视频":
Video video = new Video();
video.mediaId = "GqmIGpLu41rtwaY7WCVtJAL3ZbslzKiuLEXfWIKYDnHXGObH1CBH71xtgrGwyCa3";
video.title = "小苹果";
video.description = "小苹果搞笑视频";
responseMessage = buildVideoMessage(map, video);
break;
default:
responseMessage = buildWelcomeTextMessage(map);
break;
}
//返回响应消息
return responseMessage;
}
到此,回复想消息的相关处理代码就编写完成了,将项目部署到Tomcat服务器进行测试,记得使用Ngrok将内网的服务器映射到外网,否则无法使用微信测试,如下:
使用微信进行消息回复测试,测试效果如下:
可以看到,每一种消息都正常响应了.
这里需要说一下图片,语音,视频的回复消息构造,这三种消息构造时的都需要一个mediaId,而这个mediaId是通过素材管理接口上传多媒体文件得到的,为了构造图片,语音,视频的这几种回复消息,我事先准备好了测试素材,如下图所示:
然后通过微信公众号平台提供的素材管理接口将图片,语音,视频上传到微信服务器上,上传成功后,微信服务器会给我们返回一个mediaId,用于标识上传成功的多媒体素材,上传素材的工具类代码如下:
1 package me.gacl.wx.util;
2
3 import com.alibaba.fastjson.JSON;
4 import com.alibaba.fastjson.JSONException;
5 import com.alibaba.fastjson.JSONObject;
6 import org.apache.commons.httpclient.HttpClient;
7 import org.apache.commons.httpclient.HttpException;
8 import org.apache.commons.httpclient.methods.PostMethod;
9 import org.apache.commons.httpclient.methods.multipart.FilePart;
10 import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
11 import org.apache.commons.httpclient.methods.multipart.Part;
12 import org.apache.commons.httpclient.methods.multipart.StringPart;
13 import org.apache.commons.httpclient.protocol.Protocol;
14 import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
15 import org.apache.http.HttpStatus;
16
17 import javax.net.ssl.*;
18 import java.io.*;
19 import java.net.HttpURLConnection;
20 import java.net.URL;
21 import java.security.cert.CertificateException;
22 import java.security.cert.X509Certificate;
23
24 /**
25 * Created by allen on 2016/1/29.
26 */
27 public class WeChatApiUtil {
28 // token 接口(GET)
29 private static final String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
30 // 素材上传(POST)https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
31 private static final String UPLOAD_MEDIA = "https://api.weixin.qq.com/cgi-bin/media/upload";
32 // 素材下载:不支持视频文件的下载(GET)
33 private static final String DOWNLOAD_MEDIA = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";
34
35 public static String getTokenUrl(String appId, String appSecret) {
36 return String.format(ACCESS_TOKEN, appId, appSecret);
37 }
38
39 public static String getDownloadUrl(String token, String mediaId) {
40 return String.format(DOWNLOAD_MEDIA, token, mediaId);
41 }
42
43 /**
44 * 通用接口获取Token凭证
45 *
46 * @param appId
47 * @param appSecret
48 * @return
49 */
50 public static String getToken(String appId, String appSecret) {
51 if (appId == null || appSecret == null) {
52 return null;
53 }
54
55 String token = null;
56 String tockenUrl = WeChatApiUtil.getTokenUrl(appId, appSecret);
57 String response = httpsRequestToString(tockenUrl, "GET", null);
58 JSONObject jsonObject = JSON.parseObject(response);
59 if (null != jsonObject) {
60 try {
61 token = jsonObject.getString("access_token");
62 } catch (JSONException e) {
63 token = null;// 获取token失败
64 }
65 }
66 return token;
67 }
68
69 /**
70 * 微信服务器素材上传
71 *
72 * @param file 表单名称media
73 * @param token access_token
74 * @param type type只支持四种类型素材(video/image/voice/thumb)
75 */
76 public static JSONObject uploadMedia(File file, String token, String type) {
77 if (file == null || token == null || type == null) {
78 return null;
79 }
80
81 if (!file.exists()) {
82 System.out.println("上传文件不存在,请检查!");
83 return null;
84 }
85
86 String url = UPLOAD_MEDIA;
87 JSONObject jsonObject = null;
88 PostMethod post = new PostMethod(url);
89 post.setRequestHeader("Connection", "Keep-Alive");
90 post.setRequestHeader("Cache-Control", "no-cache");
91 FilePart media;
92 HttpClient httpClient = new HttpClient();
93 //信任任何类型的证书
94 Protocol myhttps = new Protocol("https", new SSLProtocolSocketFactory(), 443);
95 Protocol.registerProtocol("https", myhttps);
96
97 try {
98 media = new FilePart("media", file);
99 Part[] parts = new Part[]{new StringPart("access_token", token),
100 new StringPart("type", type), media};
101 MultipartRequestEntity entity = new MultipartRequestEntity(parts,
102 post.getParams());
103 post.setRequestEntity(entity);
104 int status = httpClient.executeMethod(post);
105 if (status == HttpStatus.SC_OK) {
106 String text = post.getResponseBodyAsString();
107 jsonObject = JSONObject.parseObject(text);
108 } else {
109 System.out.println("upload Media failure status is:" + status);
110 }
111 } catch (FileNotFoundException e) {
112 e.printStackTrace();
113 } catch (HttpException e) {
114 e.printStackTrace();
115 } catch (IOException e) {
116 e.printStackTrace();
117 }
118 return jsonObject;
119 }
120
121 /**
122 * 多媒体下载接口
123 *
124 * @param fileName 素材存储文件路径
125 * @param token 认证token
126 * @param mediaId 素材ID(对应上传后获取到的ID)
127 * @return 素材文件
128 * @comment 不支持视频文件的下载
129 */
130 public static File downloadMedia(String fileName, String token,
131 String mediaId) {
132 String url = getDownloadUrl(token, mediaId);
133 return httpRequestToFile(fileName, url, "GET", null);
134 }
135
136 /**
137 * 多媒体下载接口
138 *
139 * @param fileName 素材存储文件路径
140 * @param mediaId 素材ID(对应上传后获取到的ID)
141 * @return 素材文件
142 * @comment 不支持视频文件的下载
143 */
144 public static File downloadMedia(String fileName, String mediaId) {
145 String appId = "wxbe4d433e857e8bb1";
146 String appSecret = "ccbc82d560876711027b3d43a6f2ebda";
147 String token = WeChatApiUtil.getToken(appId, appSecret);
148 return downloadMedia(fileName,token,mediaId);
149 }
150
151 /**
152 * 以http方式发送请求,并将请求响应内容输出到文件
153 *
154 * @param path 请求路径
155 * @param method 请求方法
156 * @param body 请求数据
157 * @return 返回响应的存储到文件
158 */
159 public static File httpRequestToFile(String fileName, String path, String method, String body) {
160 if (fileName == null || path == null || method == null) {
161 return null;
162 }
163
164 File file = null;
165 HttpURLConnection conn = null;
166 InputStream inputStream = null;
167 FileOutputStream fileOut = null;
168 try {
169 URL url = new URL(path);
170 conn = (HttpURLConnection) url.openConnection();
171 conn.setDoOutput(true);
172 conn.setDoInput(true);
173 conn.setUseCaches(false);
174 conn.setRequestMethod(method);
175 if (null != body) {
176 OutputStream outputStream = conn.getOutputStream();
177 outputStream.write(body.getBytes("UTF-8"));
178 outputStream.close();
179 }
180
181 inputStream = conn.getInputStream();
182 if (inputStream != null) {
183 file = new File(fileName);
184 } else {
185 return file;
186 }
187
188 //写入到文件
189 fileOut = new FileOutputStream(file);
190 if (fileOut != null) {
191 int c = inputStream.read();
192 while (c != -1) {
193 fileOut.write(c);
194 c = inputStream.read();
195 }
196 }
197 } catch (Exception e) {
198 } finally {
199 if (conn != null) {
200 conn.disconnect();
201 }
202
203 /*
204 * 必须关闭文件流
205 * 否则JDK运行时,文件被占用其他进程无法访问
206 */
207 try {
208 inputStream.close();
209 fileOut.close();
210 } catch (IOException execption) {
211 }
212 }
213 return file;
214 }
215
216 /**
217 * 上传素材
218 * @param filePath 媒体文件路径(绝对路径)
219 * @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
220 * @return
221 */
222 public static JSONObject uploadMedia(String filePath,String type){
223 File f = new File(filePath); // 获取本地文件
224 String appId = "wxbe4d433e857e8bb1";
225 String appSecret = "ccbc82d560876711027b3d43a6f2ebda";
226 String token = WeChatApiUtil.getToken(appId, appSecret);
227 JSONObject jsonObject = uploadMedia(f, token, type);
228 return jsonObject;
229 }
230
231 /**
232 * 发送请求以https方式发送请求并将请求响应内容以String方式返回
233 *
234 * @param path 请求路径
235 * @param method 请求方法
236 * @param body 请求数据体
237 * @return 请求响应内容转换成字符串信息
238 */
239 public static String httpsRequestToString(String path, String method, String body) {
240 if (path == null || method == null) {
241 return null;
242 }
243
244 String response = null;
245 InputStream inputStream = null;
246 InputStreamReader inputStreamReader = null;
247 BufferedReader bufferedReader = null;
248 HttpsURLConnection conn = null;
249 try {
250 TrustManager[] tm = {new JEEWeiXinX509TrustManager()};
251 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
252 sslContext.init(null, tm, new java.security.SecureRandom());
253 SSLSocketFactory ssf = sslContext.getSocketFactory();
254 System.out.println(path);
255 URL url = new URL(path);
256 conn = (HttpsURLConnection) url.openConnection();
257 conn.setSSLSocketFactory(ssf);
258
259 conn.setDoOutput(true);
260 conn.setDoInput(true);
261 conn.setUseCaches(false);
262 conn.setRequestMethod(method);
263 if (null != body) {
264 OutputStream outputStream = conn.getOutputStream();
265 outputStream.write(body.getBytes("UTF-8"));
266 outputStream.close();
267 }
268
269 inputStream = conn.getInputStream();
270 inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
271 bufferedReader = new BufferedReader(inputStreamReader);
272 String str = null;
273 StringBuffer buffer = new StringBuffer();
274 while ((str = bufferedReader.readLine()) != null) {
275 buffer.append(str);
276 }
277
278 response = buffer.toString();
279 } catch (Exception e) {
280
281 } finally {
282 if (conn != null) {
283 conn.disconnect();
284 }
285 try {
286 bufferedReader.close();
287 inputStreamReader.close();
288 inputStream.close();
289 } catch (IOException execption) {
290
291 }
292 }
293 return response;
294 }
295
296 public static void main(String[] args) throws Exception{
297 //媒体文件路径
298 String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/image/我.jpg";
299 //String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/voice/voice.mp3";
300 //String filePath = "D:\\JavaSoftwareDevelopeFolder\\IntelliJ IDEA_Workspace\\WxStudy\\web\\media\\video\\小苹果.mp4";
301 //媒体文件类型
302 String type = "image";
303 //String type = "voice";
304 //String type = "video";
305 JSONObject uploadResult = uploadMedia(filePath, type);
306 //{"media_id":"dSQCiEHYB-pgi7ib5KpeoFlqpg09J31H28rex6xKgwWrln3HY0BTsoxnRV-xC_SQ","created_at":1455520569,"type":"image"}
307 System.out.println(uploadResult.toString());
308
309 //下载刚刚上传的图片以id命名
310 String media_id = uploadResult.getString("media_id");
311 File file = downloadMedia("D:/" + media_id + ".png", media_id);
312 System.out.println(file.getName());
313
314 }
315 }
316
317 class JEEWeiXinX509TrustManager implements X509TrustManager {
318 public void checkClientTrusted(X509Certificate[] chain, String authType)
319 throws CertificateException {
320 }
321
322 public void checkServerTrusted(X509Certificate[] chain, String authType)
323 throws CertificateException {
324 }
325
326 public X509Certificate[] getAcceptedIssuers() {
327 return null;
328 }
329 }
在工具类写一个main方法测试素材上传和下载,代码如下:
public static void main(String[] args) throws Exception{
//媒体文件路径
String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/image/我.jpg";
//String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/voice/voice.mp3";
//String filePath = "D:\\JavaSoftwareDevelopeFolder\\IntelliJ IDEA_Workspace\\WxStudy\\web\\media\\video\\小苹果.mp4";
//媒体文件类型
String type = "image";
//String type = "voice";
//String type = "video";
JSONObject uploadResult = uploadMedia(filePath, type);
//{"media_id":"dSQCiEHYB-pgi7ib5KpeoFlqpg09J31H28rex6xKgwWrln3HY0BTsoxnRV-xC_SQ","created_at":1455520569,"type":"image"}
System.out.println(uploadResult.toString());
//下载刚刚上传的图片以id命名
String media_id = uploadResult.getString("media_id");
File file = downloadMedia("D:/" + media_id + ".png", media_id);
System.out.println(file.getName());
}
运行结果如下:
可以看到,素材上传成功后,微信服务器就会返回一个media_id,用于标识上传后的文件.有了这个media_id后,我们就可以构建我们想要的图片,语音,视频回复消息了.
下面再说一下音乐的回复消息的构造,音乐素材也是我事先在服务器上准备了一个music.mp3音乐文件,并且保证可以正常使用外网访问,如下所示:
然后将MusicUrl和HQMusicUrl的地址指向了服务器上的music.mp3文件的访问地址,如下:
Music music = new Music();
music.title = "赵丽颖、许志安 - 乱世俱灭";
music.description = "电视剧《蜀山战纪》插曲";
music.musicUrl = "http://gacl.ngrok.natapp.cn/media/music/music.mp3";
music.hqMusicUrl = "http://gacl.ngrok.natapp.cn/media/music/music.mp3";
responseMessage = buildMusicMessage(map, music);
这样就可以正常构造音乐回复消息了.