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出发前可查看邮件中心视频实况,聪明避开排队。" 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
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 Listarticles; 11 12 public List getArticles() { 13 return articles; 14 } 15 16 public void setArticles(List 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 MapgetWxConfig(HttpServletRequest request) { 361 Mapret = new HashMap 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+ "×tamp=" + 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 400 * 详述:字符串加密辅助方法 401 * 开发人员:souvc 402 * 创建时间:2016-1-5 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 "邮件中心视频实况" + 36 ",聪明避开排队。"; 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="2017年8月18日" + 70 "恭喜你抽中iPhone 7一台,领奖码:xxxx" + 71 "请于2017年10月10日前联系行政同事领取"; 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 Listarticles=new ArrayList (); 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 }