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 }
复制代码
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
/**
* 图片消息
* @author hh
*
*/
public class ImgMessage extends BaseMessage {
//图片
private Media image ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Media getImage() {
return image;
}
public void setImage(Media image) {
this.image = image;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.3.2 语音消息——VoiceMessage
/**
* 语音消息
* @author hh
*
*/
public class VoiceMessage extends BaseMessage {
//语音
private Media voice ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Media getVoice() {
return voice;
}
public void setVoice(Media voice) {
this.voice = voice;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.3.3 文件消息——FileMessage
/**
* 文件消息
* @author hh
*
*/
public class FileMessage extends BaseMessage {
//文件
private Media file ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Media getFile() {
return file;
}
public void setFile(Media file) {
this.file = file;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.4 视频消息——Video、VideoMessage
Video.java
/**
* 视频
* @author hh
*
*/
public class Video {
//是 视频媒体文件id,可以调用上传临时素材接口获取
private String media_id;
//否 视频消息的标题,不超过128个字节,超过会自动截断
private String title;
//否 视频消息的描述,不超过512个字节,超过会自动截断
private String description;
public String getMedia_id() {
return media_id;
}
public void setMedia_id(String media_id) {
this.media_id = media_id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
VideoMessage.java
/**
* 视频消息
* @author hh
*
*/
public class VideoMessage extends BaseMessage {
//视频
private Video video ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Video getVideo() {
return video;
}
public void setVideo(Video video) {
this.video = video;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.5 文本卡片消息——Textcard、TextcardMessage
/**
* 文本卡片
* @author hh
*
*/
public class Textcard {
//是 标题,不超过128个字节,超过会自动截断
private String title;
//是 描述,不超过512个字节,超过会自动截断
private String description;
//是 点击后跳转的链接。
private String url;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
TextcardMessage.java
/**
* 文本卡片消息
* @author hh
*
*/
public class TextcardMessage extends BaseMessage {
//文本
private Textcard textcard;
//btntxt 否 按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
public Textcard getTextcard() {
return textcard;
}
public void setTextcard(Textcard textcard) {
this.textcard = textcard;
}
}
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
/**
* 文章
* @author hh
*
*/
public class Article {
//是 标题,不超过128个字节,超过会自动截断
private String title;
//否 描述,不超过512个字节,超过会自动截断
private String description;
//是 点击后跳转的链接。
private String url;
//否 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640320,小图8080。
private String picurl;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPicurl() {
return picurl;
}
public void setPicurl(String picurl) {
this.picurl = picurl;
}
}
News.java
import java.util.List;
/**
* 图文
* @author hh
*
*/
public class News {
//文章列表
private List<Article> articles;
public List<Article> getArticles() {
return articles;
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
}
NewsMessage.java
/**
* 图文消息
* @author hh
*
*/
public class NewsMessage extends BaseMessage {
//图文
private News news;
public News getNews() {
return news;
}
public void setNews(News news) {
this.news = news;
}
}
2.发送消息业务类——SendMessageService
package com.ray.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.json.JSONObject;
import com.google.gson.Gson;
import com.ray.pojo.message.send.BaseMessage;
import com.ray.test.UserTest;
import com.ray.util.WeiXinUtil;
/**@desc : 发送消息
*
* @author: shirayner
* @date : 2017-8-18 上午10:06:23
*/
public class SendMessageService {
private static Logger log = LoggerFactory.getLogger(UserTest.class);
private static String sendMessage_url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";
/**
* @desc :0.公共方法:发送消息
*
* @param accessToken
* @param message void
*/
public void sendMessage(String accessToken,BaseMessage message){
//1.获取json字符串:将message对象转换为json字符串
Gson gson = new Gson();
String jsonMessage =gson.toJson(message); //使用gson.toJson(user)即可将user对象顺序转成json
System.out.println("jsonTextMessage:"+jsonMessage);
//2.获取请求的url
sendMessage_url=sendMessage_url.replace("ACCESS_TOKEN", accessToken);
//3.调用接口,发送消息
JSONObject jsonObject = WeiXinUtil.httpRequest(sendMessage_url, "POST", jsonMessage);
System.out.println("jsonObject:"+jsonObject.toString());
//4.错误消息处理
if (null != jsonObject) {
if (0 != jsonObject.getInt("errcode")) {
log.error("创建成员失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
}
}
3.工具类
MyX509TrustManager.java
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* 证书信任管理器(用于https请求)
*
* @author hh
* @date 2016-08-08
*/
public class MyX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
AccessToken.java
public class AccessToken {
// 获取到的凭证
private String token;
// 凭证有效时间,单位:秒
private int expiresIn;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}
WeiXinUtil.java
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
public class WeiXinUtil {
//rivate static Logger log = LoggerFactory.getLogger(WeiXinUtil.class);
//微信的请求url
//获取access_token的接口地址(GET) 限200(次/天)
public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";
//获取jsapi_ticket的接口地址(GET) 限200(次/天)
public final static String jsapi_ticket_url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESSTOKEN";
/**
* 1.发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
ce.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return jsonObject;
}
/**
* 2.发送https请求之获取临时素材
* @param requestUrl
* @param savePath 文件的保存路径,此时还缺一个扩展名
* @return
* @throws Exception
*/
/*public static File getFile(String requestUrl,String savePath) throws Exception {
//String path=System.getProperty("user.dir")+"/img//1.png";
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
//获取文件扩展名
String ext=getExt(httpUrlConn.getContentType());
savePath=savePath+ext;
System.out.println("savePath"+savePath);
//下载文件到f文件
File file = new File(savePath);
// 获取微信返回的输入流
InputStream in = httpUrlConn.getInputStream();
//输出流,将微信返回的输入流内容写到文件中
FileOutputStream out = new FileOutputStream(file);
int length=100*1024;
byte[] byteBuffer = new byte[length]; //存储文件内容
int byteread =0;
int bytesum=0;
while (( byteread=in.read(byteBuffer)) != -1) {
bytesum += byteread; //字节数 文件大小
out.write(byteBuffer,0,byteread);
}
System.out.println("bytesum: "+bytesum);
in.close();
// 释放资源
out.close();
in = null;
out=null;
httpUrlConn.disconnect();
return file;
} */
/**
* @desc :2.微信上传素材的请求方法
*
* @param requestUrl 微信上传临时素材的接口url
* @param file 要上传的文件
* @return String 上传成功后,微信服务器返回的消息
*/
public static String httpRequest(String requestUrl, File file) {
StringBuffer buffer = new StringBuffer();
try{
//1.建立连接
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection(); //打开链接
//1.1输入输出设置
httpUrlConn.setDoInput(true);
httpUrlConn.setDoOutput(true);
httpUrlConn.setUseCaches(false); // post方式不能使用缓存
//1.2设置请求头信息
httpUrlConn.setRequestProperty("Connection", "Keep-Alive");
httpUrlConn.setRequestProperty("Charset", "UTF-8");
//1.3设置边界
String BOUNDARY = "----------" + System.currentTimeMillis();
httpUrlConn.setRequestProperty("Content-Type","multipart/form-data; boundary="+ BOUNDARY);
// 请求正文信息
// 第一部分:
//2.将文件头输出到微信服务器
StringBuilder sb = new StringBuilder();
sb.append("--"); // 必须多两道线
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + file.length()
+ "\";filename=\""+ file.getName() + "\"\r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes("utf-8");
// 获得输出流
OutputStream outputStream = new DataOutputStream(httpUrlConn.getOutputStream());
// 将表头写入输出流中:输出表头
outputStream.write(head);
//3.将文件正文部分输出到微信服务器
// 把文件以流文件的方式 写入到微信服务器中
DataInputStream in = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
outputStream.write(bufferOut, 0, bytes);
}
in.close();
//4.将结尾部分输出到微信服务器
byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
outputStream.write(foot);
outputStream.flush();
outputStream.close();
//5.将微信服务器返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (IOException e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
return buffer.toString();
}
/**
* 2.发起http请求获取返回结果
*
* @param requestUrl 请求地址
* @return
*/
public static String httpRequest(String requestUrl) {
StringBuffer buffer = new StringBuffer();
try {
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoOutput(false);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
//InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (Exception e) {
}
return buffer.toString();
}
/**
* 3.获取access_token
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static AccessToken getAccessToken(String appid, String appsecret) {
AccessToken accessToken = null;
String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
// 如果请求成功
if (null != jsonObject) {
try {
accessToken = new AccessToken();
accessToken.setToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
} catch (JSONException e) {
accessToken = null;
// 获取token失败
System.out.println("获取token失败 errcode:{} errmsg:{}"+jsonObject.getInt("errcode")+":"+ jsonObject.getString("errmsg"));
}
}
return accessToken;
}
/**
* 4. 获取JsapiTicket
* @param accessToken
* @return
*/
public static String getJsapiTicket(String accessToken){
String requestUrl = jsapi_ticket_url.replace("ACCESSTOKEN", accessToken);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
String jsapi_ticket="";
// 如果请求成功
if (null != jsonObject) {
try {
jsapi_ticket=jsonObject.getString("ticket");
} catch (JSONException e) {
e.printStackTrace();
// 获取token失败
// log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return jsapi_ticket;
}
/**
* 3.获取企业微信的JSSDK配置信息
* @param request
* @return
*/
/* public static Map<String, Object> getWxConfig(HttpServletRequest request) {
Map<String, Object> ret = new HashMap<String, Object>();
//1.准备好参与签名的字段
String nonceStr = UUID.randomUUID().toString(); // 必填,生成签名的随机串
//System.out.println("nonceStr:"+nonceStr);
String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
String jsapi_ticket =getJsapiTicket(accessToken);// 必填,生成签名的H5应用调用企业微信JS接口的临时票据
//System.out.println("jsapi_ticket:"+jsapi_ticket);
String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳
//System.out.println("timestamp:"+timestamp);
String url=request.getRequestURL().toString();
//System.out.println("url:"+url);
//2.字典序 ,注意这里参数名必须全部小写,且必须有序
String sign = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonceStr+ "×tamp=" + timestamp + "&url=" + url;
//3.sha1签名
String signature = "";
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(sign.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
//System.out.println("signature:"+signature);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret.put("appId", WeiXinParamesUtil.corpId);
ret.put("timestamp", timestamp);
ret.put("nonceStr", nonceStr);
ret.put("signature", signature);
return ret;
}*/
/**
* 方法名:byteToHex</br>
* 详述:字符串加密辅助方法 </br>
* 开发人员:souvc </br>
* 创建时间:2016-1-5 </br>
* @param hash
* @return 说明返回值含义
* @throws 说明发生此异常的条件
*/
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String getExt(String contentType){
if("image/jpeg".equals(contentType)){
return ".jpg";
}else if("image/png".equals(contentType)){
return ".png";
}else if("image/gif".equals(contentType)){
return ".gif";
}
return null;
}
}
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
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.ray.pojo.message.send.Article;
import com.ray.pojo.message.send.FileMessage;
import com.ray.pojo.message.send.ImgMessage;
import com.ray.pojo.message.send.Media;
import com.ray.pojo.message.send.News;
import com.ray.pojo.message.send.NewsMessage;
import com.ray.pojo.message.send.Text;
import com.ray.pojo.message.send.TextMessage;
import com.ray.pojo.message.send.Textcard;
import com.ray.pojo.message.send.TextcardMessage;
import com.ray.pojo.message.send.Video;
import com.ray.pojo.message.send.VideoMessage;
import com.ray.pojo.message.send.VoiceMessage;
import com.ray.service.SendMessageService;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.WeiXinUtil;
/**@desc : 消息推送之发送消息
*
* @author: hh
* @date : 2017-8-18 上午10:04:55
*/
public class SendMessageTest {
//1.发送文本消息
@Test
public void testSendTextMessage(){
//0.设置消息内容
String content="你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看" +
"<a href=\"http://work.weixin.qq.com\">邮件中心视频实况" +
"</a>,聪明避开排队。";
//1.创建文本消息对象
TextMessage message=new TextMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("text");
message.setAgentid(WeiXinParamesUtil.agentId);
Text text=new Text();
text.setContent(content);
message.setText(text);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//2.发送文本卡片消息
@Test
public void testSendTextcardMessage(){
//0.设置消息内容
String title="代办事宜";
String description="<div class=\"gray\">2017年8月18日</div> <div class=\"normal\">" +
"恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">" +
"请于2017年10月10日前联系行政同事领取</div>";
String url="";
//1.创建文本卡片消息对象
TextcardMessage message=new TextcardMessage();
//1.1非必需
message.setTouser("shirui"); //不区分大小写
//message.setToparty("1");
//message.setTotag(totag);
//message.setSafe(0);
//1.2必需
message.setMsgtype("textcard");
message.setAgentid(WeiXinParamesUtil.agentId);
Textcard textcard=new Textcard();
textcard.setTitle(title);
textcard.setDescription(description);
textcard.setUrl(url);
message.setTextcard(textcard);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//3.发送图片消息---无效的media_id
@Test
public void testSendImgMessage(){
//0.设置消息内容
String media_;
//1.创建图片消息对象
ImgMessage message=new ImgMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("image");
message.setAgentid(WeiXinParamesUtil.agentId);
Media image=new Media();
image.setMedia_id(media_id);
message.setImage(image);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//4.发送语音消息---无效的media_id
@Test
public void testSendVoiceMessage(){
//0.设置消息内容
String media_;
//1.创建语音消息对象
VoiceMessage message=new VoiceMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("image");
message.setAgentid(WeiXinParamesUtil.agentId);
Media voice=new Media();
voice.setMedia_id(media_id);
message.setVoice(voice);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//5.发送视频消息
@Test
public void testSendVideoMessage(){
//0.设置消息内容
String media_;
String title="视频示例";
String description="好看的视频";
//1.创建视频消息对象
VideoMessage message=new VideoMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//message.setToparty("1");
//message.setTotag(totag);
//message.setSafe(0);
//1.2必需
message.setMsgtype("video");
message.setAgentid(WeiXinParamesUtil.agentId);
Video video=new Video();
video.setMedia_id(media_id);
video.setTitle(title);
video.setDescription(description);
message.setVideo(video);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//6.发送文件消息
@Test
public void testSendFileMessage(){
//0.设置消息内容
String media_;
//1.创建文件对象
FileMessage message=new FileMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("file");
message.setAgentid(WeiXinParamesUtil.agentId);
Media file=new Media();
file.setMedia_id(media_id);
message.setFile(file);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//7.发送图文消息
@Test
public void testSendNewsMessage(){
//1.创建图文消息对象
NewsMessage message=new NewsMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("news");
message.setAgentid(WeiXinParamesUtil.agentId);
//设置图文消息
Article article1=new Article();
article1.setTitle("青年文摘");
article1.setDescription("这是一个很特别的描述");
article1.setPicurl("http://mat1.gtimg.com/fashion/images/index/2017/08/18/tpzs2.jpg");
article1.setUrl("");
List<Article> articles=new ArrayList<Article>();
articles.add(article1);
News news=new News();
news.setArticles(articles);
message.setNews(news);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cn</groupId>
<artifactId>upload</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<!-- <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency> -->
<!--文件上传下载所用的包============ -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- jstl-api -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- jstl-impl -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>
<!-- 标签standard包 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- 数据库配置 -->
<!--mybatis mysql-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- jdbc驱动jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
<!-- 生成token需要的jar包 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
<!-- 企业微信-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
</dependencies>
</project>
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.发送消息与被动回复消息
(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
/**
* 图片消息
* @author hh
*
*/
public class ImgMessage extends BaseMessage {
//图片
private Media image ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Media getImage() {
return image;
}
public void setImage(Media image) {
this.image = image;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.3.2 语音消息——VoiceMessage
/**
* 语音消息
* @author hh
*
*/
public class VoiceMessage extends BaseMessage {
//语音
private Media voice ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Media getVoice() {
return voice;
}
public void setVoice(Media voice) {
this.voice = voice;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.3.3 文件消息——FileMessage
/**
* 文件消息
* @author hh
*
*/
public class FileMessage extends BaseMessage {
//文件
private Media file ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Media getFile() {
return file;
}
public void setFile(Media file) {
this.file = file;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.4 视频消息——Video、VideoMessage
Video.java
/**
* 视频
* @author hh
*
*/
public class Video {
//是 视频媒体文件id,可以调用上传临时素材接口获取
private String media_id;
//否 视频消息的标题,不超过128个字节,超过会自动截断
private String title;
//否 视频消息的描述,不超过512个字节,超过会自动截断
private String description;
public String getMedia_id() {
return media_id;
}
public void setMedia_id(String media_id) {
this.media_id = media_id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
VideoMessage.java
/**
* 视频消息
* @author hh
*
*/
public class VideoMessage extends BaseMessage {
//视频
private Video video ;
//否 表示是否是保密消息,0表示否,1表示是,默认0
private int safe;
public Video getVideo() {
return video;
}
public void setVideo(Video video) {
this.video = video;
}
public int getSafe() {
return safe;
}
public void setSafe(int safe) {
this.safe = safe;
}
}
1.5 文本卡片消息——Textcard、TextcardMessage
/**
* 文本卡片
* @author hh
*
*/
public class Textcard {
//是 标题,不超过128个字节,超过会自动截断
private String title;
//是 描述,不超过512个字节,超过会自动截断
private String description;
//是 点击后跳转的链接。
private String url;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
TextcardMessage.java
/**
* 文本卡片消息
* @author hh
*
*/
public class TextcardMessage extends BaseMessage {
//文本
private Textcard textcard;
//btntxt 否 按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
public Textcard getTextcard() {
return textcard;
}
public void setTextcard(Textcard textcard) {
this.textcard = textcard;
}
}
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
/**
* 文章
* @author hh
*
*/
public class Article {
//是 标题,不超过128个字节,超过会自动截断
private String title;
//否 描述,不超过512个字节,超过会自动截断
private String description;
//是 点击后跳转的链接。
private String url;
//否 图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640320,小图8080。
private String picurl;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPicurl() {
return picurl;
}
public void setPicurl(String picurl) {
this.picurl = picurl;
}
}
News.java
import java.util.List;
/**
* 图文
* @author hh
*
*/
public class News {
//文章列表
private List<Article> articles;
public List<Article> getArticles() {
return articles;
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
}
NewsMessage.java
/**
* 图文消息
* @author hh
*
*/
public class NewsMessage extends BaseMessage {
//图文
private News news;
public News getNews() {
return news;
}
public void setNews(News news) {
this.news = news;
}
}
2.发送消息业务类——SendMessageService
package com.ray.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.json.JSONObject;
import com.google.gson.Gson;
import com.ray.pojo.message.send.BaseMessage;
import com.ray.test.UserTest;
import com.ray.util.WeiXinUtil;
/**@desc : 发送消息
*
* @author: shirayner
* @date : 2017-8-18 上午10:06:23
*/
public class SendMessageService {
private static Logger log = LoggerFactory.getLogger(UserTest.class);
private static String sendMessage_url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";
/**
* @desc :0.公共方法:发送消息
*
* @param accessToken
* @param message void
*/
public void sendMessage(String accessToken,BaseMessage message){
//1.获取json字符串:将message对象转换为json字符串
Gson gson = new Gson();
String jsonMessage =gson.toJson(message); //使用gson.toJson(user)即可将user对象顺序转成json
System.out.println("jsonTextMessage:"+jsonMessage);
//2.获取请求的url
sendMessage_url=sendMessage_url.replace("ACCESS_TOKEN", accessToken);
//3.调用接口,发送消息
JSONObject jsonObject = WeiXinUtil.httpRequest(sendMessage_url, "POST", jsonMessage);
System.out.println("jsonObject:"+jsonObject.toString());
//4.错误消息处理
if (null != jsonObject) {
if (0 != jsonObject.getInt("errcode")) {
log.error("创建成员失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
}
}
3.工具类
MyX509TrustManager.java
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* 证书信任管理器(用于https请求)
*
* @author hh
* @date 2016-08-08
*/
public class MyX509TrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
AccessToken.java
public class AccessToken {
// 获取到的凭证
private String token;
// 凭证有效时间,单位:秒
private int expiresIn;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}
WeiXinUtil.java
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
public class WeiXinUtil {
//rivate static Logger log = LoggerFactory.getLogger(WeiXinUtil.class);
//微信的请求url
//获取access_token的接口地址(GET) 限200(次/天)
public final static String access_token_url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={corpsecret}";
//获取jsapi_ticket的接口地址(GET) 限200(次/天)
public final static String jsapi_ticket_url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=ACCESSTOKEN";
/**
* 1.发起https请求并获取结果
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
ce.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return jsonObject;
}
/**
* 2.发送https请求之获取临时素材
* @param requestUrl
* @param savePath 文件的保存路径,此时还缺一个扩展名
* @return
* @throws Exception
*/
/*public static File getFile(String requestUrl,String savePath) throws Exception {
//String path=System.getProperty("user.dir")+"/img//1.png";
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
//获取文件扩展名
String ext=getExt(httpUrlConn.getContentType());
savePath=savePath+ext;
System.out.println("savePath"+savePath);
//下载文件到f文件
File file = new File(savePath);
// 获取微信返回的输入流
InputStream in = httpUrlConn.getInputStream();
//输出流,将微信返回的输入流内容写到文件中
FileOutputStream out = new FileOutputStream(file);
int length=100*1024;
byte[] byteBuffer = new byte[length]; //存储文件内容
int byteread =0;
int bytesum=0;
while (( byteread=in.read(byteBuffer)) != -1) {
bytesum += byteread; //字节数 文件大小
out.write(byteBuffer,0,byteread);
}
System.out.println("bytesum: "+bytesum);
in.close();
// 释放资源
out.close();
in = null;
out=null;
httpUrlConn.disconnect();
return file;
} */
/**
* @desc :2.微信上传素材的请求方法
*
* @param requestUrl 微信上传临时素材的接口url
* @param file 要上传的文件
* @return String 上传成功后,微信服务器返回的消息
*/
public static String httpRequest(String requestUrl, File file) {
StringBuffer buffer = new StringBuffer();
try{
//1.建立连接
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection(); //打开链接
//1.1输入输出设置
httpUrlConn.setDoInput(true);
httpUrlConn.setDoOutput(true);
httpUrlConn.setUseCaches(false); // post方式不能使用缓存
//1.2设置请求头信息
httpUrlConn.setRequestProperty("Connection", "Keep-Alive");
httpUrlConn.setRequestProperty("Charset", "UTF-8");
//1.3设置边界
String BOUNDARY = "----------" + System.currentTimeMillis();
httpUrlConn.setRequestProperty("Content-Type","multipart/form-data; boundary="+ BOUNDARY);
// 请求正文信息
// 第一部分:
//2.将文件头输出到微信服务器
StringBuilder sb = new StringBuilder();
sb.append("--"); // 必须多两道线
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data;name=\"media\";filelength=\"" + file.length()
+ "\";filename=\""+ file.getName() + "\"\r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes("utf-8");
// 获得输出流
OutputStream outputStream = new DataOutputStream(httpUrlConn.getOutputStream());
// 将表头写入输出流中:输出表头
outputStream.write(head);
//3.将文件正文部分输出到微信服务器
// 把文件以流文件的方式 写入到微信服务器中
DataInputStream in = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
outputStream.write(bufferOut, 0, bytes);
}
in.close();
//4.将结尾部分输出到微信服务器
byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
outputStream.write(foot);
outputStream.flush();
outputStream.close();
//5.将微信服务器返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (IOException e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
return buffer.toString();
}
/**
* 2.发起http请求获取返回结果
*
* @param requestUrl 请求地址
* @return
*/
public static String httpRequest(String requestUrl) {
StringBuffer buffer = new StringBuffer();
try {
URL url = new URL(requestUrl);
HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
httpUrlConn.setDoOutput(false);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
httpUrlConn.setRequestMethod("GET");
httpUrlConn.connect();
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
//InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
} catch (Exception e) {
}
return buffer.toString();
}
/**
* 3.获取access_token
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static AccessToken getAccessToken(String appid, String appsecret) {
AccessToken accessToken = null;
String requestUrl = access_token_url.replace("{corpId}", appid).replace("{corpsecret}", appsecret);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
// 如果请求成功
if (null != jsonObject) {
try {
accessToken = new AccessToken();
accessToken.setToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInt("expires_in"));
} catch (JSONException e) {
accessToken = null;
// 获取token失败
System.out.println("获取token失败 errcode:{} errmsg:{}"+jsonObject.getInt("errcode")+":"+ jsonObject.getString("errmsg"));
}
}
return accessToken;
}
/**
* 4. 获取JsapiTicket
* @param accessToken
* @return
*/
public static String getJsapiTicket(String accessToken){
String requestUrl = jsapi_ticket_url.replace("ACCESSTOKEN", accessToken);
JSONObject jsonObject = httpRequest(requestUrl, "GET", null);
String jsapi_ticket="";
// 如果请求成功
if (null != jsonObject) {
try {
jsapi_ticket=jsonObject.getString("ticket");
} catch (JSONException e) {
e.printStackTrace();
// 获取token失败
// log.error("获取token失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));
}
}
return jsapi_ticket;
}
/**
* 3.获取企业微信的JSSDK配置信息
* @param request
* @return
*/
/* public static Map<String, Object> getWxConfig(HttpServletRequest request) {
Map<String, Object> ret = new HashMap<String, Object>();
//1.准备好参与签名的字段
String nonceStr = UUID.randomUUID().toString(); // 必填,生成签名的随机串
//System.out.println("nonceStr:"+nonceStr);
String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
String jsapi_ticket =getJsapiTicket(accessToken);// 必填,生成签名的H5应用调用企业微信JS接口的临时票据
//System.out.println("jsapi_ticket:"+jsapi_ticket);
String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳
//System.out.println("timestamp:"+timestamp);
String url=request.getRequestURL().toString();
//System.out.println("url:"+url);
//2.字典序 ,注意这里参数名必须全部小写,且必须有序
String sign = "jsapi_ticket=" + jsapi_ticket + "&noncestr=" + nonceStr+ "×tamp=" + timestamp + "&url=" + url;
//3.sha1签名
String signature = "";
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(sign.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
//System.out.println("signature:"+signature);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ret.put("appId", WeiXinParamesUtil.corpId);
ret.put("timestamp", timestamp);
ret.put("nonceStr", nonceStr);
ret.put("signature", signature);
return ret;
}*/
/**
* 方法名:byteToHex</br>
* 详述:字符串加密辅助方法 </br>
* 开发人员:souvc </br>
* 创建时间:2016-1-5 </br>
* @param hash
* @return 说明返回值含义
* @throws 说明发生此异常的条件
*/
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash) {
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
private static String getExt(String contentType){
if("image/jpeg".equals(contentType)){
return ".jpg";
}else if("image/png".equals(contentType)){
return ".png";
}else if("image/gif".equals(contentType)){
return ".gif";
}
return null;
}
}
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
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.ray.pojo.message.send.Article;
import com.ray.pojo.message.send.FileMessage;
import com.ray.pojo.message.send.ImgMessage;
import com.ray.pojo.message.send.Media;
import com.ray.pojo.message.send.News;
import com.ray.pojo.message.send.NewsMessage;
import com.ray.pojo.message.send.Text;
import com.ray.pojo.message.send.TextMessage;
import com.ray.pojo.message.send.Textcard;
import com.ray.pojo.message.send.TextcardMessage;
import com.ray.pojo.message.send.Video;
import com.ray.pojo.message.send.VideoMessage;
import com.ray.pojo.message.send.VoiceMessage;
import com.ray.service.SendMessageService;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.WeiXinUtil;
/**@desc : 消息推送之发送消息
*
* @author: hh
* @date : 2017-8-18 上午10:04:55
*/
public class SendMessageTest {
//1.发送文本消息
@Test
public void testSendTextMessage(){
//0.设置消息内容
String content="你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看" +
"<a href=\"http://work.weixin.qq.com\">邮件中心视频实况" +
"</a>,聪明避开排队。";
//1.创建文本消息对象
TextMessage message=new TextMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("text");
message.setAgentid(WeiXinParamesUtil.agentId);
Text text=new Text();
text.setContent(content);
message.setText(text);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//2.发送文本卡片消息
@Test
public void testSendTextcardMessage(){
//0.设置消息内容
String title="代办事宜";
String description="<div class=\"gray\">2017年8月18日</div> <div class=\"normal\">" +
"恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">" +
"请于2017年10月10日前联系行政同事领取</div>";
String url="";
//1.创建文本卡片消息对象
TextcardMessage message=new TextcardMessage();
//1.1非必需
message.setTouser("shirui"); //不区分大小写
//message.setToparty("1");
//message.setTotag(totag);
//message.setSafe(0);
//1.2必需
message.setMsgtype("textcard");
message.setAgentid(WeiXinParamesUtil.agentId);
Textcard textcard=new Textcard();
textcard.setTitle(title);
textcard.setDescription(description);
textcard.setUrl(url);
message.setTextcard(textcard);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//3.发送图片消息---无效的media_id
@Test
public void testSendImgMessage(){
//0.设置消息内容
String media_;
//1.创建图片消息对象
ImgMessage message=new ImgMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("image");
message.setAgentid(WeiXinParamesUtil.agentId);
Media image=new Media();
image.setMedia_id(media_id);
message.setImage(image);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//4.发送语音消息---无效的media_id
@Test
public void testSendVoiceMessage(){
//0.设置消息内容
String media_;
//1.创建语音消息对象
VoiceMessage message=new VoiceMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("image");
message.setAgentid(WeiXinParamesUtil.agentId);
Media voice=new Media();
voice.setMedia_id(media_id);
message.setVoice(voice);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//5.发送视频消息
@Test
public void testSendVideoMessage(){
//0.设置消息内容
String media_;
String title="视频示例";
String description="好看的视频";
//1.创建视频消息对象
VideoMessage message=new VideoMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//message.setToparty("1");
//message.setTotag(totag);
//message.setSafe(0);
//1.2必需
message.setMsgtype("video");
message.setAgentid(WeiXinParamesUtil.agentId);
Video video=new Video();
video.setMedia_id(media_id);
video.setTitle(title);
video.setDescription(description);
message.setVideo(video);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//6.发送文件消息
@Test
public void testSendFileMessage(){
//0.设置消息内容
String media_;
//1.创建文件对象
FileMessage message=new FileMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("file");
message.setAgentid(WeiXinParamesUtil.agentId);
Media file=new Media();
file.setMedia_id(media_id);
message.setFile(file);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
//7.发送图文消息
@Test
public void testSendNewsMessage(){
//1.创建图文消息对象
NewsMessage message=new NewsMessage();
//1.1非必需
message.setTouser("@all"); //不区分大小写
//textMessage.setToparty("1");
//txtMsg.setTotag(totag);
//txtMsg.setSafe(0);
//1.2必需
message.setMsgtype("news");
message.setAgentid(WeiXinParamesUtil.agentId);
//设置图文消息
Article article1=new Article();
article1.setTitle("青年文摘");
article1.setDescription("这是一个很特别的描述");
article1.setPicurl("http://mat1.gtimg.com/fashion/images/index/2017/08/18/tpzs2.jpg");
article1.setUrl("");
List<Article> articles=new ArrayList<Article>();
articles.add(article1);
News news=new News();
news.setArticles(articles);
message.setNews(news);
//2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
System.out.println("accessToken:"+accessToken);
//3.发送消息:调用业务类,发送消息
SendMessageService sms=new SendMessageService();
sms.sendMessage(accessToken, message);
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cn</groupId>
<artifactId>upload</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.0.6.RELEASE</version>
</dependency>
<!-- <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>
</dependency> -->
<!--文件上传下载所用的包============ -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- jstl-api -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- jstl-impl -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>
<!-- 标签standard包 -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- 数据库配置 -->
<!--mybatis mysql-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- jdbc驱动jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.1.1.RELEASE</version>
</dependency>
<!-- 生成token需要的jar包 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>
<!-- 企业微信-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
</dependencies>
</project>
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 }