Java发送企业微信应用消息

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 }
View Code

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 }
View Code

可把整个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 }
View Code

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 }
View Code

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 }
View Code

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 }  
View Code

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 }
View Code

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 }  
View Code

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 }
View Code

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 }  
View Code

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 }
View Code

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 }  
View Code

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 }
View Code

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 }
View Code

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 } 
View Code

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 }
View Code

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 }


原文地址:https://www.cnblogs.com/snail90/p/10045414.html