|
@@ -9,12 +9,17 @@ import com.etotem.cfc.service.ArticleService;
|
|
|
import com.etotem.cfc.service.FileStorageService;
|
|
import com.etotem.cfc.service.FileStorageService;
|
|
|
import com.etotem.cfc.service.api.WechatServiceInterface;
|
|
import com.etotem.cfc.service.api.WechatServiceInterface;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
|
import java.util.HashMap;
|
|
import java.util.HashMap;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
|
+import java.util.concurrent.Future;
|
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import com.etotem.cfc.util.SortUtil;
|
|
import com.etotem.cfc.util.SortUtil;
|
|
|
import com.etotem.cfc.util.ParamUtils;
|
|
import com.etotem.cfc.util.ParamUtils;
|
|
|
|
|
|
|
@@ -22,6 +27,8 @@ import com.etotem.cfc.util.ParamUtils;
|
|
|
@RequestMapping("/api/admin/articles")
|
|
@RequestMapping("/api/admin/articles")
|
|
|
public class AdminArticleController {
|
|
public class AdminArticleController {
|
|
|
|
|
|
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(AdminArticleController.class);
|
|
|
|
|
+
|
|
|
@Resource
|
|
@Resource
|
|
|
private ArticleService articleService;
|
|
private ArticleService articleService;
|
|
|
|
|
|
|
@@ -37,6 +44,24 @@ public class AdminArticleController {
|
|
|
@Resource
|
|
@Resource
|
|
|
private WechatServiceInterface wechatService;
|
|
private WechatServiceInterface wechatService;
|
|
|
|
|
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private ThreadPoolTaskExecutor taskExecutor;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 文本内容安全检测:带 5 秒硬超时,超时/异常时 fail-open 放行并记录日志,
|
|
|
|
|
+ * 避免微信接口卡顿导致文章创建/更新接口耗时数十秒(BUG-J)。
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean checkTextSafe(String text) {
|
|
|
|
|
+ if (text == null || text.trim().isEmpty()) return true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ Future<Boolean> future = taskExecutor.submit(() -> wechatService.checkText(text));
|
|
|
|
|
+ return future.get(5, TimeUnit.SECONDS);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("文本内容安全检测超时或执行失败,fail-open: {}", e.getMessage());
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@PostMapping("/list")
|
|
@PostMapping("/list")
|
|
|
public Result<Page<Article>> list(@RequestBody Map<String, Object> body) {
|
|
public Result<Page<Article>> list(@RequestBody Map<String, Object> body) {
|
|
|
String status = (String) body.get("status");
|
|
String status = (String) body.get("status");
|
|
@@ -62,11 +87,11 @@ public class AdminArticleController {
|
|
|
String title = (String) body.get("title");
|
|
String title = (String) body.get("title");
|
|
|
String content = (String) body.get("content");
|
|
String content = (String) body.get("content");
|
|
|
|
|
|
|
|
- // 文本内容安全检测
|
|
|
|
|
- if (title != null && !title.isEmpty() && !wechatService.checkText(title)) {
|
|
|
|
|
|
|
+ // 文本内容安全检测(带超时,不阻塞接口)
|
|
|
|
|
+ if (!checkTextSafe(title)) {
|
|
|
return Result.error("文章标题包含敏感信息,发布失败");
|
|
return Result.error("文章标题包含敏感信息,发布失败");
|
|
|
}
|
|
}
|
|
|
- if (content != null && !content.isEmpty() && !wechatService.checkText(content)) {
|
|
|
|
|
|
|
+ if (!checkTextSafe(content)) {
|
|
|
return Result.error("文章内容包含敏感信息,发布失败");
|
|
return Result.error("文章内容包含敏感信息,发布失败");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -134,11 +159,11 @@ public class AdminArticleController {
|
|
|
String title = (String) body.get("title");
|
|
String title = (String) body.get("title");
|
|
|
String content = (String) body.get("content");
|
|
String content = (String) body.get("content");
|
|
|
|
|
|
|
|
- // 文本内容安全检测
|
|
|
|
|
- if (title != null && !title.isEmpty() && !wechatService.checkText(title)) {
|
|
|
|
|
|
|
+ // 文本内容安全检测(带超时,不阻塞接口)
|
|
|
|
|
+ if (!checkTextSafe(title)) {
|
|
|
return Result.error("文章标题包含敏感信息,更新失败");
|
|
return Result.error("文章标题包含敏感信息,更新失败");
|
|
|
}
|
|
}
|
|
|
- if (content != null && !content.isEmpty() && !wechatService.checkText(content)) {
|
|
|
|
|
|
|
+ if (!checkTextSafe(content)) {
|
|
|
return Result.error("文章内容包含敏感信息,更新失败");
|
|
return Result.error("文章内容包含敏感信息,更新失败");
|
|
|
}
|
|
}
|
|
|
|
|
|