|
4 | 4 | import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder; |
5 | 5 | import lombok.*; |
6 | 6 | import lombok.experimental.Accessors; |
| 7 | +import org.apache.commons.lang3.StringUtils; |
7 | 8 |
|
8 | 9 | import java.io.Serializable; |
9 | 10 | import java.util.ArrayList; |
10 | 11 | import java.util.List; |
| 12 | +import java.util.regex.Pattern; |
11 | 13 |
|
12 | 14 | /** |
13 | 15 | * 订阅消息 |
|
24 | 26 | public class WxMaSubscribeMessage implements Serializable { |
25 | 27 | private static final long serialVersionUID = 6846729898251286686L; |
26 | 28 |
|
| 29 | + /** |
| 30 | + * 预编译正则,避免每次调用 resetValue 时重复编译 |
| 31 | + */ |
| 32 | + private static final Pattern NUMBER_PATTERN = Pattern.compile("[^0-9.\\-]"); |
| 33 | + private static final Pattern NUMBER_VALID_PATTERN = Pattern.compile("-?\\d+\\.?\\d*|-?\\.\\d+"); |
| 34 | + private static final Pattern LETTER_PATTERN = Pattern.compile("[^a-zA-Z]"); |
| 35 | + private static final Pattern SYMBOL_PATTERN = Pattern.compile("[a-zA-Z0-9\\u4e00-\\u9fa5]"); |
| 36 | + private static final Pattern PHONE_PATTERN = Pattern.compile("[^0-9+\\-]"); |
| 37 | + private static final Pattern NAME_PATTERN = Pattern.compile("[^\\u4e00-\\u9fa5a-zA-Z \\u00b7.\\u3001\\uff0c\\u3002\\-]"); |
| 38 | + private static final Pattern CHARACTER_STRING_PATTERN = Pattern.compile("[\\u4e00-\\u9fa5]"); |
| 39 | + private static final Pattern CHINESE_PATTERN = Pattern.compile("[\\u4e00-\\u9fa5]"); |
| 40 | + private static final Pattern PHRASE_PATTERN = Pattern.compile("[^\\u4e00-\\u9fa5]"); |
| 41 | + |
27 | 42 | /** |
28 | 43 | * 接收者(用户)的 openid. |
29 | 44 | * <pre> |
@@ -75,15 +90,126 @@ public class WxMaSubscribeMessage implements Serializable { |
75 | 90 | private String lang = WxMaConstants.MiniProgramLang.ZH_CN; |
76 | 91 |
|
77 | 92 | public WxMaSubscribeMessage addData(MsgData datum) { |
| 93 | + if (datum == null) { |
| 94 | + return this; |
| 95 | + } |
78 | 96 | if (this.data == null) { |
79 | 97 | this.data = new ArrayList<>(); |
80 | 98 | } |
81 | 99 |
|
82 | | - this.data.add(datum); |
| 100 | + this.data.add(resetValue(datum)); |
83 | 101 |
|
84 | 102 | return this; |
85 | 103 | } |
86 | 104 |
|
| 105 | + /** |
| 106 | + * 处理订阅消息字符串长度及格式问题 |
| 107 | + * |
| 108 | + * @link <a href="https://developers.weixin.qq.com/miniprogram/dev/server/API/mp-message-management/subscribe-message/api_sendmessage.html">发送订阅消息</a> |
| 109 | + */ |
| 110 | + private MsgData resetValue(MsgData datum) { |
| 111 | + String name = datum.getName(); |
| 112 | + String value = datum.getValue(); |
| 113 | + |
| 114 | + if (StringUtils.isBlank(value)) { |
| 115 | + // 空值会发送失败,改为- |
| 116 | + datum.setValue("-"); |
| 117 | + return datum; |
| 118 | + } |
| 119 | + |
| 120 | + if (StringUtils.startsWith(name, "thing") && value.length() > 20) { |
| 121 | + // thing.DATA: 20个以内字符,可汉字、数字、字母或符号组合 |
| 122 | + value = StringUtils.substring(value, 0, 17) + "..."; |
| 123 | + } else if (StringUtils.startsWith(name, "number")) { |
| 124 | + // number.DATA: 32位以内数字,只能数字,可带小数 |
| 125 | + value = NUMBER_PATTERN.matcher(value).replaceAll(""); |
| 126 | + if (!NUMBER_VALID_PATTERN.matcher(value).matches()) { |
| 127 | + value = "0"; |
| 128 | + } |
| 129 | + if (value.length() > 32) { |
| 130 | + value = StringUtils.substring(value, 0, 32); |
| 131 | + } |
| 132 | + } else if (StringUtils.startsWith(name, "letter")) { |
| 133 | + // letter.DATA: 32位以内字母,只能字母 |
| 134 | + value = LETTER_PATTERN.matcher(value).replaceAll(""); |
| 135 | + if (value.isEmpty()) { |
| 136 | + value = "A"; |
| 137 | + } |
| 138 | + if (value.length() > 32) { |
| 139 | + value = StringUtils.substring(value, 0, 32); |
| 140 | + } |
| 141 | + } else if (StringUtils.startsWith(name, "symbol")) { |
| 142 | + // symbol.DATA: 5位以内符号,只能符号(除中文、英文、数字外的常见符号) |
| 143 | + value = SYMBOL_PATTERN.matcher(value).replaceAll(""); |
| 144 | + if (value.isEmpty()) { |
| 145 | + value = "-"; |
| 146 | + } |
| 147 | + if (value.length() > 5) { |
| 148 | + value = StringUtils.substring(value, 0, 5); |
| 149 | + } |
| 150 | + } else if (StringUtils.startsWith(name, "character_string")) { |
| 151 | + // character_string.DATA: 32位以内,可数字、字母或符号组合(不含中文) |
| 152 | + value = CHARACTER_STRING_PATTERN.matcher(value).replaceAll(""); |
| 153 | + if (value.isEmpty()) { |
| 154 | + value = "0"; |
| 155 | + } |
| 156 | + if (value.length() > 32) { |
| 157 | + value = StringUtils.substring(value, 0, 32); |
| 158 | + } |
| 159 | + } else if (StringUtils.startsWith(name, "phone_number")) { |
| 160 | + // phone_number.DATA: 17位以内,数字、符号 |
| 161 | + value = PHONE_PATTERN.matcher(value).replaceAll(""); |
| 162 | + // 只允许一个前导+号,且必须在开头 |
| 163 | + if (value.startsWith("+")) { |
| 164 | + value = "+" + value.substring(1).replace("+", ""); |
| 165 | + } else { |
| 166 | + value = value.replace("+", ""); |
| 167 | + } |
| 168 | + if (value.isEmpty()) { |
| 169 | + value = "0"; |
| 170 | + } |
| 171 | + if (value.length() > 17) { |
| 172 | + value = StringUtils.substring(value, 0, 17); |
| 173 | + } |
| 174 | + } else if (StringUtils.startsWith(name, "car_number")) { |
| 175 | + // car_number.DATA: 8位以内,第一位与最后一位可为汉字,其余为字母或数字 |
| 176 | + if (value.length() > 8) { |
| 177 | + value = StringUtils.substring(value, 0, 8); |
| 178 | + } |
| 179 | + } else if (StringUtils.startsWith(name, "name")) { |
| 180 | + // name.DATA: 10个以内纯汉字或20个以内纯字母或符号,中文和字母混合按中文名算10个字内 |
| 181 | + // 过滤非法字符,不保留数字(name 类型不允许数字) |
| 182 | + value = NAME_PATTERN.matcher(value).replaceAll(""); |
| 183 | + if (value.isEmpty()) { |
| 184 | + value = "-"; |
| 185 | + } |
| 186 | + boolean containsChinese = CHINESE_PATTERN.matcher(value).find(); |
| 187 | + if (containsChinese) { |
| 188 | + // 含中文,按中文名算,10个字内 |
| 189 | + if (value.length() > 10) { |
| 190 | + value = StringUtils.substring(value, 0, 7) + "..."; |
| 191 | + } |
| 192 | + } else { |
| 193 | + // 纯字母或符号,20个以内 |
| 194 | + if (value.length() > 20) { |
| 195 | + value = StringUtils.substring(value, 0, 17) + "..."; |
| 196 | + } |
| 197 | + } |
| 198 | + } else if (StringUtils.startsWith(name, "phrase")) { |
| 199 | + // phrase.DATA: 5个以内纯汉字 |
| 200 | + value = PHRASE_PATTERN.matcher(value).replaceAll(""); |
| 201 | + if (value.isEmpty()) { |
| 202 | + value = "好"; |
| 203 | + } |
| 204 | + if (value.length() > 5) { |
| 205 | + value = StringUtils.substring(value, 0, 5); |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + datum.setValue(value); |
| 210 | + return datum; |
| 211 | + } |
| 212 | + |
87 | 213 | public String toJson() { |
88 | 214 | return WxMaGsonBuilder.create().toJson(this); |
89 | 215 | } |
|
0 commit comments