北京比较好的网站建设公司网站规划书包括哪些方面

当前位置: 首页 > news >正文

北京比较好的网站建设公司,网站规划书包括哪些方面,个人简历电子版填写免费模板,网站的建设包括以下几个阶段自动审核流程介绍 做为内容类产品#xff0c;内容安全非常重要#xff0c;所以需要进行对自媒体用户发布的文章进行审核以后才能到app端展示给用户。2 WmNews 中status 代表自媒体文章的状态 status字段#xff1a;0 草稿 1 待审核 2 审核失败 3 人工审核 4 人工审核通过 …自动审核流程介绍 做为内容类产品内容安全非常重要所以需要进行对自媒体用户发布的文章进行审核以后才能到app端展示给用户。2 WmNews 中status 代表自媒体文章的状态 status字段0 草稿 1 待审核 2 审核失败 3 人工审核 4 人工审核通过   8 审核通过待发布 9 已发布 当自媒体用户提交发布文章之后会发消息给RabbitMQ提交审核 自媒体微服务提供消息监听处理自动审核 查询文章数据 判断文章id是否为1 只有1需要自动审核 文章内容中是否有自管理的敏感词如果有则审核不通过修改自媒体文章状态为2 调用阿里云文本反垃圾服务进行文本审核 审核不通过 2 人工审核 3 调用阿里云图片审核服务进行图片审核 审核不通过 2 人工审核 3 如果审核通过 判断发布时间 是否小于等于当前时间 如果小于等于 直接发消息通知 文章微服务 发布文章 如果未到发布时间将消息发送到RabbitMQ的死信队列 并设置消息失效时间 2 内容安全第三方接口对接 2.1内容安全接口选型 内容安全是识别服务支持对图片、视频、文本、语音等对象进行多样化场景检测有效降低内容违规风险。 黑马头条发布文章中有内容可能违规如何有效避免风险可以使用第三方接口进行内容检测。 目前很多平台都支持内容检测如阿里云、腾讯云、百度AI、网易云等国内大型互联网公司都对外提供了API。 按照性能和收费来看黑马头条项目使用的就是阿里云的内容安全接口使用到了图片和文本的审核。 阿里云收费标准阿里云定价_云产品价格 2.2阿里云服务介绍 2.2.1 准备工作 您在使用内容检测API之前需要先注册阿里云账号添加Access Key并签约云盾内容安全。 操作步骤 前往阿里云官网注册账号。如果已有注册账号请跳过此步骤。 进入阿里云首页后如果没有阿里云的账户需要先进行注册才可以进行登录。由于注册较为简单课程和讲义不在进行体现注册可以使用多种方式如淘宝账号、支付宝账号、微博账号等…。 需要实名认证和活体认证。 打开云盾内容安全产品试用页面单击立即开通正式开通服务。 在AccessKey管理页面管理您的AccessKeyID和AccessKeySecret。 2.2.2 阿里云安全-文本内容垃圾检测 文本垃圾内容检测接口说明 示例代码地址如何使用JavaSDK文本反垃圾接口_内容安全-阿里云帮助中心 创建项目aliyun-test 安装sdk dependencies!– 阿里云内容安全sdk –dependencygroupIdcom.aliyun/groupIdartifactIdaliyun-java-sdk-core/artifactIdversion4.1.1/version/dependencydependencygroupIdcom.aliyun/groupIdartifactIdaliyun-java-sdk-green/artifactIdversion3.6.2/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.51/version/dependencydependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion2.8.3/version/dependency ​dependencygroupIdcommons-io/groupIdartifactIdcommons-io/artifactIdversion2.4/version/dependency ​dependencygroupIdcommons-codec/groupIdartifactIdcommons-codec/artifactIdversion1.10/version/dependencydependencygroupIdcommons-logging/groupIdartifactIdcommons-logging/artifactIdversion1.2/version/dependency /dependencies 示例代码 package com.itheima.aliyun.util; ​ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.aliyun.oss.ClientException; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.exceptions.ServerException; import com.aliyuncs.green.model.v20180509.TextScanRequest; import com.aliyuncs.http.FormatType; import com.aliyuncs.http.HttpResponse; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; ​ import java.util.; ​ public class Main { ​public static void main(String[] args) throws Exception {IClientProfile profile DefaultProfile.getProfile(cn-shanghai, LTAI4F1mKL2EKYCGgN2az5M57, XjgvRoAGzM3rWQxKWDJx198VWOmO0Hz);DefaultProfile.addEndpoint(cn-shanghai, cn-shanghai, Green, green.cn-shanghai.aliyuncs.com);        IAcsClient client new DefaultAcsClient(profile);TextScanRequest textScanRequest new TextScanRequest();textScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。textScanRequest.setHttpContentType(FormatType.JSON);textScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。textScanRequest.setEncoding(UTF-8);textScanRequest.setRegionId(cn-shanghai);ListMapString, Object tasks new ArrayListMapString, Object();MapString, Object task1 new LinkedHashMapString, Object();task1.put(dataId, UUID.randomUUID().toString());/** 待检测的文本长度不超过10000个字符。/task1.put(content, 我是一个文本,买卖冰毒是违法的);tasks.add(task1);JSONObject data new JSONObject(); ​/** 检测场景。文本垃圾检测请传递antispam。/data.put(scenes, Arrays.asList(antispam));data.put(tasks, tasks);System.out.println(参数JSON.toJSONString(data, true));textScanRequest.setHttpContent(data.toJSONString().getBytes(UTF-8), UTF-8, FormatType.JSON);// 请务必设置超时时间。textScanRequest.setConnectTimeout(3000);textScanRequest.setReadTimeout(6000);try {HttpResponse httpResponse client.doAction(textScanRequest);if(httpResponse.isSuccess()){JSONObject scrResponse JSON.parseObject(new String(httpResponse.getHttpContent(), UTF-8));System.out.println(结果JSON.toJSONString(scrResponse, true));if (200 scrResponse.getInteger(code)) {JSONArray taskResults scrResponse.getJSONArray(data);for (Object taskResult : taskResults) {if(200 ((JSONObject)taskResult).getInteger(code)){JSONArray sceneResults ((JSONObject)taskResult).getJSONArray(results);for (Object sceneResult : sceneResults) {String scene ((JSONObject)sceneResult).getString(scene);String suggestion ((JSONObject)sceneResult).getString(suggestion);//根据scene和suggetion做相关处理。//suggestion pass表示未命中垃圾。suggestion block表示命中了垃圾可以通过label字段查看命中的垃圾分类。System.out.println(args [ scene ]);System.out.println(args [ suggestion ]);}}else{System.out.println(task process fail: ((JSONObject)taskResult).getInteger(code));}}} else {System.out.println(detect not success. code: scrResponse.getInteger(code));}}else{System.out.println(response not success. status: httpResponse.getStatus());}} catch (ServerException e) {e.printStackTrace();} catch (ClientException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}} ​ } 测试一输入以上的内容检测通过     2.2.3 阿里云安全-图片审核 参考阿里云提供的接口文档说明文档地址 示例代码地址 注意事项如果使用本地文件或者二进制文件检测请下载并在项目工程中引入Extension.Uploader工具类。 修改后的示例代码 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.green.model.v20180509.ImageSyncScanRequest; import com.aliyuncs.http.FormatType; import com.aliyuncs.http.HttpResponse; import com.aliyuncs.http.MethodType; import com.aliyuncs.http.ProtocolType; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.profile.IClientProfile; ​ import java.util.*; ​ public class ImgMain { ​public static void main(String[] args) throws Exception {IClientProfile profile DefaultProfile.getProfile(cn-shanghai, LTAI4FzL1ddwcgSNDv3GTfJZ1, 13ygpLlW8MUervH5U2it420vGG1AcbF);DefaultProfile.addEndpoint(cn-shanghai, cn-shanghai, Green, green.cn-shanghai.aliyuncs.com);IAcsClient client new DefaultAcsClient(profile); ​ImageSyncScanRequest imageSyncScanRequest new ImageSyncScanRequest();// 指定API返回格式。imageSyncScanRequest.setAcceptFormat(FormatType.JSON);// 指定请求方法。imageSyncScanRequest.setMethod(MethodType.POST);imageSyncScanRequest.setEncoding(utf-8);// 支持HTTP和HTTPS。imageSyncScanRequest.setProtocol(ProtocolType.HTTP); ​ ​JSONObject httpBody new JSONObject();/* 设置要检测的风险场景。计费依据此处传递的场景计算。* 一次请求中可以同时检测多张图片每张图片可以同时检测多个风险场景计费按照场景计算。* 例如检测2张图片场景传递porn和terrorism计费会按照2张图片鉴黄2张图片暴恐检测计算。* porn表示鉴黄场景。/httpBody.put(scenes, Arrays.asList(terrorism)); ​/** 设置待检测图片。一张图片对应一个task。* 多张图片同时检测时处理的时间由最后一个处理完的图片决定。* 通常情况下批量检测的平均响应时间比单张检测的要长。一次批量提交的图片数越多响应时间被拉长的概率越高。* 这里以单张图片检测作为示例, 如果是批量图片检测请自行构建多个task。/JSONObject task new JSONObject();task.put(dataId, UUID.randomUUID().toString()); ​// 设置图片链接。task.put(url, https://heimaleadnewsoss.oss-cn-shanghai.aliyuncs.com/material/2021/1/20210112/205cd5d3346a48b59352c92808709da1.jpg);task.put(time, new Date());httpBody.put(tasks, Arrays.asList(task)); ​imageSyncScanRequest.setHttpContent(org.apache.commons.codec.binary.StringUtils.getBytesUtf8(httpBody.toJSONString()),UTF-8, FormatType.JSON); ​/** 请设置超时时间。服务端全链路处理超时时间为10秒请做相应设置。* 如果您设置的ReadTimeout小于服务端处理的时间程序中会获得一个read timeout异常。/imageSyncScanRequest.setConnectTimeout(3000);imageSyncScanRequest.setReadTimeout(10000);HttpResponse httpResponse null;try {httpResponse client.doAction(imageSyncScanRequest);} catch (Exception e) {e.printStackTrace();} ​// 服务端接收到请求完成处理后返回的结果。if (httpResponse ! null httpResponse.isSuccess()) {JSONObject scrResponse JSON.parseObject(org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));System.out.println(JSON.toJSONString(scrResponse, true));int requestCode scrResponse.getIntValue(code);// 每一张图片的检测结果。JSONArray taskResults scrResponse.getJSONArray(data);if (200 requestCode) {for (Object taskResult : taskResults) {// 单张图片的处理结果。int taskCode ((JSONObject) taskResult).getIntValue(code);// 图片对应检测场景的处理结果。如果是多个场景则会有每个场景的结果。JSONArray sceneResults ((JSONObject) taskResult).getJSONArray(results);if (200 taskCode) {for (Object sceneResult : sceneResults) {String scene ((JSONObject) sceneResult).getString(scene);String suggestion ((JSONObject) sceneResult).getString(suggestion);// 根据scene和suggestion做相关处理。// 根据不同的suggestion结果做业务上的不同处理。例如将违规数据删除等。System.out.println(scene [ scene ]);System.out.println(suggestion [ suggestion ]);}} else {// 单张图片处理失败, 原因视具体的情况详细分析。System.out.println(task process fail. task response: JSON.toJSONString(taskResult));}}} else {/** 表明请求整体处理失败原因视具体的情况详细分析。/System.out.println(the whole image scan request failed. response: JSON.toJSONString(scrResponse));}}} ​ } 测试 测试结果ak47.jpg涉及兵器审核不通过itheima.jpg审核通过如果文章中有任何一张图片审核不通过则文章审核就不通过。 image1测试结果不通过 3 阿里云安全集成到项目 3.1依赖引入 创建 heima-aliyunsecurity-spring-boot-starter 模块引入阿里云sdk依赖 dependenciesdependencygroupIdcom.aliyun/groupIdartifactIdaliyun-java-sdk-core/artifactId/dependencydependencygroupIdcom.aliyun/groupIdartifactIdaliyun-java-sdk-green/artifactId/dependency!–OSS–dependencygroupIdcom.aliyun.oss/groupIdartifactIdaliyun-sdk-oss/artifactIdversion3.10.2/version/dependencydependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-autoconfigure/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency /dependencies 3.2引入图片上传工具类 从之前测试阿里云服务的工程拷贝到heima-aliyunsecurity-spring-boot-starter中结构如下 引入 资料文件夹下文本内容审核和图片审核 对应的工具类 3.3新建配置文件 在resources中新建aliyun.properties aliyun.accessKeyIdLTAI5tEFSvKvjn8WX2jA5FAc aliyun.secretQQB92dKoCByJDMd4dpOGKdEvcmeYw9 #aliyun.scenesporn,terrorism,ad,qrcode,live,logo aliyun.scenesporn 参数说明scenes当前的这个场景设置只有在图片审核的时候会用到可以根据实际情况自由组合 porn图片智能鉴黄 terrorism图片暴恐涉政 ad图文违规 qrcode图片二维码 live图片不良场景 logo图片logo 创建 META-INF/spring.factories 文件 org.springframework.boot.autoconfigure.EnableAutoConfiguration
com.heima.aliyun.config.AliyunConfig 3.4测试 后期需要在admin微服务中使用可以在admin微服中引用 在wemedia-service微服务中添加依赖支持阿里云接口服务 wemedia的pom添加依赖 dependencygroupIdcom.heima/groupIdartifactIdheima-aliyunsecurity-spring-boot-starter/artifactIdversion1.0-SNAPSHOT/version/dependency ​ 创建测试类 分别测试文本垃圾检测接口和图片审核接口 SpringBootTest RunWith(SpringRunner.class) public class AliyunTest {Autowiredprivate GreenTextScan greenTextScan;Autowiredprivate GreenImageScan greenImageScan;Testpublic void testText() throws Exception{Map map greenTextScan.greenTextScan(我是一个文本,冰毒买卖是违法的);System.out.println(map);}Testpublic void testImage() throws Exception {ListString images new ArrayList();images.add(https://heimaleadnewsoss.oss-cn-shanghai.aliyuncs.com/material/2021/1/20210112/205cd5d3346a48b59352c92808709da1.jpg);Map map greenImageScan.imageUrlScan(images);System.out.println(map);} } 4 敏感词过滤算法DFA 1文章审核需求 文章审核功能已经交付了文章也能正常发布审核。突然产品经理过来说要开会。 会议的内容核心有以下内容 文章审核不能过滤一些敏感词 私人侦探、针孔摄象、信用卡提现、广告代理、代开发票、刻章办、出售答案、小额贷款… 需要完成的功能 需要自己维护一套敏感词在文章审核的时候需要验证文章是否包含这些敏感词 2敏感词-过滤 技术选型 方案说明数据库模糊查询效率太低String.indexOf()查找数据库量大的话也是比较慢全文检索分词再匹配DFA算法确定有穷自动机(一种数据结构) 4.1DFA实现原理 DFA全称为Deterministic Finite Automaton,即确定有穷自动机。 存储一次性的把所有的敏感词存储到了多个map中就是下图表示这种结构 敏感词冰毒、大麻、大坏蛋 4.2代码实现 工具类 package com.heima.utils.common; import java.util.
; public class SensitiveWordUtil {public static MapString, Object dictionaryMap new HashMap();/*** 生成关键词字典库* param words* return/public static void initMap(CollectionString words) {if (words null) {System.out.println(敏感词列表不能为空);return ;}// map初始长度words.size()整个字典库的入口字数(小于words.size()因为不同的词可能会有相同的首字)MapString, Object map new HashMap(words.size());// 遍历过程中当前层次的数据MapString, Object curMap null;IteratorString iterator words.iterator(); ​while (iterator.hasNext()) {String word iterator.next();curMap map;int len word.length();for (int i 0; i len; i) {// 遍历每个词的字String key String.valueOf(word.charAt(i));// 当前字在当前层是否存在, 不存在则新建, 当前层数据指向下一个节点, 继续判断是否存在数据MapString, Object wordMap (MapString, Object) curMap.get(key);if (wordMap null) {// 每个节点存在两个数据: 下一个节点和isEnd(是否结束标志)wordMap new HashMap(2);wordMap.put(isEnd, 0);curMap.put(key, wordMap);}curMap wordMap;// 如果当前字是词的最后一个字则将isEnd标志置1if (i len -1) {curMap.put(isEnd, 1);}}} ​dictionaryMap map;} ​/** 搜索文本中某个文字是否匹配关键词* param text* param beginIndex* return/private static int checkWord(String text, int beginIndex) {if (dictionaryMap null) {throw new RuntimeException(字典不能为空);}boolean isEnd false;int wordLength 0;MapString, Object curMap dictionaryMap;int len text.length();// 从文本的第beginIndex开始匹配for (int i beginIndex; i len; i) {String key String.valueOf(text.charAt(i));// 获取当前key的下一个节点curMap (MapString, Object) curMap.get(key);if (curMap null) {break;} else {wordLength ;if (1.equals(curMap.get(isEnd))) {isEnd true;}}}if (!isEnd) {wordLength 0;}return wordLength;} ​/** 获取匹配的关键词和命中次数* param text* return/public static MapString, Integer matchWords(String text) {MapString, Integer wordMap new HashMap();int len text.length();for (int i 0; i len; i) {int wordLength checkWord(text, i);if (wordLength 0) {String word text.substring(i, i wordLength);// 添加关键词匹配次数if (wordMap.containsKey(word)) {wordMap.put(word, wordMap.get(word) 1);} else {wordMap.put(word, 1);}i wordLength - 1;}}return wordMap;} } 新建测试类 package com.heima.admin; import com.heima.utils.common.SensitiveWordUtil; import java.util.ArrayList; import java.util.List; import java.util.Map; public class SensitiveWordUtilTest {public static void main(String[] args) {// 初始化 敏感词 列表ListString list new ArrayList();list.add(冰毒);list.add(特朗普);SensitiveWordUtil.initMap(list);// 待查询文本String content我是一个好人买卖冰毒是违法的特朗普;// 匹配文本MapString, Integer map SensitiveWordUtil.matchWords(content);System.out.println(map);} } 5 自媒体文章审核 5.1表结构说明 wm_news 自媒体文章表 status字段0 草稿 1 待审核 2 审核失败 3 人工审核 4 人工审核通过 8 审核通过待发布 9 已发布 5.2准备远程调用接口 审核时需要进行自管理的DFA敏感词审核而敏感词信息是在admin微服务中维护需要使用feign进行调用 admin-service 中 AdSensitiveMapper 新增方法 public interface AdSensitiveMapper extends BaseMapperAdSensitive {Select(select sensitives from ad_sensitive)ListString findAllSensitives(); } admin-serivice 中 AdSensitiveService 新增方法 /** 查询敏感词内容列表* return/public ResponseResultListString selectAllSensitives(); admin-serivice 中 AdSensitiveServiceImpl 实现方法 Overridepublic ResponseResult selectAllSensitives() {return ResponseResult.okResult(adSensitiveMapper.findAllSensitives());} admin-service 中 AdSensitiveController新增方法 ApiOperation(value 查询敏感词内容list)PostMapping(/sensitives)public ResponseResult sensitives() {return sensitiveService.selectAllSensitives();} heima-leadnews-feign 服务中新增feign接口AdminFeign package com.heima.feigns; import com.heima.config.HeimaFeignAutoConfiguration; import com.heima.feigns.fallback.AdminFeignFallback; import com.heima.model.common.dtos.ResponseResult; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import java.util.List; FeignClient(value leadnews-admin,fallbackFactory AdminFeignFallback.class,configuration HeimaFeignAutoConfiguration.class ) public interface AdminFeign {// 查询敏感词内容列表PostMapping(/api/v1/sensitive/sensitives)public ResponseResultListString sensitives(); } heima-leadnews-feign 服务中新增AdminFeign服务降级实现类AdminFeignFallback package com.heima.feigns.fallback; import com.heima.feigns.AdminFeign; import com.heima.model.common.dtos.ResponseResult; import com.heima.model.common.enums.AppHttpCodeEnum; import feign.hystrix.FallbackFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.List; Slf4j Component public class AdminFeignFallback implements FallbackFactoryAdminFeign {Overridepublic AdminFeign create(Throwable throwable) {throwable.printStackTrace();return new AdminFeign() {Overridepublic ResponseResultListString sensitives() {log.error(AdminFeign sensitives 远程调用出错啦 ~~~ !!!! {} ,throwable.getMessage());return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);}};} } 5.3审核接口实现 在wemedia-service 中的service新增接口 package com.heima.wemedia.service; public interface WmNewsAutoScanService {/** 自媒体文章审核* param id 自媒体文章id/public void autoScanWmNews(Integer id); } 实现类 package com.heima.wemedia.service.impl; ​ import com.alibaba.fastjson.JSONArray; import com.heima.aliyun.GreenImageScan; import com.heima.aliyun.GreenTextScan; import com.heima.common.exception.CustException; import com.heima.feigns.AdminFeign; import com.heima.model.common.dtos.ResponseResult; import com.heima.model.common.enums.AppHttpCodeEnum; import com.heima.model.wemedia.pojos.WmNews; import com.heima.utils.common.SensitiveWordUtil; import com.heima.wemedia.mapper.WmNewsMapper; import com.heima.wemedia.service.WmNewsAutoScanService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.; import java.util.stream.Collectors; Service Slf4j public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {Autowiredprivate WmNewsMapper wmNewsMapper;Value(\({file.oss.web-site})String webSite;/*** 自动审核方法* param wmNewsId*/Overridepublic void autoScanWmNews(Integer wmNewsId) {log.info( 自动审核发布方法 被调用   当前审核发布的文章id {},wmNewsId);//1. 根据文章id 远程调用feign查询文章if (wmNewsId null) {log.error(自动审核文章失败   文章id为空);CustException.cust(AppHttpCodeEnum.PARAM_INVALID);}WmNews wmNews wmNewsMapper.selectById(wmNewsId);if (wmNewsnull) {log.error(自动审核文章失败   未查询自媒体文章信息 wmNewsId:{},wmNewsId);CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);}// 2. 判断文章状态是否为待审核状态Short status wmNews.getStatus();if(status.shortValue() WmNews.Status.SUBMIT.getCode()){// 抽取出文章中 所有的文本内容 和 所有的图片url集合   MapString,Object content 内容   images ListStringMapString,Object contentAndImageResult handleTextAndImages(wmNews);// 3.1 敏感词审核   失败   修改文章状态(2)boolean isSensivice handleSensitive((String)contentAndImageResult.get(content),wmNews);if(!isSensivice) return;log.info( 自管理敏感词审核通过   ); ​// 3.2 阿里云的文本审核   失败 状态2 不确定 状态3boolean isTextScan handleTextScan((String)contentAndImageResult.get(content),wmNews);if(!isTextScan) return;log.info( 阿里云内容审核通过   ); ​ ​// 3.3 阿里云的图片审核   失败 状态2 不确定 状态3Object images contentAndImageResult.get(images);if(images!null){boolean isImageScan handleImageScan((ListString)images,wmNews);if(!isImageScan) return;log.info( 阿里云图片审核通过   );}// 4. 判断文章发布时间是否大于当前时间   状态 8updateWmNews(wmNews,WmNews.Status.SUCCESS.getCode(),审核成功); ​//TODO 5. 通知定时发布文章}}AutowiredGreenImageScan greenImageScan;/*** 阿里云图片审核* param images 待审核的图片列表* return*/private boolean handleImageScan(ListString images,WmNews wmNews) {boolean flag true;try {Map map greenImageScan.imageUrlScan(images);String suggestion (String)map.get(suggestion);switch (suggestion){case block:updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),图片中有违规内容审核失败);flag false;break;case review:updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),图片中有不确定内容转为人工审核);flag false;break;}} catch (Exception e) {e.printStackTrace();log.error(阿里云图片审核出现异常 , 原因:{},e.getMessage());updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),阿里云内容服务异常转为人工审核);flag false;}return flag;}AutowiredGreenTextScan greenTextScan;/*** 阿里云文本* param content   block: 状态2   review: 状态3   异常: 状态3* param wmNews* return*/private boolean handleTextScan(String content, WmNews wmNews) {boolean flag true;try {Map map greenTextScan.greenTextScan(content);String suggestion (String)map.get(suggestion);switch (suggestion){case block:updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),文本中有违规内容审核失败);flag false;break;case review:updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),文本中有不确定内容转为人工审核);flag false;break;}} catch (Exception e) {e.printStackTrace();log.error(阿里云文本审核出现异常 , 原因:{},e.getMessage());updateWmNews(wmNews,WmNews.Status.ADMIN_AUTH.getCode(),阿里云内容服务异常转为人工审核);flag false;}return flag;} ​AutowiredAdminFeign adminFeign;/*** 基于DFA 检测内容是否包含敏感词* param content* param wmNews* return*/private boolean handleSensitive(String content, WmNews wmNews) {boolean flag true;// 1. 查询出数据库中的敏感词ResponseResultListString allSensitivesResult adminFeign.sensitives();if(allSensitivesResult.getCode().intValue()!0){CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,allSensitivesResult.getErrorMessage());}ListString allSensitives allSensitivesResult.getData();// 2. 将敏感词集合转发DFA数据模型SensitiveWordUtil.initMap(allSensitives);// 3. 检测敏感词MapString, Integer resultMap SensitiveWordUtil.matchWords(content);if(resultMap!null resultMap.size() 0){// 将文章状态改为2updateWmNews(wmNews,WmNews.Status.FAIL.getCode(),内容中包含敏感词: resultMap);flag false;}return flag;} ​/*** 修改文章状态* param wmNews* param status* param reason*/private void updateWmNews(WmNews wmNews, short status, String reason) {wmNews.setStatus(status);wmNews.setReason(reason);wmNewsMapper.updateById(wmNews);}/*** 抽取 文章中所有 文本内容 及 所有图片路径* param wmNews content type:text     title* return*/private MapString, Object handleTextAndImages(WmNews wmNews) {String contentJson wmNews.getContent(); // [{},{},{}]if (StringUtils.isBlank(contentJson)) {log.error(自动审核文章失败   文章内容为空);CustException.cust(AppHttpCodeEnum.PARAM_INVALID,文章内容为空);}ListMap contentMaps JSONArray.parseArray(contentJson, Map.class);// 1. 抽取文章中所有文本     家乡很美   _hmtt_   国家伟大String content contentMaps.stream().filter(map - text.equals(map.get(type))).map(map - (String) map.get(value)).collect(Collectors.joining(_hmtt_));content content _hmtt_ wmNews.getTitle(); ​// 2. 抽取文章中所有图片   content : 全路径       images : 文件名称 访问前缀ListString imageList contentMaps.stream().filter(map - image.equals(map.get(type))).map(map - (String) map.get(value)).collect(Collectors.toList());if (StringUtils.isNotBlank(wmNews.getImages())) {// 按照 逗号 切割封面字符串 得到数组   基于数组得到stream   将每一条数据都拼接一个前缀 收集成集合ListString urls Arrays.stream(wmNews.getImages().split(,)).map(url - webSite url).collect(Collectors.toList());imageList.addAll(urls);}// 3. 去重imageList imageList.stream().distinct().collect(Collectors.toList()); ​Map result new HashMap();result.put(content,content);result.put(images,imageList);return result;} } ​ 6 集成RabbitMQ实现自动审核 6.1 同步调用与异步调用 同步就是在发出一个调用时在没有得到结果之前 该调用就不返回实时处理 异步调用在发出之后这个调用就直接返回了没有返回结果分时处理 对于发表文章 及 自动审核这是属于两个不同业务功能, 如果放到一起写耦合严重。 需要采用异步的方式当发表文章完成后向消息队列发送一条消息 而自动审核会监听指定的队列 完成文章的审核操作 6.3集成RabbitMQ wemedia-service引入mq依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-amqp/artifactId/dependency nacos配置中心添加共享配置share-rabbit.yml spring:rabbitmq:host: \){spring.profiles.ip}port: 5672username: itcastpassword: 123321publisher-confirm-type: correlated  # 开启确认机制回调 必须配置这个才会确认回调publisher-returns: true # 开启return机制回调listener:simple:# acknowledge-mode: manual #手动确认acknowledge-mode: auto #自动确认   manual #手动确认# 重试策略相关配置retry:enabled: true # 是否开启重试功能max-attempts: 5 # 最大重试次数# 时间策略乘数因子   0 1 2 4 8multiplier: 2.0initial-interval: 1000ms # 第一次调用后的等待时间max-interval: 20000ms # 最大等待的时间值 添加共享配置 spring:application:name: leadnews-wemedia # 服务名称profiles:active: dev # 开发环境配置ip: 192.168.200.130  # 环境ip地址cloud:nacos:server-addr: \({spring.profiles.ip}:8848discovery: # 注册中心地址配置namespace: \){spring.profiles.active}config: # 配置中心地址配置namespace: \({spring.profiles.active}file-extension: yml # data-id 后缀name: \){spring.application.name} # data-id名称shared-configs: # 共享配置- data-id: share-feign.yml # 配置文件名-Data Idgroup: DEFAULT_GROUP   # 默认为DEFAULT_GROUPrefresh: false   # 是否动态刷新默认为false- data-id: share-seata.yml # 配置文件名-Data Idgroup: DEFAULT_GROUP   # 默认为DEFAULT_GROUPrefresh: false   # 是否动态刷新默认为fals- data-id: share-file.yml # 配置文件名-Data Idgroup: DEFAULT_GROUP   # 默认为DEFAULT_GROUPrefresh: false   # 是否动态刷新默认为fals- data-id: share-rabbit.yml # 配置文件名-Data Idgroup: DEFAULT_GROUP   # 默认为DEFAULT_GROUPrefresh: false   # 是否动态刷新默认为falsservlet:multipart:max-file-size: 5MB mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl wemedia-service创建com.heima.wemedia.config.RabbitConfig配置类 package com.heima.wemedia.config; ​ import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.connection.CorrelationData; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; /*** InitializingBean: springbean生命周期接口 代表完成bean装配后 执行的初始化方法* 这个类的目的*     设置rabbitmq消息序列化机制 默认jdk效率差*     设置rabbitmq消息发送确认 回调*     设置rabbitmq消息返还 回调/ Component Slf4j public class RabbitConfig implements InitializingBean {AutowiredRabbitTemplate rabbitTemplate;Overridepublic void afterPropertiesSet() {log.info(初始化rabbitMQ配置 );// 设置消息转换器rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());// 设置发送确认 回调方法rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {/** param correlationData 对比数据* param ack 是否成功发送到mq exchange* param cause 原因/Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {if (!ack){// TODO 可扩展自动重试 ​log.error(发送消息到mq失败 原因: {},cause);}}});// 设置消息返还 回调方法rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {/** param message 消息内容* param replyCode 回复状态* param replyText 回复文本提示* param exchange   交换机* param routingKey   路由/Overridepublic void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {// TODO 可扩展自动重试 ​log.error(消息返还回调触发 交换机: {} , 路由: {} , 消息内容: {} , 原因: {} ,exchange,routingKey,message,replyText);}});} } heima-leadnews-common中定义常量类NewsAutoScanConstants 可以将所有消息队列常量存入com.heima.common.constants.message包中 public class NewsAutoScanConstants {public static final String WM_NEWS_AUTO_SCAN_QUEUEwm.news.auto.scan.queue; } 6.4发送及消费消息 发送消息 wemedia-service 服务 WmNewsServiceImpl.submitNews /** 自媒体文章发布* param dto* return/Overridepublic ResponseResult submitNews(WmNewsDTO dto) {// 1 参数校验……略…..// 2 保存或修改文章……略…..// 3.3 保存关联关系……略…..// 3.4 发送待审核消息rabbitTemplate.convertAndSend(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE,wmNews.getId());log.info(成功发送 待审核消息 队列:{}, 文章id:{},NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC,wmNews.getId());}return ResponseResult.okResult();} 消费消息 package com.heima.wemedia.listen; import com.heima.common.constants.message.NewsAutoScanConstants; import com.heima.wemedia.service.WmNewsAutoScanService; import com.heima.wemedia.service.WmNewsService; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.IOException; Component Slf4j public class WemediaNewsAutoListener {AutowiredWmNewsAutoScanService wmNewsAutoScanService;AutowiredWmNewsService wmNewsService;/** queues: 监听指定队列* queuesToDeclare: 声明并监听指定队列* bindings: 声明队列 交换机 并通过路由绑定*/RabbitListener(queuesToDeclare {Queue(name NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_QUEUE)})public void newsAutoScanHandler(String newsId){log.info(接收到 自动审核 消息 {},newsId);// 自动审核wmNewsAutoScanService.autoScanWmNews(Integer.valueOf(newsId));} } 6.5文章自动审核功能-综合测试 服务启动列表 wemedia微服务 admin微服务 wemedia网关微服务 启动前端系统wemedia 测试动作在自媒体前端进行发布文章 结果 查看控制台日志是否触发自动审核审核的具体结果