wangwenju 1 сар өмнө
parent
commit
692ec6c213

+ 59 - 6
LiangZhiYUMao/pages/plaza/publish.vue

@@ -58,6 +58,7 @@
 
 <script>
 import api from '@/utils/api.js'
+import contentSecurityCheck from '@/utils/contentSecurityCheck.js'
 
 export default {
 	data() {
@@ -156,17 +157,56 @@ export default {
                     this.mediaList.push(...filePaths)
                     this.uploading = true
                     uni.showLoading({ title: `正在上传 ${filePaths.length} 张图片...` })
+                    
+                    let uploadedCount = 0
+                    let failedCount = 0
+                    
                     try {
                         for (const filePath of filePaths) {
                             try {
+                                // 1. 上传图片
                                 const url = await api.dynamic.uploadSingle(filePath)
                                 const idx = this.mediaList.indexOf(filePath)
-                                if (idx !== -1) this.mediaList.splice(idx, 1, url)
+                                
+                                // 2. 上传成功后进行安全检测
+                                uni.showLoading({ title: `检测第 ${uploadedCount + 1} 张图片...` })
+                                const checkResult = await contentSecurityCheck.checkImage(url)
+                                
+                                if (!checkResult.safe) {
+                                    // 图片违规,移除并提示
+                                    if (idx !== -1) this.mediaList.splice(idx, 1)
+                                    failedCount++
+                                    uni.hideLoading()
+                                    uni.showModal({
+                                        title: '图片违规',
+                                        content: checkResult.message || '该图片包含违规内容,已自动移除',
+                                        showCancel: false,
+                                        confirmText: '我知道了'
+                                    })
+                                    // 等待用户确认后继续
+                                    await new Promise(resolve => setTimeout(resolve, 500))
+                                    uni.showLoading({ title: `继续上传...` })
+                                } else {
+                                    // 图片安全,更新URL
+                                    if (idx !== -1) this.mediaList.splice(idx, 1, url)
+                                    uploadedCount++
+                                }
                             } catch (e) {
+                                console.error('上传图片失败:', e)
                                 const idx = this.mediaList.indexOf(filePath)
                                 if (idx !== -1) this.mediaList.splice(idx, 1)
+                                failedCount++
                             }
                         }
+                        
+                        // 上传完成提示
+                        if (failedCount > 0) {
+                            uni.showToast({ 
+                                title: `${uploadedCount}张上传成功,${failedCount}张被移除`, 
+                                icon: 'none',
+                                duration: 2000
+                            })
+                        }
                     } finally {
                         this.uploading = false
                         uni.hideLoading()
@@ -192,11 +232,24 @@ export default {
 				return
 			}
 			
-			// 简单敏感词检测
-			const badWords = ['傻', '坏词', '违规']
-			if (badWords.some(w => this.content.includes(w))) {
-				uni.showToast({ title: '内容包含敏感词,请修改后发布', icon: 'none' })
-				return
+			uni.showLoading({ title: '内容检测中...' })
+			
+			// 文字内容安全检测(图片在上传时已检测)
+			try {
+				const textResult = await contentSecurityCheck.checkText(this.content)
+				if (!textResult.safe) {
+					uni.hideLoading()
+					uni.showModal({
+						title: '内容违规',
+						content: textResult.message || '您发布的内容包含违规信息,请修改后重试',
+						showCancel: false,
+						confirmText: '我知道了'
+					})
+					return
+				}
+			} catch (e) {
+				console.error('内容安全检测异常:', e)
+				// 检测异常时继续发布,由后端二次校验
 			}
 			
 			uni.showLoading({ title: this.isEdit ? '正在保存...' : '正在发布...' })

+ 207 - 0
LiangZhiYUMao/utils/contentSecurityCheck.js

@@ -0,0 +1,207 @@
+/**
+ * 内容安全检测工具类
+ * 用于检测用户发布的文字、图片是否包含色情、低俗、违规等内容
+ * 使用微信小程序内容安全API
+ */
+
+const BASE_URL = 'https://api.zhongruanke.cn/api'
+
+// 敏感词列表(本地基础过滤)
+const SENSITIVE_WORDS = [
+  // 色情相关
+  '色情', '裸体', '性爱', '约炮', '一夜情', '援交', '卖淫', '嫖娼',
+  // 低俗相关
+  '傻逼', '操你', '草泥马', '妈的', '他妈的', '狗日的', '王八蛋',
+  // 违规相关
+  '赌博', '毒品', '枪支', '炸弹', '恐怖', '暴力',
+  // 诈骗相关
+  '刷单', '兼职日结', '高额返利', '免费领取'
+]
+
+export default {
+  /**
+   * 检测文字内容是否安全
+   * @param {string} content - 要检测的文字内容
+   * @returns {Promise<{safe: boolean, message: string}>}
+   */
+  async checkText(content) {
+    if (!content || !content.trim()) {
+      return { safe: true, message: '' }
+    }
+    
+    // 1. 本地敏感词过滤(快速检测)
+    const localResult = this.localTextCheck(content)
+    if (!localResult.safe) {
+      return localResult
+    }
+    
+    // 2. 调用后端接口进行内容安全检测
+    try {
+      const [error, res] = await uni.request({
+        url: `${BASE_URL}/content-security/check-text`,
+        method: 'POST',
+        data: { content: content },
+        timeout: 10000
+      })
+      
+      if (error) {
+        console.error('文字安全检测请求失败:', error)
+        // 网络错误时,仅依赖本地检测结果
+        return localResult
+      }
+      
+      if (res.statusCode === 200 && res.data) {
+        if (res.data.code === 200) {
+          const data = res.data.data
+          if (data && data.safe === false) {
+            return {
+              safe: false,
+              message: data.message || '内容包含违规信息,请修改后重试'
+            }
+          }
+        } else if (res.data.code === 87014) {
+          // 微信内容安全API返回的违规码
+          return {
+            safe: false,
+            message: '内容包含违规信息,请修改后重试'
+          }
+        }
+      }
+      
+      return { safe: true, message: '' }
+    } catch (e) {
+      console.error('文字安全检测异常:', e)
+      return localResult
+    }
+  },
+  
+  /**
+   * 本地敏感词检测
+   * @param {string} content - 要检测的文字内容
+   * @returns {{safe: boolean, message: string}}
+   */
+  localTextCheck(content) {
+    if (!content) return { safe: true, message: '' }
+    
+    const lowerContent = content.toLowerCase()
+    for (const word of SENSITIVE_WORDS) {
+      if (lowerContent.includes(word.toLowerCase())) {
+        return {
+          safe: false,
+          message: '内容包含敏感词,请修改后重试'
+        }
+      }
+    }
+    return { safe: true, message: '' }
+  },
+  
+  /**
+   * 检测图片是否安全
+   * @param {string} imageUrl - 图片URL(需要是可访问的网络地址)
+   * @returns {Promise<{safe: boolean, message: string}>}
+   */
+  async checkImage(imageUrl) {
+    if (!imageUrl) {
+      return { safe: true, message: '' }
+    }
+    
+    // 如果是本地临时文件,跳过检测(上传后再检测)
+    if (imageUrl.startsWith('wxfile://') || imageUrl.startsWith('http://tmp/')) {
+      return { safe: true, message: '' }
+    }
+    
+    try {
+      const [error, res] = await uni.request({
+        url: `${BASE_URL}/content-security/check-image`,
+        method: 'POST',
+        data: { imageUrl: imageUrl },
+        timeout: 15000
+      })
+      
+      if (error) {
+        console.error('图片安全检测请求失败:', error)
+        return { safe: true, message: '' } // 网络错误时默认通过
+      }
+      
+      if (res.statusCode === 200 && res.data) {
+        if (res.data.code === 200) {
+          const data = res.data.data
+          if (data && data.safe === false) {
+            return {
+              safe: false,
+              message: data.message || '图片包含违规内容,请更换后重试'
+            }
+          }
+        } else if (res.data.code === 87014) {
+          return {
+            safe: false,
+            message: '图片包含违规内容,请更换后重试'
+          }
+        }
+      }
+      
+      return { safe: true, message: '' }
+    } catch (e) {
+      console.error('图片安全检测异常:', e)
+      return { safe: true, message: '' }
+    }
+  },
+  
+  /**
+   * 批量检测图片是否安全
+   * @param {string[]} imageUrls - 图片URL数组
+   * @returns {Promise<{safe: boolean, message: string, failedIndex: number}>}
+   */
+  async checkImages(imageUrls) {
+    if (!imageUrls || imageUrls.length === 0) {
+      return { safe: true, message: '', failedIndex: -1 }
+    }
+    
+    // 过滤掉本地临时文件
+    const networkUrls = imageUrls.filter(url => 
+      url && !url.startsWith('wxfile://') && !url.startsWith('http://tmp/')
+    )
+    
+    if (networkUrls.length === 0) {
+      return { safe: true, message: '', failedIndex: -1 }
+    }
+    
+    // 逐个检测图片
+    for (let i = 0; i < networkUrls.length; i++) {
+      const result = await this.checkImage(networkUrls[i])
+      if (!result.safe) {
+        return {
+          safe: false,
+          message: `第${i + 1}张图片包含违规内容,请更换后重试`,
+          failedIndex: i
+        }
+      }
+    }
+    
+    return { safe: true, message: '', failedIndex: -1 }
+  },
+  
+  /**
+   * 综合检测文字和图片
+   * @param {string} content - 文字内容
+   * @param {string[]} imageUrls - 图片URL数组
+   * @returns {Promise<{safe: boolean, message: string}>}
+   */
+  async checkContent(content, imageUrls) {
+    // 1. 检测文字
+    const textResult = await this.checkText(content)
+    if (!textResult.safe) {
+      return textResult
+    }
+    
+    // 2. 检测图片
+    if (imageUrls && imageUrls.length > 0) {
+      const imageResult = await this.checkImages(imageUrls)
+      if (!imageResult.safe) {
+        return imageResult
+      }
+    }
+    
+    return { safe: true, message: '' }
+  }
+}

+ 8 - 0
gateway/src/main/resources/application.yml

@@ -108,6 +108,14 @@ spring:
           filters:
             - StripPrefix=0
 
+        # 内容安全检测路由(dynamic服务)
+        - id: content-security-route
+          uri: http://localhost:8086
+          predicates:
+            - Path=/content-security/**
+          filters:
+            - StripPrefix=0
+
         # 动态媒体文件路由
         - id: dynamic-media-route
           uri: http://localhost:8086

+ 408 - 0
service/dynamic/src/main/java/com/zhentao/controller/ContentSecurityController.java

@@ -0,0 +1,408 @@
+package com.zhentao.controller;
+
+import com.zhentao.common.Result;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ByteArrayResource;
+import org.springframework.http.*;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * 内容安全检测控制器
+ * 用于检测用户发布的文字、图片是否包含违规内容
+ * 集成微信小程序内容安全API
+ */
+@RestController
+@RequestMapping("/content-security")
+public class ContentSecurityController {
+
+    private static final Logger logger = LoggerFactory.getLogger(ContentSecurityController.class);
+
+    @Value("${wechat.miniapp.appid:}")
+    private String appId;
+
+    @Value("${wechat.miniapp.secret:}")
+    private String appSecret;
+
+    private final RestTemplate restTemplate = new RestTemplate();
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
+    private String cachedAccessToken;
+    private long tokenExpireTime = 0;
+
+    private static final List<String> SENSITIVE_WORDS = Arrays.asList(
+        "色情", "裸体", "性爱", "约炮", "一夜情", "援交", "卖淫", "嫖娼", "小姐服务",
+        "做爱", "性交", "口交", "肛交", "自慰", "手淫", "阴茎", "阴道", "乳房",
+        "傻逼", "操你", "草泥马", "妈的", "他妈的", "狗日的", "王八蛋", "贱人", "婊子",
+        "滚蛋", "去死", "废物", "垃圾", "白痴", "智障",
+        "赌博", "毒品", "枪支", "炸弹", "恐怖", "暴力", "杀人", "自杀",
+        "刷单", "兼职日结", "高额返利", "免费领取", "中奖", "彩票内幕", "稳赚不赔",
+        "法轮功", "邪教"
+    );
+
+    private static final List<Pattern> SENSITIVE_PATTERNS = new ArrayList<>();
+
+    static {
+        for (String word : SENSITIVE_WORDS) {
+            StringBuilder patternStr = new StringBuilder();
+            for (int i = 0; i < word.length(); i++) {
+                if (i > 0) {
+                    patternStr.append("[\\s\\*\\-\\_\\.]*");
+                }
+                patternStr.append(Pattern.quote(String.valueOf(word.charAt(i))));
+            }
+            SENSITIVE_PATTERNS.add(Pattern.compile(patternStr.toString(), Pattern.CASE_INSENSITIVE));
+        }
+    }
+
+    /**
+     * 检测文字内容是否安全
+     */
+    @PostMapping("/check-text")
+    public Result<Map<String, Object>> checkText(@RequestBody Map<String, String> request) {
+        String content = request.get("content");
+        
+        if (content == null || content.trim().isEmpty()) {
+            return Result.success(createSafeResult());
+        }
+
+        String localCheckResult = localTextCheck(content);
+        if (localCheckResult != null) {
+            logger.info("本地敏感词检测不通过: {}", localCheckResult);
+            return Result.success(createUnsafeResult("内容包含敏感词,请修改后重试"));
+        }
+
+        try {
+            Map<String, Object> wxResult = wxMsgSecCheck(content);
+            if (wxResult != null && Boolean.FALSE.equals(wxResult.get("safe"))) {
+                logger.info("微信内容安全检测不通过");
+                return Result.success(createUnsafeResult((String) wxResult.get("message")));
+            }
+        } catch (Exception e) {
+            logger.error("微信内容安全检测异常", e);
+        }
+
+        return Result.success(createSafeResult());
+    }
+
+    /**
+     * 检测图片是否安全(同步检测)
+     */
+    @PostMapping("/check-image")
+    public Result<Map<String, Object>> checkImage(@RequestBody Map<String, String> request) {
+        String imageUrl = request.get("imageUrl");
+        
+        if (imageUrl == null || imageUrl.trim().isEmpty()) {
+            return Result.success(createSafeResult());
+        }
+
+        logger.info("开始检测图片: {}", imageUrl);
+
+        try {
+            // 下载图片并调用微信图片安全检测API
+            Map<String, Object> wxResult = wxImgSecCheck(imageUrl);
+            if (wxResult != null && Boolean.FALSE.equals(wxResult.get("safe"))) {
+                logger.info("微信图片安全检测不通过: {}", imageUrl);
+                return Result.success(createUnsafeResult((String) wxResult.get("message")));
+            }
+            logger.info("图片检测通过: {}", imageUrl);
+        } catch (Exception e) {
+            logger.error("微信图片安全检测异常: {}", imageUrl, e);
+            // 异常时默认通过,由人工审核
+        }
+
+        return Result.success(createSafeResult());
+    }
+
+    /**
+     * 批量检测图片
+     */
+    @PostMapping("/check-images")
+    public Result<Map<String, Object>> checkImages(@RequestBody Map<String, Object> request) {
+        @SuppressWarnings("unchecked")
+        List<String> imageUrls = (List<String>) request.get("imageUrls");
+        
+        if (imageUrls == null || imageUrls.isEmpty()) {
+            return Result.success(createSafeResult());
+        }
+
+        for (int i = 0; i < imageUrls.size(); i++) {
+            String imageUrl = imageUrls.get(i);
+            if (imageUrl == null || imageUrl.trim().isEmpty()) {
+                continue;
+            }
+
+            try {
+                Map<String, Object> wxResult = wxImgSecCheck(imageUrl);
+                if (wxResult != null && Boolean.FALSE.equals(wxResult.get("safe"))) {
+                    Map<String, Object> result = createUnsafeResult("第" + (i + 1) + "张图片包含违规内容,请更换后重试");
+                    result.put("failedIndex", i);
+                    return Result.success(result);
+                }
+            } catch (Exception e) {
+                logger.error("检测第{}张图片异常: {}", i + 1, imageUrl, e);
+            }
+        }
+
+        return Result.success(createSafeResult());
+    }
+
+    private String localTextCheck(String content) {
+        String lowerContent = content.toLowerCase();
+        
+        for (String word : SENSITIVE_WORDS) {
+            if (lowerContent.contains(word.toLowerCase())) {
+                return word;
+            }
+        }
+        
+        for (int i = 0; i < SENSITIVE_PATTERNS.size(); i++) {
+            if (SENSITIVE_PATTERNS.get(i).matcher(content).find()) {
+                return SENSITIVE_WORDS.get(i);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 调用微信文字内容安全检测API
+     */
+    private Map<String, Object> wxMsgSecCheck(String content) {
+        try {
+            String accessToken = getAccessToken();
+            if (accessToken == null || accessToken.isEmpty()) {
+                logger.warn("获取access_token失败,跳过微信内容检测");
+                return null;
+            }
+
+            String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + accessToken;
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.APPLICATION_JSON);
+
+            Map<String, Object> body = new HashMap<>();
+            body.put("content", content);
+            body.put("version", 2);
+            body.put("scene", 2);
+
+            HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, headers);
+            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
+
+            if (response.getStatusCode() == HttpStatus.OK) {
+                JsonNode jsonNode = objectMapper.readTree(response.getBody());
+                int errcode = jsonNode.has("errcode") ? jsonNode.get("errcode").asInt() : 0;
+                
+                if (errcode == 0) {
+                    JsonNode result = jsonNode.get("result");
+                    if (result != null) {
+                        String suggest = result.has("suggest") ? result.get("suggest").asText() : "pass";
+                        if ("risky".equals(suggest)) {
+                            String label = result.has("label") ? result.get("label").asText() : "违规内容";
+                            return createUnsafeResult("内容包含" + getLabelText(label) + ",请修改后重试");
+                        }
+                    }
+                    return createSafeResult();
+                } else if (errcode == 87014) {
+                    return createUnsafeResult("内容包含违规信息,请修改后重试");
+                } else {
+                    logger.warn("微信内容检测返回错误码: {}", errcode);
+                }
+            }
+        } catch (Exception e) {
+            logger.error("调用微信文字内容安全API异常", e);
+        }
+        return null;
+    }
+
+    /**
+     * 调用微信图片内容安全检测API(同步,通过上传图片文件)
+     * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/sec-center/sec-check/imgSecCheck.html
+     */
+    private Map<String, Object> wxImgSecCheck(String imageUrl) {
+        try {
+            String accessToken = getAccessToken();
+            if (accessToken == null || accessToken.isEmpty()) {
+                logger.warn("获取access_token失败,跳过微信图片检测");
+                return null;
+            }
+
+            // 1. 下载图片
+            byte[] imageBytes = downloadImage(imageUrl);
+            if (imageBytes == null || imageBytes.length == 0) {
+                logger.warn("下载图片失败: {}", imageUrl);
+                return null;
+            }
+
+            // 检查图片大小(微信限制1MB)
+            if (imageBytes.length > 1024 * 1024) {
+                logger.warn("图片大小超过1MB,跳过微信检测: {} bytes", imageBytes.length);
+                // 大图片跳过微信检测,由人工审核
+                return createSafeResult();
+            }
+
+            // 2. 上传到微信进行检测
+            String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=" + accessToken;
+
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+
+            // 创建文件资源
+            ByteArrayResource fileResource = new ByteArrayResource(imageBytes) {
+                @Override
+                public String getFilename() {
+                    return "image.jpg";
+                }
+            };
+
+            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
+            body.add("media", fileResource);
+
+            HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(body, headers);
+            ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
+
+            logger.info("微信图片检测响应: {}", response.getBody());
+
+            if (response.getStatusCode() == HttpStatus.OK) {
+                JsonNode jsonNode = objectMapper.readTree(response.getBody());
+                int errcode = jsonNode.has("errcode") ? jsonNode.get("errcode").asInt() : 0;
+                
+                if (errcode == 0) {
+                    // 检测通过
+                    return createSafeResult();
+                } else if (errcode == 87014) {
+                    // 图片含有违法违规内容
+                    return createUnsafeResult("图片包含违规内容,请更换后重试");
+                } else {
+                    logger.warn("微信图片检测返回错误码: {}, errmsg: {}", 
+                        errcode, jsonNode.has("errmsg") ? jsonNode.get("errmsg").asText() : "");
+                }
+            }
+        } catch (Exception e) {
+            logger.error("调用微信图片内容安全API异常", e);
+        }
+        return null;
+    }
+
+    /**
+     * 下载图片
+     */
+    private byte[] downloadImage(String imageUrl) {
+        HttpURLConnection connection = null;
+        InputStream inputStream = null;
+        ByteArrayOutputStream outputStream = null;
+        
+        try {
+            URL url = new URL(imageUrl);
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("GET");
+            connection.setConnectTimeout(10000);
+            connection.setReadTimeout(30000);
+            connection.setRequestProperty("User-Agent", "Mozilla/5.0");
+            
+            int responseCode = connection.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                logger.warn("下载图片失败,HTTP状态码: {}", responseCode);
+                return null;
+            }
+
+            inputStream = connection.getInputStream();
+            outputStream = new ByteArrayOutputStream();
+            
+            byte[] buffer = new byte[4096];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            
+            return outputStream.toByteArray();
+        } catch (Exception e) {
+            logger.error("下载图片异常: {}", imageUrl, e);
+            return null;
+        } finally {
+            try {
+                if (inputStream != null) inputStream.close();
+                if (outputStream != null) outputStream.close();
+                if (connection != null) connection.disconnect();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+    }
+
+    private synchronized String getAccessToken() {
+        if (cachedAccessToken != null && System.currentTimeMillis() < tokenExpireTime) {
+            return cachedAccessToken;
+        }
+
+        if (appId == null || appId.isEmpty() || appSecret == null || appSecret.isEmpty()) {
+            logger.warn("微信小程序appId或appSecret未配置");
+            return null;
+        }
+
+        try {
+            String url = String.format(
+                "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
+                appId, appSecret
+            );
+
+            ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
+            if (response.getStatusCode() == HttpStatus.OK) {
+                JsonNode jsonNode = objectMapper.readTree(response.getBody());
+                if (jsonNode.has("access_token")) {
+                    cachedAccessToken = jsonNode.get("access_token").asText();
+                    int expiresIn = jsonNode.has("expires_in") ? jsonNode.get("expires_in").asInt() : 7200;
+                    tokenExpireTime = System.currentTimeMillis() + (expiresIn - 300) * 1000L;
+                    return cachedAccessToken;
+                } else {
+                    logger.error("获取access_token失败: {}", response.getBody());
+                }
+            }
+        } catch (Exception e) {
+            logger.error("获取access_token异常", e);
+        }
+        return null;
+    }
+
+    private String getLabelText(String label) {
+        Map<String, String> labelMap = new HashMap<>();
+        labelMap.put("100", "违规内容");
+        labelMap.put("10001", "广告内容");
+        labelMap.put("20001", "时政内容");
+        labelMap.put("20002", "色情内容");
+        labelMap.put("20003", "辱骂内容");
+        labelMap.put("20006", "违法犯罪内容");
+        labelMap.put("20008", "欺诈内容");
+        labelMap.put("20012", "低俗内容");
+        labelMap.put("20013", "版权内容");
+        labelMap.put("21000", "其他违规内容");
+        return labelMap.getOrDefault(label, "违规内容");
+    }
+
+    private Map<String, Object> createSafeResult() {
+        Map<String, Object> result = new HashMap<>();
+        result.put("safe", true);
+        result.put("message", "");
+        return result;
+    }
+
+    private Map<String, Object> createUnsafeResult(String message) {
+        Map<String, Object> result = new HashMap<>();
+        result.put("safe", false);
+        result.put("message", message);
+        return result;
+    }
+}

+ 5 - 0
service/dynamic/src/main/resources/application.yml

@@ -76,3 +76,8 @@ dynamic:
     url:
       prefix: http://localhost:8083/media/  # 直接访问dynamic服务
 
+# 微信小程序配置(用于内容安全检测)
+wechat:
+  miniapp:
+    appid: wx3e90d662a801266e
+    secret: d82ce405f04a47de14382bef4180239d