Java--业务场景:敏感词过滤代码实现(Fastjson配置全局序列化 @JSONField注解的serializeUsing属性)

业务场景
  • 在系统数据库中,可能存在一些用户名称,昵称,评论中有些词汇,出于保护隐私或是不符合规范等原因,不能直接展示在前端页面上,这样的敏感词需要用 * 号代替。
实现步骤
  1. 将系统需要替换的敏感词保存在数据库中,在项目启动后,获取敏感词库,保存到Redis缓存中。
  2. 编写敏感词序列化类 SensitiveWordSerializer 。
  3. 在需要敏感词过滤的实体类对应的字段上加上注解 @JSONField(serializeUsing = SensitiveWordSerializer.class)。
  4. 编写FastJson配置类 设置fastjson的全局序列化和反序列化的特性,使用FastJsonHttpMessageConverter替换spring boot默认实现(MappingJackson2HttpMessageConverter)作为HttpMessageConverters的首选实现。
具体代码如下
需要的依赖坐标
    <!--  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>
创建敏感词数据库
  • 建库语句
        DROP 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等代码
    @Data
    @TableName("sys_sensitive_word")
    public class SensitiveWord {
      @TableId(value = "id", type = IdType.ASSIGN_ID)
      private Integer id;
    
      @TableField("name")
      private String name;
    
      @ApiModelProperty(value = "创建时间")
      @TableField(fill = FieldFill.INSERT)
      private Date gmtCreate;
    
      @ApiModelProperty(value = "更新时间")
      @TableField(fill = FieldFill.INSERT_UPDATE)
      private Date gmtModified;
     }
    
编写敏感词初始化类
  • 敏感词初始化类,负责读出数据库中的敏感词表,封装数据结构加载将redis中
    /**
     * 敏感词库初始化并放入redis中
     */
    @Slf4j
    @Component
    public class SensitiveWordInit {
    
        public static final String SENSITIVE_WORD_KEY = "SENSITIVE_WORD_KEY";
        /**
         * 敏感词库
         */
        private HashMap sensitiveWordMap;
        @Autowired
        private SensitiveWordService sensitiveWordService;
    
        private RedisTemplate<String, Object> redisTemplate;
    
        @Autowired
        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工具类
    /**
     * 主要把一些常用的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 相关联的值
         */
        @SuppressWarnings(UNCHECKED)
        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
         */
         @SuppressWarnings(UNCHECKED)
         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 的头元素
         */
         @SuppressWarnings(UNCHECKED)
         public <V> V lpop(String key) {
            return (V) redisTemplate.opsForList().leftPop(key);
         }
    
       /**
        * 移除并返回列表 key 的尾元素
         */
         @SuppressWarnings(UNCHECKED)
         public <V> V rpop(String key) {
            return (V) redisTemplate.opsForList().rightPop(key);
         }
    
       /**
        * 将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
         */
         @SuppressWarnings(UNCHECKED)
         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);
         }
    
       /**
       * 返回集合中的一个随机元素
         */
         @SuppressWarnings(UNCHECKED)
         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;
       }
    }
    
编写敏感词序列化类
  • 敏感词序列化类
     /**
      * 敏感词过滤工具类
      * 使用方法    @JSONField(serializeUsing = SensitiveWordSerializer.class)
      */
      @Component
      public class SensitiveWordSerializer implements ObjectSerializer {
      
      /**
      * 敏感词库
        */
        private static Map<String,Object> sensitiveWordMap = null;
      
      private static SensitiveWordInit wordInit;
      
      @Autowired
      public void setRedisTemplate(SensitiveWordInit sensitiveWordInit) {
      SensitiveWordSerializer.wordInit = sensitiveWordInit;
      }
      @PostConstruct
      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;
      }
      
      @Override
      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)
     @Data
     @EqualsAndHashCode(callSuper = false)
     @Accessors(chain = true)
     @TableName("sys_user")
     @ApiModel(description = "用户实体类")
     public class UserDTO  {
      
         @TableId(value = "id", type = IdType.ASSIGN_ID)
         private String id;
         
         @TableField(value = "username")
         // username需要敏感词过滤
         @JSONField(serializeUsing = SensitiveWordSerializer.class)
         private String username;
         
         //......
    }
    
Fastjson配置类
  • 设置fastjson的全局序列化和反序列化的特性,使用FastJsonHttpMessageConverter替换spring boot默认实现(MappingJackson2HttpMessageConverter)作为HttpMessageConverters首选实现
    /**
     * Fastjson全局序列化配置
     *
     */
      @Configuration
      @Slf4j
      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());
              }
         }
    
      @Bean
      public HttpMessageConverters fastJsonHttpMessageConverters() {
            log.debug("启用FastJsonHttpMessageConverter,将其添加至同类HttpMessageConverter之前");
             return new HttpMessageConverters(new FastJsonHttpMessageConverter());
         }
     }
    
执行效果
  • 数据库中有一条用户数据,用户昵称为”笨蛋芝麻馅笨蛋“,”笨蛋“是我们的敏感词,启动项目,调用分页查询的接口,返回的用户昵称敏感词部分被*号代替:
  • 数据库情况
    在这里插入图片描述
  • 调用接口查找用户信息结果,发现用户昵称中的敏感词成功被*号所代替。
    在这里插入图片描述
  • 41
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻馅_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值