├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── threedr3am │ │ └── wxwork │ │ ├── bean │ │ └── robot │ │ │ ├── MessageBase.java │ │ │ └── message │ │ │ ├── ImageMessage.java │ │ │ ├── MarkdownMessage.java │ │ │ ├── NewsMessage.java │ │ │ └── TextMessage.java │ │ ├── enums │ │ └── MsgType.java │ │ ├── support │ │ ├── MessageBuilder.java │ │ ├── RobotMagPush.java │ │ └── SSLs.java │ │ └── util │ │ ├── Base64Translater.java │ │ ├── HexTranslater.java │ │ ├── JsonMapper.java │ │ └── Md5Crypto.java └── resource │ └── duolaAmeng.jpg └── test └── java └── com └── threedr3am └── wxwork ├── AppTest.java ├── ImageMessageTest.java ├── MarkdownMessageTest.java ├── NewsMessageTest.java └── TextMessageTest.java /README.md: -------------------------------------------------------------------------------- 1 | ## 企业微信工具包 2 | 目前具有以下实现: 3 | 1. 机器人webhook utils 4 | 5 | ------ 6 | 7 | ### 机器人webhook utils 8 | ##### 1.构建文本消息(TextMessage) 9 | 10 | **MessageBuilder快速构建** 11 | 12 | 作用:发送文本"test",并且@所有手机号对应的用户 13 | ``` 14 | MessageBuilder 15 | .buildTextMessage("test",false,true) 16 | .build() 17 | ``` 18 | 条件:参数 19 | ``` 20 | String msg :发送的文本消息内容 21 | boolean forAllUserIds :是否@所有userId发送 22 | boolean forAllMobiles :是否@所有手机号发送 23 | public static TextMessage buildTextMessage(String msg, boolean forAllUserIds, boolean forAllMobiles); 24 | ``` 25 | --- 26 | 27 | 作用:发送文本"test",并且@userId为1、2、3以及手机号为4、5、6的用户 28 | ``` 29 | MessageBuilder 30 | .buildTextMessage("test",Arrays.asList("1","2","3"),Arrays.asList("4","5","6")) 31 | .build() 32 | ``` 33 | 条件:参数 34 | ``` 35 | String msg :发送的文本消息内容 36 | List userIds :@的用户userId集合 37 | List mobiles :@的用户手机号集合 38 | public static TextMessage buildTextMessage(String msg, List userIds, List mobiles) 39 | ``` 40 | 41 | **TextMessage自定义构建** 42 | 43 | 作用:发送文本内容"test",并且@手机号为1、2、3的用户以及userId为4、5、6的用户 44 | ``` 45 | new TextMessage() 46 | .msg("test") 47 | .addMobileReceiver("1") 48 | .addUserIdReceiver("2") 49 | .setMobileReceiver(Arrays.asList("1","2","3")) 50 | .setUserIdReceiver(Arrays.asList("4","5","6")) 51 | .build(); 52 | ``` 53 | 方法 54 | ``` 55 | addMobileReceiver :添加@用户手机号 56 | addUserIdReceiver :添加@用户userId 57 | setMobileReceiver :设置@用户手机号列表 58 | setUserIdReceiver :设置@用户userId列表 59 | ``` 60 | 61 | ##### 2. 构建Markdown消息(MarkdownMessage) 62 | 63 | 封装了markdown语法快捷使用方法 64 | 65 | ``` 66 | new MarkdownMessage() 67 | .appendLevelTitle("二级标题",2) 68 | .appendNormal("自定义内容") 69 | .newLine()//换行 70 | .appendBold("文字加粗") 71 | .appendHref("https://www.baidu.com","百度链接") 72 | .appendReference("引用") 73 | .appendInfoMsg("绿色文字") 74 | .appendCommentMsg("灰色文字") 75 | .appendWarningMsg("橙红色文字") 76 | .appendLineCode("new MarkdownMessage();//单行代码") 77 | .build(); 78 | ``` 79 | warpper支持 80 | ``` 81 | String msg = new MarkdownMessage() 82 | .appendNormal(MarkdownMessage.Warpper.warpLevelTitle("二级标题",2)) 83 | .appendNormal("自定义内容") 84 | .newLine()//换行 85 | .appendNormal(MarkdownMessage.Warpper.warpBold("文字加粗")) 86 | .appendNormal(MarkdownMessage.Warpper.warpHref("https://www.baidu.com","百度链接")) 87 | .appendNormal(MarkdownMessage.Warpper.warpReference("引用")) 88 | .appendNormal(MarkdownMessage.Warpper.warpInfoMsg("绿色文字")) 89 | .appendNormal(MarkdownMessage.Warpper.warpCommentMsg("灰色文字")) 90 | .appendNormal(MarkdownMessage.Warpper.warpWarningMsg("橙红色文字")) 91 | .appendNormal(MarkdownMessage.Warpper.warpLineCode("new MarkdownMessage();//单行代码")) 92 | .build(); 93 | ``` 94 | 95 | ##### 3. 构建图片消息(ImageMessage) 96 | 97 | file文件构建 98 | ``` 99 | String msg = new ImageMessage() 100 | .file(new File(ImageMessageTest.class.getClassLoader().getResource("duolaAmeng.jpg").getFile())) 101 | .build(); 102 | ``` 103 | 104 | byte字节数组构建 105 | ``` 106 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 107 | Path path = Paths.get(ImageMessageTest.class.getClassLoader().getResource("duolaAmeng.jpg").getPath()); 108 | Files.copy(path, byteArrayOutputStream); 109 | String msg = new ImageMessage() 110 | .bytes(byteArrayOutputStream.toByteArray()) 111 | .build(); 112 | ``` 113 | 114 | ##### 4. 构建图文消息(NewsMessage) 115 | 116 | ``` 117 | String msg = new NewsMessage() 118 | .addArticle("图文消息标题", "图文消息简述", "https://图文链接", "https://图文消息封面图") 119 | .build(); 120 | ``` 121 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.threedr3am.wxwork 8 | sdk-utils 9 | 1.0-SNAPSHOT 10 | 11 | sdk-utils 12 | 13 | 14 | UTF-8 15 | 1.8 16 | 1.8 17 | 18 | 19 | 20 | 21 | com.fasterxml.jackson.core 22 | jackson-core 23 | 2.9.9 24 | 25 | 26 | com.fasterxml.jackson.core 27 | jackson-annotations 28 | 2.9.9 29 | 30 | 31 | com.fasterxml.jackson.core 32 | jackson-databind 33 | 2.9.9 34 | 35 | 36 | 37 | 38 | org.projectlombok 39 | lombok 40 | 1.18.8 41 | provided 42 | 43 | 44 | 45 | 46 | org.slf4j 47 | slf4j-api 48 | 1.7.26 49 | 50 | 51 | 52 | 53 | org.apache.commons 54 | commons-lang3 55 | 3.9 56 | 57 | 58 | 59 | org.apache.httpcomponents 60 | httpclient 61 | 4.5.8 62 | 63 | 64 | org.apache.httpcomponents 65 | httpasyncclient 66 | 4.1.4 67 | 68 | 69 | 70 | junit 71 | junit 72 | 4.11 73 | test 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | maven-clean-plugin 83 | 3.1.0 84 | 85 | 86 | 87 | maven-resources-plugin 88 | 3.0.2 89 | 90 | 91 | maven-compiler-plugin 92 | 3.8.0 93 | 94 | 95 | maven-surefire-plugin 96 | 2.22.1 97 | 98 | 99 | maven-jar-plugin 100 | 3.0.2 101 | 102 | 103 | maven-install-plugin 104 | 2.5.2 105 | 106 | 107 | maven-deploy-plugin 108 | 2.8.2 109 | 110 | 111 | 112 | maven-site-plugin 113 | 3.7.1 114 | 115 | 116 | maven-project-info-reports-plugin 117 | 3.0.0 118 | 119 | 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-compiler-plugin 125 | 126 | 8 127 | 8 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/bean/robot/MessageBase.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.bean.robot; 2 | 3 | import com.threedr3am.wxwork.util.JsonMapper; 4 | 5 | public abstract class MessageBase { 6 | 7 | protected abstract void preHandle(); 8 | 9 | public String build() { 10 | preHandle(); 11 | return JsonMapper.nonNullMapper().toJson(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/bean/robot/message/ImageMessage.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.bean.robot.message; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.threedr3am.wxwork.bean.robot.MessageBase; 6 | import com.threedr3am.wxwork.enums.MsgType; 7 | import com.threedr3am.wxwork.util.Base64Translater; 8 | import com.threedr3am.wxwork.util.HexTranslater; 9 | import com.threedr3am.wxwork.util.Md5Crypto; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.nio.file.Files; 14 | import lombok.Getter; 15 | 16 | /** 17 | * 图片消息 18 | */ 19 | @Getter 20 | @JsonInclude(JsonInclude.Include.NON_NULL) 21 | public class ImageMessage extends MessageBase { 22 | 23 | @JsonProperty("msgtype") 24 | private String msgType = MsgType.IMAGE.getType(); 25 | 26 | private Image image = new Image(); 27 | 28 | @Getter 29 | public static class Image { 30 | 31 | /** 32 | * 图片内容的base64编码 33 | */ 34 | private String base64; 35 | 36 | /** 37 | * 图片内容(base64编码前)的md5值 38 | */ 39 | private String md5; 40 | 41 | private File tmpFile; 42 | 43 | private byte[] tmpBytes; 44 | 45 | private Image() { 46 | } 47 | 48 | } 49 | 50 | @Override 51 | protected void preHandle() { 52 | if (this.image.tmpFile != null && this.image.tmpFile.exists()) { 53 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 54 | try { 55 | Files.copy(this.image.tmpFile.toPath(),byteArrayOutputStream); 56 | byte[] bytes = byteArrayOutputStream.toByteArray(); 57 | this.image.tmpBytes = bytes; 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | if (this.image.tmpBytes != null) { 63 | try { 64 | this.image.md5 = HexTranslater.asciiCharacter2Hex(Md5Crypto.md5(this.image.tmpBytes)); 65 | this.image.base64 = Base64Translater.encode2String(this.image.tmpBytes); 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | assert (this.image.base64 != null && this.image.md5 != null); 71 | } 72 | 73 | public ImageMessage base64(String base64) { 74 | this.image.base64 = base64; 75 | return this; 76 | } 77 | 78 | public ImageMessage md5(String md5) { 79 | this.image.md5 = md5; 80 | return this; 81 | } 82 | 83 | public ImageMessage file(File file) { 84 | this.image.tmpFile = file; 85 | return this; 86 | } 87 | 88 | public ImageMessage bytes(byte[] bytes) { 89 | this.image.tmpBytes = bytes; 90 | return this; 91 | } 92 | 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/bean/robot/message/MarkdownMessage.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.bean.robot.message; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.fasterxml.jackson.annotation.JsonInclude; 5 | import com.fasterxml.jackson.annotation.JsonProperty; 6 | import com.threedr3am.wxwork.bean.robot.MessageBase; 7 | import com.threedr3am.wxwork.enums.MsgType; 8 | import lombok.Getter; 9 | 10 | /** 11 | * markdown消息 12 | */ 13 | @Getter 14 | @JsonInclude(JsonInclude.Include.NON_NULL) 15 | public class MarkdownMessage extends MessageBase { 16 | 17 | @JsonProperty("msgtype") 18 | private String msgType = MsgType.MD.getType(); 19 | 20 | private Markdown markdown = new Markdown(); 21 | 22 | 23 | @Getter 24 | public static class Markdown { 25 | 26 | private String content; 27 | 28 | @JsonIgnore 29 | private StringBuilder tmp = new StringBuilder(); 30 | 31 | private Markdown() { 32 | 33 | } 34 | 35 | } 36 | 37 | @Override 38 | protected void preHandle() { 39 | assert (this.markdown.content != null || this.markdown.tmp.length() > 0); 40 | if (this.markdown.tmp.length() > 0) { 41 | this.markdown.content = this.markdown.tmp.toString(); 42 | } 43 | } 44 | 45 | public MarkdownMessage markdown(String markdown) { 46 | this.markdown.content = markdown; 47 | return this; 48 | } 49 | 50 | /** 51 | * 换行 52 | * @return 53 | */ 54 | public MarkdownMessage newLine() { 55 | this.markdown.tmp.append("\n"); 56 | return this; 57 | } 58 | 59 | /** 60 | * 自定义内容 61 | * @param normal 62 | * @return 63 | */ 64 | public MarkdownMessage appendNormal(String normal) { 65 | this.markdown.tmp.append(normal); 66 | return this; 67 | } 68 | 69 | /** 70 | * 1-6级标题追加 71 | * @param title 72 | * @param level 73 | * @return 74 | */ 75 | public MarkdownMessage appendLevelTitle(String title, int level) { 76 | assert (level > 0 && level < 7); 77 | for (int i = 0; i < level; i++) { 78 | this.markdown.tmp.append("#"); 79 | } 80 | this.markdown.tmp.append(" ".concat(title)); 81 | return this; 82 | } 83 | 84 | /** 85 | * 加粗 86 | * @param bold 87 | * @return 88 | */ 89 | public MarkdownMessage appendBold(String bold) { 90 | this.markdown.tmp.append("**".concat(bold).concat("**")); 91 | return this; 92 | } 93 | 94 | /** 95 | * 链接 96 | * @param url 97 | * @param text 98 | * @return 99 | */ 100 | public MarkdownMessage appendHref(String url, String text) { 101 | this.markdown.tmp.append("[".concat(text).concat("](").concat(url).concat(")")); 102 | return this; 103 | } 104 | 105 | /** 106 | * 行内代码 107 | * @param code 108 | * @return 109 | */ 110 | public MarkdownMessage appendLineCode(String code) { 111 | this.markdown.tmp.append("`".concat(code).concat("`")); 112 | return this; 113 | } 114 | 115 | /** 116 | * 引用 117 | * @param reference 118 | * @return 119 | */ 120 | public MarkdownMessage appendReference(String reference) { 121 | this.markdown.tmp.append("> ".concat(reference)); 122 | return this; 123 | } 124 | 125 | /** 126 | * 绿色文字 127 | * @param text 128 | * @return 129 | */ 130 | public MarkdownMessage appendInfoMsg(String text) { 131 | this.markdown.tmp.append("".concat(text).concat("")); 132 | return this; 133 | } 134 | 135 | /** 136 | * 灰色文字 137 | * @param text 138 | * @return 139 | */ 140 | public MarkdownMessage appendCommentMsg(String text) { 141 | this.markdown.tmp.append("".concat(text).concat("")); 142 | return this; 143 | } 144 | 145 | /** 146 | * 橙红色文字 147 | * @param text 148 | * @return 149 | */ 150 | public MarkdownMessage appendWarningMsg(String text) { 151 | this.markdown.tmp.append("".concat(text).concat("")); 152 | return this; 153 | } 154 | 155 | 156 | /** 157 | * 包装MarkDown支持 158 | */ 159 | public static class Warpper { 160 | 161 | /** 162 | * 构造1-6级标题返回 163 | * @param title 164 | * @param level 165 | * @return 166 | */ 167 | public static String warpLevelTitle(String title, int level) { 168 | assert (level > 0 && level < 7); 169 | StringBuilder tmp = new StringBuilder(); 170 | for (int i = 0; i < level; i++) { 171 | tmp.append("#"); 172 | } 173 | tmp.append(" ".concat(title)); 174 | return tmp.toString(); 175 | } 176 | 177 | /** 178 | * 构造加粗文字返回 179 | * @param bold 180 | * @return 181 | */ 182 | public static String warpBold(String bold) { 183 | return "**".concat(bold).concat("**"); 184 | } 185 | 186 | /** 187 | * 构造链接返回 188 | * @param url 189 | * @param text 190 | * @return 191 | */ 192 | public static String warpHref(String url, String text) { 193 | return "[".concat(text).concat("](").concat(url).concat(")"); 194 | } 195 | 196 | /** 197 | * 构造行内代码返回 198 | * @param code 199 | * @return 200 | */ 201 | public static String warpLineCode(String code) { 202 | return "`".concat(code).concat("`"); 203 | } 204 | 205 | /** 206 | * 构造引用返回 207 | * @param reference 208 | * @return 209 | */ 210 | public static String warpReference(String reference) { 211 | return "> ".concat(reference); 212 | } 213 | 214 | /** 215 | * 构造绿色文字返回 216 | * @param text 217 | * @return 218 | */ 219 | public static String warpInfoMsg(String text) { 220 | return "".concat(text).concat(""); 221 | } 222 | 223 | /** 224 | * 构造灰色文字返回 225 | * @param text 226 | * @return 227 | */ 228 | public static String warpCommentMsg(String text) { 229 | return "".concat(text).concat(""); 230 | } 231 | 232 | /** 233 | * 构造橙红色文字返回 234 | * @param text 235 | * @return 236 | */ 237 | public static String warpWarningMsg(String text) { 238 | return "".concat(text).concat(""); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/bean/robot/message/NewsMessage.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.bean.robot.message; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.threedr3am.wxwork.bean.robot.MessageBase; 6 | import com.threedr3am.wxwork.enums.MsgType; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | /** 13 | * 图文消息 14 | */ 15 | @Getter 16 | @JsonInclude(JsonInclude.Include.NON_NULL) 17 | public class NewsMessage extends MessageBase { 18 | 19 | @JsonProperty("msgtype") 20 | private String msgType = MsgType.NEWS.getType(); 21 | 22 | private News news = new News(); 23 | 24 | @Getter 25 | public static class News { 26 | 27 | private List
articles = new ArrayList<>(); 28 | 29 | private News() { 30 | } 31 | 32 | } 33 | 34 | @Getter 35 | @Setter 36 | public static class Article { 37 | 38 | private String title; 39 | private String description; 40 | private String url; 41 | private String picurl; 42 | 43 | private Article() { 44 | } 45 | } 46 | 47 | @Override 48 | protected void preHandle() { 49 | assert (!this.news.articles.isEmpty()); 50 | } 51 | 52 | public NewsMessage addArticle(String title, String description, String url, String picurl) { 53 | Article article = new Article(); 54 | article.setTitle(title); 55 | article.setDescription(description); 56 | article.setUrl(url); 57 | article.setPicurl(picurl); 58 | this.news.articles.add(article); 59 | return this; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/bean/robot/message/TextMessage.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.bean.robot.message; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.threedr3am.wxwork.bean.robot.MessageBase; 6 | import com.threedr3am.wxwork.enums.MsgType; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import lombok.Getter; 10 | 11 | /** 12 | * 普通文本消息 13 | */ 14 | @Getter 15 | @JsonInclude(JsonInclude.Include.NON_NULL) 16 | public class TextMessage extends MessageBase { 17 | 18 | @JsonProperty("msgtype") 19 | private String msgType = MsgType.TEXT.getType(); 20 | 21 | private Text text = new Text(); 22 | 23 | @Getter 24 | public static class Text { 25 | 26 | private String content; 27 | 28 | @JsonProperty("mentioned_list") 29 | private List mentionedList; 30 | 31 | @JsonProperty("mentioned_mobile_list") 32 | private List mentionedMobileList; 33 | 34 | private Text() { 35 | } 36 | 37 | } 38 | 39 | @Override 40 | protected void preHandle() { 41 | assert (this.text.content != null); 42 | } 43 | 44 | public TextMessage msg(String msg) { 45 | this.text.content = msg; 46 | return this; 47 | } 48 | 49 | public TextMessage setMobileReceiver(List mobiles) { 50 | assert (mobiles != null && !mobiles.isEmpty()); 51 | if (this.text.mentionedMobileList == null) { 52 | synchronized (this.text) { 53 | if (this.text.mentionedMobileList == null) { 54 | this.text.mentionedMobileList = mobiles; 55 | } 56 | } 57 | } 58 | return this; 59 | } 60 | 61 | public TextMessage addMobileReceiver(String mobile) { 62 | assert (mobile != null && mobile.length() > 0); 63 | if (this.text.mentionedMobileList == null) { 64 | synchronized (this.text) { 65 | if (this.text.mentionedMobileList == null) { 66 | this.text.mentionedMobileList = new ArrayList<>(); 67 | } 68 | } 69 | } 70 | this.text.mentionedMobileList.add(mobile); 71 | return this; 72 | } 73 | 74 | public TextMessage mobileReceiverWithAll() { 75 | if (this.text.mentionedMobileList == null) { 76 | synchronized (this.text) { 77 | if (this.text.mentionedMobileList == null) { 78 | this.text.mentionedMobileList = new ArrayList<>(); 79 | } 80 | } 81 | } 82 | this.text.mentionedMobileList.add("@all"); 83 | return this; 84 | } 85 | 86 | public TextMessage setUserIdReceiver(List userIds) { 87 | assert (userIds != null && !userIds.isEmpty()); 88 | if (this.text.mentionedList == null) { 89 | synchronized (this.text) { 90 | if (this.text.mentionedList == null) { 91 | this.text.mentionedList = userIds; 92 | } 93 | } 94 | } 95 | return this; 96 | } 97 | 98 | public TextMessage addUserIdReceiver(String userId) { 99 | assert (userId != null && userId.length() > 0); 100 | if (this.text.mentionedList == null) { 101 | synchronized (this.text) { 102 | if (this.text.mentionedList == null) { 103 | this.text.mentionedList = new ArrayList<>(); 104 | } 105 | } 106 | } 107 | this.text.mentionedList.add(userId); 108 | return this; 109 | } 110 | 111 | public TextMessage userIdReceiverWithAll() { 112 | if (this.text.mentionedList == null) { 113 | synchronized (this.text) { 114 | if (this.text.mentionedList == null) { 115 | this.text.mentionedList = new ArrayList<>(); 116 | } 117 | } 118 | } 119 | this.text.mentionedList.add("@all"); 120 | return this; 121 | } 122 | 123 | 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/enums/MsgType.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.enums; 2 | 3 | public enum MsgType { 4 | TEXT("text","文本消息"), 5 | MD("markdown","markdown"), 6 | IMAGE("image","图片消息"), 7 | NEWS("news","图文"), 8 | ; 9 | 10 | private String type; 11 | private String desc; 12 | 13 | MsgType(String type, String desc) { 14 | this.type = type; 15 | this.desc = desc; 16 | } 17 | 18 | public String getType() { 19 | return type; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/support/MessageBuilder.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.support; 2 | 3 | import com.threedr3am.wxwork.bean.robot.message.MarkdownMessage; 4 | import com.threedr3am.wxwork.bean.robot.message.TextMessage; 5 | import java.util.List; 6 | 7 | /** 8 | * 机器人消息快速构建类 9 | */ 10 | public class MessageBuilder { 11 | public static TextMessage buildTextMessage(String msg, List userIds, List mobiles) { 12 | return new TextMessage().msg(msg).setUserIdReceiver(userIds).setMobileReceiver(mobiles); 13 | } 14 | 15 | public static TextMessage buildTextMessage(String msg, boolean forAllUserIds, boolean forAllMobiles) { 16 | TextMessage textMessage = new TextMessage().msg(msg); 17 | if (forAllUserIds) 18 | textMessage.userIdReceiverWithAll(); 19 | if (forAllMobiles) 20 | textMessage.mobileReceiverWithAll(); 21 | return textMessage; 22 | } 23 | 24 | public static MarkdownMessage buildMarkdownMessage(String markdown) { 25 | return new MarkdownMessage().markdown(markdown); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/support/RobotMagPush.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.support; 2 | 3 | import com.threedr3am.wxwork.bean.robot.MessageBase; 4 | import java.io.IOException; 5 | import java.io.InterruptedIOException; 6 | import java.io.UnsupportedEncodingException; 7 | import java.net.UnknownHostException; 8 | import javax.net.ssl.SSLException; 9 | import javax.net.ssl.SSLHandshakeException; 10 | import org.apache.http.HttpEntityEnclosingRequest; 11 | import org.apache.http.HttpRequest; 12 | import org.apache.http.NoHttpResponseException; 13 | import org.apache.http.client.HttpRequestRetryHandler; 14 | import org.apache.http.client.config.RequestConfig; 15 | import org.apache.http.client.entity.EntityBuilder; 16 | import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; 17 | import org.apache.http.client.methods.HttpPost; 18 | import org.apache.http.client.methods.HttpRequestBase; 19 | import org.apache.http.client.protocol.HttpClientContext; 20 | import org.apache.http.config.Registry; 21 | import org.apache.http.config.RegistryBuilder; 22 | import org.apache.http.conn.ConnectTimeoutException; 23 | import org.apache.http.conn.socket.ConnectionSocketFactory; 24 | import org.apache.http.conn.socket.PlainConnectionSocketFactory; 25 | import org.apache.http.entity.ContentType; 26 | import org.apache.http.impl.client.CloseableHttpClient; 27 | import org.apache.http.impl.client.HttpClientBuilder; 28 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; 29 | import org.apache.http.protocol.HttpContext; 30 | import org.apache.http.util.EntityUtils; 31 | 32 | /** 33 | * 机器人消息推送 34 | */ 35 | public class RobotMagPush { 36 | 37 | public static RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); 38 | public static HttpClientBuilder httpClientBuilder = new HttpClient(); 39 | 40 | static class HttpClient extends HttpClientBuilder {} 41 | 42 | static { 43 | requestConfigBuilder.setConnectTimeout(5000); 44 | requestConfigBuilder.setSocketTimeout(5000); 45 | requestConfigBuilder.setConnectionRequestTimeout(5000); 46 | requestConfigBuilder.setRedirectsEnabled(false); 47 | 48 | Registry socketFactoryRegistry = RegistryBuilder 49 | .create() 50 | .register("http", PlainConnectionSocketFactory.INSTANCE) 51 | .register("https", new SSLs().getSSLConnectionSocketFactory(SSLs.SSLProtocolVersion.SSLv3)).build(); 52 | //设置连接池大小 53 | PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); 54 | connManager.setMaxTotal(20);// Increase max total connection to $maxTotal 55 | connManager.setDefaultMaxPerRoute(10);// Increase default max connection per route to $defaultMaxPerRoute 56 | //connManager.setMaxPerRoute(route, max);// Increase max connections for $route(eg:localhost:80) to 50 57 | httpClientBuilder.setConnectionManager(connManager); 58 | 59 | // 请求重试处理 60 | HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { 61 | public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { 62 | if (executionCount >= 3) {// 如果已经重试了n次,就放弃 63 | return false; 64 | } 65 | if (exception instanceof NoHttpResponseException) {// 如果服务器丢掉了连接,那么就重试 66 | return true; 67 | } 68 | if (exception instanceof SSLHandshakeException) {// 不要重试SSL握手异常 69 | return false; 70 | } 71 | if (exception instanceof InterruptedIOException) {// 超时 72 | //return false; 73 | return false; 74 | } 75 | if (exception instanceof UnknownHostException) {// 目标服务器不可达 76 | return true; 77 | } 78 | if (exception instanceof ConnectTimeoutException) {// 连接被拒绝 79 | return false; 80 | } 81 | if (exception instanceof SSLException) {// SSL握手异常 82 | return false; 83 | } 84 | 85 | HttpClientContext clientContext = HttpClientContext.adapt(context); 86 | HttpRequest request = clientContext.getRequest(); 87 | // 如果请求是幂等的,就再次尝试 88 | if (!(request instanceof HttpEntityEnclosingRequest)) { 89 | return true; 90 | } 91 | return false; 92 | } 93 | }; 94 | httpClientBuilder.setRetryHandler(httpRequestRetryHandler); 95 | } 96 | 97 | /** 98 | * 消息推送 99 | * @param webhook 100 | * @param message 101 | * @return 102 | */ 103 | public static String push(String webhook, MessageBase message) { 104 | HttpEntityEnclosingRequestBase httpBase = new HttpPost(webhook); 105 | EntityBuilder entityBuilder = EntityBuilder.create(); 106 | try { 107 | entityBuilder.setBinary(message.build().getBytes("UTF-8")); 108 | } catch (UnsupportedEncodingException e) { 109 | e.printStackTrace(); 110 | } 111 | entityBuilder.setContentEncoding("UTF-8"); 112 | entityBuilder.setContentType(ContentType.APPLICATION_JSON); 113 | httpBase.setEntity(entityBuilder.build()); 114 | //创建请求对象 115 | HttpRequestBase request = httpBase; 116 | request.setConfig(requestConfigBuilder.build()); 117 | CloseableHttpClient client = httpClientBuilder.build(); 118 | 119 | try { 120 | return EntityUtils.toString(client.execute(request).getEntity()); 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | } finally { 124 | try { 125 | client.close(); 126 | } catch (IOException e) { 127 | e.printStackTrace(); 128 | } 129 | } 130 | return null; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/support/SSLs.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.support; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.security.KeyManagementException; 8 | import java.security.KeyStore; 9 | import java.security.KeyStoreException; 10 | import java.security.NoSuchAlgorithmException; 11 | import java.security.cert.CertificateException; 12 | import java.security.cert.X509Certificate; 13 | import javax.net.ssl.HostnameVerifier; 14 | import javax.net.ssl.SSLContext; 15 | import javax.net.ssl.SSLSession; 16 | import javax.net.ssl.SSLSocketFactory; 17 | import javax.net.ssl.TrustManager; 18 | import javax.net.ssl.X509TrustManager; 19 | import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 20 | import org.apache.http.conn.ssl.TrustSelfSignedStrategy; 21 | import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy; 22 | import org.apache.http.ssl.SSLContexts; 23 | 24 | /** 25 | * 设置ssl 26 | */ 27 | public class SSLs { 28 | 29 | private static final SimpleVerifier simpleVerifier = new SimpleVerifier(); 30 | private static SSLSocketFactory sslSocketFactory; 31 | private static SSLConnectionSocketFactory sslConnectionSocketFactory; 32 | private static SSLIOSessionStrategy sslIOSessionStrategy; 33 | private static SSLs sslutil = new SSLs(); 34 | private SSLContext sslContext; 35 | 36 | public static SSLs getInstance() { 37 | return sslutil; 38 | } 39 | 40 | public static SSLs custom() { 41 | return new SSLs(); 42 | } 43 | 44 | /** 45 | * 重写X509TrustManager类的三个方法,信任服务器证书 46 | */ 47 | private static class SimpleVerifier implements X509TrustManager, HostnameVerifier { 48 | 49 | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 50 | 51 | } 52 | 53 | public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { 54 | 55 | } 56 | 57 | public X509Certificate[] getAcceptedIssuers() { 58 | return new X509Certificate[]{}; 59 | } 60 | 61 | public boolean verify(String paramString, SSLSession paramSSLSession) { 62 | return true; 63 | } 64 | } 65 | 66 | /** 67 | * 信任主机 68 | */ 69 | public static HostnameVerifier getHostnameVerifier() { 70 | return simpleVerifier; 71 | } 72 | 73 | public synchronized SSLSocketFactory getSSLSocketFactory(SSLProtocolVersion sslProtocolVersion) { 74 | if (sslSocketFactory != null) 75 | return sslSocketFactory; 76 | try { 77 | SSLContext sc = getSSLContext(sslProtocolVersion); 78 | sc.init(null, new TrustManager[]{simpleVerifier}, null); 79 | sslSocketFactory = sc.getSocketFactory(); 80 | } catch (KeyManagementException e) { 81 | e.printStackTrace(); 82 | } 83 | return sslSocketFactory; 84 | } 85 | 86 | public synchronized SSLConnectionSocketFactory getSSLConnectionSocketFactory(SSLProtocolVersion sslpv) { 87 | if (sslConnectionSocketFactory != null) 88 | return sslConnectionSocketFactory; 89 | try { 90 | SSLContext sc = getSSLContext(sslpv); 91 | sc.init(null, new TrustManager[]{simpleVerifier}, new java.security.SecureRandom()); 92 | sslConnectionSocketFactory = new SSLConnectionSocketFactory(sc, simpleVerifier); 93 | } catch (KeyManagementException e) { 94 | e.printStackTrace(); 95 | } 96 | return sslConnectionSocketFactory; 97 | } 98 | 99 | public synchronized SSLIOSessionStrategy getSSLIOSessionStrategy(SSLProtocolVersion sslProtocolVersion) { 100 | if (sslIOSessionStrategy != null) 101 | return sslIOSessionStrategy; 102 | try { 103 | SSLContext sslContext = getSSLContext(sslProtocolVersion); 104 | sslContext.init(null, new TrustManager[]{simpleVerifier}, new java.security.SecureRandom()); 105 | sslIOSessionStrategy = new SSLIOSessionStrategy(sslContext, simpleVerifier); 106 | } catch (KeyManagementException e) { 107 | e.printStackTrace(); 108 | } 109 | return sslIOSessionStrategy; 110 | } 111 | 112 | public SSLs customSSL(String keyStorePath, String keyStorepass) { 113 | FileInputStream instream = null; 114 | KeyStore trustStore = null; 115 | try { 116 | trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); 117 | instream = new FileInputStream(new File(keyStorePath)); 118 | trustStore.load(instream, keyStorepass.toCharArray()); 119 | // 相信自己的CA和所有自签名的证书 120 | sslContext = SSLContexts 121 | .custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build(); 122 | } catch (KeyManagementException e) { 123 | e.printStackTrace(); 124 | } catch (KeyStoreException e) { 125 | e.printStackTrace(); 126 | } catch (FileNotFoundException e) { 127 | e.printStackTrace(); 128 | } catch (NoSuchAlgorithmException e) { 129 | e.printStackTrace(); 130 | } catch (CertificateException e) { 131 | e.printStackTrace(); 132 | } catch (IOException e) { 133 | e.printStackTrace(); 134 | } finally { 135 | try { 136 | instream.close(); 137 | } catch (IOException e) { 138 | } 139 | } 140 | return this; 141 | } 142 | 143 | public SSLContext getSSLContext(SSLProtocolVersion sslpv) { 144 | if (sslContext == null) { 145 | try { 146 | sslContext = SSLContext.getInstance(sslpv.getName()); 147 | } catch (NoSuchAlgorithmException e) { 148 | e.printStackTrace(); 149 | } 150 | } 151 | return sslContext; 152 | } 153 | 154 | /** 155 | * The SSL protocol version (SSLv3, TLSv1, TLSv1.1, TLSv1.2) 156 | * 157 | * @author arron 158 | * @version 1.0 159 | */ 160 | public enum SSLProtocolVersion { 161 | SSL("SSL"), 162 | SSLv3("SSLv3"), 163 | TLSv1("TLSv1"), 164 | TLSv1_1("TLSv1.1"), 165 | TLSv1_2("TLSv1.2"),; 166 | private String name; 167 | 168 | SSLProtocolVersion(String name) { 169 | this.name = name; 170 | } 171 | 172 | public String getName() { 173 | return this.name; 174 | } 175 | 176 | public static SSLProtocolVersion find(String name) { 177 | for (SSLProtocolVersion pv : SSLProtocolVersion.values()) { 178 | if (pv.getName().toUpperCase().equals(name.toUpperCase())) { 179 | return pv; 180 | } 181 | } 182 | throw new RuntimeException("未支持当前ssl版本号:" + name); 183 | } 184 | 185 | } 186 | } -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/util/Base64Translater.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.Base64; 5 | 6 | /** 7 | * base64转换 8 | */ 9 | public class Base64Translater { 10 | 11 | public static String decode2String(String str) 12 | throws UnsupportedEncodingException { 13 | return new String(Base64.getDecoder().decode(str),"UTF-8"); 14 | } 15 | 16 | public static String decode2String(String str, String charsetName) 17 | throws UnsupportedEncodingException { 18 | return new String(Base64.getDecoder().decode(str),charsetName); 19 | } 20 | 21 | public static byte[] decode2Bytes(String str) { 22 | return Base64.getDecoder().decode(str); 23 | } 24 | 25 | public static byte[] decode2Bytes(byte[] bytes) { 26 | return Base64.getDecoder().decode(bytes); 27 | } 28 | 29 | public static String encode2String(String str) throws UnsupportedEncodingException { 30 | return encode2String(str, "UTF-8"); 31 | } 32 | 33 | public static String encode2String(String str, String charsetName) 34 | throws UnsupportedEncodingException { 35 | return encode2String(str.getBytes(charsetName)); 36 | } 37 | 38 | public static byte[] encode2Bytes(String str) { 39 | return encode2Bytes(str.getBytes()); 40 | } 41 | 42 | public static String encode2String(byte[] bytes) { 43 | return Base64.getEncoder().encodeToString(bytes); 44 | } 45 | 46 | public static byte[] encode2Bytes(byte[] bytes) { 47 | return Base64.getEncoder().encode(bytes); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/util/HexTranslater.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.util; 2 | 3 | /** 4 | * 十六进制转换 5 | */ 6 | public class HexTranslater { 7 | 8 | /** 9 | * 十六进制字符串转ascii字符串(例:666C61672E6A7067 转 flag.jpg) 10 | * @param hex 11 | * @return 12 | * @throws Exception 13 | */ 14 | public static String hex2AsciiCharacter(String hex) throws Exception { 15 | if (hex != null && hex.length() > 0 && hex.length() % 2 == 0) { 16 | StringBuilder stringBuilder = new StringBuilder(); 17 | for (int i = 0; i < hex.length(); i+=2) { 18 | String tmp = hex.substring(i,i+2); 19 | stringBuilder.append(Character.toString((char) Integer.parseInt(tmp,16))); 20 | } 21 | return stringBuilder.toString(); 22 | } 23 | throw new Exception("16进制字符串不合法"); 24 | } 25 | 26 | /** 27 | * 十六进制字符串转byte(例:66 转 102) 28 | * @param hex 29 | * @return 30 | * @throws Exception 31 | */ 32 | public static byte[] hex2Bytes(String hex) throws Exception { 33 | if (hex != null && hex.length() > 0 && hex.length() % 2 == 0) { 34 | StringBuilder stringBuilder = new StringBuilder(); 35 | byte[] bytes = new byte[hex.length()]; 36 | for (int i = 0; i < hex.length(); i+=2) { 37 | String tmp = hex.substring(i,i+2); 38 | bytes[i] = (byte) Integer.parseInt(tmp,16); 39 | } 40 | return bytes; 41 | } 42 | throw new Exception("16进制字符串不合法"); 43 | } 44 | 45 | 46 | 47 | /** 48 | * ascii字符串转十六进制字符串(例:flag.jpg 转 666C61672E6A7067) 49 | * @param asciiCharacter 50 | * @return 51 | * @throws Exception 52 | */ 53 | public static String asciiCharacter2Hex(String asciiCharacter) throws Exception { 54 | return asciiCharacter2Hex(asciiCharacter.getBytes()); 55 | } 56 | 57 | public static String asciiCharacter2Hex(String asciiCharacter,String charsetName) throws Exception { 58 | return asciiCharacter2Hex(asciiCharacter.getBytes(charsetName)); 59 | } 60 | 61 | public static String asciiCharacter2Hex(byte[] bytes) throws Exception { 62 | if (bytes != null && bytes.length > 0) { 63 | StringBuilder stringBuilder = new StringBuilder(); 64 | for (int i = 0; i < bytes.length; i++) { 65 | stringBuilder.append(Integer.toHexString((bytes[i] & 0xFF) | 0x100).substring(1, 3)); 66 | } 67 | return stringBuilder.toString(); 68 | } 69 | throw new Exception("ascii字符串不合法"); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/util/JsonMapper.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.util; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.JavaType; 6 | import com.fasterxml.jackson.databind.ObjectMapper; 7 | import com.fasterxml.jackson.databind.SerializationFeature; 8 | import com.fasterxml.jackson.databind.util.JSONPObject; 9 | import org.apache.commons.lang3.StringUtils; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.io.IOException; 14 | import java.util.Collection; 15 | import java.util.Map; 16 | 17 | /** 18 | * 简单封装Jackson,实现JSON String<->Java Object转换的Mapper. 19 | *

20 | * 可以直接使用公共示例JsonMapper.INSTANCE, 也可以使用不同的builder函数创建实例,封装不同的输出风格, 21 | *

22 | * 不要使用GSON, 在对象稍大时非常缓慢. 23 | *

24 | * 注意: 需要参考本模块的POM文件,显式引用jackson. 25 | * 26 | * @author calvin 27 | */ 28 | public class JsonMapper { 29 | 30 | private static Logger logger = LoggerFactory.getLogger(JsonMapper.class); 31 | 32 | public static final JsonMapper INSTANCE = new JsonMapper(); 33 | 34 | private ObjectMapper mapper; 35 | 36 | public JsonMapper() { 37 | this(null); 38 | } 39 | 40 | public JsonMapper(Include include) { 41 | mapper = new ObjectMapper(); 42 | // 设置输出时包含属性的风格 43 | if (include != null) { 44 | mapper.setSerializationInclusion(include); 45 | } 46 | // 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性 47 | mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); 48 | } 49 | 50 | /** 51 | * 创建只输出非Null的属性到Json字符串的Mapper. 52 | */ 53 | public static JsonMapper nonNullMapper() { 54 | return new JsonMapper(Include.NON_NULL); 55 | } 56 | 57 | /** 58 | * 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper. 59 | *

60 | * 注意,要小心使用, 特别留意empty的情况. 61 | */ 62 | public static JsonMapper nonEmptyMapper() { 63 | return new JsonMapper(Include.NON_EMPTY); 64 | } 65 | 66 | /** 67 | * 默认的全部输出的Mapper, 区别于INSTANCE,可以做进一步的配置 68 | */ 69 | public static JsonMapper defaultMapper() { 70 | return new JsonMapper(); 71 | } 72 | 73 | /** 74 | * Object可以是POJO,也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]". 75 | */ 76 | public String toJson(Object object) { 77 | 78 | try { 79 | return mapper.writeValueAsString(object); 80 | } catch (IOException e) { 81 | logger.warn("write to json string error:" + object, e); 82 | return null; 83 | } 84 | } 85 | 86 | /** 87 | * 反序列化POJO或简单Collection如List. 88 | *

89 | * 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合. 90 | *

91 | * 如需反序列化复杂Collection如List, 请使用fromJson(String, JavaType) 92 | * 93 | * @see #fromJson(String, JavaType) 94 | */ 95 | public T fromJson(String jsonString, Class clazz) { 96 | if (StringUtils.isEmpty(jsonString)) { 97 | return null; 98 | } 99 | 100 | try { 101 | return mapper.readValue(jsonString, clazz); 102 | } catch (IOException e) { 103 | logger.warn("parse json string error:" + jsonString, e); 104 | return null; 105 | } 106 | } 107 | 108 | /** 109 | * 反序列化复杂Collection如List, contructCollectionType()或contructMapType()构造类型, 然后调用本函数. 110 | */ 111 | public T fromJson(String jsonString, JavaType javaType) { 112 | if (StringUtils.isEmpty(jsonString)) { 113 | return null; 114 | } 115 | 116 | try { 117 | return mapper.readValue(jsonString, javaType); 118 | } catch (IOException e) { 119 | logger.warn("parse json string error:" + jsonString, e); 120 | return null; 121 | } 122 | } 123 | 124 | /** 125 | * 构造Collection类型. 126 | */ 127 | public JavaType buildCollectionType(Class collectionClass, Class elementClass) { 128 | return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass); 129 | } 130 | 131 | /** 132 | * 构造Map类型. 133 | */ 134 | public JavaType buildMapType(Class mapClass, Class keyClass, Class valueClass) { 135 | return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass); 136 | } 137 | 138 | /** 139 | * 当JSON里只含有Bean的部分属性時,更新一個已存在Bean,只覆盖該部分的属性. 140 | */ 141 | public void update(String jsonString, Object object) { 142 | try { 143 | mapper.readerForUpdating(object).readValue(jsonString); 144 | } catch (IOException e) { 145 | logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e); 146 | } 147 | } 148 | 149 | /** 150 | * 輸出JSONP格式數據. 151 | */ 152 | public String toJsonP(String functionName, Object object) { 153 | return toJson(new JSONPObject(functionName, object)); 154 | } 155 | 156 | /** 157 | * 設定是否使用Enum的toString函數來讀寫Enum, 為False時時使用Enum的name()函數來讀寫Enum, 默認為False. 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用. 158 | */ 159 | public void enableEnumUseToString() { 160 | mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); 161 | mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING); 162 | } 163 | 164 | /** 165 | * 取出Mapper做进一步的设置或使用其他序列化API. 166 | */ 167 | public ObjectMapper getMapper() { 168 | return mapper; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/main/java/com/threedr3am/wxwork/util/Md5Crypto.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | 7 | /** 8 | * md5 9 | */ 10 | public class Md5Crypto { 11 | 12 | public static byte[] md5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException { 13 | MessageDigest md = MessageDigest.getInstance("MD5"); 14 | byte[] array = md.digest(str.getBytes("utf-8")); 15 | return array; 16 | } 17 | 18 | public static byte[] md5(byte[] bytes) throws NoSuchAlgorithmException { 19 | MessageDigest md = MessageDigest.getInstance("MD5"); 20 | byte[] array = md.digest(bytes); 21 | return array; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resource/duolaAmeng.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/threedr3am/wxwork-sdk-utils/409827de94e7135cba67131a66b991f4ec6b6ee9/src/main/resource/duolaAmeng.jpg -------------------------------------------------------------------------------- /src/test/java/com/threedr3am/wxwork/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | { 12 | /** 13 | * Rigorous Test :-) 14 | */ 15 | @Test 16 | public void shouldAnswerWithTrue() 17 | { 18 | assertTrue( true ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/threedr3am/wxwork/ImageMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import com.threedr3am.wxwork.bean.robot.message.ImageMessage; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.File; 8 | import java.io.FileNotFoundException; 9 | import java.io.IOException; 10 | import java.nio.file.Files; 11 | import java.nio.file.Path; 12 | import java.nio.file.Paths; 13 | import org.junit.Test; 14 | 15 | /** 16 | * Unit test for ImageMessage. 17 | */ 18 | public class ImageMessageTest { 19 | 20 | @Test 21 | public void shouldAnswerWithTrue() { 22 | String template = "{\"image\":{\"base64\":\"/9j/4AAQSk"; 23 | String template2 = "AAEhwAC+ogNlKiJqGJDm8B//Z\"},\"msgtype\":\"image\"}"; 24 | String msg = new ImageMessage() 25 | .file(new File( 26 | ImageMessageTest.class.getClassLoader().getResource("duolaAmeng.jpg").getFile())) 27 | .build(); 28 | assertTrue(msg.startsWith(template) && msg.endsWith(template2)); 29 | } 30 | 31 | @Test 32 | public void shouldAnswerWithTrue2() { 33 | String template = "{\"image\":{\"base64\":\"/9j/4AAQSk"; 34 | String template2 = "AAEhwAC+ogNlKiJqGJDm8B//Z\"},\"msgtype\":\"image\"}"; 35 | try { 36 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 37 | Path path = Paths.get( 38 | ImageMessageTest.class.getClassLoader().getResource("duolaAmeng.jpg").getPath()); 39 | Files.copy(path, byteArrayOutputStream); 40 | String msg = new ImageMessage() 41 | .bytes(byteArrayOutputStream.toByteArray()) 42 | .build(); 43 | assertTrue(msg.startsWith(template) && msg.endsWith(template2)); 44 | } catch (FileNotFoundException e) { 45 | e.printStackTrace(); 46 | } catch (IOException e) { 47 | e.printStackTrace(); 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/threedr3am/wxwork/MarkdownMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import com.threedr3am.wxwork.bean.robot.message.MarkdownMessage; 6 | import com.threedr3am.wxwork.support.MessageBuilder; 7 | import java.util.Map; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.junit.Test; 10 | 11 | /** 12 | * Unit test for MarkdownMessage. 13 | */ 14 | public class MarkdownMessageTest 15 | { 16 | @Test 17 | public void shouldAnswerWithTrue() 18 | { 19 | String template = "{\"markdown\":{\"content\":\"test\"},\"msgtype\":\"markdown\"}"; 20 | String msg = MessageBuilder.buildMarkdownMessage("test").build(); 21 | assertTrue(StringUtils.equals(template,msg)); 22 | } 23 | 24 | @Test 25 | public void shouldAnswerWithTrue2() 26 | { 27 | String template = "{\"markdown\":{\"content\":\"## 二级标题自定义内容\\n**文字加粗**[百度链接](https://www.baidu.com)> 引用绿色文字灰色文字橙红色文字`new MarkdownMessage();//单行代码`\"},\"msgtype\":\"markdown\"}"; 28 | String msg = new MarkdownMessage() 29 | .appendLevelTitle("二级标题",2) 30 | .appendNormal("自定义内容") 31 | .newLine()//换行 32 | .appendBold("文字加粗") 33 | .appendHref("https://www.baidu.com","百度链接") 34 | .appendReference("引用") 35 | .appendInfoMsg("绿色文字") 36 | .appendCommentMsg("灰色文字") 37 | .appendWarningMsg("橙红色文字") 38 | .appendLineCode("new MarkdownMessage();//单行代码") 39 | .build(); 40 | assertTrue(StringUtils.equals(template,msg)); 41 | } 42 | 43 | @Test 44 | public void shouldAnswerWithTrue3() 45 | { 46 | String template = "{\"markdown\":{\"content\":\"## 二级标题自定义内容\\n**文字加粗**[百度链接](https://www.baidu.com)> 引用绿色文字灰色文字橙红色文字`new MarkdownMessage();//单行代码`\"},\"msgtype\":\"markdown\"}"; 47 | String msg = new MarkdownMessage() 48 | .appendNormal(MarkdownMessage.Warpper.warpLevelTitle("二级标题",2)) 49 | .appendNormal("自定义内容") 50 | .newLine()//换行 51 | .appendNormal(MarkdownMessage.Warpper.warpBold("文字加粗")) 52 | .appendNormal(MarkdownMessage.Warpper.warpHref("https://www.baidu.com","百度链接")) 53 | .appendNormal(MarkdownMessage.Warpper.warpReference("引用")) 54 | .appendNormal(MarkdownMessage.Warpper.warpInfoMsg("绿色文字")) 55 | .appendNormal(MarkdownMessage.Warpper.warpCommentMsg("灰色文字")) 56 | .appendNormal(MarkdownMessage.Warpper.warpWarningMsg("橙红色文字")) 57 | .appendNormal(MarkdownMessage.Warpper.warpLineCode("new MarkdownMessage();//单行代码")) 58 | .build(); 59 | assertTrue(StringUtils.equals(template,msg)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/com/threedr3am/wxwork/NewsMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import com.threedr3am.wxwork.bean.robot.message.ImageMessage; 6 | import com.threedr3am.wxwork.bean.robot.message.NewsMessage; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.junit.Test; 9 | 10 | /** 11 | * Unit test for NewsMessage. 12 | */ 13 | public class NewsMessageTest { 14 | 15 | @Test 16 | public void shouldAnswerWithTrue() { 17 | String template = "{\"news\":{\"articles\":[{\"title\":\"图文消息标题\",\"description\":\"图文消息简述\",\"url\":\"https://图文链接\",\"picurl\":\"https://图文消息封面图\"}]},\"msgtype\":\"news\"}"; 18 | String msg = new NewsMessage() 19 | .addArticle("图文消息标题", "图文消息简述", "https://图文链接", "https://图文消息封面图") 20 | .build(); 21 | assertTrue(StringUtils.equals(msg, template)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/com/threedr3am/wxwork/TextMessageTest.java: -------------------------------------------------------------------------------- 1 | package com.threedr3am.wxwork; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import com.threedr3am.wxwork.support.MessageBuilder; 6 | import java.util.Arrays; 7 | import org.apache.commons.lang3.StringUtils; 8 | import org.junit.Test; 9 | 10 | /** 11 | * Unit test for TextMessage. 12 | */ 13 | public class TextMessageTest 14 | { 15 | @Test 16 | public void shouldAnswerWithTrue() 17 | { 18 | String template = "{\"text\":{\"content\":\"test\",\"mentioned_list\":[\"1\",\"2\",\"3\"],\"mentioned_mobile_list\":[\"4\",\"5\",\"6\"]},\"msgtype\":\"text\"}"; 19 | String msg = MessageBuilder.buildTextMessage("test",Arrays.asList("1","2","3"),Arrays.asList("4","5","6")).build(); 20 | assertTrue(StringUtils.equals(template,msg)); 21 | } 22 | 23 | @Test 24 | public void shouldAnswerWithTrue2() 25 | { 26 | String template = "{\"text\":{\"content\":\"test\",\"mentioned_mobile_list\":[\"@all\"]},\"msgtype\":\"text\"}"; 27 | String msg = MessageBuilder.buildTextMessage("test",false,true).build(); 28 | assertTrue(StringUtils.equals(template,msg)); 29 | } 30 | 31 | @Test 32 | public void shouldAnswerWithTrue3() 33 | { 34 | String template = "{\"text\":{\"content\":\"test\",\"mentioned_list\":[\"@all\"]},\"msgtype\":\"text\"}"; 35 | String msg = MessageBuilder.buildTextMessage("test",true,false).build(); 36 | assertTrue(StringUtils.equals(template,msg)); 37 | } 38 | } 39 | --------------------------------------------------------------------------------