mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-30 09:48:43 +08:00 
			
		
		
		
	同步 SensitiveWord 敏感词代码,原分支未正确关联仓库
This commit is contained in:
		| @@ -0,0 +1,22 @@ | ||||
| GET http://localhost:81/dev-api/admin-api/system/sensitive-word/get-all-tags | ||||
| Accept: application/json | ||||
| Authorization: Bearer 385d533b781f44f6bb21ea08afeec47c | ||||
|  | ||||
|  | ||||
|  | ||||
| ### | ||||
| POST http://localhost:81/dev-api/admin-api/system/sensitive-word/create | ||||
| Content-Type: application/json | ||||
| Authorization: Bearer 1649ff1f8b9a4eeeb458fe93a71c78b5 | ||||
|  | ||||
| { | ||||
|   "name": "test", | ||||
|   "tags": [ | ||||
|     "bbb,aaa" | ||||
|   ], | ||||
|   "description": "test", | ||||
|   "status": true | ||||
| } | ||||
|  | ||||
|  | ||||
| ### | ||||
| @@ -0,0 +1,104 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||||
| import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.*; | ||||
| import cn.iocoder.yudao.module.system.convert.sensitiveword.SensitiveWordConvert; | ||||
| import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; | ||||
| import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService; | ||||
| import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiImplicitParam; | ||||
| import io.swagger.annotations.ApiOperation; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| import javax.validation.Valid; | ||||
| import java.io.IOException; | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||
| import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; | ||||
|  | ||||
| @Api(tags = "管理后台 - 敏感词") | ||||
| @RestController | ||||
| @RequestMapping("/system/sensitive-word") | ||||
| @Validated | ||||
| public class SensitiveWordController { | ||||
|  | ||||
|     @Resource | ||||
|     private SensitiveWordService sensitiveWordService; | ||||
|  | ||||
|     @PostMapping("/create") | ||||
|     @ApiOperation("创建敏感词") | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:create')") | ||||
|     public CommonResult<Long> createSensitiveWord(@Valid @RequestBody SensitiveWordCreateReqVO createReqVO) { | ||||
|         return success(sensitiveWordService.createSensitiveWord(createReqVO)); | ||||
|     } | ||||
|  | ||||
|     @PutMapping("/update") | ||||
|     @ApiOperation("更新敏感词") | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:update')") | ||||
|     public CommonResult<Boolean> updateSensitiveWord(@Valid @RequestBody SensitiveWordUpdateReqVO updateReqVO) { | ||||
|         sensitiveWordService.updateSensitiveWord(updateReqVO); | ||||
|         return success(true); | ||||
|     } | ||||
|  | ||||
|     @DeleteMapping("/delete") | ||||
|     @ApiOperation("删除敏感词") | ||||
|     @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:delete')") | ||||
|     public CommonResult<Boolean> deleteSensitiveWord(@RequestParam("id") Long id) { | ||||
|         sensitiveWordService.deleteSensitiveWord(id); | ||||
|         return success(true); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get") | ||||
|     @ApiOperation("获得敏感词") | ||||
|     @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class) | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')") | ||||
|     public CommonResult<SensitiveWordRespVO> getSensitiveWord(@RequestParam("id") Long id) { | ||||
|         SensitiveWordDO sensitiveWord = sensitiveWordService.getSensitiveWord(id); | ||||
|         return success(SensitiveWordConvert.INSTANCE.convert(sensitiveWord)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/page") | ||||
|     @ApiOperation("获得敏感词分页") | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')") | ||||
|     public CommonResult<PageResult<SensitiveWordRespVO>> getSensitiveWordPage(@Valid SensitiveWordPageReqVO pageVO) { | ||||
|         PageResult<SensitiveWordDO> pageResult = sensitiveWordService.getSensitiveWordPage(pageVO); | ||||
|         return success(SensitiveWordConvert.INSTANCE.convertPage(pageResult)); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/get-tags") | ||||
|     @ApiOperation("获取所有敏感词的标签数组") | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:query')") | ||||
|     public CommonResult<Set<String>> getSensitiveWordTags() throws IOException { | ||||
|         return success(sensitiveWordService.getSensitiveWordTags()); | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/export-excel") | ||||
|     @ApiOperation("导出敏感词 Excel") | ||||
|     @PreAuthorize("@ss.hasPermission('system:sensitive-word:export')") | ||||
|     @OperateLog(type = EXPORT) | ||||
|     public void exportSensitiveWordExcel(@Valid SensitiveWordExportReqVO exportReqVO, | ||||
|               HttpServletResponse response) throws IOException { | ||||
|         List<SensitiveWordDO> list = sensitiveWordService.getSensitiveWordList(exportReqVO); | ||||
|         // 导出 Excel | ||||
|         List<SensitiveWordExcelVO> datas = SensitiveWordConvert.INSTANCE.convertList02(list); | ||||
|         ExcelUtils.write(response, "敏感词.xls", "数据", SensitiveWordExcelVO.class, datas); | ||||
|     } | ||||
|  | ||||
| //    @GetMapping("/is-sensitive-word-by-text-and-tag") | ||||
| //    @ApiOperation("通过tag判断传入text是否含有敏感词") | ||||
| //    @PreAuthorize("@ss.hasPermission('system:sensitive-word:checkbytextandtag')") | ||||
| //    public CommonResult<Boolean> isSensitiveWordByTextAndTag(@NotBlank String text, @NotBlank String tag) throws IOException { | ||||
| //        return success(sensitiveWordApi.isSensitiveWordByTextAndTag(text,tag)); | ||||
| //    } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,31 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import io.swagger.annotations.ApiModelProperty; | ||||
| import lombok.Data; | ||||
|  | ||||
| import javax.validation.constraints.NotNull; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
| * 敏感词 Base VO,提供给添加、修改、详细的子 VO 使用 | ||||
| * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | ||||
| */ | ||||
| @Data | ||||
| public class SensitiveWordBaseVO { | ||||
|  | ||||
|     @ApiModelProperty(value = "敏感词", required = true, example = "敏感词") | ||||
|     @NotNull(message = "敏感词不能为空") | ||||
|     private String name; | ||||
|  | ||||
|     @ApiModelProperty(value = "标签", required = true, example = "短信,评论") | ||||
|     @NotNull(message = "标签不能为空") | ||||
|     private List<String> tags; | ||||
|  | ||||
|     @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 CommonStatusEnum 枚举类") | ||||
|     @NotNull(message = "状态不能为空") | ||||
|     private Integer status; | ||||
|  | ||||
|     @ApiModelProperty(value = "描述", example = "污言秽语") | ||||
|     private String description; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,14 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import io.swagger.annotations.ApiModel; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
|  | ||||
| @ApiModel("管理后台 - 敏感词创建 Request VO") | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class SensitiveWordCreateReqVO extends SensitiveWordBaseVO { | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import com.alibaba.excel.annotation.ExcelProperty; | ||||
| import lombok.Data; | ||||
|  | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 敏感词 Excel VO | ||||
|  * | ||||
|  * @author 永不言败 | ||||
|  */ | ||||
| @Data | ||||
| public class SensitiveWordExcelVO { | ||||
|  | ||||
|     @ExcelProperty("编号") | ||||
|     private Long id; | ||||
|  | ||||
|     @ExcelProperty("敏感词") | ||||
|     private String name; | ||||
|  | ||||
|     @ExcelProperty("标签") | ||||
|     private List<String> tags; | ||||
|  | ||||
|     @ExcelProperty("状态,true-启用,false-禁用") | ||||
|     private Integer status; | ||||
|  | ||||
|     @ExcelProperty("描述") | ||||
|     private String description; | ||||
|  | ||||
|     @ExcelProperty("创建时间") | ||||
|     private Date createTime; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import io.swagger.annotations.ApiModel; | ||||
| import io.swagger.annotations.ApiModelProperty; | ||||
| import lombok.Data; | ||||
| import org.springframework.format.annotation.DateTimeFormat; | ||||
|  | ||||
| import java.util.Date; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||
|  | ||||
| @ApiModel(value = "管理后台 - 敏感词 Excel 导出 Request VO", description = "参数和 SensitiveWordPageReqVO 是一致的") | ||||
| @Data | ||||
| public class SensitiveWordExportReqVO { | ||||
|  | ||||
|     @ApiModelProperty(value = "敏感词", example = "敏感词") | ||||
|     private String name; | ||||
|  | ||||
|     @ApiModelProperty(value = "标签", example = "短信,评论") | ||||
|     private String tag; | ||||
|  | ||||
|     @ApiModelProperty(value = "状态", example = "true-启用,false-禁用") | ||||
|     private Integer status; | ||||
|  | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|     @ApiModelProperty(value = "开始创建时间") | ||||
|     private Date beginCreateTime; | ||||
|  | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|     @ApiModelProperty(value = "结束创建时间") | ||||
|     private Date endCreateTime; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,38 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||||
| import io.swagger.annotations.ApiModel; | ||||
| import io.swagger.annotations.ApiModelProperty; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
| import org.springframework.format.annotation.DateTimeFormat; | ||||
|  | ||||
| import java.util.Date; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||
|  | ||||
| @ApiModel("管理后台 - 敏感词分页 Request VO") | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class SensitiveWordPageReqVO extends PageParam { | ||||
|  | ||||
|     @ApiModelProperty(value = "敏感词", example = "敏感词") | ||||
|     private String name; | ||||
|  | ||||
|     @ApiModelProperty(value = "标签", example = "短信,评论") | ||||
|     private String tag; | ||||
|  | ||||
|     @ApiModelProperty(value = "状态", example = "true-启用,true-禁用") | ||||
|     private Integer status; | ||||
|  | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|     @ApiModelProperty(value = "开始创建时间") | ||||
|     private Date beginCreateTime; | ||||
|  | ||||
|     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||
|     @ApiModelProperty(value = "结束创建时间") | ||||
|     private Date endCreateTime; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,23 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import io.swagger.annotations.ApiModel; | ||||
| import io.swagger.annotations.ApiModelProperty; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
|  | ||||
| import java.util.Date; | ||||
|  | ||||
| @ApiModel("管理后台 - 敏感词 Response VO") | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class SensitiveWordRespVO extends SensitiveWordBaseVO { | ||||
|  | ||||
|     @ApiModelProperty(value = "编号", required = true, example = "1") | ||||
|     private Long id; | ||||
|  | ||||
|     @ApiModelProperty(value = "创建时间", required = true) | ||||
|     private Date createTime; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo; | ||||
|  | ||||
| import io.swagger.annotations.ApiModel; | ||||
| import io.swagger.annotations.ApiModelProperty; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
| import lombok.ToString; | ||||
|  | ||||
| import javax.validation.constraints.NotNull; | ||||
|  | ||||
| @ApiModel("管理后台 - 敏感词更新 Request VO") | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| @ToString(callSuper = true) | ||||
| public class SensitiveWordUpdateReqVO extends SensitiveWordBaseVO { | ||||
|  | ||||
|     @ApiModelProperty(value = "编号", required = true, example = "1") | ||||
|     @NotNull(message = "编号不能为空") | ||||
|     private Long id; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,36 @@ | ||||
| package cn.iocoder.yudao.module.system.convert.sensitiveword; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordCreateReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordExcelVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordRespVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordUpdateReqVO; | ||||
| import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; | ||||
| import org.mapstruct.Mapper; | ||||
| import org.mapstruct.factory.Mappers; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 敏感词 Convert | ||||
|  * | ||||
|  * @author 永不言败 | ||||
|  */ | ||||
| @Mapper | ||||
| public interface SensitiveWordConvert { | ||||
|  | ||||
|     SensitiveWordConvert INSTANCE = Mappers.getMapper(SensitiveWordConvert.class); | ||||
|  | ||||
|     SensitiveWordDO convert(SensitiveWordCreateReqVO bean); | ||||
|  | ||||
|     SensitiveWordDO convert(SensitiveWordUpdateReqVO bean); | ||||
|  | ||||
|     SensitiveWordRespVO convert(SensitiveWordDO bean); | ||||
|  | ||||
|     List<SensitiveWordRespVO> convertList(List<SensitiveWordDO> list); | ||||
|  | ||||
|     PageResult<SensitiveWordRespVO> convertPage(PageResult<SensitiveWordDO> page); | ||||
|  | ||||
|     List<SensitiveWordExcelVO> convertList02(List<SensitiveWordDO> list); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,56 @@ | ||||
| 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.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) | ||||
| @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; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| 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.SensitiveWordExportReqVO; | ||||
| 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.util.Date; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 敏感词 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.getBeginCreateTime(), reqVO.getEndCreateTime()) | ||||
|                 .orderByDesc(SensitiveWordDO::getId)); | ||||
|     } | ||||
|  | ||||
|     default List<SensitiveWordDO> selectList(SensitiveWordExportReqVO reqVO) { | ||||
|         return selectList(new LambdaQueryWrapperX<SensitiveWordDO>() | ||||
|                 .likeIfPresent(SensitiveWordDO::getName, reqVO.getName()) | ||||
|                 .likeIfPresent(SensitiveWordDO::getTags, reqVO.getTag()) | ||||
|                 .eqIfPresent(SensitiveWordDO::getStatus, reqVO.getStatus()) | ||||
|                 .betweenIfPresent(SensitiveWordDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) | ||||
|                 .orderByDesc(SensitiveWordDO::getId)); | ||||
|     } | ||||
|  | ||||
|     default SensitiveWordDO selectByName(String name) { | ||||
|         return selectOne(SensitiveWordDO::getName, name); | ||||
|     } | ||||
|  | ||||
|     @Select("SELECT id FROM system_sensitive_word WHERE update_time > #{maxUpdateTime} LIMIT 1") | ||||
|     SensitiveWordDO selectExistsByUpdateTimeAfter(Date maxUpdateTime); | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| package cn.iocoder.yudao.module.system.mq.consumer.sensitiveword; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener; | ||||
| import cn.iocoder.yudao.module.system.mq.message.sensitiveword.SensitiveWordRefreshMessage; | ||||
| import cn.iocoder.yudao.module.system.service.sensitiveword.SensitiveWordService; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
|  | ||||
| /** | ||||
|  * 针对 {@link SensitiveWordRefreshMessage} 的消费者 | ||||
|  * | ||||
|  * @author 芋道源码 | ||||
|  */ | ||||
| @Component | ||||
| @Slf4j | ||||
| public class SensitiveWordRefreshConsumer extends AbstractChannelMessageListener<SensitiveWordRefreshMessage> { | ||||
|  | ||||
|     @Resource | ||||
|     private SensitiveWordService sensitiveWordService; | ||||
|  | ||||
|     @Override | ||||
|     public void onMessage(SensitiveWordRefreshMessage message) { | ||||
|         log.info("[onMessage][收到 SensitiveWord 刷新消息]"); | ||||
|         sensitiveWordService.initLocalCache(); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,19 @@ | ||||
| package cn.iocoder.yudao.module.system.mq.message.sensitiveword; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessage; | ||||
| import lombok.Data; | ||||
| import lombok.EqualsAndHashCode; | ||||
|  | ||||
| /** | ||||
|  * 敏感词的刷新 Message | ||||
|  */ | ||||
| @Data | ||||
| @EqualsAndHashCode(callSuper = true) | ||||
| public class SensitiveWordRefreshMessage extends AbstractChannelMessage { | ||||
|  | ||||
|     @Override | ||||
|     public String getChannel() { | ||||
|         return "system.sensitive-word.refresh"; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,26 @@ | ||||
| package cn.iocoder.yudao.module.system.mq.producer.sensitiveword; | ||||
|  | ||||
| import cn.iocoder.yudao.framework.mq.core.RedisMQTemplate; | ||||
| import cn.iocoder.yudao.module.system.mq.message.sensitiveword.SensitiveWordRefreshMessage; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import javax.annotation.Resource; | ||||
|  | ||||
| /** | ||||
|  * 敏感词相关的 Producer | ||||
|  */ | ||||
| @Component | ||||
| public class SensitiveWordProducer { | ||||
|  | ||||
|     @Resource | ||||
|     private RedisMQTemplate redisMQTemplate; | ||||
|  | ||||
|     /** | ||||
|      * 发送 {@link SensitiveWordRefreshMessage} 消息 | ||||
|      */ | ||||
|     public void sendSensitiveWordRefreshMessage() { | ||||
|         SensitiveWordRefreshMessage message = new SensitiveWordRefreshMessage(); | ||||
|         redisMQTemplate.send(message); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,86 @@ | ||||
| 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.SensitiveWordCreateReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordExportReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordUpdateReqVO; | ||||
| import cn.iocoder.yudao.module.system.dal.dataobject.sensitiveword.SensitiveWordDO; | ||||
|  | ||||
| import javax.validation.Valid; | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
|  | ||||
| /** | ||||
|  * 敏感词 Service 接口 | ||||
|  * | ||||
|  * @author 永不言败 | ||||
|  */ | ||||
| public interface SensitiveWordService { | ||||
|  | ||||
|     /** | ||||
|      * 初始化本地缓存 | ||||
|      */ | ||||
|     void initLocalCache(); | ||||
|  | ||||
|     /** | ||||
|      * 创建敏感词 | ||||
|      * | ||||
|      * @param createReqVO 创建信息 | ||||
|      * @return 编号 | ||||
|      */ | ||||
|     Long createSensitiveWord(@Valid SensitiveWordCreateReqVO createReqVO); | ||||
|  | ||||
|     /** | ||||
|      * 更新敏感词 | ||||
|      * | ||||
|      * @param updateReqVO 更新信息 | ||||
|      */ | ||||
|     void updateSensitiveWord(@Valid SensitiveWordUpdateReqVO 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); | ||||
|  | ||||
|     /** | ||||
|      * 获得敏感词列表, 用于 Excel 导出 | ||||
|      * | ||||
|      * @param exportReqVO 查询条件 | ||||
|      * @return 敏感词列表 | ||||
|      */ | ||||
|     List<SensitiveWordDO> getSensitiveWordList(SensitiveWordExportReqVO exportReqVO); | ||||
|  | ||||
|     /** | ||||
|      * 获得所有敏感词的标签数组 | ||||
|      * | ||||
|      * @return 标签数组 | ||||
|      */ | ||||
|     Set<String> getSensitiveWordTags(); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,206 @@ | ||||
| package cn.iocoder.yudao.module.system.service.sensitiveword; | ||||
|  | ||||
| import cn.hutool.core.collection.CollUtil; | ||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordCreateReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordExportReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordPageReqVO; | ||||
| import cn.iocoder.yudao.module.system.controller.admin.sensitiveword.vo.SensitiveWordUpdateReqVO; | ||||
| import cn.iocoder.yudao.module.system.convert.sensitiveword.SensitiveWordConvert; | ||||
| 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.mq.producer.sensitiveword.SensitiveWordProducer; | ||||
| import lombok.Getter; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.scheduling.annotation.Scheduled; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.validation.annotation.Validated; | ||||
|  | ||||
| import javax.annotation.PostConstruct; | ||||
| import javax.annotation.Resource; | ||||
| import java.util.*; | ||||
|  | ||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||
| import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; | ||||
|  | ||||
| /** | ||||
|  * 敏感词 Service 实现类 | ||||
|  * | ||||
|  * @author 永不言败 | ||||
|  */ | ||||
| @Service | ||||
| @Slf4j | ||||
| @Validated | ||||
| public class SensitiveWordServiceImpl implements SensitiveWordService { | ||||
|  | ||||
|     /** | ||||
|      * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 | ||||
|      * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 | ||||
|      */ | ||||
|     private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | ||||
|  | ||||
|     /** | ||||
|      * 敏感词缓存 | ||||
|      * key:敏感词编号 {@link SensitiveWordDO#getId()} | ||||
|      * <p> | ||||
|      * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | ||||
|      */ | ||||
|     @Getter | ||||
|     private volatile Map<Long, SensitiveWordDO> sensitiveWordCache = Collections.emptyMap(); | ||||
|  | ||||
|     /** | ||||
|      * 敏感词标签缓存 | ||||
|      * key:敏感词编号 {@link SensitiveWordDO#getId()} | ||||
|      * <p> | ||||
|      * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | ||||
|      */ | ||||
|     @Getter | ||||
|     private volatile Set<String> sensitiveWordTagsCache = Collections.emptySet(); | ||||
|  | ||||
|     /** | ||||
|      * 缓存敏感词的最大更新时间,用于后续的增量轮询,判断是否有更新 | ||||
|      */ | ||||
|     @Getter | ||||
|     private volatile Date maxUpdateTime; | ||||
|  | ||||
|     @Resource | ||||
|     private SensitiveWordMapper sensitiveWordMapper; | ||||
|  | ||||
|     @Resource | ||||
|     private SensitiveWordProducer sensitiveWordProducer; | ||||
|  | ||||
|     @Resource | ||||
|     @Lazy | ||||
|     private SensitiveWordService self; | ||||
|  | ||||
|     /** | ||||
|      * 初始化 {@link #sensitiveWordCache} 缓存 | ||||
|      */ | ||||
|     @Override | ||||
|     @PostConstruct | ||||
|     public void initLocalCache() { | ||||
|         // 获取敏感词列表,如果有更新 | ||||
|         List<SensitiveWordDO> sensitiveWordList = loadSensitiveWordIfUpdate(maxUpdateTime); | ||||
|         if (CollUtil.isEmpty(sensitiveWordList)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 写入 sensitiveWordTagsCache 缓存 | ||||
|         Set<String> tags = new HashSet<>(); | ||||
|         sensitiveWordList.forEach(word -> tags.addAll(word.getTags())); | ||||
|         sensitiveWordTagsCache = tags; | ||||
|         // 写入 sensitiveWordCache 缓存 | ||||
|         sensitiveWordCache = CollectionUtils.convertMap(sensitiveWordList, SensitiveWordDO::getId); | ||||
|         maxUpdateTime = CollectionUtils.getMaxValue(sensitiveWordList, SensitiveWordDO::getUpdateTime); | ||||
|         log.info("[initLocalCache][初始化 敏感词 数量为 {}]", sensitiveWordList.size()); | ||||
|     } | ||||
|  | ||||
|     @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) | ||||
|     public void schedulePeriodicRefresh() { | ||||
|         self.initLocalCache(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 如果敏感词发生变化,从数据库中获取最新的全量敏感词。 | ||||
|      * 如果未发生变化,则返回空 | ||||
|      * | ||||
|      * @param maxUpdateTime 当前敏感词的最大更新时间 | ||||
|      * @return 敏感词列表 | ||||
|      */ | ||||
|     private List<SensitiveWordDO> loadSensitiveWordIfUpdate(Date maxUpdateTime) { | ||||
|         // 第一步,判断是否要更新。 | ||||
|         // 如果更新时间为空,说明 DB 一定有新数据 | ||||
|         if (maxUpdateTime == null) { | ||||
|             log.info("[loadSensitiveWordIfUpdate][首次加载全量敏感词]"); | ||||
|         } else { // 判断数据库中是否有更新的敏感词 | ||||
|             if (sensitiveWordMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) { | ||||
|                 return null; | ||||
|             } | ||||
|             log.info("[loadSensitiveWordIfUpdate][增量加载全量敏感词]"); | ||||
|         } | ||||
|         // 第二步,如果有更新,则从数据库加载所有敏感词 | ||||
|         return sensitiveWordMapper.selectList(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Long createSensitiveWord(SensitiveWordCreateReqVO createReqVO) { | ||||
|         // 校验唯一性 | ||||
|         checkSensitiveWordNameUnique(null, createReqVO.getName()); | ||||
|         // 插入 | ||||
|         SensitiveWordDO sensitiveWord = SensitiveWordConvert.INSTANCE.convert(createReqVO); | ||||
|         sensitiveWordMapper.insert(sensitiveWord); | ||||
|         // 发送消息,刷新缓存 | ||||
|         sensitiveWordProducer.sendSensitiveWordRefreshMessage(); | ||||
|         return sensitiveWord.getId(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void updateSensitiveWord(SensitiveWordUpdateReqVO updateReqVO) { | ||||
|         // 校验唯一性 | ||||
|         checkSensitiveWordExists(updateReqVO.getId()); | ||||
|         checkSensitiveWordNameUnique(updateReqVO.getId(), updateReqVO.getName()); | ||||
|         // 更新 | ||||
|         SensitiveWordDO updateObj = SensitiveWordConvert.INSTANCE.convert(updateReqVO); | ||||
|         sensitiveWordMapper.updateById(updateObj); | ||||
|         // 发送消息,刷新缓存 | ||||
|         sensitiveWordProducer.sendSensitiveWordRefreshMessage(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deleteSensitiveWord(Long id) { | ||||
|         // 校验存在 | ||||
|         checkSensitiveWordExists(id); | ||||
|         // 删除 | ||||
|         sensitiveWordMapper.deleteById(id); | ||||
|         // 发送消息,刷新缓存 | ||||
|         sensitiveWordProducer.sendSensitiveWordRefreshMessage(); | ||||
|     } | ||||
|  | ||||
|     private void checkSensitiveWordNameUnique(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 checkSensitiveWordExists(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 List<SensitiveWordDO> getSensitiveWordList(SensitiveWordExportReqVO exportReqVO) { | ||||
|         return sensitiveWordMapper.selectList(exportReqVO); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Set<String> getSensitiveWordTags() { | ||||
|         return sensitiveWordTagsCache; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,143 @@ | ||||
| package cn.iocoder.yudao.module.system.util.collection; | ||||
|  | ||||
| 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(List<String> strs) { | ||||
|         children = new HashMap<>(); | ||||
|         // 构建树 | ||||
|         Collections.sort(strs); // 排序,优先使用较短的前缀 | ||||
|         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 是否 ok | ||||
|      */ | ||||
|     public boolean isValid(String text) { | ||||
|         // 遍历 text,使用每一个 [i, n) 段的字符串,使用 children 前缀树匹配,是否包含敏感词 | ||||
|         for (int i = 0; i < text.length() - 1; 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 是否包含 | ||||
|      */ | ||||
|     private boolean recursion(String text, int index, Map<Character, Object> child) { | ||||
|         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() - 1; 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 (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)); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| /** | ||||
|  * 每个模块的 util 包,放专属当前模块的 Utils 工具类 | ||||
|  */ | ||||
| package cn.iocoder.yudao.module.system.util; | ||||
| @@ -17,3 +17,4 @@ DELETE FROM "system_error_code"; | ||||
| DELETE FROM "system_social_user"; | ||||
| DELETE FROM "system_tenant"; | ||||
| DELETE FROM "system_tenant_package"; | ||||
| DELETE FROM "system_sensitive_word"; | ||||
|   | ||||
| @@ -426,3 +426,17 @@ CREATE TABLE IF NOT EXISTS "system_tenant_package" ( | ||||
|     "deleted" bit NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '租户套餐表'; | ||||
|  | ||||
| CREATE TABLE IF NOT EXISTS "system_sensitive_word" ( | ||||
|     "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||||
|     "name" varchar(255) NOT NULL, | ||||
|     "tags" varchar(1024) NOT NULL, | ||||
|     "status" bit NOT NULL DEFAULT FALSE, | ||||
|     "description" varchar(512), | ||||
|     "creator" varchar(64) DEFAULT '', | ||||
|     "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||
|     "updater" varchar(64) DEFAULT '', | ||||
|     "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||||
|     "deleted" bit NOT NULL DEFAULT FALSE, | ||||
|     PRIMARY KEY ("id") | ||||
| ) COMMENT '系统敏感词'; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV