springboot接入企业微信群机器人消息推送
企业微信群机器人消息推送文档地址
链接: 企业微信群机器人消息推送配置说明
import java.io.File;/*** 企业微信机器人消息推送* @author zhou*/
public interface WxWebHookHttpClient {/*** 消息推送* @param robotId 机器人key* @param body 消息参数* @return*/WebhookResponse send(String robotId, WebhookBody body);/*** 消息推送* @param robotId 机器人key* @param jsonParam 消息参数JSON格式* @return*/WebhookResponse send(String robotId, String jsonParam);/*** 上传文件* 使用multipart/form-data POST上传文件或语音, 文件标识名为"media"** 所有类型的文件大小均要求大于5个字节* 普通文件(file):文件大小不超过20M* 语音(voice):文件大小不超过2M,播放长度不超过60s,仅支持AMR格式** @param robotId 机器人key* @param type 文件类型,分别有语音(voice)和普通文件(file)* @param file* @return*/WebhookUploadMediaResponse uploadFile(String robotId, String type, File file);}
public abstract class WebhookBody {private final String msgtype;protected WebhookBody(String msgtype) {this.msgtype = msgtype;}public String getMsgtype() {return msgtype;}@Overridepublic String toString() {return "WebhookBody(msgtype=" + this.getMsgtype() + ")";}}
/*** 文件类型消息体*/
public class WebhookFileBody extends WebhookBody {private final WebhookFile file;private WebhookFileBody(WebhookFile file) {super("file");this.file = file;}public WebhookFile getFile() {return file;}@Overridepublic String toString() {return "WebhookFileBody{" +"file=" + file +'}';}/*** 创建文件消息* @param mediaId 文件id,通过文件上传接口获取*/public static WebhookFileBody from(String mediaId) {if (mediaId == null || mediaId.trim().isEmpty()) {throw new IllegalArgumentException("mediaId不能为空");}return new WebhookFileBody(new WebhookFile(mediaId));}/*** 文件消息内容*/public static class WebhookFile {/*** 文件id,通过下文的文件上传接口获取*/private String media_id;public WebhookFile(String media_id) {this.media_id = media_id;}public String getMedia_id() {return media_id;}public void setMedia_id(String media_id) {this.media_id = media_id;}@Overridepublic String toString() {return "WebhookFile{" +"media_id='" + media_id + '\'' +'}';}}
}
/*** 图片类型消息体*/
public class WebhookImageBody extends WebhookBody {private final WebhookImage image;private WebhookImageBody(WebhookImage image) {super("image");this.image = image;}public WebhookImage getImage() {return image;}@Overridepublic String toString() {return "WebhookImageBody{" +"image=" + image +'}';}/*** 创建图片消息* @param base64 图片内容的base64编码* @param md5 图片内容(base64编码前)的md5值*/public static WebhookImageBody from(String base64, String md5) {return new WebhookImageBody(new WebhookImage(base64, md5));}/*** 图片消息内容*/public static class WebhookImage {/*** 图片内容的base64编码*/private String base64;/*** 图片内容(base64编码前)的md5值*/private String md5;public WebhookImage(String base64, String md5) {this.base64 = base64;this.md5 = md5;}public String getBase64() {return base64;}public void setBase64(String base64) {this.base64 = base64;}public String getMd5() {return md5;}public void setMd5(String md5) {this.md5 = md5;}@Overridepublic String toString() {return "WebhookImage{" +"base64='" + base64 + '\'' +", md5='" + md5 + '\'' +'}';}}
}
public class WebhookMarkdownBody extends WebhookBody {private final WebhookMarkdown markdown;private WebhookMarkdownBody(WebhookMarkdown markdown) {super("markdown");this.markdown = markdown;}public WebhookMarkdown getMarkdown() {return markdown;}@Overridepublic String toString() {return "WebhookMarkdownBody{" +"markdown=" + markdown +'}';}/*** 构造markdown消息* @param content markdown内容,最长不超过4096个字节,必须是utf8编码*/public static WebhookMarkdownBody from(String content) {return new WebhookMarkdownBody(new WebhookMarkdown(content));}/*** Markdown消息内容*/public static class WebhookMarkdown {/*** markdown内容,最长不超过4096个字节,必须是utf8编码* 支持标准markdown语法,同时支持部分HTML标签* 支持的颜色标签:<font color="warning">、<font color="comment">、<font color="info">等*/private String content;public WebhookMarkdown(String content) {this.content = content;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overridepublic String toString() {return "WebhookMarkdown{" +"content='" + content + '\'' +'}';}}}
/*** 图文类型消息体*/
public class WebhookNewsBody extends WebhookBody {/*** 图文消息,一个图文消息支持1到8条图文*/private final WebhookNews news;private WebhookNewsBody(WebhookNews news) {super("news");this.news = news;}public WebhookNews getNews() {return news;}@Overridepublic String toString() {return "WebhookNewsBody{" +"news=" + news +'}';}/*** 创建图文消息* @param articles 图文列表(1-8条)*/public static WebhookNewsBody from(List<Article> articles) {return new WebhookNewsBody(new WebhookNews(articles));}/*** 图文消息内容*/public static class WebhookNews {private List<Article> articles;public WebhookNews(List<Article> articles) {this.articles = articles;}public List<Article> getArticles() {return articles;}public void setArticles(List<Article> articles) {this.articles = articles;}@Overridepublic String toString() {return "WebhookNews{" +"articles=" + articles +'}';}}/*** 单篇图文*/public static class Article {/*** 标题,不超过128个字节*/private String title;/*** 描述,不超过512个字节(可选)*/private String description;/*** 点击后跳转的链接*/private String url;/*** 图片链接(可选)* 支持JPG/PNG格式,推荐尺寸:大图1068 * 455,小图150 * 150*/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;}@Overridepublic String toString() {return "Article{" +"title='" + title + '\'' +", description='" + description + '\'' +", url='" + url + '\'' +", picurl='" + picurl + '\'' +'}';}}
}
public class WebhookResponse {/*** 错误码*/private Integer errcode;/*** 错误提示*/private String errmsg;/*** 成功响应*/public boolean isSuccessful() {return errcode != null && errcode == 0;}/*** 错误响应*/public boolean isError() {return errcode != null && errcode != 0;}public Integer getErrcode() {return errcode;}public void setErrcode(Integer errcode) {this.errcode = errcode;}public String getErrmsg() {return errmsg;}public void setErrmsg(String errmsg) {this.errmsg = errmsg;}@Overridepublic String toString() {return "WebhookResponse{" +"errcode=" + errcode +", errmsg='" + errmsg + '\'' +'}';}
}
public class WebhookTemplateCardNewsNoticeBody extends WebhookBody {private final TemplateCard template_card;private WebhookTemplateCardNewsNoticeBody(TemplateCard templateCard) {super("template_card");this.template_card = templateCard;}public TemplateCard getTemplate_card() {return template_card;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;if (!super.equals(o)) return false;WebhookTemplateCardNewsNoticeBody that = (WebhookTemplateCardNewsNoticeBody) o;return Objects.equals(template_card, that.template_card);}@Overridepublic int hashCode() {return Objects.hash(super.hashCode(), template_card);}@Overridepublic String toString() {return "WebhookTemplateCardNewsNoticeBody(super=" + super.toString() +", template_card=" + template_card + ")";}/*** 创建图文展示模版卡片消息** @param mainTitle 主标题* @param cardImage 卡片图片* @param cardAction 卡片点击动作* @return 消息体*/public static WebhookTemplateCardNewsNoticeBody create(MainTitle mainTitle, CardImage cardImage, CardAction cardAction) {return builder().cardType("news_notice").mainTitle(mainTitle).cardImage(cardImage).cardAction(cardAction).build();}/*** 创建构建器*/public static TemplateCardBuilder builder() {return new TemplateCardBuilder();}/*** 模版卡片构建器*/public static class TemplateCardBuilder {private String cardType = "news_notice";private Source source;private MainTitle mainTitle;private CardImage cardImage;private ImageTextArea imageTextArea;private QuoteArea quoteArea;private List<VerticalContent> verticalContentList;private List<HorizontalContent> horizontalContentList;private List<JumpItem> jumpList;private CardAction cardAction;public TemplateCardBuilder cardType(String cardType) {this.cardType = cardType;return this;}public TemplateCardBuilder source(Source source) {this.source = source;return this;}public TemplateCardBuilder mainTitle(MainTitle mainTitle) {this.mainTitle = mainTitle;return this;}public TemplateCardBuilder cardImage(CardImage cardImage) {this.cardImage = cardImage;return this;}public TemplateCardBuilder imageTextArea(ImageTextArea imageTextArea) {this.imageTextArea = imageTextArea;return this;}public TemplateCardBuilder quoteArea(QuoteArea quoteArea) {this.quoteArea = quoteArea;return this;}public TemplateCardBuilder verticalContentList(List<VerticalContent> verticalContentList) {this.verticalContentList = verticalContentList;return this;}public TemplateCardBuilder horizontalContentList(List<HorizontalContent> horizontalContentList) {this.horizontalContentList = horizontalContentList;return this;}public TemplateCardBuilder jumpList(List<JumpItem> jumpList) {this.jumpList = jumpList;return this;}public TemplateCardBuilder cardAction(CardAction cardAction) {this.cardAction = cardAction;return this;}/*** 构建模版卡片消息*/public WebhookTemplateCardNewsNoticeBody build() {// 校验必填条件if (mainTitle == null) {throw new IllegalArgumentException("main_title为必填项");}if (cardImage == null) {throw new IllegalArgumentException("card_image为必填项");}if (cardAction == null) {throw new IllegalArgumentException("news_notice模版卡片中card_action为必填项");}if (imageTextArea != null && imageTextArea.getImage_url() == null) {throw new IllegalArgumentException("image_text_area中image_url为必填项");}TemplateCard templateCard = new TemplateCard(cardType, source, mainTitle, cardImage, imageTextArea, quoteArea,verticalContentList, horizontalContentList, jumpList, cardAction);return new WebhookTemplateCardNewsNoticeBody(templateCard);}}/*** 模版卡片*/public static class TemplateCard {/*** 模版卡片的模版类型,图文展示模版卡片的类型为news_notice*/private final String card_type;/*** 卡片来源样式信息,不需要来源样式可不填写*/private final Source source;/*** 模版卡片的主要内容,包括一级标题和标题辅助信息*/private final MainTitle main_title;/*** 图片样式*/private final CardImage card_image;/*** 左图右文样式*/private final ImageTextArea image_text_area;/*** 引用文献样式,建议不与关键数据共用*/private final QuoteArea quote_area;/*** 卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4*/private final List<VerticalContent> vertical_content_list;/*** 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6*/private final List<HorizontalContent> horizontal_content_list;/*** 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3*/private final List<JumpItem> jump_list;/*** 整体卡片的点击跳转事件,news_notice模版卡片中该字段为必填项*/private final CardAction card_action;public TemplateCard(String card_type, Source source, MainTitle main_title, CardImage card_image,ImageTextArea image_text_area, QuoteArea quote_area,List<VerticalContent> vertical_content_list,List<HorizontalContent> horizontal_content_list,List<JumpItem> jump_list, CardAction card_action) {this.card_type = card_type;this.source = source;this.main_title = main_title;this.card_image = card_image;this.image_text_area = image_text_area;this.quote_area = quote_area;this.vertical_content_list = vertical_content_list;this.horizontal_content_list = horizontal_content_list;this.jump_list = jump_list;this.card_action = card_action;}// Getterspublic String getCard_type() { return card_type; }public Source getSource() { return source; }public MainTitle getMain_title() { return main_title; }public CardImage getCard_image() { return card_image; }public ImageTextArea getImage_text_area() { return image_text_area; }public QuoteArea getQuote_area() { return quote_area; }public List<VerticalContent> getVertical_content_list() { return vertical_content_list; }public List<HorizontalContent> getHorizontal_content_list() { return horizontal_content_list; }public List<JumpItem> getJump_list() { return jump_list; }public CardAction getCard_action() { return card_action; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;TemplateCard that = (TemplateCard) o;return Objects.equals(card_type, that.card_type) &&Objects.equals(source, that.source) &&Objects.equals(main_title, that.main_title) &&Objects.equals(card_image, that.card_image) &&Objects.equals(image_text_area, that.image_text_area) &&Objects.equals(quote_area, that.quote_area) &&Objects.equals(vertical_content_list, that.vertical_content_list) &&Objects.equals(horizontal_content_list, that.horizontal_content_list) &&Objects.equals(jump_list, that.jump_list) &&Objects.equals(card_action, that.card_action);}@Overridepublic int hashCode() {return Objects.hash(card_type, source, main_title, card_image, image_text_area,quote_area, vertical_content_list, horizontal_content_list,jump_list, card_action);}@Overridepublic String toString() {return "TemplateCard{" +"card_type='" + card_type + '\'' +", source=" + source +", main_title=" + main_title +", card_image=" + card_image +", image_text_area=" + image_text_area +", quote_area=" + quote_area +", vertical_content_list=" + vertical_content_list +", horizontal_content_list=" + horizontal_content_list +", jump_list=" + jump_list +", card_action=" + card_action +'}';}}/*** 卡片来源样式信息*/public static class Source {/*** 来源图片的url*/private final String icon_url;/*** 来源图片的描述,建议不超过13个字*/private final String desc;/*** 来源文字的颜色,目前支持:0(默认) 灰色,1 黑色,2 红色,3 绿色*/private final Integer desc_color;private Source(String icon_url, String desc, Integer desc_color) {this.icon_url = icon_url;this.desc = desc;this.desc_color = desc_color;}// Getterspublic String getIcon_url() { return icon_url; }public String getDesc() { return desc; }public Integer getDesc_color() { return desc_color; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Source source = (Source) o;return Objects.equals(icon_url, source.icon_url) &&Objects.equals(desc, source.desc) &&Objects.equals(desc_color, source.desc_color);}@Overridepublic int hashCode() {return Objects.hash(icon_url, desc, desc_color);}@Overridepublic String toString() {return "Source{" +"icon_url='" + icon_url + '\'' +", desc='" + desc + '\'' +", desc_color=" + desc_color +'}';}// Builderpublic static class Builder {private String icon_url;private String desc;private Integer desc_color = 0;public Builder icon_url(String icon_url) {this.icon_url = icon_url;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public Builder desc_color(Integer desc_color) {this.desc_color = desc_color;return this;}public Source build() {return new Source(icon_url, desc, desc_color);}}public static Builder builder() {return new Builder();}}/*** 模版卡片的主要内容*/public static class MainTitle {/*** 一级标题,建议不超过26个字*/private final String title;/*** 标题辅助信息,建议不超过30个字*/private final String desc;private MainTitle(String title, String desc) {this.title = title;this.desc = desc;}// Getterspublic String getTitle() { return title; }public String getDesc() { return desc; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;MainTitle mainTitle = (MainTitle) o;return Objects.equals(title, mainTitle.title) &&Objects.equals(desc, mainTitle.desc);}@Overridepublic int hashCode() {return Objects.hash(title, desc);}@Overridepublic String toString() {return "MainTitle{" +"title='" + title + '\'' +", desc='" + desc + '\'' +'}';}// Builderpublic static class Builder {private String title;private String desc;public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public MainTitle build() {return new MainTitle(title, desc);}}public static Builder builder() {return new Builder();}}/*** 图片样式*/public static class CardImage {/*** 图片的url*/private final String url;/*** 图片的宽高比,宽高比要小于2.25,大于1.3,不填该参数默认1.3*/private final Float aspect_ratio;private CardImage(String url, Float aspect_ratio) {this.url = url;this.aspect_ratio = aspect_ratio;}// Getterspublic String getUrl() { return url; }public Float getAspect_ratio() { return aspect_ratio; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;CardImage cardImage = (CardImage) o;return Objects.equals(url, cardImage.url) &&Objects.equals(aspect_ratio, cardImage.aspect_ratio);}@Overridepublic int hashCode() {return Objects.hash(url, aspect_ratio);}@Overridepublic String toString() {return "CardImage{" +"url='" + url + '\'' +", aspect_ratio=" + aspect_ratio +'}';}// Builderpublic static class Builder {private String url;private Float aspect_ratio = 1.3f;public Builder url(String url) {this.url = url;return this;}public Builder aspect_ratio(Float aspect_ratio) {this.aspect_ratio = aspect_ratio;return this;}public CardImage build() {return new CardImage(url, aspect_ratio);}}public static Builder builder() {return new Builder();}}/*** 左图右文样式*/public static class ImageTextArea {/*** 左图右文样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 点击跳转的url,image_text_area.type是1时必填*/private final String url;/*** 点击跳转的小程序的appid,必须是与当前应用关联的小程序,image_text_area.type是2时必填*/private final String appid;/*** 点击跳转的小程序的pagepath,image_text_area.type是2时选填*/private final String pagepath;/*** 左图右文样式的标题*/private final String title;/*** 左图右文样式的描述*/private final String desc;/*** 左图右文样式的图片url*/private final String image_url;private ImageTextArea(Integer type, String url, String appid, String pagepath,String title, String desc, String image_url) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;this.title = title;this.desc = desc;this.image_url = image_url;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }public String getTitle() { return title; }public String getDesc() { return desc; }public String getImage_url() { return image_url; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;ImageTextArea that = (ImageTextArea) o;return Objects.equals(type, that.type) &&Objects.equals(url, that.url) &&Objects.equals(appid, that.appid) &&Objects.equals(pagepath, that.pagepath) &&Objects.equals(title, that.title) &&Objects.equals(desc, that.desc) &&Objects.equals(image_url, that.image_url);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath, title, desc, image_url);}@Overridepublic String toString() {return "ImageTextArea{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +", title='" + title + '\'' +", desc='" + desc + '\'' +", image_url='" + image_url + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String url;private String appid;private String pagepath;private String title;private String desc;private String image_url;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public Builder image_url(String image_url) {this.image_url = image_url;return this;}public ImageTextArea build() {return new ImageTextArea(type, url, appid, pagepath, title, desc, image_url);}}public static Builder builder() {return new Builder();}}/*** 引用文献样式*/public static class QuoteArea {/*** 引用文献样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 点击跳转的url,quote_area.type是1时必填*/private final String url;/*** 点击跳转的小程序的appid,quote_area.type是2时必填*/private final String appid;/*** 点击跳转的小程序的pagepath,quote_area.type是2时选填*/private final String pagepath;/*** 引用文献样式的标题*/private final String title;/*** 引用文献样式的引用文案*/private final String quote_text;private QuoteArea(Integer type, String url, String appid, String pagepath,String title, String quote_text) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;this.title = title;this.quote_text = quote_text;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }public String getTitle() { return title; }public String getQuote_text() { return quote_text; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;QuoteArea quoteArea = (QuoteArea) o;return Objects.equals(type, quoteArea.type) &&Objects.equals(url, quoteArea.url) &&Objects.equals(appid, quoteArea.appid) &&Objects.equals(pagepath, quoteArea.pagepath) &&Objects.equals(title, quoteArea.title) &&Objects.equals(quote_text, quoteArea.quote_text);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath, title, quote_text);}@Overridepublic String toString() {return "QuoteArea{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +", title='" + title + '\'' +", quote_text='" + quote_text + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String url;private String appid;private String pagepath;private String title;private String quote_text;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public Builder title(String title) {this.title = title;return this;}public Builder quote_text(String quote_text) {this.quote_text = quote_text;return this;}public QuoteArea build() {return new QuoteArea(type, url, appid, pagepath, title, quote_text);}}public static Builder builder() {return new Builder();}}/*** 垂直内容*/public static class VerticalContent {/*** 卡片二级标题,建议不超过26个字*/private final String title;/*** 二级普通文本,建议不超过112个字*/private final String desc;private VerticalContent(String title, String desc) {this.title = title;this.desc = desc;}// Getterspublic String getTitle() { return title; }public String getDesc() { return desc; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;VerticalContent that = (VerticalContent) o;return Objects.equals(title, that.title) &&Objects.equals(desc, that.desc);}@Overridepublic int hashCode() {return Objects.hash(title, desc);}@Overridepublic String toString() {return "VerticalContent{" +"title='" + title + '\'' +", desc='" + desc + '\'' +'}';}// Builderpublic static class Builder {private String title;private String desc;public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public VerticalContent build() {return new VerticalContent(title, desc);}}public static Builder builder() {return new Builder();}}/*** 水平内容列表项*/public static class HorizontalContent {/*** 模版卡片的二级标题信息内容支持的类型,1是url,2是文件附件,3 代表点击跳转成员详情*/private final Integer type;/*** 二级标题,建议不超过5个字*/private final String keyname;/*** 二级文本,如果horizontal_content_list.type是2,该字段代表文件名称(要包含文件类型),建议不超过26个字*/private final String value;/*** 链接跳转的url,horizontal_content_list.type是1时必填*/private final String url;/*** 附件的media_id,horizontal_content_list.type是2时必填*/private final String media_id;/*** 成员详情的userid,horizontal_content_list.type是3时必填*/private final String userid;private HorizontalContent(Integer type, String keyname, String value,String url, String media_id, String userid) {this.type = type;this.keyname = keyname;this.value = value;this.url = url;this.media_id = media_id;this.userid = userid;}// Getterspublic Integer getType() { return type; }public String getKeyname() { return keyname; }public String getValue() { return value; }public String getUrl() { return url; }public String getMedia_id() { return media_id; }public String getUserid() { return userid; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;HorizontalContent that = (HorizontalContent) o;return Objects.equals(type, that.type) &&Objects.equals(keyname, that.keyname) &&Objects.equals(value, that.value) &&Objects.equals(url, that.url) &&Objects.equals(media_id, that.media_id) &&Objects.equals(userid, that.userid);}@Overridepublic int hashCode() {return Objects.hash(type, keyname, value, url, media_id, userid);}@Overridepublic String toString() {return "HorizontalContent{" +"type=" + type +", keyname='" + keyname + '\'' +", value='" + value + '\'' +", url='" + url + '\'' +", media_id='" + media_id + '\'' +", userid='" + userid + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String keyname;private String value;private String url;private String media_id;private String userid;public Builder type(Integer type) {this.type = type;return this;}public Builder keyname(String keyname) {this.keyname = keyname;return this;}public Builder value(String value) {this.value = value;return this;}public Builder url(String url) {this.url = url;return this;}public Builder media_id(String media_id) {this.media_id = media_id;return this;}public Builder userid(String userid) {this.userid = userid;return this;}public HorizontalContent build() {return new HorizontalContent(type, keyname, value, url, media_id, userid);}}public static Builder builder() {return new Builder();}}/*** 跳转指引项*/public static class JumpItem {/*** 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 跳转链接样式的文案内容,建议不超过13个字*/private final String title;/*** 跳转链接的url,jump_list.type是1时必填*/private final String url;/*** 跳转链接的小程序的appid,jump_list.type是2时必填*/private final String appid;/*** 跳转链接的小程序的pagepath,jump_list.type是2时选填*/private final String pagepath;private JumpItem(Integer type, String title, String url, String appid, String pagepath) {this.type = type;this.title = title;this.url = url;this.appid = appid;this.pagepath = pagepath;}// Getterspublic Integer getType() { return type; }public String getTitle() { return title; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;JumpItem jumpItem = (JumpItem) o;return Objects.equals(type, jumpItem.type) &&Objects.equals(title, jumpItem.title) &&Objects.equals(url, jumpItem.url) &&Objects.equals(appid, jumpItem.appid) &&Objects.equals(pagepath, jumpItem.pagepath);}@Overridepublic int hashCode() {return Objects.hash(type, title, url, appid, pagepath);}@Overridepublic String toString() {return "JumpItem{" +"type=" + type +", title='" + title + '\'' +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String title;private String url;private String appid;private String pagepath;public Builder type(Integer type) {this.type = type;return this;}public Builder title(String title) {this.title = title;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public JumpItem build() {return new JumpItem(type, title, url, appid, pagepath);}}public static Builder builder() {return new Builder();}}/*** 卡片点击动作*/public static class CardAction {/*** 卡片跳转类型,1 代表跳转url,2 代表打开小程序。news_notice模版卡片中该字段取值范围为[1,2]*/private final Integer type;/*** 跳转事件的url,card_action.type是1时必填*/private final String url;/*** 跳转事件的小程序的appid,card_action.type是2时必填*/private final String appid;/*** 跳转事件的小程序的pagepath,card_action.type是2时选填*/private final String pagepath;private CardAction(Integer type, String url, String appid, String pagepath) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;CardAction that = (CardAction) o;return Objects.equals(type, that.type) &&Objects.equals(url, that.url) &&Objects.equals(appid, that.appid) &&Objects.equals(pagepath, that.pagepath);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath);}@Overridepublic String toString() {return "CardAction{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +'}';}// Builderpublic static class Builder {private Integer type;private String url;private String appid;private String pagepath;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public CardAction build() {return new CardAction(type, url, appid, pagepath);}}public static Builder builder() {return new Builder();}}public static void main(String[] args) {// 创建简单的图文展示模版卡片WebhookTemplateCardNewsNoticeBody.MainTitle mainTitle = WebhookTemplateCardNewsNoticeBody.MainTitle.builder().title("欢迎使用企业微信").desc("您的好友正在邀请您加入企业微信").build();WebhookTemplateCardNewsNoticeBody.CardImage cardImage = WebhookTemplateCardNewsNoticeBody.CardImage.builder().url("https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0").aspect_ratio(2.25f).build();WebhookTemplateCardNewsNoticeBody.CardAction cardAction = WebhookTemplateCardNewsNoticeBody.CardAction.builder().type(1).url("https://work.weixin.qq.com/?from=openApi").build();WebhookTemplateCardNewsNoticeBody simpleCard = WebhookTemplateCardNewsNoticeBody.create(mainTitle, cardImage, cardAction);// 创建复杂的图文展示模版卡片WebhookTemplateCardNewsNoticeBody.Source source = WebhookTemplateCardNewsNoticeBody.Source.builder().icon_url("https://wework.qpic.cn/wwpic/252813_jOfDHtcISzuodLa_1629280209/0").desc("企业微信").desc_color(0).build();WebhookTemplateCardNewsNoticeBody.ImageTextArea imageTextArea = WebhookTemplateCardNewsNoticeBody.ImageTextArea.builder().type(1).url("https://work.weixin.qq.com").title("欢迎使用企业微信").desc("您的好友正在邀请您加入企业微信").image_url("https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0").build();WebhookTemplateCardNewsNoticeBody.QuoteArea quoteArea = WebhookTemplateCardNewsNoticeBody.QuoteArea.builder().type(1).url("https://work.weixin.qq.com/?from=openApi").title("引用文本标题").quote_text("Jack:企业微信真的很好用~\nBalian:超级好的一款软件!").build();List<VerticalContent> verticalContents = Arrays.asList(WebhookTemplateCardNewsNoticeBody.VerticalContent.builder().title("惊喜红包等你来拿").desc("下载企业微信还能抢红包!").build());List<HorizontalContent> horizontalContents = Arrays.asList(WebhookTemplateCardNewsNoticeBody.HorizontalContent.builder().keyname("邀请人").value("张三").build(),WebhookTemplateCardNewsNoticeBody.HorizontalContent.builder().type(1).keyname("企微官网").value("点击访问").url("https://work.weixin.qq.com/?from=openApi").build(),WebhookTemplateCardNewsNoticeBody.HorizontalContent.builder().type(2).keyname("企微下载").value("企业微信.apk").media_id("38Kz4vLCb49gfGvfOPw_y2f4nrik8lA_1xqNFmIzhtgkZVBoLoEYDQ7WopEKGnCTG").build());List<JumpItem> jumpList = Arrays.asList(WebhookTemplateCardNewsNoticeBody.JumpItem.builder().type(1).title("企业微信官网").url("https://work.weixin.qq.com/?from=openApi").build(),WebhookTemplateCardNewsNoticeBody.JumpItem.builder().type(2).title("跳转小程序").appid("APPID").pagepath("PAGEPATH").build());WebhookTemplateCardNewsNoticeBody complexCard = WebhookTemplateCardNewsNoticeBody.builder().source(source).mainTitle(mainTitle).cardImage(cardImage).imageTextArea(imageTextArea).quoteArea(quoteArea).verticalContentList(verticalContents).horizontalContentList(horizontalContents).jumpList(jumpList).cardAction(cardAction).build();System.out.println(complexCard);}
}
public class WebhookTemplateCardNewsNoticeBody extends WebhookBody {private final TemplateCard template_card;private WebhookTemplateCardNewsNoticeBody(TemplateCard templateCard) {super("template_card");this.template_card = templateCard;}public TemplateCard getTemplate_card() {return template_card;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;if (!super.equals(o)) return false;WebhookTemplateCardNewsNoticeBody that = (WebhookTemplateCardNewsNoticeBody) o;return Objects.equals(template_card, that.template_card);}@Overridepublic int hashCode() {return Objects.hash(super.hashCode(), template_card);}@Overridepublic String toString() {return "WebhookTemplateCardNewsNoticeBody(super=" + super.toString() +", template_card=" + template_card + ")";}/*** 创建图文展示模版卡片消息** @param mainTitle 主标题* @param cardImage 卡片图片* @param cardAction 卡片点击动作* @return 消息体*/public static WebhookTemplateCardNewsNoticeBody create(MainTitle mainTitle, CardImage cardImage, CardAction cardAction) {return builder().cardType("news_notice").mainTitle(mainTitle).cardImage(cardImage).cardAction(cardAction).build();}/*** 创建构建器*/public static TemplateCardBuilder builder() {return new TemplateCardBuilder();}/*** 模版卡片构建器*/public static class TemplateCardBuilder {private String cardType = "news_notice";private Source source;private MainTitle mainTitle;private CardImage cardImage;private ImageTextArea imageTextArea;private QuoteArea quoteArea;private List<VerticalContent> verticalContentList;private List<HorizontalContent> horizontalContentList;private List<JumpItem> jumpList;private CardAction cardAction;public TemplateCardBuilder cardType(String cardType) {this.cardType = cardType;return this;}public TemplateCardBuilder source(Source source) {this.source = source;return this;}public TemplateCardBuilder mainTitle(MainTitle mainTitle) {this.mainTitle = mainTitle;return this;}public TemplateCardBuilder cardImage(CardImage cardImage) {this.cardImage = cardImage;return this;}public TemplateCardBuilder imageTextArea(ImageTextArea imageTextArea) {this.imageTextArea = imageTextArea;return this;}public TemplateCardBuilder quoteArea(QuoteArea quoteArea) {this.quoteArea = quoteArea;return this;}public TemplateCardBuilder verticalContentList(List<VerticalContent> verticalContentList) {this.verticalContentList = verticalContentList;return this;}public TemplateCardBuilder horizontalContentList(List<HorizontalContent> horizontalContentList) {this.horizontalContentList = horizontalContentList;return this;}public TemplateCardBuilder jumpList(List<JumpItem> jumpList) {this.jumpList = jumpList;return this;}public TemplateCardBuilder cardAction(CardAction cardAction) {this.cardAction = cardAction;return this;}/*** 构建模版卡片消息*/public WebhookTemplateCardNewsNoticeBody build() {// 校验必填条件if (mainTitle == null) {throw new IllegalArgumentException("main_title为必填项");}if (cardImage == null) {throw new IllegalArgumentException("card_image为必填项");}if (cardAction == null) {throw new IllegalArgumentException("news_notice模版卡片中card_action为必填项");}if (imageTextArea != null && imageTextArea.getImage_url() == null) {throw new IllegalArgumentException("image_text_area中image_url为必填项");}TemplateCard templateCard = new TemplateCard(cardType, source, mainTitle, cardImage, imageTextArea, quoteArea,verticalContentList, horizontalContentList, jumpList, cardAction);return new WebhookTemplateCardNewsNoticeBody(templateCard);}}/*** 模版卡片*/public static class TemplateCard {/*** 模版卡片的模版类型,图文展示模版卡片的类型为news_notice*/private final String card_type;/*** 卡片来源样式信息,不需要来源样式可不填写*/private final Source source;/*** 模版卡片的主要内容,包括一级标题和标题辅助信息*/private final MainTitle main_title;/*** 图片样式*/private final CardImage card_image;/*** 左图右文样式*/private final ImageTextArea image_text_area;/*** 引用文献样式,建议不与关键数据共用*/private final QuoteArea quote_area;/*** 卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4*/private final List<VerticalContent> vertical_content_list;/*** 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6*/private final List<HorizontalContent> horizontal_content_list;/*** 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3*/private final List<JumpItem> jump_list;/*** 整体卡片的点击跳转事件,news_notice模版卡片中该字段为必填项*/private final CardAction card_action;public TemplateCard(String card_type, Source source, MainTitle main_title, CardImage card_image,ImageTextArea image_text_area, QuoteArea quote_area,List<VerticalContent> vertical_content_list,List<HorizontalContent> horizontal_content_list,List<JumpItem> jump_list, CardAction card_action) {this.card_type = card_type;this.source = source;this.main_title = main_title;this.card_image = card_image;this.image_text_area = image_text_area;this.quote_area = quote_area;this.vertical_content_list = vertical_content_list;this.horizontal_content_list = horizontal_content_list;this.jump_list = jump_list;this.card_action = card_action;}// Getterspublic String getCard_type() { return card_type; }public Source getSource() { return source; }public MainTitle getMain_title() { return main_title; }public CardImage getCard_image() { return card_image; }public ImageTextArea getImage_text_area() { return image_text_area; }public QuoteArea getQuote_area() { return quote_area; }public List<VerticalContent> getVertical_content_list() { return vertical_content_list; }public List<HorizontalContent> getHorizontal_content_list() { return horizontal_content_list; }public List<JumpItem> getJump_list() { return jump_list; }public CardAction getCard_action() { return card_action; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;TemplateCard that = (TemplateCard) o;return Objects.equals(card_type, that.card_type) &&Objects.equals(source, that.source) &&Objects.equals(main_title, that.main_title) &&Objects.equals(card_image, that.card_image) &&Objects.equals(image_text_area, that.image_text_area) &&Objects.equals(quote_area, that.quote_area) &&Objects.equals(vertical_content_list, that.vertical_content_list) &&Objects.equals(horizontal_content_list, that.horizontal_content_list) &&Objects.equals(jump_list, that.jump_list) &&Objects.equals(card_action, that.card_action);}@Overridepublic int hashCode() {return Objects.hash(card_type, source, main_title, card_image, image_text_area,quote_area, vertical_content_list, horizontal_content_list,jump_list, card_action);}@Overridepublic String toString() {return "TemplateCard{" +"card_type='" + card_type + '\'' +", source=" + source +", main_title=" + main_title +", card_image=" + card_image +", image_text_area=" + image_text_area +", quote_area=" + quote_area +", vertical_content_list=" + vertical_content_list +", horizontal_content_list=" + horizontal_content_list +", jump_list=" + jump_list +", card_action=" + card_action +'}';}}/*** 卡片来源样式信息*/public static class Source {/*** 来源图片的url*/private final String icon_url;/*** 来源图片的描述,建议不超过13个字*/private final String desc;/*** 来源文字的颜色,目前支持:0(默认) 灰色,1 黑色,2 红色,3 绿色*/private final Integer desc_color;private Source(String icon_url, String desc, Integer desc_color) {this.icon_url = icon_url;this.desc = desc;this.desc_color = desc_color;}// Getterspublic String getIcon_url() { return icon_url; }public String getDesc() { return desc; }public Integer getDesc_color() { return desc_color; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Source source = (Source) o;return Objects.equals(icon_url, source.icon_url) &&Objects.equals(desc, source.desc) &&Objects.equals(desc_color, source.desc_color);}@Overridepublic int hashCode() {return Objects.hash(icon_url, desc, desc_color);}@Overridepublic String toString() {return "Source{" +"icon_url='" + icon_url + '\'' +", desc='" + desc + '\'' +", desc_color=" + desc_color +'}';}// Builderpublic static class Builder {private String icon_url;private String desc;private Integer desc_color = 0;public Builder icon_url(String icon_url) {this.icon_url = icon_url;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public Builder desc_color(Integer desc_color) {this.desc_color = desc_color;return this;}public Source build() {return new Source(icon_url, desc, desc_color);}}public static Builder builder() {return new Builder();}}/*** 模版卡片的主要内容*/public static class MainTitle {/*** 一级标题,建议不超过26个字*/private final String title;/*** 标题辅助信息,建议不超过30个字*/private final String desc;private MainTitle(String title, String desc) {this.title = title;this.desc = desc;}// Getterspublic String getTitle() { return title; }public String getDesc() { return desc; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;MainTitle mainTitle = (MainTitle) o;return Objects.equals(title, mainTitle.title) &&Objects.equals(desc, mainTitle.desc);}@Overridepublic int hashCode() {return Objects.hash(title, desc);}@Overridepublic String toString() {return "MainTitle{" +"title='" + title + '\'' +", desc='" + desc + '\'' +'}';}// Builderpublic static class Builder {private String title;private String desc;public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public MainTitle build() {return new MainTitle(title, desc);}}public static Builder builder() {return new Builder();}}/*** 图片样式*/public static class CardImage {/*** 图片的url*/private final String url;/*** 图片的宽高比,宽高比要小于2.25,大于1.3,不填该参数默认1.3*/private final Float aspect_ratio;private CardImage(String url, Float aspect_ratio) {this.url = url;this.aspect_ratio = aspect_ratio;}// Getterspublic String getUrl() { return url; }public Float getAspect_ratio() { return aspect_ratio; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;CardImage cardImage = (CardImage) o;return Objects.equals(url, cardImage.url) &&Objects.equals(aspect_ratio, cardImage.aspect_ratio);}@Overridepublic int hashCode() {return Objects.hash(url, aspect_ratio);}@Overridepublic String toString() {return "CardImage{" +"url='" + url + '\'' +", aspect_ratio=" + aspect_ratio +'}';}// Builderpublic static class Builder {private String url;private Float aspect_ratio = 1.3f;public Builder url(String url) {this.url = url;return this;}public Builder aspect_ratio(Float aspect_ratio) {this.aspect_ratio = aspect_ratio;return this;}public CardImage build() {return new CardImage(url, aspect_ratio);}}public static Builder builder() {return new Builder();}}/*** 左图右文样式*/public static class ImageTextArea {/*** 左图右文样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 点击跳转的url,image_text_area.type是1时必填*/private final String url;/*** 点击跳转的小程序的appid,必须是与当前应用关联的小程序,image_text_area.type是2时必填*/private final String appid;/*** 点击跳转的小程序的pagepath,image_text_area.type是2时选填*/private final String pagepath;/*** 左图右文样式的标题*/private final String title;/*** 左图右文样式的描述*/private final String desc;/*** 左图右文样式的图片url*/private final String image_url;private ImageTextArea(Integer type, String url, String appid, String pagepath,String title, String desc, String image_url) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;this.title = title;this.desc = desc;this.image_url = image_url;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }public String getTitle() { return title; }public String getDesc() { return desc; }public String getImage_url() { return image_url; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;ImageTextArea that = (ImageTextArea) o;return Objects.equals(type, that.type) &&Objects.equals(url, that.url) &&Objects.equals(appid, that.appid) &&Objects.equals(pagepath, that.pagepath) &&Objects.equals(title, that.title) &&Objects.equals(desc, that.desc) &&Objects.equals(image_url, that.image_url);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath, title, desc, image_url);}@Overridepublic String toString() {return "ImageTextArea{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +", title='" + title + '\'' +", desc='" + desc + '\'' +", image_url='" + image_url + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String url;private String appid;private String pagepath;private String title;private String desc;private String image_url;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public Builder image_url(String image_url) {this.image_url = image_url;return this;}public ImageTextArea build() {return new ImageTextArea(type, url, appid, pagepath, title, desc, image_url);}}public static Builder builder() {return new Builder();}}/*** 引用文献样式*/public static class QuoteArea {/*** 引用文献样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 点击跳转的url,quote_area.type是1时必填*/private final String url;/*** 点击跳转的小程序的appid,quote_area.type是2时必填*/private final String appid;/*** 点击跳转的小程序的pagepath,quote_area.type是2时选填*/private final String pagepath;/*** 引用文献样式的标题*/private final String title;/*** 引用文献样式的引用文案*/private final String quote_text;private QuoteArea(Integer type, String url, String appid, String pagepath,String title, String quote_text) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;this.title = title;this.quote_text = quote_text;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }public String getTitle() { return title; }public String getQuote_text() { return quote_text; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;QuoteArea quoteArea = (QuoteArea) o;return Objects.equals(type, quoteArea.type) &&Objects.equals(url, quoteArea.url) &&Objects.equals(appid, quoteArea.appid) &&Objects.equals(pagepath, quoteArea.pagepath) &&Objects.equals(title, quoteArea.title) &&Objects.equals(quote_text, quoteArea.quote_text);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath, title, quote_text);}@Overridepublic String toString() {return "QuoteArea{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +", title='" + title + '\'' +", quote_text='" + quote_text + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String url;private String appid;private String pagepath;private String title;private String quote_text;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public Builder title(String title) {this.title = title;return this;}public Builder quote_text(String quote_text) {this.quote_text = quote_text;return this;}public QuoteArea build() {return new QuoteArea(type, url, appid, pagepath, title, quote_text);}}public static Builder builder() {return new Builder();}}/*** 垂直内容*/public static class VerticalContent {/*** 卡片二级标题,建议不超过26个字*/private final String title;/*** 二级普通文本,建议不超过112个字*/private final String desc;private VerticalContent(String title, String desc) {this.title = title;this.desc = desc;}// Getterspublic String getTitle() { return title; }public String getDesc() { return desc; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;VerticalContent that = (VerticalContent) o;return Objects.equals(title, that.title) &&Objects.equals(desc, that.desc);}@Overridepublic int hashCode() {return Objects.hash(title, desc);}@Overridepublic String toString() {return "VerticalContent{" +"title='" + title + '\'' +", desc='" + desc + '\'' +'}';}// Builderpublic static class Builder {private String title;private String desc;public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public VerticalContent build() {return new VerticalContent(title, desc);}}public static Builder builder() {return new Builder();}}/*** 水平内容列表项*/public static class HorizontalContent {/*** 模版卡片的二级标题信息内容支持的类型,1是url,2是文件附件,3 代表点击跳转成员详情*/private final Integer type;/*** 二级标题,建议不超过5个字*/private final String keyname;/*** 二级文本,如果horizontal_content_list.type是2,该字段代表文件名称(要包含文件类型),建议不超过26个字*/private final String value;/*** 链接跳转的url,horizontal_content_list.type是1时必填*/private final String url;/*** 附件的media_id,horizontal_content_list.type是2时必填*/private final String media_id;/*** 成员详情的userid,horizontal_content_list.type是3时必填*/private final String userid;private HorizontalContent(Integer type, String keyname, String value,String url, String media_id, String userid) {this.type = type;this.keyname = keyname;this.value = value;this.url = url;this.media_id = media_id;this.userid = userid;}// Getterspublic Integer getType() { return type; }public String getKeyname() { return keyname; }public String getValue() { return value; }public String getUrl() { return url; }public String getMedia_id() { return media_id; }public String getUserid() { return userid; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;HorizontalContent that = (HorizontalContent) o;return Objects.equals(type, that.type) &&Objects.equals(keyname, that.keyname) &&Objects.equals(value, that.value) &&Objects.equals(url, that.url) &&Objects.equals(media_id, that.media_id) &&Objects.equals(userid, that.userid);}@Overridepublic int hashCode() {return Objects.hash(type, keyname, value, url, media_id, userid);}@Overridepublic String toString() {return "HorizontalContent{" +"type=" + type +", keyname='" + keyname + '\'' +", value='" + value + '\'' +", url='" + url + '\'' +", media_id='" + media_id + '\'' +", userid='" + userid + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String keyname;private String value;private String url;private String media_id;private String userid;public Builder type(Integer type) {this.type = type;return this;}public Builder keyname(String keyname) {this.keyname = keyname;return this;}public Builder value(String value) {this.value = value;return this;}public Builder url(String url) {this.url = url;return this;}public Builder media_id(String media_id) {this.media_id = media_id;return this;}public Builder userid(String userid) {this.userid = userid;return this;}public HorizontalContent build() {return new HorizontalContent(type, keyname, value, url, media_id, userid);}}public static Builder builder() {return new Builder();}}/*** 跳转指引项*/public static class JumpItem {/*** 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 跳转链接样式的文案内容,建议不超过13个字*/private final String title;/*** 跳转链接的url,jump_list.type是1时必填*/private final String url;/*** 跳转链接的小程序的appid,jump_list.type是2时必填*/private final String appid;/*** 跳转链接的小程序的pagepath,jump_list.type是2时选填*/private final String pagepath;private JumpItem(Integer type, String title, String url, String appid, String pagepath) {this.type = type;this.title = title;this.url = url;this.appid = appid;this.pagepath = pagepath;}// Getterspublic Integer getType() { return type; }public String getTitle() { return title; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;JumpItem jumpItem = (JumpItem) o;return Objects.equals(type, jumpItem.type) &&Objects.equals(title, jumpItem.title) &&Objects.equals(url, jumpItem.url) &&Objects.equals(appid, jumpItem.appid) &&Objects.equals(pagepath, jumpItem.pagepath);}@Overridepublic int hashCode() {return Objects.hash(type, title, url, appid, pagepath);}@Overridepublic String toString() {return "JumpItem{" +"type=" + type +", title='" + title + '\'' +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String title;private String url;private String appid;private String pagepath;public Builder type(Integer type) {this.type = type;return this;}public Builder title(String title) {this.title = title;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public JumpItem build() {return new JumpItem(type, title, url, appid, pagepath);}}public static Builder builder() {return new Builder();}}/*** 卡片点击动作*/public static class CardAction {/*** 卡片跳转类型,1 代表跳转url,2 代表打开小程序。news_notice模版卡片中该字段取值范围为[1,2]*/private final Integer type;/*** 跳转事件的url,card_action.type是1时必填*/private final String url;/*** 跳转事件的小程序的appid,card_action.type是2时必填*/private final String appid;/*** 跳转事件的小程序的pagepath,card_action.type是2时选填*/private final String pagepath;private CardAction(Integer type, String url, String appid, String pagepath) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;CardAction that = (CardAction) o;return Objects.equals(type, that.type) &&Objects.equals(url, that.url) &&Objects.equals(appid, that.appid) &&Objects.equals(pagepath, that.pagepath);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath);}@Overridepublic String toString() {return "CardAction{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +'}';}// Builderpublic static class Builder {private Integer type;private String url;private String appid;private String pagepath;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public CardAction build() {return new CardAction(type, url, appid, pagepath);}}public static Builder builder() {return new Builder();}}public static void main(String[] args) {// 创建简单的图文展示模版卡片WebhookTemplateCardNewsNoticeBody.MainTitle mainTitle = WebhookTemplateCardNewsNoticeBody.MainTitle.builder().title("欢迎使用企业微信").desc("您的好友正在邀请您加入企业微信").build();WebhookTemplateCardNewsNoticeBody.CardImage cardImage = WebhookTemplateCardNewsNoticeBody.CardImage.builder().url("https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0").aspect_ratio(2.25f).build();WebhookTemplateCardNewsNoticeBody.CardAction cardAction = WebhookTemplateCardNewsNoticeBody.CardAction.builder().type(1).url("https://work.weixin.qq.com/?from=openApi").build();WebhookTemplateCardNewsNoticeBody simpleCard = WebhookTemplateCardNewsNoticeBody.create(mainTitle, cardImage, cardAction);// 创建复杂的图文展示模版卡片WebhookTemplateCardNewsNoticeBody.Source source = WebhookTemplateCardNewsNoticeBody.Source.builder().icon_url("https://wework.qpic.cn/wwpic/252813_jOfDHtcISzuodLa_1629280209/0").desc("企业微信").desc_color(0).build();WebhookTemplateCardNewsNoticeBody.ImageTextArea imageTextArea = WebhookTemplateCardNewsNoticeBody.ImageTextArea.builder().type(1).url("https://work.weixin.qq.com").title("欢迎使用企业微信").desc("您的好友正在邀请您加入企业微信").image_url("https://wework.qpic.cn/wwpic/354393_4zpkKXd7SrGMvfg_1629280616/0").build();WebhookTemplateCardNewsNoticeBody.QuoteArea quoteArea = WebhookTemplateCardNewsNoticeBody.QuoteArea.builder().type(1).url("https://work.weixin.qq.com/?from=openApi").title("引用文本标题").quote_text("Jack:企业微信真的很好用~\nBalian:超级好的一款软件!").build();List<VerticalContent> verticalContents = Arrays.asList(WebhookTemplateCardNewsNoticeBody.VerticalContent.builder().title("惊喜红包等你来拿").desc("下载企业微信还能抢红包!").build());List<HorizontalContent> horizontalContents = Arrays.asList(WebhookTemplateCardNewsNoticeBody.HorizontalContent.builder().keyname("邀请人").value("张三").build(),WebhookTemplateCardNewsNoticeBody.HorizontalContent.builder().type(1).keyname("企微官网").value("点击访问").url("https://work.weixin.qq.com/?from=openApi").build(),WebhookTemplateCardNewsNoticeBody.HorizontalContent.builder().type(2).keyname("企微下载").value("企业微信.apk").media_id("38Kz4vLCb49gfGvfOPw_y2f4nrik8lA_1xqNFmIzhtgkZVBoLoEYDQ7WopEKGnCTG").build());List<JumpItem> jumpList = Arrays.asList(WebhookTemplateCardNewsNoticeBody.JumpItem.builder().type(1).title("企业微信官网").url("https://work.weixin.qq.com/?from=openApi").build(),WebhookTemplateCardNewsNoticeBody.JumpItem.builder().type(2).title("跳转小程序").appid("APPID").pagepath("PAGEPATH").build());WebhookTemplateCardNewsNoticeBody complexCard = WebhookTemplateCardNewsNoticeBody.builder().source(source).mainTitle(mainTitle).cardImage(cardImage).imageTextArea(imageTextArea).quoteArea(quoteArea).verticalContentList(verticalContents).horizontalContentList(horizontalContents).jumpList(jumpList).cardAction(cardAction).build();System.out.println(complexCard);}
}
import java.util.Arrays;
import java.util.List;
import java.util.Objects;/*** 文本通知模版卡片消息体*/
public class WebhookTemplateCardTextNoticeBody extends WebhookBody {private final TemplateCard template_card;private WebhookTemplateCardTextNoticeBody(TemplateCard templateCard) {super("template_card");this.template_card = templateCard;}public TemplateCard getTemplate_card() {return template_card;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;if (!super.equals(o)) return false;WebhookTemplateCardTextNoticeBody that = (WebhookTemplateCardTextNoticeBody) o;return Objects.equals(template_card, that.template_card);}@Overridepublic int hashCode() {return Objects.hash(super.hashCode(), template_card);}@Overridepublic String toString() {return "WebhookTemplateCardTextNoticeBody(super=" + super.toString() +", template_card=" + template_card + ")";}/*** 创建文本通知模版卡片消息* @param mainTitle 主标题* @param cardAction 卡片点击动作* @return 消息体*/public static WebhookTemplateCardTextNoticeBody create(MainTitle mainTitle, CardAction cardAction) {return builder().cardType("text_notice").mainTitle(mainTitle).cardAction(cardAction).build();}/*** 创建构建器*/public static TemplateCardBuilder builder() {return new TemplateCardBuilder();}/*** 模版卡片构建器*/public static class TemplateCardBuilder {private String cardType = "text_notice";private Source source;private MainTitle mainTitle;private EmphasisContent emphasisContent;private QuoteArea quoteArea;private String subTitleText;private List<HorizontalContent> horizontalContentList;private List<JumpItem> jumpList;private CardAction cardAction;public TemplateCardBuilder cardType(String cardType) {this.cardType = cardType;return this;}public TemplateCardBuilder source(Source source) {this.source = source;return this;}public TemplateCardBuilder mainTitle(MainTitle mainTitle) {this.mainTitle = mainTitle;return this;}public TemplateCardBuilder emphasisContent(EmphasisContent emphasisContent) {this.emphasisContent = emphasisContent;return this;}public TemplateCardBuilder quoteArea(QuoteArea quoteArea) {this.quoteArea = quoteArea;return this;}public TemplateCardBuilder subTitleText(String subTitleText) {this.subTitleText = subTitleText;return this;}public TemplateCardBuilder horizontalContentList(List<HorizontalContent> horizontalContentList) {this.horizontalContentList = horizontalContentList;return this;}public TemplateCardBuilder jumpList(List<JumpItem> jumpList) {this.jumpList = jumpList;return this;}public TemplateCardBuilder cardAction(CardAction cardAction) {this.cardAction = cardAction;return this;}/*** 构建模版卡片消息* 校验:main_title.title和sub_title_text必须有一项填写*/public WebhookTemplateCardTextNoticeBody build() {// 校验必填条件if (mainTitle == null || (mainTitle.getTitle() == null && subTitleText == null)) {throw new IllegalArgumentException("main_title.title和sub_title_text必须有一项填写");}if (cardAction == null) {throw new IllegalArgumentException("text_notice模版卡片中card_action为必填项");}TemplateCard templateCard = new TemplateCard(cardType, source, mainTitle, emphasisContent, quoteArea,subTitleText, horizontalContentList, jumpList, cardAction);return new WebhookTemplateCardTextNoticeBody(templateCard);}}/*** 模版卡片*/public static class TemplateCard {/*** 模版卡片的模版类型,文本通知模版卡片的类型为text_notice*/private final String card_type;/*** 卡片来源样式信息,不需要来源样式可不填写*/private final Source source;/*** 模版卡片的主要内容,包括一级标题和标题辅助信息*/private final MainTitle main_title;/*** 关键数据样式*/private final EmphasisContent emphasis_content;/*** 引用文献样式,建议不与关键数据共用*/private final QuoteArea quote_area;/*** 二级普通文本,建议不超过112个字。模版卡片主要内容的一级标题main_title.title和二级普通文本sub_title_text必须有一项填写*/private final String sub_title_text;/*** 二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6*/private final List<HorizontalContent> horizontal_content_list;/*** 跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3*/private final List<JumpItem> jump_list;/*** 整体卡片的点击跳转事件,text_notice模版卡片中该字段为必填项*/private final CardAction card_action;public TemplateCard(String card_type, Source source, MainTitle main_title,EmphasisContent emphasis_content, QuoteArea quote_area,String sub_title_text, List<HorizontalContent> horizontal_content_list,List<JumpItem> jump_list, CardAction card_action) {this.card_type = card_type;this.source = source;this.main_title = main_title;this.emphasis_content = emphasis_content;this.quote_area = quote_area;this.sub_title_text = sub_title_text;this.horizontal_content_list = horizontal_content_list;this.jump_list = jump_list;this.card_action = card_action;}// Getterspublic String getCard_type() { return card_type; }public Source getSource() { return source; }public MainTitle getMain_title() { return main_title; }public EmphasisContent getEmphasis_content() { return emphasis_content; }public QuoteArea getQuote_area() { return quote_area; }public String getSub_title_text() { return sub_title_text; }public List<HorizontalContent> getHorizontal_content_list() { return horizontal_content_list; }public List<JumpItem> getJump_list() { return jump_list; }public CardAction getCard_action() { return card_action; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;TemplateCard that = (TemplateCard) o;return Objects.equals(card_type, that.card_type) &&Objects.equals(source, that.source) &&Objects.equals(main_title, that.main_title) &&Objects.equals(emphasis_content, that.emphasis_content) &&Objects.equals(quote_area, that.quote_area) &&Objects.equals(sub_title_text, that.sub_title_text) &&Objects.equals(horizontal_content_list, that.horizontal_content_list) &&Objects.equals(jump_list, that.jump_list) &&Objects.equals(card_action, that.card_action);}@Overridepublic int hashCode() {return Objects.hash(card_type, source, main_title, emphasis_content, quote_area,sub_title_text, horizontal_content_list, jump_list, card_action);}@Overridepublic String toString() {return "TemplateCard{" +"card_type='" + card_type + '\'' +", source=" + source +", main_title=" + main_title +", emphasis_content=" + emphasis_content +", quote_area=" + quote_area +", sub_title_text='" + sub_title_text + '\'' +", horizontal_content_list=" + horizontal_content_list +", jump_list=" + jump_list +", card_action=" + card_action +'}';}}/*** 卡片来源样式信息*/public static class Source {/*** 来源图片的url*/private final String icon_url;/*** 来源图片的描述,建议不超过13个字*/private final String desc;/*** 来源文字的颜色,目前支持:0(默认) 灰色,1 黑色,2 红色,3 绿色*/private final Integer desc_color;private Source(String icon_url, String desc, Integer desc_color) {this.icon_url = icon_url;this.desc = desc;this.desc_color = desc_color;}// Getterspublic String getIcon_url() { return icon_url; }public String getDesc() { return desc; }public Integer getDesc_color() { return desc_color; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Source source = (Source) o;return Objects.equals(icon_url, source.icon_url) &&Objects.equals(desc, source.desc) &&Objects.equals(desc_color, source.desc_color);}@Overridepublic int hashCode() {return Objects.hash(icon_url, desc, desc_color);}@Overridepublic String toString() {return "Source{" +"icon_url='" + icon_url + '\'' +", desc='" + desc + '\'' +", desc_color=" + desc_color +'}';}// Builderpublic static class Builder {private String icon_url;private String desc;private Integer desc_color = 0;public Builder icon_url(String icon_url) {this.icon_url = icon_url;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public Builder desc_color(Integer desc_color) {this.desc_color = desc_color;return this;}public Source build() {return new Source(icon_url, desc, desc_color);}}public static Builder builder() {return new Builder();}}/*** 模版卡片的主要内容*/public static class MainTitle {/*** 一级标题,建议不超过26个字。模版卡片主要内容的一级标题main_title.title和二级普通文本sub_title_text必须有一项填写*/private final String title;/*** 标题辅助信息,建议不超过30个字*/private final String desc;private MainTitle(String title, String desc) {this.title = title;this.desc = desc;}// Getterspublic String getTitle() { return title; }public String getDesc() { return desc; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;MainTitle mainTitle = (MainTitle) o;return Objects.equals(title, mainTitle.title) &&Objects.equals(desc, mainTitle.desc);}@Overridepublic int hashCode() {return Objects.hash(title, desc);}@Overridepublic String toString() {return "MainTitle{" +"title='" + title + '\'' +", desc='" + desc + '\'' +'}';}// Builderpublic static class Builder {private String title;private String desc;public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public MainTitle build() {return new MainTitle(title, desc);}}public static Builder builder() {return new Builder();}}/*** 关键数据样式*/public static class EmphasisContent {/*** 关键数据样式的数据内容,建议不超过10个字*/private final String title;/*** 关键数据样式的数据描述内容,建议不超过15个字*/private final String desc;private EmphasisContent(String title, String desc) {this.title = title;this.desc = desc;}// Getterspublic String getTitle() { return title; }public String getDesc() { return desc; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;EmphasisContent that = (EmphasisContent) o;return Objects.equals(title, that.title) &&Objects.equals(desc, that.desc);}@Overridepublic int hashCode() {return Objects.hash(title, desc);}@Overridepublic String toString() {return "EmphasisContent{" +"title='" + title + '\'' +", desc='" + desc + '\'' +'}';}// Builderpublic static class Builder {private String title;private String desc;public Builder title(String title) {this.title = title;return this;}public Builder desc(String desc) {this.desc = desc;return this;}public EmphasisContent build() {return new EmphasisContent(title, desc);}}public static Builder builder() {return new Builder();}}/*** 引用文献样式*/public static class QuoteArea {/*** 引用文献样式区域点击事件,0或不填代表没有点击事件,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 点击跳转的url,quote_area.type是1时必填*/private final String url;/*** 点击跳转的小程序的appid,quote_area.type是2时必填*/private final String appid;/*** 点击跳转的小程序的pagepath,quote_area.type是2时选填*/private final String pagepath;/*** 引用文献样式的标题*/private final String title;/*** 引用文献样式的引用文案*/private final String quote_text;private QuoteArea(Integer type, String url, String appid, String pagepath,String title, String quote_text) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;this.title = title;this.quote_text = quote_text;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }public String getTitle() { return title; }public String getQuote_text() { return quote_text; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;QuoteArea quoteArea = (QuoteArea) o;return Objects.equals(type, quoteArea.type) &&Objects.equals(url, quoteArea.url) &&Objects.equals(appid, quoteArea.appid) &&Objects.equals(pagepath, quoteArea.pagepath) &&Objects.equals(title, quoteArea.title) &&Objects.equals(quote_text, quoteArea.quote_text);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath, title, quote_text);}@Overridepublic String toString() {return "QuoteArea{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +", title='" + title + '\'' +", quote_text='" + quote_text + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String url;private String appid;private String pagepath;private String title;private String quote_text;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public Builder title(String title) {this.title = title;return this;}public Builder quote_text(String quote_text) {this.quote_text = quote_text;return this;}public QuoteArea build() {return new QuoteArea(type, url, appid, pagepath, title, quote_text);}}public static Builder builder() {return new Builder();}}/*** 水平内容列表项*/public static class HorizontalContent {/*** 模版卡片的二级标题信息内容支持的类型,1是url,2是文件附件,3 代表点击跳转成员详情*/private final Integer type;/*** 二级标题,建议不超过5个字*/private final String keyname;/*** 二级文本,如果horizontal_content_list.type是2,该字段代表文件名称(要包含文件类型),建议不超过26个字*/private final String value;/*** 链接跳转的url,horizontal_content_list.type是1时必填*/private final String url;/*** 附件的media_id,horizontal_content_list.type是2时必填*/private final String media_id;/*** 成员详情的userid,horizontal_content_list.type是3时必填*/private final String userid;private HorizontalContent(Integer type, String keyname, String value,String url, String media_id, String userid) {this.type = type;this.keyname = keyname;this.value = value;this.url = url;this.media_id = media_id;this.userid = userid;}// Getterspublic Integer getType() { return type; }public String getKeyname() { return keyname; }public String getValue() { return value; }public String getUrl() { return url; }public String getMedia_id() { return media_id; }public String getUserid() { return userid; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;HorizontalContent that = (HorizontalContent) o;return Objects.equals(type, that.type) &&Objects.equals(keyname, that.keyname) &&Objects.equals(value, that.value) &&Objects.equals(url, that.url) &&Objects.equals(media_id, that.media_id) &&Objects.equals(userid, that.userid);}@Overridepublic int hashCode() {return Objects.hash(type, keyname, value, url, media_id, userid);}@Overridepublic String toString() {return "HorizontalContent{" +"type=" + type +", keyname='" + keyname + '\'' +", value='" + value + '\'' +", url='" + url + '\'' +", media_id='" + media_id + '\'' +", userid='" + userid + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String keyname;private String value;private String url;private String media_id;private String userid;public Builder type(Integer type) {this.type = type;return this;}public Builder keyname(String keyname) {this.keyname = keyname;return this;}public Builder value(String value) {this.value = value;return this;}public Builder url(String url) {this.url = url;return this;}public Builder media_id(String media_id) {this.media_id = media_id;return this;}public Builder userid(String userid) {this.userid = userid;return this;}public HorizontalContent build() {return new HorizontalContent(type, keyname, value, url, media_id, userid);}}public static Builder builder() {return new Builder();}}/*** 跳转指引项*/public static class JumpItem {/*** 跳转链接类型,0或不填代表不是链接,1 代表跳转url,2 代表跳转小程序*/private final Integer type;/*** 跳转链接样式的文案内容,建议不超过13个字*/private final String title;/*** 跳转链接的url,jump_list.type是1时必填*/private final String url;/*** 跳转链接的小程序的appid,jump_list.type是2时必填*/private final String appid;/*** 跳转链接的小程序的pagepath,jump_list.type是2时选填*/private final String pagepath;private JumpItem(Integer type, String title, String url, String appid, String pagepath) {this.type = type;this.title = title;this.url = url;this.appid = appid;this.pagepath = pagepath;}// Getterspublic Integer getType() { return type; }public String getTitle() { return title; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;JumpItem jumpItem = (JumpItem) o;return Objects.equals(type, jumpItem.type) &&Objects.equals(title, jumpItem.title) &&Objects.equals(url, jumpItem.url) &&Objects.equals(appid, jumpItem.appid) &&Objects.equals(pagepath, jumpItem.pagepath);}@Overridepublic int hashCode() {return Objects.hash(type, title, url, appid, pagepath);}@Overridepublic String toString() {return "JumpItem{" +"type=" + type +", title='" + title + '\'' +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +'}';}// Builderpublic static class Builder {private Integer type = 0;private String title;private String url;private String appid;private String pagepath;public Builder type(Integer type) {this.type = type;return this;}public Builder title(String title) {this.title = title;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public JumpItem build() {return new JumpItem(type, title, url, appid, pagepath);}}public static Builder builder() {return new Builder();}}/*** 卡片点击动作*/public static class CardAction {/*** 卡片跳转类型,1 代表跳转url,2 代表打开小程序。text_notice模版卡片中该字段取值范围为[1,2]*/private final Integer type;/*** 跳转事件的url,card_action.type是1时必填*/private final String url;/*** 跳转事件的小程序的appid,card_action.type是2时必填*/private final String appid;/*** 跳转事件的小程序的pagepath,card_action.type是2时选填*/private final String pagepath;private CardAction(Integer type, String url, String appid, String pagepath) {this.type = type;this.url = url;this.appid = appid;this.pagepath = pagepath;}// Getterspublic Integer getType() { return type; }public String getUrl() { return url; }public String getAppid() { return appid; }public String getPagepath() { return pagepath; }@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;CardAction that = (CardAction) o;return Objects.equals(type, that.type) &&Objects.equals(url, that.url) &&Objects.equals(appid, that.appid) &&Objects.equals(pagepath, that.pagepath);}@Overridepublic int hashCode() {return Objects.hash(type, url, appid, pagepath);}@Overridepublic String toString() {return "CardAction{" +"type=" + type +", url='" + url + '\'' +", appid='" + appid + '\'' +", pagepath='" + pagepath + '\'' +'}';}// Builderpublic static class Builder {private Integer type;private String url;private String appid;private String pagepath;public Builder type(Integer type) {this.type = type;return this;}public Builder url(String url) {this.url = url;return this;}public Builder appid(String appid) {this.appid = appid;return this;}public Builder pagepath(String pagepath) {this.pagepath = pagepath;return this;}public CardAction build() {return new CardAction(type, url, appid, pagepath);}}public static Builder builder() {return new Builder();}}// 创建复杂的文本通知模public static void main(String[] args) {// 创建简单的文本通知模版卡片WebhookTemplateCardTextNoticeBody.MainTitle mainTitle = WebhookTemplateCardTextNoticeBody.MainTitle.builder().title("欢迎使用企业微信").desc("您的好友正在邀请您加入企业微信").build();WebhookTemplateCardTextNoticeBody.CardAction cardAction = WebhookTemplateCardTextNoticeBody.CardAction.builder().type(1).url("https://work.weixin.qq.com/?from=openApi").build();WebhookTemplateCardTextNoticeBody simpleCard = WebhookTemplateCardTextNoticeBody.create(mainTitle, cardAction);// 创建复杂的文本通知模版卡片WebhookTemplateCardTextNoticeBody.Source source = WebhookTemplateCardTextNoticeBody.Source.builder().icon_url("https://wework.qpic.cn/wwpic/252813_jOfDHtcISzuodLa_1629280209/0").desc("企业微信").desc_color(0).build();WebhookTemplateCardTextNoticeBody.EmphasisContent emphasisContent = WebhookTemplateCardTextNoticeBody.EmphasisContent.builder().title("100").desc("数据含义").build();WebhookTemplateCardTextNoticeBody.QuoteArea quoteArea = WebhookTemplateCardTextNoticeBody.QuoteArea.builder().type(1).url("https://work.weixin.qq.com/?from=openApi").title("引用文本标题").quote_text("Jack:企业微信真的很好用~\nBalian:超级好的一款软件!").build();List<HorizontalContent> horizontalContents = Arrays.asList(WebhookTemplateCardTextNoticeBody.HorizontalContent.builder().keyname("邀请人").value("张三").build(),WebhookTemplateCardTextNoticeBody.HorizontalContent.builder().type(1).keyname("企微官网").value("点击访问").url("https://work.weixin.qq.com/?from=openApi").build(),WebhookTemplateCardTextNoticeBody.HorizontalContent.builder().type(2).keyname("企微下载").value("企业微信.apk").media_id("38Kz4vLCb49gfGvfOPw_y2f4nrik8lA_1xqNFmIzhtgkZVBoLoEYDQ7WopEKGnCTG").build());// WebhookUploadMediaResponse{errcode=0, errmsg='ok', type='file', media_id='38Kz4vLCb49gfGvfOPw_y2f4nrik8lA_1xqNFmIzhtgkZVBoLoEYDQ7WopEKGnCTG', created_at='1761102339'}List<JumpItem> jumpList = Arrays.asList(WebhookTemplateCardTextNoticeBody.JumpItem.builder().type(1).title("企业微信官网").url("https://work.weixin.qq.com/?from=openApi").build()
// WebhookTemplateCardTextNoticeBody.JumpItem.builder()
// .type(2)
// .title("跳转小程序")
// .appid("APPID")
// .pagepath("PAGEPATH")
// .build());WebhookTemplateCardTextNoticeBody complexCard = WebhookTemplateCardTextNoticeBody.builder().source(source).mainTitle(mainTitle).emphasisContent(emphasisContent).quoteArea(quoteArea).subTitleText("下载企业微信还能抢红包!").horizontalContentList(horizontalContents).jumpList(jumpList).cardAction(cardAction).build();System.out.println(complexCard);}}
/*** 文本类型*/
public class WebhookTextBody extends WebhookBody {private final WebhookText text;WebhookTextBody(WebhookText text) {super("text");this.text = text;}public WebhookText getText() {return text;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;if (!super.equals(o)) return false;WebhookTextBody that = (WebhookTextBody) o;return Objects.equals(text, that.text);}@Overridepublic int hashCode() {return Objects.hash(super.hashCode(), text);}@Overridepublic String toString() {return "WebhookTextBody(super=" + super.toString() + ", text=" + text + ")";}/*** 传入文本* @param content 文本内容* @return*/public static WebhookTextBody from(String content) {return from(content, null);}/*** 传入文本* @param content 文本内容* @param mentionedMobileList 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人* @return*/public static WebhookTextBody from(String content, List<String> mentionedMobileList) {return from(content, null, mentionedMobileList);}/*** 传入文本* @param content 文本内容* @param mentionedList userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人,如果开发者获取不到userid,可以使用mentioned_mobile_list* @param mentionedMobileList 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人* @return*/public static WebhookTextBody from(String content, List<String> mentionedList, List<String> mentionedMobileList) {WebhookText webhookText = new WebhookText(content);webhookText.setMentioned_list(mentionedList);webhookText.setMentioned_mobile_list(mentionedMobileList);return new WebhookTextBody(webhookText);}/*** 文本类型*/public static class WebhookText {/*** 文本内容,最长不超过2048个字节,必须是utf8编码*/private final String content;/*** userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人,如果开发者获取不到userid,可以使用mentioned_mobile_list*/private List<String> mentioned_list;/*** 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人*/private List<String> mentioned_mobile_list;public WebhookText(String content) {this.content = content;}// Getterspublic String getContent() {return content;}public List<String> getMentioned_list() {return mentioned_list;}public List<String> getMentioned_mobile_list() {return mentioned_mobile_list;}// Setterspublic void setMentioned_list(List<String> mentioned_list) {this.mentioned_list = mentioned_list;}public void setMentioned_mobile_list(List<String> mentioned_mobile_list) {this.mentioned_mobile_list = mentioned_mobile_list;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;WebhookText that = (WebhookText) o;return Objects.equals(content, that.content) &&Objects.equals(mentioned_list, that.mentioned_list) &&Objects.equals(mentioned_mobile_list, that.mentioned_mobile_list);}@Overridepublic int hashCode() {return Objects.hash(content, mentioned_list, mentioned_mobile_list);}@Overridepublic String toString() {return "WebhookText{" +"content='" + content + '\'' +", mentioned_list=" + mentioned_list +", mentioned_mobile_list=" + mentioned_mobile_list +'}';}}
}
public class WebhookUploadMediaResponse extends WebhookResponse{private Integer errcode;private String errmsg;private String type;private String media_id;private String created_at;public WebhookUploadMediaResponse(){}public WebhookUploadMediaResponse(Integer errcode, String errmsg, String type, String media_id, String created_at) {this.errcode = errcode;this.errmsg = errmsg;this.type = type;this.media_id = media_id;this.created_at = created_at;}public String getMedia_id() {return media_id;}public void setMedia_id(String media_id) {this.media_id = media_id;}public String getType() {return type;}public void setType(String type) {this.type = type;}public String getCreated_at() {return created_at;}public void setCreated_at(String created_at) {this.created_at = created_at;}@Overridepublic String toString() {return "WebhookUploadMediaResponse{" +"errcode=" + errcode +", errmsg='" + errmsg + '\'' +", type='" + type + '\'' +", media_id='" + media_id + '\'' +", created_at='" + created_at + '\'' +'}';}}
/*** 语音类型消息体*/
public class WebhookVoiceBody extends WebhookBody {private final WebhookVoice voice;private WebhookVoiceBody(WebhookVoice voice) {super("voice");this.voice = voice;}public WebhookVoice getVoice() {return voice;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;if (!super.equals(o)) return false;WebhookVoiceBody that = (WebhookVoiceBody) o;return Objects.equals(voice, that.voice);}@Overridepublic int hashCode() {return Objects.hash(super.hashCode(), voice);}@Overridepublic String toString() {return "WebhookVoiceBody(super=" + super.toString() +", voice=" + voice + ")";}/*** 创建语音消息* @param mediaId 语音文件id,通过文件上传接口获取*/public static WebhookVoiceBody from(String mediaId) {if (mediaId == null || mediaId.trim().isEmpty()) {throw new IllegalArgumentException("mediaId不能为空");}return new WebhookVoiceBody(new WebhookVoice(mediaId));}/*** 语音消息内容*/public static class WebhookVoice {/*** 语音文件id,通过下文的文件上传接口获取*/private final String media_id;public WebhookVoice(String media_id) {this.media_id = media_id;}public String getMedia_id() {return media_id;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;WebhookVoice that = (WebhookVoice) o;return Objects.equals(media_id, that.media_id);}@Overridepublic int hashCode() {return Objects.hash(media_id);}@Overridepublic String toString() {return "WebhookVoice(media_id=" + media_id + ")";}}
}
上面定义了接口
下面是具体的实现类
<dependencies><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version></dependency><!-- httpclient http客户端--><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.13</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><!-- https://www.xuxueli.com/xxl-tool/# --><dependency><groupId>com.xuxueli</groupId><artifactId>xxl-tool</artifactId><version>1.5.1</version></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><!-- 推荐使用 2.10.1(截至2025年稳定版本) --><version>2.10.1</version></dependency></dependencies>
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.TimeUnit;public class RestClient {private RestClient() {}private final static Logger log = LoggerFactory.getLogger(RestClient.class);/*** 建立连接时间*/private static final int CONNECTION_TIME = 3000;/*** 发送请求时间*/private static final int CONNECTION_REQUEST_TIME = 30000;/*** 读取数据时间*/private static final int SOCKET_TIME = 180000;/*** 重试次数*/private static final int RETRY = 3;/*** 连接池最大连接数*/private static final int MAX_TOTAL = 100;/*** 最大路由*/private static final int MAX_PER_ROUTE = 5;// 它是线程安全的,所有的线程都可以使用它一起发送http请求private static final CloseableHttpClient httpClient;public static CloseableHttpClient getHttpClient() {return httpClient;}static {log.info("初始化HttpClientTest~~~开始");httpClient = getConnection();log.info("初始化HttpClientTest~~~结束");}static class miTM implements TrustManager, X509TrustManager {@Overridepublic X509Certificate[] getAcceptedIssuers() {return null;}@Overridepublic void checkServerTrusted(X509Certificate[] certs, String authType) {//don't check}@Overridepublic void checkClientTrusted(X509Certificate[] certs, String authType) {//don't check}}private static SSLConnectionSocketFactory trustAllHttpsCertificates() {SSLConnectionSocketFactory socketFactory = null;TrustManager[] trustAllCerts = new TrustManager[1];TrustManager tm = new miTM();trustAllCerts[0] = tm;SSLContext sc = null;try {sc = SSLContext.getInstance("TLS");sc.init(null, trustAllCerts, null);socketFactory = new SSLConnectionSocketFactory(sc, NoopHostnameVerifier.INSTANCE);// HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();}return socketFactory;}/*** 忽略证书验证的CloseableHttpClient对象,适配Http/Https** @return CloseableHttpClient*/public static CloseableHttpClient getConnection() {CloseableHttpClient closeableHttpClient = null;try {closeableHttpClient = HttpClients.custom()// 设置超时时间.setDefaultRequestConfig(getRequestConfig())// 设置连接池.setConnectionManager(getPoolingManager())// 设置重试策略,框架层面重试,可以在业务层面重试//.setRetryHandler(getRetryHandler()).setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))// 连接池清理过期连接.evictExpiredConnections()// 连接池释放空闲连接.evictIdleConnections(60, TimeUnit.SECONDS).build();} catch (KeyManagementException e) {log.error("KeyManagement error", e);} catch (NoSuchAlgorithmException e) {log.error("No Such Algorithm error", e);}return closeableHttpClient;}/*** HTTP Post:Form表单方式* Content-type:application/x-www-form-urlencoded; charset=UTF-8** @param url 请求的url地址* @param headerMap 请求头的参数* @param params 请求的参数*/public static String postToJson(String url, String params, Map<String, String> headerMap) {// 创建Post请求HttpPost httpPost = new HttpPost(url);// post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中httpPost.setEntity(new StringEntity(params, StandardCharsets.UTF_8));httpPost.setHeader("Content-Type", "application/json;charset=utf8");for (Map.Entry<String, String> entry : headerMap.entrySet()) {httpPost.setHeader(entry.getKey(), entry.getValue());}try (CloseableHttpResponse response = getHttpClient().execute(httpPost)) {HttpEntity responseEntity = response.getEntity();if (responseEntity != null) {return EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);}return null;} catch (IOException e) {log.error( "request failure! error {}", e.getMessage());throw new RuntimeException("request failure! error " + e.getMessage());}}public static String getStringFromStream(final InputStreamReader isr) throws Exception{final BufferedReader br = new BufferedReader(isr);final StringBuilder sb = new StringBuilder();String tmp;while((tmp = br.readLine())!=null){sb.append(tmp);sb.append("\r\n");}br.close();isr.close();return sb.toString();}public static byte[] postToJsonToByte(String url, String params, Map<String, String> headerMap) {// 创建Post请求HttpPost httpPost = new HttpPost(url);// post请求是将参数放在请求体里面传过去的;这里将entity放入post请求体中httpPost.setEntity(new StringEntity(params, StandardCharsets.UTF_8));httpPost.setHeader("Content-Type", "application/json;charset=utf8");for (Map.Entry<String, String> entry : headerMap.entrySet()) {httpPost.setHeader(entry.getKey(), entry.getValue());}try (CloseableHttpResponse response = getHttpClient().execute(httpPost)) {HttpEntity responseEntity = response.getEntity();if (responseEntity != null) {return EntityUtils.toByteArray(responseEntity);}return null;} catch (IOException e) {log.error( "request failure! error {}", e.getMessage());throw new RuntimeException("request failure! error " + e.getMessage());}}/*** 发送 multipart/form-data 请求* @param url 请求地址* @param params 请求参数* @param headerMap 请求头* @param file 文件* @return*/public static String postToFormData(String url, Map<String, String> params, Map<String, String> headerMap,File file) {HttpPost httpPost = new HttpPost(url);MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();String filesKey = "file";// (多个文件的话,使用同一个key就行,后端用数组或集合进行接收即可)// 文件名其实是放在请求头的Content-Disposition里面进行传输的,如其值为form-data; name="files"; filename="头像.jpg"multipartEntityBuilder.addBinaryBody(filesKey, file, ContentType.DEFAULT_BINARY, encode(file.getName()));// 其它参数(注:自定义contentType,设置UTF-8是为了防止服务端拿到的参数出现乱码)ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);for (Map.Entry<String, String> entry : params.entrySet()) {multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue(), contentType);}HttpEntity httpEntity = multipartEntityBuilder.build();httpPost.setEntity(httpEntity);for (Map.Entry<String, String> entry : headerMap.entrySet()) {httpPost.setHeader(entry.getKey(), entry.getValue());}try (CloseableHttpResponse response = getHttpClient().execute(httpPost)) {HttpEntity responseEntity = response.getEntity();if (responseEntity != null) {return EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);}return null;} catch (IOException e) {throw new RuntimeException("request failure! error " + e.getMessage());}}/*** 发送 multipart/form-data 请求* @param url 请求地址* @param params 请求参数* @param headerMap 请求头* @return*/public static String postToFormData(String url, Map<String, String> params, Map<String, String> headerMap) {HttpPost httpPost = new HttpPost(url);MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();// 其它参数(注:自定义contentType,设置UTF-8是为了防止服务端拿到的参数出现乱码)ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);for (Map.Entry<String, String> entry : params.entrySet()) {multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue(), contentType);}HttpEntity httpEntity = multipartEntityBuilder.build();httpPost.setEntity(httpEntity);for (Map.Entry<String, String> entry : headerMap.entrySet()) {httpPost.setHeader(entry.getKey(), entry.getValue());}try (CloseableHttpResponse response = getHttpClient().execute(httpPost)) {HttpEntity responseEntity = response.getEntity();if (responseEntity != null) {return EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);}return null;} catch (IOException e) {throw new RuntimeException("request failure! error " + e.getMessage());}}public static String encode(String str) {String encode = null;try {encode = URLEncoder.encode(str, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return encode;}/*** Http连接池配置** @return HttpClientConnectionManager*/public static HttpClientConnectionManager getPoolingManager() throws NoSuchAlgorithmException, KeyManagementException {Registry<ConnectionSocketFactory> socketFactoryRegistry =RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.INSTANCE).register("https", trustAllHttpsCertificates()).build();PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);// 设置整个连接池最大连接数connectionManager.setMaxTotal(MAX_TOTAL);// 最大路由connectionManager.setDefaultMaxPerRoute(MAX_PER_ROUTE);return connectionManager;}/*** 封装RequestConfig** @return RequestConfig*/public static RequestConfig getRequestConfig() {return RequestConfig.custom().setConnectTimeout(getConnectionTime()).setConnectionRequestTimeout(getConnectionRequestTime()).setSocketTimeout(getSocketTime()).build();}/*** HttpClient的重试策略** @return HttpRequestRetryHandler*/public static HttpRequestRetryHandler getRetryHandler() {HttpRequestRetryHandler retryHandler = (exception, executionCount, context) -> {// 重试三次if (executionCount >= RETRY) {return false;}if (exception instanceof InterruptedIOException) {// 超时return false;}if (exception instanceof UnknownHostException) {// 目标服务器不可达return false;}if (exception instanceof SSLException) {// SSL握手异常return false;}HttpClientContext clientContext = HttpClientContext.adapt(context);HttpRequest request = clientContext.getRequest();boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);if (idempotent) {// 如果请求是幂等的,就再次尝试return true;}return false;};return retryHandler;}public static Integer getConnectionTime() {return CONNECTION_TIME;}public static Integer getConnectionRequestTime() {return CONNECTION_REQUEST_TIME;}public static Integer getSocketTime() {return SOCKET_TIME;}/*** 校验url,支持扩展** @param url*/private static void checkUrl(String url) {if (StringUtils.isBlank(url)) {log.error("rest client request url not null");throw new RuntimeException("rest client request url not null");}}/*** 关闭流资源** @param closeable*/private static void close(Closeable closeable) {try {closeable.close();} catch (IOException e) {log.error("close error", e);}}}
import com.fjdci.sdk.wechat.webhook.api.dto.WebhookBody;
import com.fjdci.sdk.wechat.webhook.api.dto.WebhookResponse;
import com.fjdci.sdk.wechat.webhook.api.dto.WebhookUploadMediaResponse;
import com.fjdci.sdk.wechat.webhook.api.service.WxWebHookHttpClient;
import com.xxl.tool.gson.GsonTool;import java.io.File;
import java.util.HashMap;
import java.util.Map;public class defaultWxWebHookHttpClient implements WxWebHookHttpClient {private String webhookurl;public defaultWxWebHookHttpClient(String webhookurl) {this.webhookurl = webhookurl;}/*** 消息推送* @param robotId 机器人key* @param body 请求参数体* @return*/@Overridepublic WebhookResponse send(String robotId, WebhookBody body) {String sendUrl = webhookurl + "/send?key=" + robotId;String params = GsonTool.toJson(body);Map<String, String> headerMap = new HashMap<>();String resJson = RestClient.postToJson(sendUrl, params, headerMap);return GsonTool.fromJson(resJson, WebhookResponse.class);}/*** 消息推送* @param robotId 机器人key* @param jsonParam 请求参数JSON* @return*/@Overridepublic WebhookResponse send(String robotId, String jsonParam) {String sendUrl = webhookurl + "/send?key=" + robotId;Map<String, String> headerMap = new HashMap<>();String resJson = RestClient.postToJson(sendUrl, jsonParam, headerMap);return GsonTool.fromJson(resJson, WebhookResponse.class);}/*** 上传文件* 使用multipart/form-data POST上传文件或语音, 文件标识名为"media"** 所有类型的文件大小均要求大于5个字节* 普通文件(file):文件大小不超过20M* 语音(voice):文件大小不超过2M,播放长度不超过60s,仅支持AMR格式** @param robotId 机器人key* @param type 文件类型,分别有语音(voice)和普通文件(file)* @param file* @return*/@Overridepublic WebhookUploadMediaResponse uploadFile(String robotId, String type, File file) {// 上传文件String urlString = webhookurl + "/upload_media?key=" + robotId + "&type=file";HashMap<String, String> params = new HashMap<>();// 调用接口凭证, 消息推送webhookurl中的key参数params.put("key", robotId);// 文件类型,分别有语音(voice)和普通文件(file)params.put("type", type);HashMap<String, String> headerMap = new HashMap<>();String resJson = RestClient.postToFormData(urlString, params, headerMap, file);// {"errcode":0,"errmsg":"ok","type":"file","media_id":"31mP38KDISpVm8FHlYHkYAoUmcIPTjSGjZU8aBF0LHwN5lk1Vev4h6ADufssKKib4urz3MbMrTVZ8e-ulXeqvCg","created_at":"1742282248"}return GsonTool.fromJson(resJson, WebhookUploadMediaResponse.class);}}