Java--业务场景:敏感词过滤代码实现(Fastjson配置全局序列化 @JSONField注解的serializeUsing属性)
业务场景
- 将系统需要替换的敏感词保存在数据库中,在项目启动后,获取敏感词库,保存到Redis缓存中。
- 编写敏感词序列化类 SensitiveWordSerializer 。
- 在需要敏感词过滤的实体类对应的字段上加上注解 @JSONField(serializeUsing = SensitiveWordSerializer.class)。
- 编写FastJson配置类 设置
fastjson
的全局序列化和反序列化的特性,使用FastJsonHttpMessageConverter
替换spring boot默认实现(MappingJackson2HttpMessageConverter
)作为HttpMessageConverters
的首选实现。具体代码如下
需要的依赖坐标
1
2
3
4
5
6
7
8
9
10<!-- fastjson 依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>创建敏感词数据库
- 建库语句
1
2
3
4
5
6
7
8DROP TABLE IF EXISTS `sys_sensitive_word`;
CREATE TABLE `sys_sensitive_word` (
`id` varchar(100) NOT NULL COMMENT 'id',
`name` varchar(100) DEFAULT NULL COMMENT '敏感词文本',
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='敏感词表'; - 插入敏感词数据
- 编写相关的敏感词实体类,service,mapper等代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class SensitiveWord {
private Integer id;
private String name;
private Date gmtCreate;
private Date gmtModified;
}编写敏感词初始化类
- 敏感词初始化类,负责读出数据库中的敏感词表,封装数据结构加载将redis中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90/**
* 敏感词库初始化并放入redis中
*/
public class SensitiveWordInit {
public static final String SENSITIVE_WORD_KEY = "SENSITIVE_WORD_KEY";
/**
* 敏感词库
*/
private HashMap sensitiveWordMap;
private SensitiveWordService sensitiveWordService;
private RedisTemplate<String, Object> redisTemplate;
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 初始化敏感词
*
* @return
*/
public Map<String,Object> initKeyWord() {
try {
List<SensitiveWord> sensitiveWords = sensitiveWordService.selectAll();
// 从敏感词集合对象中取出敏感词并封装到Set集合中
Set<String> keyWordSet = new HashSet();
for (SensitiveWord s : sensitiveWords) {
keyWordSet.add(s.getName().trim());
}
// 将敏感词库加入到HashMap中
addSensitiveWordToHashMap(keyWordSet);
RedisOperation redisOperation = new RedisOperation(this.redisTemplate);
redisOperation.set(SENSITIVE_WORD_KEY,sensitiveWordMap);
} catch (Exception e) {
log.error("初始化敏感词失败");
}
return sensitiveWordMap;
}
public Map getSensitiveWordFromRedis()
{
RedisOperation redisOperation = new RedisOperation(this.redisTemplate);
Map map = redisOperation.get(SENSITIVE_WORD_KEY);
return map;
}
/**
* 封装敏感词库
*
* @param keyWordSet
*/
private void addSensitiveWordToHashMap(Set<String> keyWordSet) {
// 初始化HashMap对象并控制容器的大小
sensitiveWordMap = new HashMap<String,Object>(keyWordSet.size());
// 敏感词
String key = null;
// 用来按照相应的格式保存敏感词库数据
Map nowMap = null;
// 用来辅助构建敏感词库
Map<String, String> newWorMap ;
// 使用一个迭代器来循环敏感词集合
Iterator<String> iterator = keyWordSet.iterator();
while (iterator.hasNext()) {
key = iterator.next();
// 等于敏感词库,HashMap对象在内存中占用的是同一个地址,所以此nowMap对象的变化,sensitiveWordMap对象也会跟着改变
nowMap = sensitiveWordMap;
for (int i = MagicNum.ZERO; i < key.length(); i++) {
// 截取敏感词当中的字,在敏感词库中字为HashMap对象的Key键值
char keyChar = key.charAt(i);
// 判断这个字是否存在于敏感词库中
Object wordMap = nowMap.get(keyChar);
if (wordMap != null) {
nowMap = (Map) wordMap;
} else {
newWorMap = new HashMap();
newWorMap.put("isEnd", "0");
nowMap.put(keyChar, newWorMap);
nowMap = newWorMap;
// 如果该字是当前敏感词的最后一个字,则标识为结尾字
if (i == key.length() - MagicNum.ONE) {
nowMap.put("isEnd", "1");
}
}
}
}}} - 附上上面涉及到的RedisOperation工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400/**
* 主要把一些常用的redis操作使用redisTemplate包装为redis命令名的方式
*/
public final class RedisOperation {
private static final String UNCHECKED = "unchecked";
private RedisTemplate<String, Object> redisTemplate;
public RedisOperation(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 返回与键 key 相关联的值
*/
public <V> V get(String key) {
return (V) redisTemplate.opsForValue().get(key);
}
/**
* 删除key
*/
public Boolean del(String key) {
return redisTemplate.delete(key);
}
/**
* 批量删除
*/
public Long del(Collection<String> keys) {
return redisTemplate.delete(keys);
}
/**
* 返回给定的一个或多个字符串键的值
*/
public List<Object> mget(String... keys) {
return redisTemplate.opsForValue().multiGet(Arrays.asList(keys));
}
/**
* 将value对象序列化后的字符串 关联到key<br/>
* 如果key已经持有其他值,SET就覆写旧值,无视类型。
*/
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 同时为多个键设置值<br/>
* 如果某个给定键已经存在,那么MSET将使用新值去覆盖旧值
*/
public void mset(Map<String, Object> map) {
redisTemplate.opsForValue().multiSet(map);
}
/**
* 同时为多个键设置值<br/>
* 如果键key已经存在,则MSETNX命令不做任何动作
*/
public void msetnx(Map<String, Object> map) {
redisTemplate.opsForValue().multiSetIfAbsent(map);
}
/**
* 将键key的值设置为value对象的序列化字符串,并将键key的生存时间设置为timeout<br/>
* 如果键key已经存在,那么将覆盖已有的值
*/
public void setex(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
/**
* 只在键key不存在的情况下, 将键key的值设置为value<br/>
* 若键key已经存在,则SETNX命令不做任何动作
*/
public void setnx(String key, Object value) {
redisTemplate.opsForValue().setIfAbsent(key, value);
}
/**
* 只在键key不存在的情况下,将键key的值设置为value,且同时设置过期时间<br/>
* 若键key已经存在,则SETNX命令不做任何动作。
*/
public void setnx(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
}
/**
* 为键key储存的数字值加上一
*/
public Long incr(String key) {
return incr(key, 1);
}
/**
* 为键key储存的数字值加上增量increment
*/
public Long incr(String key, long increment) {
return redisTemplate.opsForValue().increment(key, increment);
}
/**
* 将键key储存的整数值减去减量decrement
*/
public Long decr(String key, long decrement) {
return redisTemplate.opsForValue().decrement(key, decrement);
}
/**
* 为键key储存的数字减一
*/
public Long decr(String key) {
return decr(key, 1);
}
/**
* HGET命令在默认情况下返回给定域的值<br/>
* 如果给定域不存在于哈希表中,又或者给定的哈希表并不存在,那么命令返回 nil
*/
public <V> V hget(String key, String field) {
return (V) redisTemplate.opsForHash().get(key, field);
}
/**
* 如果给定的域不存在于哈希表,那么返回一个nil值<br/>
* 因为不存在的key被当作一个空哈希表来处理,所以对一个不存在的key进行HMGET操作将返回一个只带有 nil 值的表
*/
public List<Object> hmget(String key, String... fields) {
return redisTemplate.opsForHash().multiGet(key, new ArrayList<>(Arrays.asList(fields)));
}
/**
* 返回哈希表 key 中,所有的域和值
*/
public Map<Object, Object> hgetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 如果给定的哈希表并不存在,那么一个新的哈希表将被创建并执行HSET操作<br/>
* 如果域field已经存在于哈希表中, 那么它的旧值将被新值 value 覆盖。
*/
public <V> void hset(String key, String field, V value) {
redisTemplate.opsForHash().put(key, field, value);
}
/**
* 同时将多个field-value(域-值)对设置到哈希表key中<br/>
* 此命令会覆盖哈希表中已存在的域<br/>
* 如果 key 不存在,一个空哈希表被创建并执行 HMSET 操作。
*/
public void hmset(String key, Map<String, ?> data) {
redisTemplate.opsForHash().putAll(key, data);
}
/**
* 检查给定field是否存在于哈希表hash当中
*/
public Boolean hexists(String key, String field) {
return redisTemplate.opsForHash().hasKey(key, field);
}
/**
* 删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略
*/
public Long hdel(String key, Object... fields) {
return redisTemplate.opsForHash().delete(key, fields);
}
/**
* 将一个或多个值 value 插入到列表 key 的表尾(最右边)<br/>
* 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作<br />
* 当 key 存在但不是列表类型时,返回一个错误
*/
public Long rpush(String key, Object... values) {
return redisTemplate.opsForList().rightPushAll(key, values);
}
/**
* 将一个或多个值 value 插入到列表 key 的表头<br />
* 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作<br />
* 当 key 存在但不是列表类型时,返回一个错误
*/
public Long lpush(String key, Object... values) {
return redisTemplate.opsForList().leftPushAll(key, values);
}
/**
* 移除并返回列表 key 的头元素
*/
public <V> V lpop(String key) {
return (V) redisTemplate.opsForList().leftPop(key);
}
/**
* 移除并返回列表 key 的尾元素
*/
public <V> V rpop(String key) {
return (V) redisTemplate.opsForList().rightPop(key);
}
/**
* 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
*/
public <V> Long sadd(String key, V... members) {
return redisTemplate.opsForSet().add(key, members);
}
/**
* 判断 member 元素是否集合 key 的成员
*/
public Boolean sismember(String key, Object member) {
return redisTemplate.opsForSet().isMember(key, member);
}
/**
* 返回集合中的一个随机元素
*/
public <V> V srandmember(String key) {
return (V) redisTemplate.opsForSet().randomMember(key);
}
/**
* 返回集合中的随机元素。<p/>
* 如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合。<p/>
* 如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
*/
public List<Object> srandmembers(String key, long count) {
return redisTemplate.opsForSet().randomMembers(key, count);
}
/**
* 返回集合 key 中的所有成员。<br />
* 不存在的 key 被视为空集合
*/
public Set<Object> smembers(String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 返回集合key的基数(集合中元素的数量)
*/
public Long scard(String key) {
return redisTemplate.opsForSet().size(key);
}
/**
* 移除集合key中的一个或多个member元素,不存在的member元素会被忽略。<br />
* 当key不是集合类型,返回一个错误
*/
public Long srem(String key, Object... values) {
return redisTemplate.opsForSet().remove(key, values);
}
/**
* 将一个元素及其score值加入到有序集key当中
*/
public <V> Boolean zadd(String key, V value, double score) {
return redisTemplate.opsForZSet().add(key, value, score);
}
/**
* 返回有序集key中,成员member的score值
*/
public Double zscore(String key, Object member) {
return redisTemplate.opsForZSet().score(key, member);
}
/**
* 为有序集key的成员member的score值加上增量increment
*/
public Double zincrby(String key, Object member, double increment) {
return redisTemplate.opsForZSet().incrementScore(key, member, increment);
}
/**
* 返回有序集key中,指定区间内的成员
*/
public Set<Object> zrange(String key, long start, long end) {
return redisTemplate.opsForZSet().range(key, start, end);
}
/**
* 返回有序集key中,指定区间内的成员。且带有score
*/
public Set<ZSetOperations.TypedTuple<Object>> zrangewithscore(String key, long start, long end) {
return redisTemplate.opsForZSet().rangeWithScores(key, start, end);
}
/**
* 返回有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。<br />
* 有序集成员按score值递增(从小到大)次序排列
*/
public Set<Object> zrangebyscore(String key, double min, double max) {
return redisTemplate.opsForZSet().rangeByScore(key, min, max);
}
/**
* 返回有序集key中,指定区间内的成员<br />
* 成员的位置按score值递减(从大到小)来排列
*/
public Set<Object> zrevrange(String key, long start, long end) {
return redisTemplate.opsForZSet().reverseRange(key, start, end);
}
/**
* 返回有序集key中,指定区间内的成员。且带有score
*/
public Set<ZSetOperations.TypedTuple<Object>> zrevrangewithscores(String key, long start, long end) {
return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
}
/**
* 返回有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。<br />
* 有序集成员按score值递增(从大到小)次序排列
*/
public Set<Object> zrevrangebyscore(String key, double min, double max) {
return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
}
/**
* 移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员
*/
public Long zremrangebyscore(String key, double min, double max) {
return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
}
/**
* 移除有序集key中,指定排名(rank)区间内的所有成员。
*/
public Long zremrangebyrank(String key, long start, long end) {
return redisTemplate.opsForZSet().removeRange(key, start, end);
}
/**
* 移除有序集key中的一个或多个成员,不存在的成员将被忽略
*/
public Long zrem(String key, Object... values) {
return redisTemplate.opsForZSet().remove(key, values);
}
/**
* 获取元素value在有序集合中的位置排名
*/
public Long zrank(String key, Object value) {
return redisTemplate.opsForZSet().reverseRank(key, value);
}
/**
* 当key存在且是有序集类型时,返回有序集的基数。当key不存在时,返回0
*/
public Long zcard(String key) {
return redisTemplate.opsForZSet().size(key);
}
/**
* 返回有序集key中,score值在min和max之间(默认包括score值等于min或max)的成员的数量
*/
public Long zcount(String key, double min, double max) {
return redisTemplate.opsForZSet().count(key, min, max);
}
/**
* 设置过期时间
*
* @param timeout 过期时间,单位毫秒
*/
public Boolean expire(String key, long timeout) {
return redisTemplate.expire(key, timeout, TimeUnit.MILLISECONDS);
}
/**
* 获取key的存活时长,单位毫秒
*/
public Long ttl(String key) {
return redisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
}
/**
* 判断key是否存在
*/
public Boolean exist(String key) {
return redisTemplate.hasKey(key);
}
/**
* 获取底层redisTemplate
*/
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
}编写敏感词序列化类
- 敏感词序列化类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122/**
* 敏感词过滤工具类
* 使用方法 @JSONField(serializeUsing = SensitiveWordSerializer.class)
*/
public class SensitiveWordSerializer implements ObjectSerializer {
/**
* 敏感词库
*/
private static Map<String,Object> sensitiveWordMap = null;
private static SensitiveWordInit wordInit;
public void setRedisTemplate(SensitiveWordInit sensitiveWordInit) {
SensitiveWordSerializer.wordInit = sensitiveWordInit;
}
public void initSensitiveWord() {
sensitiveWordMap = SensitiveWordSerializer.wordInit.initKeyWord();
}
/**
* 获取敏感词内容
*
* @param txt
* @param matchType
* @return 敏感词内容
*/
public Set<String> getSensitiveWord(String txt, int matchType) {
Set<String> sensitiveWordList = new HashSet();
for (int i = MagicNum.ZERO; i < txt.length(); i++) {
int length = checkSensitiveWord(txt, i, matchType);
if (length > MagicNum.ZERO) {
// 将检测出的敏感词保存到集合中
sensitiveWordList.add(txt.substring(i, i + length));
i = i + length - MagicNum.ONE;
}
}
return sensitiveWordList;
}
/**
* 替换敏感词
*
* @param txt
* @param matchType
* @param replaceChar
* @return
*/
public String replaceSensitiveWord(String txt, int matchType, String replaceChar) {
sensitiveWordMap = wordInit.getSensitiveWordFromRedis();
String resultTxt = txt;
Set<String> set = getSensitiveWord(txt, matchType);
Iterator<String> iterator = set.iterator();
String word ;
String replaceString ;
while (iterator.hasNext()) {
word = iterator.next();
replaceString = getReplaceChars(replaceChar, word.length());
resultTxt = resultTxt.replaceAll(word, replaceString);
}
return resultTxt;
}
/**
* 替换敏感词内容
*
* @param replaceChar
* @param length
* @return
*/
private String getReplaceChars(String replaceChar, int length) {
StringBuilder resultReplace = new StringBuilder(replaceChar);
for (int i = MagicNum.ONE; i < length; i++) {
resultReplace.append(replaceChar);
}
return resultReplace.toString();
}
/**
* 检查敏感词数量
*
* @param txt
* @param beginIndex
* @param matchType
* @return
*/
public int checkSensitiveWord(String txt, int beginIndex, int matchType) {
boolean flag = false;
// 记录敏感词数量
int matchFlag = MagicNum.ZERO;
String word ;
Map<String,Object> nowMap = sensitiveWordMap;
for (int i = beginIndex; i < txt.length(); i++) {
word = String.valueOf(txt.charAt(i));
// 判断该字是否存在于敏感词库中
nowMap = (Map<String,Object>) nowMap.get(word);
if (nowMap != null) {
matchFlag++;
// 判断是否是敏感词的结尾字,如果是结尾字则判断是否继续检测
if ("1".equals(nowMap.get("isEnd"))) {
flag = true;
// 判断过滤类型,如果是小过滤则跳出循环,否则继续循环
}
} else {
break;
}
}
if (!flag) {
matchFlag = 0;
}
return matchFlag;
}
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
String value = replaceSensitiveWord((String) object, MagicNum.TWO, "*");
serializer.write(value);
}
}在需要敏感词过滤的实体上加上注解
- 加上注解 @JSONField(serializeUsing = SensitiveWordSerializer.class)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserDTO {
private String id;
// username需要敏感词过滤
private String username;
//......
}Fastjson配置类
- 设置
fastjson
的全局序列化和反序列化的特性,使用FastJsonHttpMessageConverter
替换spring boot默认实现(MappingJackson2HttpMessageConverter
)作为HttpMessageConverters
首选实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36/**
* Fastjson全局序列化配置
*
*/
public class FastJsonConfig {
private static final Map<SerializerFeature, String> SERIALIZER_FEATURES = new EnumMap<>(SerializerFeature.class);
private static final Map<Feature, String> PARSER_FEATURES = new EnumMap<>(Feature.class);
static {
SERIALIZER_FEATURES.put(SerializerFeature.WriteMapNullValue, "WriteMapNullValue:输出值为null的字段");
SERIALIZER_FEATURES.put(SerializerFeature.WriteDateUseDateFormat, "WriteDateUseDateFormat:根据全局日期格式格式化");
SERIALIZER_FEATURES.put(SerializerFeature.WriteBigDecimalAsPlain, "WriteBigDecimalAsPlain:大数序列化为文本");
SERIALIZER_FEATURES.put(SerializerFeature.DisableCircularReferenceDetect, "DisableCircularReferenceDetect:关闭循环引用发现");
PARSER_FEATURES.put(Feature.AllowISO8601DateFormat, "AllowISO8601DateFormat:支持ISO8601格式的日期");
PARSER_FEATURES.put(Feature.DisableCircularReferenceDetect, "DisableCircularReferenceDetect:关闭循环引用发现");
log.debug("全局启用Fastjson下列序列化选项");
for (Map.Entry<SerializerFeature, String> entry : SERIALIZER_FEATURES.entrySet()) {
JSON.DEFAULT_GENERATE_FEATURE |= entry.getKey().getMask();
log.debug(entry.getValue());
}
log.debug("全局启用Fastjson下列反序列化选项");
for (Map.Entry<Feature, String> entry : PARSER_FEATURES.entrySet()) {
JSON.DEFAULT_PARSER_FEATURE |= entry.getKey().getMask();
log.debug(entry.getValue());
}
}
public HttpMessageConverters fastJsonHttpMessageConverters() {
log.debug("启用FastJsonHttpMessageConverter,将其添加至同类HttpMessageConverter之前");
return new HttpMessageConverters(new FastJsonHttpMessageConverter());
}
}执行效果
- 数据库中有一条用户数据,用户昵称为”笨蛋芝麻馅笨蛋“,”笨蛋“是我们的敏感词,启动项目,调用分页查询的接口,返回的用户昵称敏感词部分被*号代替:
- 数据库情况
- 调用接口查找用户信息结果,发现用户昵称中的敏感词成功被*号所代替。
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.