最近需要定时提示同事分享文章等,因此做了一个企业微信机器人定时发送消息。
官网指导文档:
群机器人配置说明
发送应用消息
1.根据文档里的JSON格式,我们先定义要用到的消息实体对象和枚举类。
(1) Message
/**
* @description: 企业微信机器人消息实体类
* @author: DreamflyChen
* @create: 2020-08-30 13:03
*/
@Data
public class Message {
/**
* 消息类型
*/
private MessageTypeEnum msgtype;
/**
* 文本消息
*/
private JSONObject text;
/**
* 图片消息
*/
private JSONObject image;
/**
* 表示是否是保密消息,0表示否,1表示是,默认0
*/
private Integer safe;
}
(2) ImageMessage
/**
* @description: 图片类型消息
* @author: DreamflyChen
* @create: 2020-08-30 13:16
*/
@Data
public class ImageMessage {
/**
* 图片内容的base64编码
* 注:图片(base64编码前)最大不能超过2M,支持JPG,PNG格式
*/
private String base64;
/**
* 图片内容(base64编码前)的md5值
*/
private String md5;
}
(3) TextMessage
/**
* @description: 文本消息实体类
* @author: DreamflyChen
* @create: 2020-08-30 13:11
*/
@Data
public class TextMessage {
/**
* 文本内容,最长不超过2048个字节,必须是utf8编码(必填)
*/
private String content;
/**
* userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人,如果开发者获取不到userid,可以使用mentioned_mobile_list
* (非必填)
*/
private List<String> mentioned_list;
/**
* 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人
*/
private List<String> mentioned_mobile_list;
}
(4)MessageTypeEnum 消息类型枚举
/**
* 消息类型枚举
*
* @author DreamflyChen
* @create 2020-8-30 14:25:06
*/
@Getter
@Slf4j
public enum MessageTypeEnum {
unknown_type(-1, "未知类型"),
text(1, "文本类型"),
image(2, "图片类型");
private final int value;
private final String desc;
MessageTypeEnum(int value, String desc) {
this.value = value;
this.desc = desc;
}
/**
* 根据值返回枚举
*
* @param value
* @return
*/
public static MessageTypeEnum getEnumByValue(int value) {
for (MessageTypeEnum v : MessageTypeEnum.values()) {
if (v.getValue() == value) {
return v;
}
}
return unknown_type;
}
/**
* 根据编码获取描述信息
*
* @param value
* @return
*/
public static String getDescByValue(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
try {
int discount = Integer.parseInt(value.trim());
for (MessageTypeEnum v : MessageTypeEnum.values()) {
if (v.getValue() == discount) {
return v.getDesc();
}
}
return "未知类型: " + value;
} catch (Exception e) {
log.info("字符串格式转数字异常,str: {}", value);
return null;
}
}
}
2.封装处理器,主要是发送消息的方法,图片转Base64字符串(注意要去掉换行符,这一点官网文档没有说明),文件md5加密。
(1) ImageManager
/**
* @description: 图片处理
* @author: DreamflyChen
* @create: 2020-08-29 23:05
*/
@Slf4j
public class ImageManager {
/**
* @Description 图片转base64字符串
* @param imgUrl 图片路径(Resources目录下, 如/img/pic1.png)
* @return
*/
public static String imageToBase64Str(String imgUrl) {
InputStream inputStream;
byte[] data;
try {
inputStream = ImageManager.class.getResourceAsStream(imgUrl);
data = new byte[inputStream.available()];
inputStream.read(data);
inputStream.close();
} catch (IOException e) {
log.error("图片转base64字符串异常, 异常信息如下:{}", e.getMessage());
return null;
}
// 加密
BASE64Encoder encoder = new BASE64Encoder();
//去掉换行符
String result = encoder.encode(data).replaceAll("\r|\n", "");
return result;
}
/**
* @Description 生成文件的md5值
* @param fileUrl 文件路径(Resources目录下, 如/img/pic1.png)
* @return MD5值
*/
public static String getStringMd5(String fileUrl) throws Exception {
String value;
//toURI() 解决中文路径乱码问题
String path = ImageManager.class.getResource(fileUrl).toURI().getPath();
try (FileInputStream in = new FileInputStream(path)) {
MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, new File(path).length());
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(byteBuffer);
BigInteger bi = new BigInteger(1, md5.digest());
value = bi.toString(16);
}
return value;
}
}
(2) MessageManager
/**
* @description: 消息处理器
* @author: DreamflyChen
* @create: 2020-08-30 13:33
*/
@Slf4j
public class MessageManager {
public static boolean sendMessage(Message message, String webHookAddress) {
OkHttpClient client = new OkHttpClient.Builder()
// 设置连接超时时间
.connectTimeout(10, TimeUnit.SECONDS)
// 设置读取超时时间
.readTimeout(20, TimeUnit.SECONDS)
.build();
MediaType contentType = MediaType.parse("application/json; charset=utf-8");
RequestBody body = RequestBody.create(JSONObject.toJSONString(message), contentType);
Request request = new Request.Builder().url(webHookAddress).post(body).addHeader("cache-control", "no-cache").build();
try {
Response response = client.newCall(request).execute();
byte[] datas = response.body().bytes();
String respMsg = new String(datas);
JSONObject resultJSON = JSONObject.parseObject(respMsg);
if (resultJSON.getIntValue("errcode") == 0) {
log.info("消息发送成功!");
return true;
}
log.error("消息发送失败, 错误信息如下: {}", resultJSON.getString("errmsg"));
return false;
} catch (IOException e) {
log.error("消息发送失败, 异常信息如下: {}", e.getMessage());
return false;
}
}
}
3.定时任务例子,使用@Scheduled
注解与Cron表达式, 跑main
方法可以立刻看到效果哦!
在线Cron表达式生成地址:https://qqe2.com/cron
/**
* @description: 日报提醒和分享任务
* @author: DreamflyChen
* @create: 2020-08-29 21:51
*/
@Component
public class DailyTipAndShareTask {
@Scheduled(cron = "0 0 10 ? * 1")
public void ShareTip() throws Exception {
String webHookAddress = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=...";
//发送文本消息
Message message = new Message();
message.setMsgtype(MessageTypeEnum.text);
TextMessage textMessage = new TextMessage();
textMessage.setContent("这里写文本消息内容。");
textMessage.setMentioned_list(Arrays.asList("user id list"));
JSONObject text = JSONObject.parseObject(JSONObject.toJSONString(textMessage));
message.setText(text);
MessageManager.sendMessage(message, webHookAddress);
//发送图片消息
message.setText(null);
message.setMsgtype(MessageTypeEnum.image);
ImageMessage imageMessage = new ImageMessage();
imageMessage.setBase64(ImageManager.imageToBase64Str("/img/朱茵.jpg"));
imageMessage.setMd5(ImageManager.getStringMd5("/img/朱茵.jpg"));
JSONObject image = JSONObject.parseObject(JSONObject.toJSONString(imageMessage));
message.setImage(image);
MessageManager.sendMessage(message, webHookAddress);
}
public static void main(String[] args) throws Exception {
new DailyTipAndShareTask().ShareTip();
}
}
https://gitee.com/cqh_i/qiyeweixin-robot