mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 10:57:15 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
		| @@ -593,6 +593,13 @@ | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|             <!-- 敏感词模块 --> | ||||
|             <dependency> | ||||
|                 <groupId>top.continew</groupId> | ||||
|                 <artifactId>continew-starter-sensitive-words</artifactId> | ||||
|                 <version>${revision}</version> | ||||
|             </dependency> | ||||
|  | ||||
|         </dependencies> | ||||
|     </dependencyManagement> | ||||
|  | ||||
|   | ||||
							
								
								
									
										42
									
								
								continew-starter-sensitive-words/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								continew-starter-sensitive-words/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||
|          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <parent> | ||||
|         <groupId>top.continew</groupId> | ||||
|         <artifactId>continew-starter</artifactId> | ||||
|         <version>${revision}</version> | ||||
|     </parent> | ||||
|  | ||||
|     <artifactId>continew-starter-sensitive-words</artifactId> | ||||
|     <description>Continew starter sensitive words 模块</description> | ||||
|  | ||||
|     <dependencies> | ||||
|         <!-- Spring Boot Starter(自动配置相关依赖) --> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter</artifactId> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-configuration-processor</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <!-- Hutool(工具类库) --> | ||||
|         <dependency> | ||||
|             <groupId>cn.hutool</groupId> | ||||
|             <artifactId>hutool-dfa</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.springframework.boot</groupId> | ||||
|             <artifactId>spring-boot-starter-validation</artifactId> | ||||
|         </dependency> | ||||
|  | ||||
|         <dependency> | ||||
|             <groupId>org.projectlombok</groupId> | ||||
|             <artifactId>lombok</artifactId> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| </project> | ||||
| @@ -0,0 +1,39 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.autoconfigure; | ||||
|  | ||||
| import jakarta.annotation.PostConstruct; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.springframework.boot.autoconfigure.AutoConfiguration; | ||||
|  | ||||
| /** | ||||
|  * JSR 303 校验器自动配置 | ||||
|  * | ||||
|  * @author Charles7c | ||||
|  * @since 2.3.0 | ||||
|  */ | ||||
| @AutoConfiguration | ||||
| public class SensitiveWordsAutoConfiguration { | ||||
|  | ||||
|     private static final Logger log = LoggerFactory.getLogger(SensitiveWordsAutoConfiguration.class); | ||||
|  | ||||
|     @PostConstruct | ||||
|     public void postConstruct() { | ||||
|         log.debug("[ContiNew Starter] - Auto Configuration 'sensitive words service' completed initialization."); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.autoconfigure; | ||||
|  | ||||
| import lombok.Data; | ||||
| import org.springframework.boot.context.properties.ConfigurationProperties; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @Data | ||||
| @Component | ||||
| @ConfigurationProperties(prefix = "continew.sensitive-words") | ||||
| public class SensitiveWordsProperties { | ||||
|     // 敏感词注入类型 | ||||
|     private String type; | ||||
|     private List<String> values; | ||||
| } | ||||
| @@ -0,0 +1,45 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.service; | ||||
|  | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | ||||
| import org.springframework.stereotype.Component; | ||||
| import top.continew.starter.sensitive.words.autoconfigure.SensitiveWordsProperties; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 默认敏感词配置 | ||||
|  */ | ||||
| @Component | ||||
| @ConditionalOnProperty(prefix = "continew.sensitive-words", name = "type", havingValue = "default", matchIfMissing = true) | ||||
| public class DefaultSensitiveWordsConfig implements SensitiveWordsConfig { | ||||
|  | ||||
|     private final SensitiveWordsProperties properties; | ||||
|  | ||||
|     public DefaultSensitiveWordsConfig(SensitiveWordsProperties properties) { | ||||
|         this.properties = properties; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<String> getWords() { | ||||
|         if (properties.getValues() != null) { | ||||
|             return properties.getValues(); | ||||
|         } | ||||
|         return List.of(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,49 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.service; | ||||
|  | ||||
| import cn.hutool.dfa.WordTree; | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; | ||||
| import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 默认敏感词服务 | ||||
|  */ | ||||
| @Component | ||||
| @ConditionalOnBean(SensitiveWordsConfig.class) | ||||
| @ConditionalOnMissingBean(SensitiveWordsService.class) | ||||
| public class DefaultSensitiveWordsService implements SensitiveWordsService { | ||||
|  | ||||
|     private final SensitiveWordsConfig sensitiveWordsConfig; | ||||
|  | ||||
|     private WordTree tree = new WordTree(); | ||||
|  | ||||
|     public DefaultSensitiveWordsService(SensitiveWordsConfig sensitiveWordsConfig) { | ||||
|         this.sensitiveWordsConfig = sensitiveWordsConfig; | ||||
|         if (sensitiveWordsConfig != null && sensitiveWordsConfig.getWords() != null) { | ||||
|             tree.addWords(sensitiveWordsConfig.getWords()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public List<String> check(String content) { | ||||
|         return tree.matchAll(content, -1, false, true); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,28 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.service; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 敏感词配置 | ||||
|  */ | ||||
| public interface SensitiveWordsConfig { | ||||
|  | ||||
|     List<String> getWords(); | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.service; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public interface SensitiveWordsService { | ||||
|     /** | ||||
|      * 检查敏感词 | ||||
|      * | ||||
|      * @param content 待检测字符串 | ||||
|      * @return 敏感词列表 | ||||
|      */ | ||||
|     List<String> check(String content); | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.validate; | ||||
|  | ||||
| import jakarta.validation.Constraint; | ||||
| import jakarta.validation.Payload; | ||||
|  | ||||
| import java.lang.annotation.*; | ||||
|  | ||||
| @Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Documented | ||||
| @Constraint(validatedBy = {SensitiveWordValidator.class}) | ||||
| public @interface SensitiveWord { | ||||
|  | ||||
|     String message() default "有敏感词,请检测!"; | ||||
|  | ||||
|     Class<?>[] groups() default {}; | ||||
|  | ||||
|     Class<? extends Payload>[] payload() default {}; | ||||
| } | ||||
| @@ -0,0 +1,60 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words.validate; | ||||
|  | ||||
| import jakarta.annotation.Resource; | ||||
| import jakarta.validation.ConstraintValidator; | ||||
| import jakarta.validation.ConstraintValidatorContext; | ||||
| import top.continew.starter.sensitive.words.service.SensitiveWordsService; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public class SensitiveWordValidator implements ConstraintValidator<SensitiveWord, String> { | ||||
|  | ||||
|     @Resource | ||||
|     private SensitiveWordsService sensitiveWordsService; | ||||
|  | ||||
|     /** | ||||
|      * 初始化方法,可以用自定义注解中获取值进行初始化 | ||||
|      * | ||||
|      * @param {@link SensitiveWord } constraintAnnotation 注解值内容 | ||||
|      */ | ||||
|     @Override | ||||
|     public void initialize(SensitiveWord constraintAnnotation) { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 实际校验自定义注解 value 值 | ||||
|      * | ||||
|      * @param {@link String} value 待检测字符串 | ||||
|      * @param {@link ConstraintValidatorContext } constraintValidatorContext 检测的上下文 | ||||
|      * @return boolean 是否通过检测 | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean isValid(String value, ConstraintValidatorContext context) { | ||||
|         List<String> res = sensitiveWordsService.check(value); | ||||
|         if (!res.isEmpty()) { | ||||
|             // 动态设置错误消息 | ||||
|             context.disableDefaultConstraintViolation(); // 禁用默认消息 | ||||
|             context.buildConstraintViolationWithTemplate("包含敏感词: " + String.join(",", res)) | ||||
|                     .addConstraintViolation(); | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,4 @@ | ||||
| top.continew.starter.sensitive.words.autoconfigure.SensitiveWordsAutoConfiguration | ||||
| top.continew.starter.sensitive.words.autoconfigure.SensitiveWordsProperties | ||||
| top.continew.starter.sensitive.words.service.DefaultSensitiveWordsConfig | ||||
| top.continew.starter.sensitive.words.service.DefaultSensitiveWordsService | ||||
| @@ -0,0 +1,49 @@ | ||||
| /* | ||||
|  * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. | ||||
|  * <p> | ||||
|  * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * <p> | ||||
|  * http://www.gnu.org/licenses/lgpl.html | ||||
|  * <p> | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| package top.continew.starter.sensitive.words; | ||||
|  | ||||
| import cn.hutool.dfa.FoundWord; | ||||
| import cn.hutool.dfa.WordTree; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| public class SensitiveWordsTest { | ||||
|     public static void main(String[] args) { | ||||
|         WordTree tree = new WordTree(); | ||||
|         tree.addWord("大"); | ||||
|         tree.addWord("大土豆"); | ||||
|         tree.addWord("土豆"); | ||||
|         tree.addWord("刚出锅"); | ||||
|         tree.addWord("出锅"); | ||||
|         //正文 | ||||
|         String text = "我有一颗大土豆,刚出锅的"; | ||||
|  | ||||
|         // 匹配到【大】,由于非密集匹配,因此从下一个字符开始查找,匹配到【土豆】接着被匹配 | ||||
|         // 由于【刚出锅】被匹配,由于非密集匹配,【出锅】被跳过 | ||||
|         List<String> matchAll = tree.matchAll(text, -1, false, true); | ||||
|         for (String s : matchAll) { | ||||
|             System.out.println(s); | ||||
|         } | ||||
|         System.out.println("-------------------"); | ||||
|         String match = tree.match(text); | ||||
|         System.out.println(match); | ||||
|  | ||||
|         System.out.println("-------------------"); | ||||
|         FoundWord matchText = tree.matchWord(text); | ||||
|         System.out.println(matchText.getFoundWord()); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user