Java发送企业微信应用消息

时间:2024-01-13 17:25:38

1.发送消息与被动回复消息

(1)流程不同:发送消息是第三方服务器主动通知微信服务器向用户发消息。而被动回复消息是 用户发送消息之后,微信服务器将消息传递给 第三方服务器,第三方服务器接收到消息后,再对消息做出相应的回复消息。

(2)消息是否加密:在发送消息的流程中,对封装好的回复消息(json字符串)是不进行AES加密的。

而在被动回复消息的流程中,第三方服务器接收消息时,需要先解密微信发过来的消息,在最后发送回复消息前,需要先加密(AES)回复消息。

(3)数据交换的格式不同:在发送消息的流程中,第三方服务器将消息(json字符串格式)发送给微信服务器

而在被动回复消息的过程中,第三方服务器接收的消息和被动回复的消息都是以xml字符串格式的。

二、代码实现

1.实体类

1.1 消息基类(企业号 -> 普通用户) ——BaseMessage

 1
2 /**
3 * 消息基类(企业号 -> 普通用户)
4 * @author hh
5 *
6 */
7 public class BaseMessage {
8 // 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向该企业应用的全部成员发送
9 private String touser;
10 // 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
11 private String toparty;
12 // 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
13 private String totag;
14 // 是 消息类型
15 private String msgtype;
16 // 是 企业应用的id,整型。可在应用的设置页面查看
17 private int agentid;
18
19
20 public String getTouser() {
21 return touser;
22 }
23 public void setTouser(String touser) {
24 this.touser = touser;
25 }
26 public String getToparty() {
27 return toparty;
28 }
29 public void setToparty(String toparty) {
30 this.toparty = toparty;
31 }
32 public String getTotag() {
33 return totag;
34 }
35 public void setTotag(String totag) {
36 this.totag = totag;
37 }
38 public String getMsgtype() {
39 return msgtype;
40 }
41 public void setMsgtype(String msgtype) {
42 this.msgtype = msgtype;
43 }
44 public int getAgentid() {
45 return agentid;
46 }
47 public void setAgentid(int agentid) {
48 this.agentid = agentid;
49 }
50 }

1.2 文本消息——Text、TextMessage

企业微信官方文档中关于文本消息请求包的说明

 1 {
2 "touser" : "UserID1|UserID2|UserID3",
3 "toparty" : " PartyID1|PartyID2 ",
4 "totag" : " TagID1 | TagID2 ",
5 "msgtype" : "text",
6 "agentid" : 1,
7 "text" : {
8 "content" : "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"
9 },
10 "safe":0
11 }

可把整个json对象看做一个java对象,而在这个json对象中又包含一个text对象。(json中的对象用{ }包裹起来,json中的数组用[  ] 包裹起来)

需注意agentid、safe为int型。于是可以把text看做一个java对象,这样TextMessage类组合了Text类,转json字符串的时候,就可以直接使用 String jsonTextMessage=gson.toJson(textMessage).

于是,我们开始对文本消息进行封装

Text.java

 1 /**
2 * 文本
3 * @author hh
4 *
5 */
6 public class Text {
7 //是 消息内容,最长不超过2048个字节
8 private String content;
9
10 public String getContent() {
11 return content;
12 }
13
14 public void setContent(String content) {
15 this.content = content;
16 }
17 }

TextMessage.java

 1 /**
2 * 文本消息
3 * @author hh
4 *
5 */
6 public class TextMessage extends BaseMessage {
7 //文本
8 private Text text;
9 //否 表示是否是保密消息,0表示否,1表示是,默认0
10 private int safe;
11
12 public Text getText() {
13 return text;
14 }
15 public void setText(Text text) {
16 this.text = text;
17 }
18 public int getSafe() {
19 return safe;
20 }
21 public void setSafe(int safe) {
22 this.safe = safe;
23 }
24 }

1.3 图片类、语音类、文件类——Media

通过对微信官方文档的仔细阅读,可以看到图片消息、语音消息、文件消息中的的json对象都内含同一个Jason对象(media_id),于是我们根据这个对象封装Media.java

 1 /**
2 * 图片、语音、文件
3 * @author hh
4 *
5 */
6 public class Media {
7 //是 图片/语音/文件 媒体文件id,可以调用上传临时素材接口获取
8 private String media_id;
9
10 public String getMedia_id() {
11 return media_id;
12 }
13
14 public void setMedia_id(String media_id) {
15 this.media_id = media_id;
16 }
17 }

1.3.1 图片消息——ImgMessage

 1 /**
2 * 图片消息
3 * @author hh
4 *
5 */
6 public class ImgMessage extends BaseMessage {
7 //图片
8 private Media image ;
9 //否 表示是否是保密消息,0表示否,1表示是,默认0
10 private int safe;
11
12 public Media getImage() {
13 return image;
14 }
15 public void setImage(Media image) {
16 this.image = image;
17 }
18 public int getSafe() {
19 return safe;
20 }
21 public void setSafe(int safe) {
22 this.safe = safe;
23 }
24 }

1.3.2 语音消息——VoiceMessage

 1 /**
2 * 语音消息
3 * @author hh
4 *
5 */
6 public class VoiceMessage extends BaseMessage {
7 //语音
8 private Media voice ;
9 //否 表示是否是保密消息,0表示否,1表示是,默认0
10 private int safe;
11
12 public Media getVoice() {
13 return voice;
14 }
15 public void setVoice(Media voice) {
16 this.voice = voice;
17 }
18 public int getSafe() {
19 return safe;
20 }
21 public void setSafe(int safe) {
22 this.safe = safe;
23 }
24 }

1.3.3 文件消息——FileMessage

 1 /**
2 * 文件消息
3 * @author hh
4 *
5 */
6 public class FileMessage extends BaseMessage {
7 //文件
8 private Media file ;
9 //否 表示是否是保密消息,0表示否,1表示是,默认0
10 private int safe;
11
12 public Media getFile() {
13 return file;
14 }
15 public void setFile(Media file) {
16 this.file = file;
17 }
18 public int getSafe() {
19 return safe;
20 }
21 public void setSafe(int safe) {
22 this.safe = safe;
23 }
24 }

1.4  视频消息——Video、VideoMessage

Video.java

 1 /**
2 * 视频
3 * @author hh
4 *
5 */
6 public class Video {
7 //是 视频媒体文件id,可以调用上传临时素材接口获取
8 private String media_id;
9 //否 视频消息的标题,不超过128个字节,超过会自动截断
10 private String title;
11 //否 视频消息的描述,不超过512个字节,超过会自动截断
12 private String description;
13
14 public String getMedia_id() {
15 return media_id;
16 }
17 public void setMedia_id(String media_id) {
18 this.media_id = media_id;
19 }
20 public String getTitle() {
21 return title;
22 }
23 public void setTitle(String title) {
24 this.title = title;
25 }
26 public String getDescription() {
27 return description;
28 }
29 public void setDescription(String description) {
30 this.description = description;
31 }
32 }

VideoMessage.java

 1 /**
2 * 视频消息
3 * @author hh
4 *
5 */
6 public class VideoMessage extends BaseMessage {
7 //视频
8 private Video video ;
9 //否 表示是否是保密消息,0表示否,1表示是,默认0
10 private int safe;
11
12 public Video getVideo() {
13 return video;
14 }
15 public void setVideo(Video video) {
16 this.video = video;
17 }
18 public int getSafe() {
19 return safe;
20 }
21 public void setSafe(int safe) {
22 this.safe = safe;
23 }
24 }

1.5 文本卡片消息——Textcard、TextcardMessage

Textcard.java

 1 /**
2 * 文本卡片
3 * @author hh
4 *
5 */
6 public class Textcard {
7 //是 标题,不超过128个字节,超过会自动截断
8 private String title;
9 //是 描述,不超过512个字节,超过会自动截断
10 private String description;
11 //是 点击后跳转的链接。
12 private String url;
13 public String getTitle() {
14 return title;
15 }
16 public void setTitle(String title) {
17 this.title = title;
18 }
19 public String getDescription() {
20 return description;
21 }
22 public void setDescription(String description) {
23 this.description = description;
24 }
25 public String getUrl() {
26 return url;
27 }
28 public void setUrl(String url) {
29 this.url = url;
30 }
31 }

TextcardMessage.java

 1 /**
2 * 文本卡片消息
3 * @author hh
4 *
5 */
6 public class TextcardMessage extends BaseMessage {
7 //文本
8 private Textcard textcard;
9
10 //btntxt 否 按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
11
12 public Textcard getTextcard() {
13 return textcard;
14 }
15
16 public void setTextcard(Textcard textcard) {
17 this.textcard = textcard;
18 }
19 }

1.6 图文消息——Article、News、NewsMessage

企业微信官方文档中关于图文消息请求包的说明:

{
"touser" : "UserID1|UserID2|UserID3",
"toparty" : " PartyID1 | PartyID2 ",
"totag" : " TagID1 | TagID2 ",
"msgtype" : "news",
"agentid" : 1,
"news" : {
"articles" : [
{
"title" : "中秋节礼品领取",
"description" : "今年中秋节公司有豪礼相送",
"url" : "URL",
"picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png"
}
]
}
}

可以看到NewsMessage类组合了News类,News类组合了List<Aticle> articles(即Article数组),于是得到以下实体类。

Article.java

 1 /**
2 * 文章
3 * @author hh
4 *
5 */
6 public class Article {
7 //是 标题,不超过128个字节,超过会自动截断
8 private String title;
9 //否 描述,不超过512个字节,超过会自动截断
10 private String description;
11 //是 点击后跳转的链接。
12 private String url;
13 //否 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640320,小图8080。
14 private String picurl;
15 public String getTitle() {
16 return title;
17 }
18 public void setTitle(String title) {
19 this.title = title;
20 }
21 public String getDescription() {
22 return description;
23 }
24 public void setDescription(String description) {
25 this.description = description;
26 }
27 public String getUrl() {
28 return url;
29 }
30 public void setUrl(String url) {
31 this.url = url;
32 }
33 public String getPicurl() {
34 return picurl;
35 }
36 public void setPicurl(String picurl) {
37 this.picurl = picurl;
38 }
39 }

News.java

 1 import java.util.List;
2
3 /**
4 * 图文
5 * @author hh
6 *
7 */
8 public class News {
9 //文章列表
10 private List<Article> articles;
11
12 public List<Article> getArticles() {
13 return articles;
14 }
15
16 public void setArticles(List<Article> articles) {
17 this.articles = articles;
18 }
19 }

NewsMessage.java

 1 /**
2 * 图文消息
3 * @author hh
4 *
5 */
6 public class NewsMessage extends BaseMessage {
7 //图文
8 private News news;
9
10 public News getNews() {
11 return news;
12 }
13
14 public void setNews(News news) {
15 this.news = news;
16 }
17 }

2.发送消息业务类——SendMessageService

 1 package com.ray.service;
2
3 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory;
5
6 import net.sf.json.JSONObject;
7
8 import com.google.gson.Gson;
9 import com.ray.pojo.message.send.BaseMessage;
10
11 import com.ray.test.UserTest;
12 import com.ray.util.WeiXinUtil;
13
14 /**@desc : 发送消息
15 *
16 * @author: shirayner
17 * @date : 2017-8-18 上午10:06:23
18 */
19 public class SendMessageService {
20 private static Logger log = LoggerFactory.getLogger(UserTest.class);
21
22 private static String sendMessage_url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";
23
24 /**
25 * @desc :0.公共方法:发送消息
26 *
27 * @param accessToken
28 * @param message void
29 */
30 public void sendMessage(String accessToken,BaseMessage message){
31
32 //1.获取json字符串:将message对象转换为json字符串
33 Gson gson = new Gson();
34 String jsonMessage =gson.toJson(message); //使用gson.toJson(user)即可将user对象顺序转成json
35 System.out.println("jsonTextMessage:"+jsonMessage);
36
37
38 //2.获取请求的url
39 sendMessage_url=sendMessage_url.replace("ACCESS_TOKEN", accessToken);
40
41 //3.调用接口,发送消息
42 JSONObject jsonObject = WeiXinUtil.httpRequest(sendMessage_url, "POST", jsonMessage);
43 System.out.println("jsonObject:"+jsonObject.toString());
44
45 //4.错误消息处理
46 if (null != jsonObject) {
47 if (0 != jsonObject.getInt("errcode")) {
48 log.error("创建成员失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
49 }
50 }
51 }
52 }

3.工具类

MyX509TrustManager.java

 1 import java.security.cert.CertificateException;
2 import java.security.cert.X509Certificate;
3
4 import javax.net.ssl.X509TrustManager;
5
6 /**
7 * 证书信任管理器(用于https请求)
8 *
9 * @author hh
10 * @date 2016-08-08
11 */
12 public class MyX509TrustManager implements X509TrustManager {
13
14 public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
15 }
16
17 public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
18 }
19
20 public X509Certificate[] getAcceptedIssuers() {
21 return null;
22 }
23 }

AccessToken.java

 1 public class AccessToken {
2 // 获取到的凭证
3 private String token;
4 // 凭证有效时间,单位:秒
5 private int expiresIn;
6
7 public String getToken() {
8 return token;
9 }
10
11 public void setToken(String token) {
12 this.token = token;
13 }
14
15 public int getExpiresIn() {
16 return expiresIn;
17 }
18
19 public void setExpiresIn(int expiresIn) {
20 this.expiresIn = expiresIn;
21 }
22 }

WeiXinUtil.java

  1 import java.io.BufferedReader;
2 import java.io.DataInputStream;
3 import java.io.DataOutputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.InputStreamReader;
10 import java.io.OutputStream;
11 import java.io.UnsupportedEncodingException;
12 import java.net.ConnectException;
13 import java.net.HttpURLConnection;
14 import java.net.URL;
15 import java.security.MessageDigest;
16 import java.security.NoSuchAlgorithmException;
17 import java.util.Formatter;
18 import java.util.HashMap;
19 import java.util.Map;
20 import java.util.UUID;
21
22 import javax.net.ssl.HttpsURLConnection;
23 import javax.net.ssl.SSLContext;
24 import javax.net.ssl.SSLSocketFactory;
25 import javax.net.ssl.TrustManager;
26 import javax.servlet.http.HttpServletRequest;
27
28 import net.sf.json.JSONException;
29 import net.sf.json.JSONObject;
30
31 public class WeiXinUtil {
32 //rivate static Logger log = LoggerFactory.getLogger(WeiXinUtil.class);
33 //微信的请求url
34 //获取access_token的接口地址(GET) 限200(次/天)
35 public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";
36 //获取jsapi_ticket的接口地址(GET) 限200(次/天)
37 public final static String jsapi_ticket_url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESSTOKEN";
38
39
40
41 /**
42 * 1.发起https请求并获取结果
43 *
44 * @param requestUrl 请求地址
45 * @param requestMethod 请求方式(GET、POST)
46 * @param outputStr 提交的数据
47 * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
48 */
49 public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
50 JSONObject jsonObject = null;
51 StringBuffer buffer = new StringBuffer();
52 try {
53 // 创建SSLContext对象,并使用我们指定的信任管理器初始化
54 TrustManager[] tm = { new MyX509TrustManager() };
55 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
56 sslContext.init(null, tm, new java.security.SecureRandom());
57 // 从上述SSLContext对象中得到SSLSocketFactory对象
58 SSLSocketFactory ssf = sslContext.getSocketFactory();
59
60 URL url = new URL(requestUrl);
61 HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
62 httpUrlConn.setSSLSocketFactory(ssf);
63
64 httpUrlConn.setDoOutput(true);
65 httpUrlConn.setDoInput(true);
66 httpUrlConn.setUseCaches(false);
67 // 设置请求方式(GET/POST)
68 httpUrlConn.setRequestMethod(requestMethod);
69
70 if ("GET".equalsIgnoreCase(requestMethod))
71 httpUrlConn.connect();
72
73 // 当有数据需要提交时
74 if (null != outputStr) {
75 OutputStream outputStream = httpUrlConn.getOutputStream();
76 // 注意编码格式,防止中文乱码
77 outputStream.write(outputStr.getBytes("UTF-8"));
78 outputStream.close();
79 }
80
81 // 将返回的输入流转换成字符串
82 InputStream inputStream = httpUrlConn.getInputStream();
83 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
84 BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
85
86 String str = null;
87 while ((str = bufferedReader.readLine()) != null) {
88 buffer.append(str);
89 }
90 bufferedReader.close();
91 inputStreamReader.close();
92 // 释放资源
93 inputStream.close();
94 inputStream = null;
95 httpUrlConn.disconnect();
96 jsonObject = JSONObject.fromObject(buffer.toString());
97 } catch (ConnectException ce) {
98 ce.printStackTrace();
99 } catch (Exception e) {
100 e.printStackTrace();
101 }
102 return jsonObject;
103 }
104
105 /**
106 * 2.发送https请求之获取临时素材
107 * @param requestUrl
108 * @param savePath 文件的保存路径,此时还缺一个扩展名
109 * @return
110 * @throws Exception
111 */
112 /*public static File getFile(String requestUrl,String savePath) throws Exception {
113 //String path=System.getProperty("user.dir")+"/img//1.png";
114
115
116 // 创建SSLContext对象,并使用我们指定的信任管理器初始化
117 TrustManager[] tm = { new MyX509TrustManager() };
118 SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
119 sslContext.init(null, tm, new java.security.SecureRandom());
120 // 从上述SSLContext对象中得到SSLSocketFactory对象
121 SSLSocketFactory ssf = sslContext.getSocketFactory();
122
123 URL url = new URL(requestUrl);
124 HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
125 httpUrlConn.setSSLSocketFactory(ssf);
126
127 httpUrlConn.setDoOutput(true);
128 httpUrlConn.setDoInput(true);
129 httpUrlConn.setUseCaches(false);
130 // 设置请求方式(GET/POST)
131 httpUrlConn.setRequestMethod("GET");
132
133 httpUrlConn.connect();
134
135 //获取文件扩展名
136 String ext=getExt(httpUrlConn.getContentType());
137 savePath=savePath+ext;
138 System.out.println("savePath"+savePath);
139 //下载文件到f文件
140 File file = new File(savePath);
141
142
143 // 获取微信返回的输入流
144 InputStream in = httpUrlConn.getInputStream();
145
146 //输出流,将微信返回的输入流内容写到文件中
147 FileOutputStream out = new FileOutputStream(file);
148
149 int length=100*1024;
150 byte[] byteBuffer = new byte[length]; //存储文件内容
151
152 int byteread =0;
153 int bytesum=0;
154
155 while (( byteread=in.read(byteBuffer)) != -1) {
156 bytesum += byteread; //字节数 文件大小
157 out.write(byteBuffer,0,byteread);
158
159 }
160 System.out.println("bytesum: "+bytesum);
161
162 in.close();
163 // 释放资源
164 out.close();
165 in = null;
166 out=null;
167
168 httpUrlConn.disconnect();
169
170
171 return file;
172 } */
173
174
175
176 /**
177 * @desc :2.微信上传素材的请求方法
178 *
179 * @param requestUrl 微信上传临时素材的接口url
180 * @param file 要上传的文件
181 * @return String 上传成功后,微信服务器返回的消息
182 */
183 public static String httpRequest(String requestUrl, File file) {
184 StringBuffer buffer = new StringBuffer();
185
186 try{
187 //1.建立连接
188 URL url = new URL(requestUrl);
189 HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection(); //打开链接
190
191 //1.1输入输出设置
192 httpUrlConn.setDoInput(true);
193 httpUrlConn.setDoOutput(true);
194 httpUrlConn.setUseCaches(false); // post方式不能使用缓存
195 //1.2设置请求头信息
196 httpUrlConn.setRequestProperty("Connection", "Keep-Alive");
197 httpUrlConn.setRequestProperty("Charset", "UTF-8");
198 //1.3设置边界
199 String BOUNDARY = "----------" + System.currentTimeMillis();
200 httpUrlConn.setRequestProperty("Content-Type","multipart/form-data; boundary="+ BOUNDARY);
201
202 // 请求正文信息
203 // 第一部分:
204 //2.将文件头输出到微信服务器
205 StringBuilder sb = new StringBuilder();
206 sb.append("--"); // 必须多两道线
207 sb.append(BOUNDARY);
208 sb.append("\r\n");
209 sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + file.length()
210 + "\";filename=\""+ file.getName() + "\"\r\n");
211 sb.append("Content-Type:application/octet-stream\r\n\r\n");
212 byte[] head = sb.toString().getBytes("utf-8");
213 // 获得输出流
214 OutputStream outputStream = new DataOutputStream(httpUrlConn.getOutputStream());
215 // 将表头写入输出流中:输出表头
216 outputStream.write(head);
217
218 //3.将文件正文部分输出到微信服务器
219 // 把文件以流文件的方式 写入到微信服务器中
220 DataInputStream in = new DataInputStream(new FileInputStream(file));
221 int bytes = 0;
222 byte[] bufferOut = new byte[1024];
223 while ((bytes = in.read(bufferOut)) != -1) {
224 outputStream.write(bufferOut, 0, bytes);
225 }
226 in.close();
227 //4.将结尾部分输出到微信服务器
228 byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
229 outputStream.write(foot);
230 outputStream.flush();
231 outputStream.close();
232
233
234 //5.将微信服务器返回的输入流转换成字符串
235 InputStream inputStream = httpUrlConn.getInputStream();
236 InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
237 BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
238
239 String str = null;
240 while ((str = bufferedReader.readLine()) != null) {
241 buffer.append(str);
242 }
243
244 bufferedReader.close();
245 inputStreamReader.close();
246 // 释放资源
247 inputStream.close();
248 inputStream = null;
249 httpUrlConn.disconnect();
250
251
252 } catch (IOException e) {
253 System.out.println("发送POST请求出现异常!" + e);
254 e.printStackTrace();
255 }
256 return buffer.toString();
257 }
258
259 /**
260 * 2.发起http请求获取返回结果
261 *
262 * @param requestUrl 请求地址
263 * @return
264 */
265 public static String httpRequest(String requestUrl) {
266 StringBuffer buffer = new StringBuffer();
267 try {
268 URL url = new URL(requestUrl);
269 HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
270
271 httpUrlConn.setDoOutput(false);
272 httpUrlConn.setDoInput(true);
273 httpUrlConn.setUseCaches(false);
274
275 httpUrlConn.setRequestMethod("GET");
276 httpUrlConn.connect();
277
278 // 将返回的输入流转换成字符串
279 InputStream inputStream = httpUrlConn.getInputStream();
280 //InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
281 InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
282 BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
283
284 String str = null;
285 while ((str = bufferedReader.readLine()) != null) {
286 buffer.append(str);
287
288 }
289 bufferedReader.close();
290 inputStreamReader.close();
291 // 释放资源
292 inputStream.close();
293 inputStream = null;
294 httpUrlConn.disconnect();
295
296 } catch (Exception e) {
297 }
298 return buffer.toString();
299 }
300
301
302 /**
303 * 3.获取access_token
304 *
305 * @param appid 凭证
306 * @param appsecret 密钥
307 * @return
308 */
309 public static AccessToken getAccessToken(String appid, String appsecret) {
310 AccessToken accessToken = null;
311
312 String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);
313 JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
314 // 如果请求成功
315 if (null != jsonObject) {
316 try {
317 accessToken = new AccessToken();
318 accessToken.setToken(jsonObject.getString("access_token"));
319 accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
320 } catch (JSONException e) {
321 accessToken = null;
322 // 获取token失败
323 System.out.println("获取token失败 errcode:{} errmsg:{}"+jsonObject.getInt("errcode")+":"+ jsonObject.getString("errmsg"));
324 }
325 }
326 return accessToken;
327 }
328
329 /**
330 * 4. 获取JsapiTicket
331 * @param accessToken
332 * @return
333 */
334 public static String getJsapiTicket(String accessToken){
335
336
337 String requestUrl = jsapi_ticket_url.replace("ACCESSTOKEN", accessToken);
338 JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
339
340 String jsapi_ticket="";
341 // 如果请求成功
342 if (null != jsonObject) {
343 try {
344 jsapi_ticket=jsonObject.getString("ticket");
345
346 } catch (JSONException e) {
347 e.printStackTrace();
348 // 获取token失败
349 // log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
350 }
351 }
352 return jsapi_ticket;
353 }
354
355 /**
356 * 3.获取企业微信的JSSDK配置信息
357 * @param request
358 * @return
359 */
360 /* public static Map<String, Object> getWxConfig(HttpServletRequest request) {
361 Map<String, Object> ret = new HashMap<String, Object>();
362 //1.准备好参与签名的字段
363
364 String nonceStr = UUID.randomUUID().toString(); // 必填,生成签名的随机串
365 //System.out.println("nonceStr:"+nonceStr);
366 String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
367 String jsapi_ticket =getJsapiTicket(accessToken);// 必填,生成签名的H5应用调用企业微信JS接口的临时票据
368 //System.out.println("jsapi_ticket:"+jsapi_ticket);
369 String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳
370 //System.out.println("timestamp:"+timestamp);
371 String url=request.getRequestURL().toString();
372 //System.out.println("url:"+url);
373
374 //2.字典序 ,注意这里参数名必须全部小写,且必须有序
375 String sign = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonceStr+ "&timestamp=" + timestamp + "&url=" + url;
376
377 //3.sha1签名
378 String signature = "";
379 try {
380 MessageDigest crypt = MessageDigest.getInstance("SHA-1");
381 crypt.reset();
382 crypt.update(sign.getBytes("UTF-8"));
383 signature = byteToHex(crypt.digest());
384 //System.out.println("signature:"+signature);
385 } catch (NoSuchAlgorithmException e) {
386 e.printStackTrace();
387 } catch (UnsupportedEncodingException e) {
388 e.printStackTrace();
389 }
390 ret.put("appId", WeiXinParamesUtil.corpId);
391 ret.put("timestamp", timestamp);
392 ret.put("nonceStr", nonceStr);
393 ret.put("signature", signature);
394 return ret;
395 }*/
396
397
398 /**
399 * 方法名:byteToHex</br>
400 * 详述:字符串加密辅助方法 </br>
401 * 开发人员:souvc </br>
402 * 创建时间:2016-1-5 </br>
403 * @param hash
404 * @return 说明返回值含义
405 * @throws 说明发生此异常的条件
406 */
407 private static String byteToHex(final byte[] hash) {
408 Formatter formatter = new Formatter();
409 for (byte b : hash) {
410 formatter.format("%02x", b);
411 }
412 String result = formatter.toString();
413 formatter.close();
414 return result;
415
416 }
417
418
419
420 private static String getExt(String contentType){
421 if("image/jpeg".equals(contentType)){
422 return ".jpg";
423 }else if("image/png".equals(contentType)){
424 return ".png";
425 }else if("image/gif".equals(contentType)){
426 return ".gif";
427 }
428
429 return null;
430 }
431 }

WeiXinParamesUtil.java

public class WeiXinParamesUtil {
//1.微信参数
//token
public final static String token = "ray";
// encodingAESKey
public final static String encodingAESKey = "z2W9lyOAR1XjY8mopEmiSqib0TlBZzCFiCLp6IdS2Iv";
//企业ID
public final static String corpId = "xxxxxx"; //应用的凭证密钥
public final static String agentSecret = "xxxxx";
//通讯录秘钥
public final static String contactsSecret = "1m_9XP62YrXjSxxxxxiLVWBThukiK5sH7wm1TM";
//打卡的凭证密钥
public final static String checkInSecret = "LLTMcHo5oxxxxxU0F6wX_gRIc";
//审批的凭证密钥
public final static String approveSecret = "6X7Ft0hIZXYxxxxxefWZE0-8"; //企业应用的id,整型。可在应用的设置页面查看
public final static int agentId = 1000014;
}

4.发送消息测试类——SendMessageTest

  1 import java.util.ArrayList;
2 import java.util.List;
3
4 import org.junit.Test;
5
6 import com.ray.pojo.message.send.Article;
7 import com.ray.pojo.message.send.FileMessage;
8 import com.ray.pojo.message.send.ImgMessage;
9 import com.ray.pojo.message.send.Media;
10 import com.ray.pojo.message.send.News;
11 import com.ray.pojo.message.send.NewsMessage;
12 import com.ray.pojo.message.send.Text;
13 import com.ray.pojo.message.send.TextMessage;
14 import com.ray.pojo.message.send.Textcard;
15 import com.ray.pojo.message.send.TextcardMessage;
16 import com.ray.pojo.message.send.Video;
17 import com.ray.pojo.message.send.VideoMessage;
18 import com.ray.pojo.message.send.VoiceMessage;
19 import com.ray.service.SendMessageService;
20 import com.ray.util.WeiXinParamesUtil;
21 import com.ray.util.WeiXinUtil;
22
23 /**@desc : 消息推送之发送消息
24 *
25 * @author: hh
26 * @date : 2017-8-18 上午10:04:55
27 */
28 public class SendMessageTest {
29
30 //1.发送文本消息
31 @Test
32 public void testSendTextMessage(){
33 //0.设置消息内容
34 String content="你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看" +
35 "<a href=\"http://work.weixin.qq.com\">邮件中心视频实况" +
36 "</a>,聪明避开排队。";
37
38 //1.创建文本消息对象
39 TextMessage message=new TextMessage();
40 //1.1非必需
41 message.setTouser("@all"); //不区分大小写
42 //textMessage.setToparty("1");
43 //txtMsg.setTotag(totag);
44 //txtMsg.setSafe(0);
45
46 //1.2必需
47 message.setMsgtype("text");
48 message.setAgentid(WeiXinParamesUtil.agentId);
49
50 Text text=new Text();
51 text.setContent(content);
52 message.setText(text);
53
54 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
55 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
56 System.out.println("accessToken:"+accessToken);
57
58 //3.发送消息:调用业务类,发送消息
59 SendMessageService sms=new SendMessageService();
60 sms.sendMessage(accessToken, message);
61
62 }
63
64 //2.发送文本卡片消息
65 @Test
66 public void testSendTextcardMessage(){
67 //0.设置消息内容
68 String title="代办事宜";
69 String description="<div class=\"gray\">2017年8月18日</div> <div class=\"normal\">" +
70 "恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">" +
71 "请于2017年10月10日前联系行政同事领取</div>";
72 String url="http://www.cnblogs.com/shirui/p/7297872.html";
73
74 //1.创建文本卡片消息对象
75 TextcardMessage message=new TextcardMessage();
76 //1.1非必需
77 message.setTouser("shirui"); //不区分大小写
78 //message.setToparty("1");
79 //message.setTotag(totag);
80 //message.setSafe(0);
81
82 //1.2必需
83 message.setMsgtype("textcard");
84 message.setAgentid(WeiXinParamesUtil.agentId);
85
86 Textcard textcard=new Textcard();
87 textcard.setTitle(title);
88 textcard.setDescription(description);
89 textcard.setUrl(url);
90 message.setTextcard(textcard);
91
92 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
93 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
94 System.out.println("accessToken:"+accessToken);
95
96 //3.发送消息:调用业务类,发送消息
97 SendMessageService sms=new SendMessageService();
98 sms.sendMessage(accessToken, message);
99
100 }
101
102 //3.发送图片消息---无效的media_id
103 @Test
104 public void testSendImgMessage(){
105 //0.设置消息内容
106 String media_;
107 //1.创建图片消息对象
108 ImgMessage message=new ImgMessage();
109 //1.1非必需
110 message.setTouser("@all"); //不区分大小写
111 //textMessage.setToparty("1");
112 //txtMsg.setTotag(totag);
113 //txtMsg.setSafe(0);
114
115 //1.2必需
116 message.setMsgtype("image");
117 message.setAgentid(WeiXinParamesUtil.agentId);
118
119 Media image=new Media();
120 image.setMedia_id(media_id);
121 message.setImage(image);
122
123 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
124 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
125 System.out.println("accessToken:"+accessToken);
126
127 //3.发送消息:调用业务类,发送消息
128 SendMessageService sms=new SendMessageService();
129 sms.sendMessage(accessToken, message);
130
131 }
132
133
134 //4.发送语音消息---无效的media_id
135 @Test
136 public void testSendVoiceMessage(){
137 //0.设置消息内容
138 String media_;
139 //1.创建语音消息对象
140 VoiceMessage message=new VoiceMessage();
141 //1.1非必需
142 message.setTouser("@all"); //不区分大小写
143 //textMessage.setToparty("1");
144 //txtMsg.setTotag(totag);
145 //txtMsg.setSafe(0);
146
147 //1.2必需
148 message.setMsgtype("image");
149 message.setAgentid(WeiXinParamesUtil.agentId);
150
151 Media voice=new Media();
152 voice.setMedia_id(media_id);
153 message.setVoice(voice);
154
155 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
156 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
157 System.out.println("accessToken:"+accessToken);
158
159 //3.发送消息:调用业务类,发送消息
160 SendMessageService sms=new SendMessageService();
161 sms.sendMessage(accessToken, message);
162
163 }
164
165 //5.发送视频消息
166 @Test
167 public void testSendVideoMessage(){
168 //0.设置消息内容
169 String media_;
170 String title="视频示例";
171 String description="好看的视频";
172
173
174 //1.创建视频消息对象
175 VideoMessage message=new VideoMessage();
176 //1.1非必需
177 message.setTouser("@all"); //不区分大小写
178 //message.setToparty("1");
179 //message.setTotag(totag);
180 //message.setSafe(0);
181
182 //1.2必需
183 message.setMsgtype("video");
184 message.setAgentid(WeiXinParamesUtil.agentId);
185
186 Video video=new Video();
187 video.setMedia_id(media_id);
188 video.setTitle(title);
189 video.setDescription(description);
190 message.setVideo(video);
191
192 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
193 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
194 System.out.println("accessToken:"+accessToken);
195
196 //3.发送消息:调用业务类,发送消息
197 SendMessageService sms=new SendMessageService();
198 sms.sendMessage(accessToken, message);
199
200 }
201
202 //6.发送文件消息
203 @Test
204 public void testSendFileMessage(){
205 //0.设置消息内容
206 String media_;
207
208 //1.创建文件对象
209 FileMessage message=new FileMessage();
210 //1.1非必需
211 message.setTouser("@all"); //不区分大小写
212 //textMessage.setToparty("1");
213 //txtMsg.setTotag(totag);
214 //txtMsg.setSafe(0);
215
216 //1.2必需
217 message.setMsgtype("file");
218 message.setAgentid(WeiXinParamesUtil.agentId);
219
220 Media file=new Media();
221 file.setMedia_id(media_id);
222 message.setFile(file);
223
224 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
225 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
226 System.out.println("accessToken:"+accessToken);
227
228 //3.发送消息:调用业务类,发送消息
229 SendMessageService sms=new SendMessageService();
230 sms.sendMessage(accessToken, message);
231
232 }
233
234 //7.发送图文消息
235 @Test
236 public void testSendNewsMessage(){
237
238 //1.创建图文消息对象
239 NewsMessage message=new NewsMessage();
240 //1.1非必需
241 message.setTouser("@all"); //不区分大小写
242 //textMessage.setToparty("1");
243 //txtMsg.setTotag(totag);
244 //txtMsg.setSafe(0);
245
246 //1.2必需
247 message.setMsgtype("news");
248 message.setAgentid(WeiXinParamesUtil.agentId);
249 //设置图文消息
250 Article article1=new Article();
251 article1.setTitle("青年文摘");
252 article1.setDescription("这是一个很特别的描述");
253 article1.setPicurl("http://mat1.gtimg.com/fashion/images/index/2017/08/18/tpzs2.jpg");
254 article1.setUrl("http://www.cnblogs.com/shirui/p/7297872.html");
255
256 List<Article> articles=new ArrayList<Article>();
257 articles.add(article1);
258
259 News news=new News();
260 news.setArticles(articles);
261 message.setNews(news);
262
263 //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
264 String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
265 System.out.println("accessToken:"+accessToken);
266
267 //3.发送消息:调用业务类,发送消息
268 SendMessageService sms=new SendMessageService();
269 sms.sendMessage(accessToken, message);
270
271 }
272 }