如何使用群机器人
假设webhook是:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa
特别特别要注意:一定要保护好机器人的webhook地址,避免泄漏!不要分享到github、博客等可被公开查阅的地方,否则坏人就可以用你的机器人来发垃圾消息了。
以下是用curl工具往群组推送文本消息的示例(注意要将url替换成你的机器人webhook地址,content必须是utf8编码):
curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=693axxx6-7aoc-4bc4-97a0-0ec2sifa5aaa' \
-H 'Content-Type: application/json' \
-d '
{
"msgtype": "text",
"text": {
"content": "hello world"
}
}'
我们发现msgtype字段是通用的封装。所以可以构建一个父级类WebhookBody:
@Getter
public abstract class WebhookBody {
private final String msgtype;
/**
* 构造函数
*
* @param msgtype 消息类型
*/
protected WebhookBody(String msgtype) {
this.msgtype = msgtype;
}
}
text消息体WebhookTextBody类:
@EqualsAndHashCode(callSuper = true)
@ToString
@Getter
public class WebhookTextBody extends WebhookBody {
private final WebhookText text;
/**
* Instantiates a new Webhook text body.
*
* @param text the text
*/
WebhookTextBody(WebhookText text) {
super("text");
this.text = text;
}
/**
* From webhook text body.
*
* @param content the content
* @return the webhook text body
*/
public static WebhookTextBody from(String content, List<String> mentionedList,
List<String> mentionedMobileList) {
WebhookText webhookText = new WebhookTextBody.WebhookText(content);
webhookText.setMentionedList(mentionedList);
webhookText.setMentionedMobileList(mentionedMobileList);
return new WebhookTextBody(webhookText);
}
@ToString
@Getter
@Setter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public static class WebhookText {
/**
* 消息内容
*/
private final String content;
/**
* 被@人的列表,若为空则不会@人
*/
private List<String> mentionedList;
/**
* 被@人的手机列表,若为空则不会@人
*/
private List<String> mentionedMobileList;
}
图片类型
{
"msgtype": "image",
"image": {
"base64": "DATA",
"md5": "MD5"
}
}
图片封装WebhookImgBody:
@EqualsAndHashCode(callSuper = true)
@ToString
@Getter
public class WebhookImgBody extends WebhookBody {
private final ContentImage image;
@ToString
@Getter
public static class ContentImage {
private final String base64;
private final String md5;
public ContentImage(String base64, String md5) {
this.base64 = base64;
this.md5 = md5;
}
}
WebhookImgBody(ContentImage image) {
super("image");
this.image = image;
}
/**
* From webhook text body.
*
* @return the webhook text body
*/
public static WebhookImgBody from(InputStream inputStream) {
//base64编码
byte[] bytes = IoUtil.readBytes(inputStream);
String encode = Base64.encode(bytes);
//md5
String md5 = MD5.create().digestHex(bytes);
ContentImage image = new ContentImage(encode, md5);
return new WebhookImgBody(image);
}
}
MarkDown消息
{
"msgtype": "markdown",
"markdown": {
"content": "实时新增用户反馈<font color=\"warning\">132例</font>,请相关同事注意。\n
>类型:<font color=\"comment\">用户反馈</font>
>普通用户反馈:<font color=\"comment\">117例</font>
>VIP用户反馈:<font color=\"comment\">15例</font>"
}
}
MarkDown 的消息体WebhookMarkDownBody类:
@EqualsAndHashCode(callSuper = true)
@ToString
@Getter
public class WebhookMarkDownBody extends WebhookBody {
private final ContentText markdown;
@ToString
@Getter
public static class ContentText {
private final String content;
/**
* Instantiates a new Content text.
*
* @param content the content
*/
public ContentText(String content) {
this.content = content;
}
}
WebhookMarkDownBody(ContentText markdown) {
super("markdown");
this.markdown = markdown;
}
/**
* From webhook text body.
*
* @param content the content
* @return the webhook text body
*/
public static WebhookMarkDownBody from(ContentText content) {
return new WebhookMarkDownBody(content);
}
}
图文消息
{
"msgtype": "news",
"news": {
"articles" : [
{
"title" : "中秋节礼品领取",
"description" : "今年中秋节公司有豪礼相送",
"url" : "www.qq.com",
"picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png"
}
]
}
}
代码:
@EqualsAndHashCode(callSuper = true)
@ToString
@Getter
public class WebhookNewsBody extends WebhookBody {
private final ContentNews news;
@ToString
@Getter
public static class ContentNews {
private List<ContentArticle> articles;
public ContentNews(List<ContentArticle> articles) {
this.articles = articles;
}
}
WebhookNewsBody(ContentNews news) {
super("news");
this.news = news;
}
/**
* From webhook text body.
*
* @return the webhook text body
*/
public static WebhookNewsBody from(List<ContentArticle> articles) {
return new WebhookNewsBody(new ContentNews(articles));
}
}
图文消息类ContentArticle:
@Data
public class ContentArticle {
/**
* 图文消息标题
*/
private String title;
/**
* 图文消息描述
*/
private String description;
/**
* 图文消息点击跳转链接
*/
private String url;
/**
* 图文消息封面图片链接
*/
private String picurl;
}
请求工具类WeChatRobotRequest
有了请求体还需要最后的WeChatRobotRequest发送消息类,botKey是配置文件中的一个机器人key。使用Spring框架的@Value注解注入配置文件中的机器人密钥(botKey),并利用HTTP客户端发送消息至企业微信机器人:
@Component
@Slf4j
public class WeChatRobotRequest {
private final static String URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send";
@Value("${weChatRobot:}")
private String botKey;
/**
* 发送消息
*
* @param body 消息
*/
public String post(String body) {
if (StrUtil.isBlank(botKey)) {
return null;
}
String jsonStr = JSONUtil.toJsonStr(body);
//返回暂无用
String post = HttpUtil.post(URL + "?key=" + botKey, jsonStr);
log.info("wechat send result:{}",post);
return post;
}
}
同时,为了保证安全性,应确保botKey是从安全可靠的途径获取,并且在实际应用中考虑异常处理机制。
文件上传接口
请求方式:POST(HTTPS)
请求地址:https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=KEY&type=TYPE
使用multipart/form-data POST上传文件或语音, 文件标识名为"media"
POST https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa&type=file HTTP/1.1
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
Content-Length: 220
---------------------------acebdf13572468
Content-Disposition: form-data; name="media";filename="wework.txt"; filelength=6
Content-Type: application/octet-stream
mytext
---------------------------acebdf13572468--
返回:
{
"errcode": 0,
"errmsg": "ok",
"type": "file",
"media_id": "1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0",
"created_at": "1380000000"
}
注意事项
消息发送频率限制:每个机器人发送的消息不能超过20条/分钟。