mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	【移除】敏感词的管理,简化项目的复杂度
This commit is contained in:
		@@ -1,29 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.api.sensitiveword;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 敏感词 API 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author 永不言败
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
public class SensitiveWordApiImpl implements SensitiveWordApi {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SensitiveWordService sensitiveWordService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> validateText(String text, List<String> tags) {
 | 
			
		||||
        return sensitiveWordService.validateText(text, tags);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isTextValid(String text, List<String> tags) {
 | 
			
		||||
        return sensitiveWordService.isTextValid(text, tags);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
### 请求 /system/sensitive-word/validate-text 接口 => 成功
 | 
			
		||||
GET {{baseUrl}}/system/sensitive-word/validate-text?text=XXX&tags=短信&tags=蔬菜
 | 
			
		||||
Authorization: Bearer {{token}}
 | 
			
		||||
tenant-id: {{adminTenentId}}
 | 
			
		||||
@@ -1,108 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.sensitiveword;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordRespVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Parameter;
 | 
			
		||||
import io.swagger.v3.oas.annotations.tags.Tag;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import jakarta.validation.Valid;
 | 
			
		||||
import org.springframework.security.access.prepost.PreAuthorize;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 | 
			
		||||
 | 
			
		||||
@Tag(name = "管理后台 - 敏感词")
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/system/sensitive-word")
 | 
			
		||||
@Validated
 | 
			
		||||
public class SensitiveWordController {
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SensitiveWordService sensitiveWordService;
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/create")
 | 
			
		||||
    @Operation(summary = "创建敏感词")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:create')")
 | 
			
		||||
    public CommonResult<Long> createSensitiveWord(@Valid @RequestBody SensitiveWordSaveVO createReqVO) {
 | 
			
		||||
        return success(sensitiveWordService.createSensitiveWord(createReqVO));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PutMapping("/update")
 | 
			
		||||
    @Operation(summary = "更新敏感词")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:update')")
 | 
			
		||||
    public CommonResult<Boolean> updateSensitiveWord(@Valid @RequestBody SensitiveWordSaveVO updateReqVO) {
 | 
			
		||||
        sensitiveWordService.updateSensitiveWord(updateReqVO);
 | 
			
		||||
        return success(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @DeleteMapping("/delete")
 | 
			
		||||
    @Operation(summary = "删除敏感词")
 | 
			
		||||
    @Parameter(name = "id", description = "编号", required = true)
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:delete')")
 | 
			
		||||
    public CommonResult<Boolean> deleteSensitiveWord(@RequestParam("id") Long id) {
 | 
			
		||||
        sensitiveWordService.deleteSensitiveWord(id);
 | 
			
		||||
        return success(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get")
 | 
			
		||||
    @Operation(summary = "获得敏感词")
 | 
			
		||||
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')")
 | 
			
		||||
    public CommonResult<SensitiveWordRespVO> getSensitiveWord(@RequestParam("id") Long id) {
 | 
			
		||||
        SensitiveWordDO sensitiveWord = sensitiveWordService.getSensitiveWord(id);
 | 
			
		||||
        return success(BeanUtils.toBean(sensitiveWord, SensitiveWordRespVO.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/page")
 | 
			
		||||
    @Operation(summary = "获得敏感词分页")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')")
 | 
			
		||||
    public CommonResult<PageResult<SensitiveWordRespVO>> getSensitiveWordPage(@Valid SensitiveWordPageReqVO pageVO) {
 | 
			
		||||
        PageResult<SensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(pageVO);
 | 
			
		||||
        return success(BeanUtils.toBean(pageResult, SensitiveWordRespVO.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/export-excel")
 | 
			
		||||
    @Operation(summary = "导出敏感词 Excel")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:export')")
 | 
			
		||||
    @ApiAccessLog(operateType = EXPORT)
 | 
			
		||||
    public void exportSensitiveWordExcel(@Valid SensitiveWordPageReqVO exportReqVO,
 | 
			
		||||
              HttpServletResponse response) throws IOException {
 | 
			
		||||
        exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
 | 
			
		||||
        List<SensitiveWordDO> list = sensitiveWordService.getSensitiveWordPage(exportReqVO).getList();
 | 
			
		||||
        // 导出 Excel
 | 
			
		||||
        ExcelUtils.write(response, "敏感词.xls", "数据", SensitiveWordRespVO.class,
 | 
			
		||||
                BeanUtils.toBean(list, SensitiveWordRespVO.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/get-tags")
 | 
			
		||||
    @Operation(summary = "获取所有敏感词的标签数组")
 | 
			
		||||
    @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')")
 | 
			
		||||
    public CommonResult<Set<String>> getSensitiveWordTagSet() {
 | 
			
		||||
        return success(sensitiveWordService.getSensitiveWordTagSet());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/validate-text")
 | 
			
		||||
    @Operation(summary = "获得文本所包含的不合法的敏感词数组")
 | 
			
		||||
    public CommonResult<List<String>> validateText(@RequestParam("text") String text,
 | 
			
		||||
                                                   @RequestParam(value = "tags", required = false) List<String> tags) {
 | 
			
		||||
        return success(sensitiveWordService.validateText(text, tags));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.ToString;
 | 
			
		||||
import org.springframework.format.annotation.DateTimeFormat;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 | 
			
		||||
 | 
			
		||||
@Schema(description = "管理后台 - 敏感词分页 Request VO")
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@ToString(callSuper = true)
 | 
			
		||||
public class SensitiveWordPageReqVO extends PageParam {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "敏感词", example = "敏感词")
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "标签", example = "短信,评论")
 | 
			
		||||
    private String tag;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "状态,参见 CommonStatusEnum 枚举类", example = "1")
 | 
			
		||||
    private Integer status;
 | 
			
		||||
 | 
			
		||||
    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
 | 
			
		||||
    @Schema(description = "创建时间")
 | 
			
		||||
    private LocalDateTime[] createTime;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
 | 
			
		||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
 | 
			
		||||
import cn.iocoder.yudao.framework.excel.core.convert.JsonConvert;
 | 
			
		||||
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
 | 
			
		||||
import com.alibaba.excel.annotation.ExcelProperty;
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.ToString;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Schema(description = "管理后台 - 敏感词 Response VO")
 | 
			
		||||
@Data
 | 
			
		||||
public class SensitiveWordRespVO {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    @ExcelProperty("编号")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "敏感词", requiredMode = Schema.RequiredMode.REQUIRED, example = "敏感词")
 | 
			
		||||
    @ExcelProperty("敏感词")
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "短信,评论")
 | 
			
		||||
    @ExcelProperty(value = "标签", converter = JsonConvert.class)
 | 
			
		||||
    private List<String> tags;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    @ExcelProperty(value = "状态", converter = DictConvert.class)
 | 
			
		||||
    @DictFormat(DictTypeConstants.COMMON_STATUS)
 | 
			
		||||
    private Integer status;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "描述", example = "污言秽语")
 | 
			
		||||
    @ExcelProperty("描述")
 | 
			
		||||
    private String description;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
			
		||||
    @ExcelProperty("创建时间")
 | 
			
		||||
    private LocalDateTime createTime;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.constraints.NotNull;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Schema(description = "管理后台 - 敏感词创建/修改 Request VO")
 | 
			
		||||
@Data
 | 
			
		||||
public class SensitiveWordSaveVO {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "编号", example = "1")
 | 
			
		||||
    private Long id;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "敏感词", requiredMode = Schema.RequiredMode.REQUIRED, example = "敏感词")
 | 
			
		||||
    @NotNull(message = "敏感词不能为空")
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "标签", requiredMode = Schema.RequiredMode.REQUIRED, example = "短信,评论")
 | 
			
		||||
    @NotNull(message = "标签不能为空")
 | 
			
		||||
    private List<String> tags;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
 | 
			
		||||
    @NotNull(message = "状态不能为空")
 | 
			
		||||
    private Integer status;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "描述", example = "污言秽语")
 | 
			
		||||
    private String description;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,58 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.KeySequence;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableField;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableId;
 | 
			
		||||
import com.baomidou.mybatisplus.annotation.TableName;
 | 
			
		||||
import lombok.*;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 敏感词 DO
 | 
			
		||||
 *
 | 
			
		||||
 * @author 永不言败
 | 
			
		||||
 */
 | 
			
		||||
@TableName(value = "system_sensitive_word", autoResultMap = true)
 | 
			
		||||
@KeySequence("system_sensitive_word_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@ToString(callSuper = true)
 | 
			
		||||
@Builder
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class SensitiveWordDO extends BaseDO {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 编号
 | 
			
		||||
     */
 | 
			
		||||
    @TableId
 | 
			
		||||
    private Long id;
 | 
			
		||||
    /**
 | 
			
		||||
     * 敏感词
 | 
			
		||||
     */
 | 
			
		||||
    private String name;
 | 
			
		||||
    /**
 | 
			
		||||
     * 描述
 | 
			
		||||
     */
 | 
			
		||||
    private String description;
 | 
			
		||||
    /**
 | 
			
		||||
     * 标签数组
 | 
			
		||||
     *
 | 
			
		||||
     * 用于实现不同的业务场景下,需要使用不同标签的敏感词。
 | 
			
		||||
     * 例如说,tag 有短信、论坛两种,敏感词 "推广" 在短信下是敏感词,在论坛下不是敏感词。
 | 
			
		||||
     * 此时,我们会存储一条敏感词记录,它的 name 为"推广",tag 为短信。
 | 
			
		||||
     */
 | 
			
		||||
    @TableField(typeHandler = StringListTypeHandler.class)
 | 
			
		||||
    private List<String> tags;
 | 
			
		||||
    /**
 | 
			
		||||
     * 状态
 | 
			
		||||
     *
 | 
			
		||||
     * 枚举 {@link CommonStatusEnum}
 | 
			
		||||
     */
 | 
			
		||||
    private Integer status;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,36 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.dal.mysql.sensitiveword;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 | 
			
		||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
import org.apache.ibatis.annotations.Select;
 | 
			
		||||
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 敏感词 Mapper
 | 
			
		||||
 *
 | 
			
		||||
 * @author 永不言败
 | 
			
		||||
 */
 | 
			
		||||
@Mapper
 | 
			
		||||
public interface SensitiveWordMapper extends BaseMapperX<SensitiveWordDO> {
 | 
			
		||||
 | 
			
		||||
    default PageResult<SensitiveWordDO> selectPage(SensitiveWordPageReqVO reqVO) {
 | 
			
		||||
        return selectPage(reqVO, new LambdaQueryWrapperX<SensitiveWordDO>()
 | 
			
		||||
                .likeIfPresent(SensitiveWordDO::getName, reqVO.getName())
 | 
			
		||||
                .likeIfPresent(SensitiveWordDO::getTags, reqVO.getTag())
 | 
			
		||||
                .eqIfPresent(SensitiveWordDO::getStatus, reqVO.getStatus())
 | 
			
		||||
                .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getCreateTime())
 | 
			
		||||
                .orderByDesc(SensitiveWordDO::getId));
 | 
			
		||||
    }
 | 
			
		||||
    default SensitiveWordDO selectByName(String name) {
 | 
			
		||||
        return selectOne(SensitiveWordDO::getName, name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Select("SELECT COUNT(*) FROM system_sensitive_word WHERE update_time > #{maxUpdateTime}")
 | 
			
		||||
    Long selectCountByUpdateTimeGt(LocalDateTime maxTime);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,89 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.sensitiveword;
 | 
			
		||||
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
 | 
			
		||||
 | 
			
		||||
import jakarta.validation.Valid;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 敏感词 Service 接口
 | 
			
		||||
 *
 | 
			
		||||
 * @author 永不言败
 | 
			
		||||
 */
 | 
			
		||||
public interface SensitiveWordService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param createReqVO 创建信息
 | 
			
		||||
     * @return 编号
 | 
			
		||||
     */
 | 
			
		||||
    Long createSensitiveWord(@Valid SensitiveWordSaveVO createReqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 更新敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param updateReqVO 更新信息
 | 
			
		||||
     */
 | 
			
		||||
    void updateSensitiveWord(@Valid SensitiveWordSaveVO updateReqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 删除敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 编号
 | 
			
		||||
     */
 | 
			
		||||
    void deleteSensitiveWord(Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param id 编号
 | 
			
		||||
     * @return 敏感词
 | 
			
		||||
     */
 | 
			
		||||
    SensitiveWordDO getSensitiveWord(Long id);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得敏感词列表
 | 
			
		||||
     *
 | 
			
		||||
     * @return 敏感词列表
 | 
			
		||||
     */
 | 
			
		||||
    List<SensitiveWordDO> getSensitiveWordList();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得敏感词分页
 | 
			
		||||
     *
 | 
			
		||||
     * @param pageReqVO 分页查询
 | 
			
		||||
     * @return 敏感词分页
 | 
			
		||||
     */
 | 
			
		||||
    PageResult<SensitiveWordDO> getSensitiveWordPage(SensitiveWordPageReqVO pageReqVO);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得所有敏感词的标签数组
 | 
			
		||||
     *
 | 
			
		||||
     * @return 标签数组
 | 
			
		||||
     */
 | 
			
		||||
    Set<String> getSensitiveWordTagSet();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得文本所包含的不合法的敏感词数组
 | 
			
		||||
     *
 | 
			
		||||
     * @param text 文本
 | 
			
		||||
     * @param tags 标签数组
 | 
			
		||||
     * @return 不合法的敏感词数组
 | 
			
		||||
     */
 | 
			
		||||
    List<String> validateText(String text, List<String> tags);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 判断文本是否包含敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param text 文本
 | 
			
		||||
     * @param tags 标签数组
 | 
			
		||||
     * @return 是否包含敏感词
 | 
			
		||||
     */
 | 
			
		||||
    boolean isTextValid(String text, List<String> tags);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,262 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.service.sensitiveword;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordSaveVO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO;
 | 
			
		||||
import cn.iocoder.yudao.module.system.dal.mysql.sensitiveword.SensitiveWordMapper;
 | 
			
		||||
import cn.iocoder.yudao.module.system.util.collection.SimpleTrie;
 | 
			
		||||
import com.google.common.collect.HashMultimap;
 | 
			
		||||
import com.google.common.collect.Multimap;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.springframework.scheduling.annotation.Scheduled;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.validation.annotation.Validated;
 | 
			
		||||
 | 
			
		||||
import jakarta.annotation.PostConstruct;
 | 
			
		||||
import jakarta.annotation.Resource;
 | 
			
		||||
import java.time.LocalDateTime;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.TimeUnit;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_EXISTS;
 | 
			
		||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.SENSITIVE_WORD_NOT_EXISTS;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 敏感词 Service 实现类
 | 
			
		||||
 *
 | 
			
		||||
 * @author 永不言败
 | 
			
		||||
 */
 | 
			
		||||
@Service
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Validated
 | 
			
		||||
public class SensitiveWordServiceImpl implements SensitiveWordService {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 是否开启敏感词功能
 | 
			
		||||
     */
 | 
			
		||||
    public static Boolean ENABLED = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 敏感词列表缓存
 | 
			
		||||
     */
 | 
			
		||||
    @Getter
 | 
			
		||||
    private volatile List<SensitiveWordDO> sensitiveWordCache = Collections.emptyList();
 | 
			
		||||
    /**
 | 
			
		||||
     * 敏感词标签缓存
 | 
			
		||||
     * key:敏感词编号 {@link SensitiveWordDO#getId()}
 | 
			
		||||
     * <p>
 | 
			
		||||
     * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
 | 
			
		||||
     */
 | 
			
		||||
    @Getter
 | 
			
		||||
    private volatile Set<String> sensitiveWordTagsCache = Collections.emptySet();
 | 
			
		||||
 | 
			
		||||
    @Resource
 | 
			
		||||
    private SensitiveWordMapper sensitiveWordMapper;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 默认的敏感词的字典树,包含所有敏感词
 | 
			
		||||
     */
 | 
			
		||||
    @Getter
 | 
			
		||||
    private volatile SimpleTrie defaultSensitiveWordTrie = new SimpleTrie(Collections.emptySet());
 | 
			
		||||
    /**
 | 
			
		||||
     * 标签与敏感词的字段数的映射
 | 
			
		||||
     */
 | 
			
		||||
    @Getter
 | 
			
		||||
    private volatile Map<String, SimpleTrie> tagSensitiveWordTries = Collections.emptyMap();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 初始化缓存
 | 
			
		||||
     */
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void initLocalCache() {
 | 
			
		||||
        if (!ENABLED) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 第一步:查询数据
 | 
			
		||||
        List<SensitiveWordDO> sensitiveWords = sensitiveWordMapper.selectList();
 | 
			
		||||
        log.info("[initLocalCache][缓存敏感词,数量为:{}]", sensitiveWords.size());
 | 
			
		||||
 | 
			
		||||
        // 第二步:构建缓存
 | 
			
		||||
        // 写入 sensitiveWordTagsCache 缓存
 | 
			
		||||
        Set<String> tags = new HashSet<>();
 | 
			
		||||
        sensitiveWords.forEach(word -> tags.addAll(word.getTags()));
 | 
			
		||||
        sensitiveWordTagsCache = tags;
 | 
			
		||||
        sensitiveWordCache = sensitiveWords;
 | 
			
		||||
        // 写入 defaultSensitiveWordTrie、tagSensitiveWordTries 缓存
 | 
			
		||||
        initSensitiveWordTrie(sensitiveWords);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initSensitiveWordTrie(List<SensitiveWordDO> wordDOs) {
 | 
			
		||||
        // 过滤禁用的敏感词
 | 
			
		||||
        wordDOs = filterList(wordDOs, word -> word.getStatus().equals(CommonStatusEnum.ENABLE.getStatus()));
 | 
			
		||||
 | 
			
		||||
        // 初始化默认的 defaultSensitiveWordTrie
 | 
			
		||||
        this.defaultSensitiveWordTrie = new SimpleTrie(CollectionUtils.convertList(wordDOs, SensitiveWordDO::getName));
 | 
			
		||||
 | 
			
		||||
        // 初始化 tagSensitiveWordTries
 | 
			
		||||
        Multimap<String, String> tagWords = HashMultimap.create();
 | 
			
		||||
        for (SensitiveWordDO word : wordDOs) {
 | 
			
		||||
            if (CollUtil.isEmpty(word.getTags())) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            word.getTags().forEach(tag -> tagWords.put(tag, word.getName()));
 | 
			
		||||
        }
 | 
			
		||||
        // 添加到 tagSensitiveWordTries 中
 | 
			
		||||
        Map<String, SimpleTrie> tagSensitiveWordTries = new HashMap<>();
 | 
			
		||||
        tagWords.asMap().forEach((tag, words) -> tagSensitiveWordTries.put(tag, new SimpleTrie(words)));
 | 
			
		||||
        this.tagSensitiveWordTries = tagSensitiveWordTries;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 通过定时任务轮询,刷新缓存
 | 
			
		||||
     *
 | 
			
		||||
     * 目的:多节点部署时,通过轮询”通知“所有节点,进行刷新
 | 
			
		||||
     */
 | 
			
		||||
    @Scheduled(initialDelay = 60, fixedRate = 60, timeUnit = TimeUnit.SECONDS)
 | 
			
		||||
    public void refreshLocalCache() {
 | 
			
		||||
        // 情况一:如果缓存里没有数据,则直接刷新缓存
 | 
			
		||||
        if (CollUtil.isEmpty(sensitiveWordCache)) {
 | 
			
		||||
            initLocalCache();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 情况二,如果缓存里数据,则通过 updateTime 判断是否有数据变更,有变更则刷新缓存
 | 
			
		||||
        LocalDateTime maxTime = getMaxValue(sensitiveWordCache, SensitiveWordDO::getUpdateTime);
 | 
			
		||||
        if (sensitiveWordMapper.selectCountByUpdateTimeGt(maxTime) > 0) {
 | 
			
		||||
            initLocalCache();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Long createSensitiveWord(SensitiveWordSaveVO createReqVO) {
 | 
			
		||||
        // 校验唯一性
 | 
			
		||||
        validateSensitiveWordNameUnique(null, createReqVO.getName());
 | 
			
		||||
 | 
			
		||||
        // 插入
 | 
			
		||||
        SensitiveWordDO sensitiveWord = BeanUtils.toBean(createReqVO, SensitiveWordDO.class);
 | 
			
		||||
        sensitiveWordMapper.insert(sensitiveWord);
 | 
			
		||||
 | 
			
		||||
        // 刷新缓存
 | 
			
		||||
        initLocalCache();
 | 
			
		||||
        return sensitiveWord.getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void updateSensitiveWord(SensitiveWordSaveVO updateReqVO) {
 | 
			
		||||
        // 校验唯一性
 | 
			
		||||
        validateSensitiveWordExists(updateReqVO.getId());
 | 
			
		||||
        validateSensitiveWordNameUnique(updateReqVO.getId(), updateReqVO.getName());
 | 
			
		||||
 | 
			
		||||
        // 更新
 | 
			
		||||
        SensitiveWordDO updateObj = BeanUtils.toBean(updateReqVO, SensitiveWordDO.class);
 | 
			
		||||
        sensitiveWordMapper.updateById(updateObj);
 | 
			
		||||
 | 
			
		||||
        // 刷新缓存
 | 
			
		||||
        initLocalCache();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteSensitiveWord(Long id) {
 | 
			
		||||
        // 校验存在
 | 
			
		||||
        validateSensitiveWordExists(id);
 | 
			
		||||
        // 删除
 | 
			
		||||
        sensitiveWordMapper.deleteById(id);
 | 
			
		||||
 | 
			
		||||
        // 刷新缓存
 | 
			
		||||
        initLocalCache();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateSensitiveWordNameUnique(Long id, String name) {
 | 
			
		||||
        SensitiveWordDO word = sensitiveWordMapper.selectByName(name);
 | 
			
		||||
        if (word == null) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // 如果 id 为空,说明不用比较是否为相同 id 的敏感词
 | 
			
		||||
        if (id == null) {
 | 
			
		||||
            throw exception(SENSITIVE_WORD_EXISTS);
 | 
			
		||||
        }
 | 
			
		||||
        if (!word.getId().equals(id)) {
 | 
			
		||||
            throw exception(SENSITIVE_WORD_EXISTS);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void validateSensitiveWordExists(Long id) {
 | 
			
		||||
        if (sensitiveWordMapper.selectById(id) == null) {
 | 
			
		||||
            throw exception(SENSITIVE_WORD_NOT_EXISTS);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public SensitiveWordDO getSensitiveWord(Long id) {
 | 
			
		||||
        return sensitiveWordMapper.selectById(id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<SensitiveWordDO> getSensitiveWordList() {
 | 
			
		||||
        return sensitiveWordMapper.selectList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public PageResult<SensitiveWordDO> getSensitiveWordPage(SensitiveWordPageReqVO pageReqVO) {
 | 
			
		||||
        return sensitiveWordMapper.selectPage(pageReqVO);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Set<String> getSensitiveWordTagSet() {
 | 
			
		||||
        return sensitiveWordTagsCache;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<String> validateText(String text, List<String> tags) {
 | 
			
		||||
        Assert.isTrue(ENABLED, "敏感词功能未开启,请将 ENABLED 设置为 true");
 | 
			
		||||
 | 
			
		||||
        // 无标签时,默认所有
 | 
			
		||||
        if (CollUtil.isEmpty(tags)) {
 | 
			
		||||
            return defaultSensitiveWordTrie.validate(text);
 | 
			
		||||
        }
 | 
			
		||||
        // 有标签的情况
 | 
			
		||||
        Set<String> result = new HashSet<>();
 | 
			
		||||
        tags.forEach(tag -> {
 | 
			
		||||
            SimpleTrie trie = tagSensitiveWordTries.get(tag);
 | 
			
		||||
            if (trie == null) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            result.addAll(trie.validate(text));
 | 
			
		||||
        });
 | 
			
		||||
        return new ArrayList<>(result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isTextValid(String text, List<String> tags) {
 | 
			
		||||
        Assert.isTrue(ENABLED, "敏感词功能未开启,请将 ENABLED 设置为 true");
 | 
			
		||||
 | 
			
		||||
        // 无标签时,默认所有
 | 
			
		||||
        if (CollUtil.isEmpty(tags)) {
 | 
			
		||||
            return defaultSensitiveWordTrie.isValid(text);
 | 
			
		||||
        }
 | 
			
		||||
        // 有标签的情况
 | 
			
		||||
        for (String tag : tags) {
 | 
			
		||||
            SimpleTrie trie = tagSensitiveWordTries.get(tag);
 | 
			
		||||
            if (trie == null) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // 如果有一个标签不合法,则返回 false 不合法
 | 
			
		||||
            if (!trie.isValid(text)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,152 +0,0 @@
 | 
			
		||||
package cn.iocoder.yudao.module.system.util.collection;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 基于前缀树,实现敏感词的校验
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 相比 Apache Common 提供的 PatriciaTrie 来说,性能可能会更加好一些。
 | 
			
		||||
 *
 | 
			
		||||
 * @author 芋道源码
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("unchecked")
 | 
			
		||||
public class SimpleTrie {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 一个敏感词结束后对应的 key
 | 
			
		||||
     */
 | 
			
		||||
    private static final Character CHARACTER_END = '\0';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 使用敏感词,构建的前缀树
 | 
			
		||||
     */
 | 
			
		||||
    private final Map<Character, Object> children;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 基于字符串,构建前缀树
 | 
			
		||||
     *
 | 
			
		||||
     * @param strs 字符串数组
 | 
			
		||||
     */
 | 
			
		||||
    public SimpleTrie(Collection<String> strs) {
 | 
			
		||||
        // 排序,优先使用较短的前缀
 | 
			
		||||
        strs = CollUtil.sort(strs, String::compareTo);
 | 
			
		||||
        // 构建树
 | 
			
		||||
        children = new HashMap<>();
 | 
			
		||||
        for (String str : strs) {
 | 
			
		||||
            Map<Character, Object> child = children;
 | 
			
		||||
            // 遍历每个字符
 | 
			
		||||
            for (Character c : str.toCharArray()) {
 | 
			
		||||
                // 如果已经到达结束,就没必要在添加更长的敏感词。
 | 
			
		||||
                // 例如说,有两个敏感词是:吃饭啊、吃饭。输入一句话是 “我要吃饭啊”,则只要匹配到 “吃饭” 这个敏感词即可。
 | 
			
		||||
                if (child.containsKey(CHARACTER_END)) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                if (!child.containsKey(c)) {
 | 
			
		||||
                    child.put(c, new HashMap<>());
 | 
			
		||||
                }
 | 
			
		||||
                child = (Map<Character, Object>) child.get(c);
 | 
			
		||||
            }
 | 
			
		||||
            // 结束
 | 
			
		||||
            child.put(CHARACTER_END, null);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证文本是否合法,即不包含敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param text 文本
 | 
			
		||||
     * @return 是否 true-合法 false-不合法
 | 
			
		||||
     */
 | 
			
		||||
    public boolean isValid(String text) {
 | 
			
		||||
        // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词
 | 
			
		||||
        for (int i = 0; i < text.length(); i++) {
 | 
			
		||||
            Map<Character, Object> child = (Map<Character, Object>) children.get(text.charAt(i));
 | 
			
		||||
            if (child == null) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            boolean ok = recursion(text, i + 1, child);
 | 
			
		||||
            if (!ok) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 验证文本从指定位置开始,是否不包含某个敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * @param text  文本
 | 
			
		||||
     * @param index 开始位置
 | 
			
		||||
     * @param child 节点(当前遍历到的)
 | 
			
		||||
     * @return 是否不包含 true-不包含 false-包含
 | 
			
		||||
     */
 | 
			
		||||
    private boolean recursion(String text, int index, Map<Character, Object> child) {
 | 
			
		||||
        if (child.containsKey(CHARACTER_END)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (index == text.length()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        child = (Map<Character, Object>) child.get(text.charAt(index));
 | 
			
		||||
        return child == null || !child.containsKey(CHARACTER_END) && recursion(text, ++index, child);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得文本所包含的不合法的敏感词
 | 
			
		||||
     *
 | 
			
		||||
     * 注意,才当即最短匹配原则。例如说:当敏感词存在 “煞笔”,“煞笔二货 ”时,只会返回 “煞笔”。
 | 
			
		||||
     *
 | 
			
		||||
     * @param text 文本
 | 
			
		||||
     * @return 匹配的敏感词
 | 
			
		||||
     */
 | 
			
		||||
    public List<String> validate(String text) {
 | 
			
		||||
        Set<String> results = new HashSet<>();
 | 
			
		||||
        for (int i = 0; i < text.length(); i++) {
 | 
			
		||||
            Character c = text.charAt(i);
 | 
			
		||||
            Map<Character, Object> child = (Map<Character, Object>) children.get(c);
 | 
			
		||||
            if (child == null) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            StringBuilder result = new StringBuilder().append(c);
 | 
			
		||||
            boolean ok = recursionWithResult(text, i + 1, child, result);
 | 
			
		||||
            if (!ok) {
 | 
			
		||||
                results.add(result.toString());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return new ArrayList<>(results);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 返回文本从 index 开始的敏感词,并使用 StringBuilder 参数进行返回
 | 
			
		||||
     *
 | 
			
		||||
     * 逻辑和 {@link #recursion(String, int, Map)} 是一致,只是多了 result 返回结果
 | 
			
		||||
     *
 | 
			
		||||
     * @param text   文本
 | 
			
		||||
     * @param index  开始未知
 | 
			
		||||
     * @param child  节点(当前遍历到的)
 | 
			
		||||
     * @param result 返回敏感词
 | 
			
		||||
     * @return 是否有敏感词
 | 
			
		||||
     */
 | 
			
		||||
    @SuppressWarnings("unchecked")
 | 
			
		||||
    private static boolean recursionWithResult(String text, int index, Map<Character, Object> child, StringBuilder result) {
 | 
			
		||||
        if (child.containsKey(CHARACTER_END)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (index == text.length()) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        Character c = text.charAt(index);
 | 
			
		||||
        child = (Map<Character, Object>) child.get(c);
 | 
			
		||||
        if (child == null) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (child.containsKey(CHARACTER_END)) {
 | 
			
		||||
            result.append(c);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return recursionWithResult(text, ++index, child, result.append(c));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user