- 按消息的来源,可以将消息分为两种,一种是用户过来的消息(即接受的普通消息),另一种是我的服务器返回给用户的消息(即被动回复消息)。
- 用户发送的普通消息可以是:文本,图片,语音,视频,小视频,地址位置,连接,这7种类型。点击跳转官方文档说明
- 被动回复消息只能是:文本,图片,语音,视频,音乐,图文,这6种类型。点击跳转官方文档说明
下面就重点讲解一下,如何依照官方文档编写被动回复消息的java代码,本文以image消息为例。
图片消息
xml格式:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>#
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[media_id]]></MediaId>
</Image>
</xml>
参数说明:
1 如何获取MediaId?
- 要想获得MediaId,就必须将多媒体文件上传到通过素材管理中的接口地址中。
- 在官方文档中,素材管理-新增临时素材查看详细说明,点我查看官方说明
接口url:
https://api.weixin.qq.com/cgibin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
- url地址参数说明
- 所以,下面我们就需要获取参数access_token(type我们代码中手动写入,media文件上传的时候会指定)。
2 如何获取access_token?
- 在官方文档中,开始开发-获取access_token,查看详细说明,点我查看官方说明
- 公众号可以使用AppID和AppSecret调用本接口来获取access_token。AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。
3 如何用代码实现回复image消息?
- 要构建image的xml格式(除了前4个基本元素外,还有个image元素,它内部又包含一个MediaId元素,所以就需要给MediaId传值),就要先获得MediaId,要想获得MediaId,又必须先获得access_token。
- 所以基本思路:
第一步 获取access_token
第一步 获取MediaId
第三步 拼装image的xml格式
3.1 获取access_token
- 导入7个jar包
<!-- https://mvnrepository.com/artifact/net.sf.json-lib/json-lib -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-logging/commons-logging -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.6</version>
</dependency>
- 定义AccessToken对象
public class AccessToken{
private String access_token;
private int expires_in;
public String getAccess_token() {
return access_token;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
}
public int getExpires_in() {
return expires_in;
}
public void setExpires_in(int expires_in) {
this.expires_in = expires_in;
}
}
- 定义常量传入需要的值
public final static String APPID="wxb66105e88b4179b6";
public final static String APPSECRET="e1e872b97cf1591adfa56813f2a87559";
public final static String AccessTokenUrl="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
- 定义getAccessToken方法
public static AccessToken getAccessToken(){
AccessToken token = new AccessToken();
String url = AccessTokenUrl.replace("APPID", APPID).replaceAll("APPSECRET", APPSECRET);//替换到接口地址中的APPID和APPSECRET
JSONObject jsonObject = doGet(url);//调用doGet方法发送get请求到url
System.out.println("微信服务器返回的accessToken数据:"+jsonObject);
if (jsonObject!=null) {
token.setAccess_token(jsonObject.getString("access_token"));
token.setExpires_in(jsonObject.getInt("expires_in"));
}
return token;
}
- 定义doGet方法
public static JSONObject doGet(String url){
JSONObject jsonObject = null;
CloseableHttpClient httpClient = HttpClients.createDefault();//替代DefaultHttpClient
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
if (entity!=null) {
String result = EntityUtils.toString(entity);
jsonObject=JSONObject.fromObject(result);
}
}
catch (ClientProtocolException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return jsonObject;
}
- 测试
@Test
public void test1() throws Exception{
AccessToken token = weiXinUtil.getAccessToken();
System.out.println("票据:"+token.getAccess_token());
System.out.println("accessToken有效时间:"+token.getExpires_in());
}
-
- 正确输出
微信服务器返回的accessToken数据:{"access_token":"NrnXLx8Q5WWYHKgnswgf_EnM4FulqKj0O59jotaJWZ-6MTFXasE-qwqY_EeHmC1xfY5zzN9waAoNJe0Y6Lz6T31wKThQAk-onBk5NUq1xAVvwewcAisUGwKyQ9JqPM5GSVSfACALOL","expires_in":7200}
-
- 如果console输出:
微信服务器返回的accessToken数据:{"errcode":40164,"errmsg":"invalid ip 60.12.8.170, not in whitelist hint:
添加本机IP(60.12.8.170)到白名单,如下图
-
- 如果console输出:
微信服务器返回的accessToken数据:{"errcode":40125,"errmsg":"invalid appsecret, view more at http://t.cn/RAEkdVq hint: [e89qca0917nfo1]"}
说明:工具类weixinUtil中的常量public final static String APPSECRET=””与基本配置中的AppSecret不一致
3.2 获取MediaId
微信服务器返回的json数据包:{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}
- 素材上传接口地址
public final static String UploadUrl=
"https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE";
- 文件上传工具类upload
public static String upload(String filePath,String accessToken,String type) throws IOException{
File file = new File(filePath);
if (!file.isFile() || !file.exists()) {
throw new IOException("文件不存在");
}
String url = UploadUrl.replace("ACCESS_TOKEN", accessToken).replaceAll("TYPE", type);
URL urlObj = new URL(url);
HttpURLConnection connection = (HttpURLConnection)urlObj.openConnection();
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
//设置请求头
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("Charset", "utf-8");
//设置边界
String BOUNDARY = "----------"+System.currentTimeMillis();
connection.setRequestProperty("Content-Type","multipart/form-data;boundary="+BOUNDARY);
StringBuilder sb = new StringBuilder();
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition;form-data;name=\"flie\";filename=\""+file.getName()+"\"\r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes("utf-8");
//获取输出流
OutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(head);
//文件正文部分,把文件以流的方式push到url中
DataInputStream in = new DataInputStream(new FileInputStream(file));
int bytes=0;
byte[] bufferOut = new byte[1024];
while((bytes = in.read(bufferOut))!=-1){
out.write(bufferOut,0,bytes);
}
in.close();
//结尾部分
byte[] foot = ("\r\n--"+BOUNDARY+"--\r\n").getBytes("utf-8");
out.write(foot);
out.close();
StringBuffer buffer = new StringBuffer();
BufferedReader reader = null;
String result = null;
try {
//读取url响应结果
reader=new BufferedReader(new InputStreamReader(connection.getInputStream() ));
String line = null;
while((line = reader.readLine())!=null){
buffer.append(line);
}
if (result==null) {
result=buffer.toString();
}
} catch (Exception e) {
// TODO: handle exception
} finally {
if (reader!=null) {
reader.close();
}
}
JSONObject jsonObject = JSONObject.fromObject(result);
System.out.println(jsonObject);
String mediaId = jsonObject.getString("media_id");
return mediaId;
}
- 测试
@Test
public void test2() throws Exception{
AccessToken token = weiXinUtil.getAccessToken();
String path = "D:/3.jpg";
String mediaId = weiXinUtil.upload(path, token.getAccess_token(), "image");
System.out.println("微信服务器返回的mediaId:"+mediaId);
}
微信服务器返回的mediaId:
hcBIDu0UhtNpm3oixqLgpJ8HjbaAgLBbfFq6oJ8aoQW3mDWX90aVpoC4pEiONNw2
3.3 拼装image的xml格式
- 创建Image实体对象
public class Image {
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
}
- 创建imageMessage实体对象
public class baseMessage {
private String ToUserName;
private String FromUserName;
private long CreateTime;
private String MsgType;
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public long getCreateTime() {
return CreateTime;
}
public void setCreateTime(long createTime) {
CreateTime = createTime;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String msgType) {
MsgType = msgType;
}
}
public class imageMessage extends baseMessage{
private Image Image;
public Image getImage() {
return Image;
}
public void setImage(Image image) {
Image = image;
}
}
- 创建sendImageMessage方法
public final static String userResp_message_type_image = "image";//常量
public static String sendImageMessage(String toUserName,String fromUserName) throws Exception{
Image img = new Image();
String mediaId ="p483hrUP4Zf19H7XRWLKaT-Vt3FTArsj7dQPrWAy_lLbEgGc6DTrLvQT3_iqJ8j3";//复制成功上传文件后返回的media_id
img.setMediaId(mediaId);//上传多媒体文件到素材管理的接口中,微信服务器会返回mediaId
imageMessage image = new imageMessage();
image.setFromUserName(toUserName);
image.setToUserName(fromUserName);
image.setCreateTime(new Date().getTime());
image.setMsgType(messageUtil.userResp_message_type_image);
image.setImage(img);
String reponseMessage = messageUtil.imageMessageToXml(image);//利用写好的工具类将text类型消息拼装成微信服务器接受的xml格式
System.out.println("imgReponseMessage=\n"+reponseMessage);
return reponseMessage;
}
- handleRequestUtil的reponseInfo方法处理用户请求(用户发送B,服务器就回复一张图片)
if ("B".equals(map.get("Content").toUpperCase())) {
reponseMessage = messageUtil.sendImageMessage(toUserName, fromUserName);
}
- Sevlet执行doPost请求
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String responseMessage = handleRequestUtil.reponseInfo(request);
//工具类 handleRequestUtil的reponseInfo方法处理用户请求
PrintWriter out = response.getWriter();
out.print(responseMessage);
out.close();
}
- 测试