【黑马头条】-day04自媒体文章审核-阿里云接口-敏感词分析DFA-图像识别OCR-异步调用MQ

news/2024/4/29 22:39:17/文章来源:https://blog.csdn.net/qq_45400167/article/details/137120788

文章目录

  • day4学习内容
  • 自媒体文章自动审核
    • 今日内容
  • 1 自媒体文章自动审核
    • 1.1 审核流程
    • 1.2 内容安全第三方接口
    • 1.3 引入阿里云内容安全接口
      • 1.3.1 添加依赖
      • 1.3.2 导入aliyun模块
      • 1.3.3 注入Bean测试
  • 2 app端文章保存接口
    • 2.1 表结构说明
    • 2.2 分布式id
      • 2.2.1 分布式id-技术选型
      • 2.2.2 雪花算法
      • 2.2.3 配置雪花算法
    • 2.3 保存app端文章-思路分析
    • 2.4 实现接口
      • 2.4.1 实现步骤
      • 2.4.2 定义feign接口
        • 2.4.2.1 导入feign远程调用依赖
        • 2.4.2.2 定义文章端远程接口
        • 2.4.2.3 导入ArticleDto
      • 2.4.3 实现feign接口
      • 2.4.4 创建mapper
      • 2.4.5 为AparticleConfig设置默认参数
      • 2.4.6 在ApArticleService的实现类ApArticleServiceImpl中实现方法
      • 2.4.7 启动ArticleApplication
  • 3 自媒体文章审核实现
    • 3.1 创建审核接口
    • 3.2 实现审核接口
    • 3.3 启动类扫描feign
    • 3.4 测试
  • 4 自媒体调用文章微服务feign远程调用服务降级
    • 4.1 feign远程调用服务降级处理的逻辑
    • 4.2 编写降级逻辑
    • 4.3 指定IArticleClient接口指向Feign降级逻辑
    • 4.4 加载feign降级逻辑
    • 4.5 配置降级策略
    • 4.6 测试
  • 5 文章审核异步调用
    • 5.1 在自动审核的方法加上@Async注解
    • 5.2 在文章发布后调用自动审核方法
    • 5.3 在启动类中添加注解开启异步调用
    • 5.4 综合测试
    • 5.5 使用rabbit MQ来完成异步调用
      • 5.5.1 引入依赖
      • 5.5.2 为微服务配置MQ
      • 5.5.3 改造方法,创建监听队列
      • 5.5.4 序列化MQ消息
      • 5.5.5 加上mq后的综合测试
  • 6 自管理敏感词过滤
    • 6.1 DFA实现原理
    • 6.2 DFA检索过程
    • 6.3 实现步骤
      • 6.3.1 创建敏感词表
      • 6.3.2 将wm_sensitive对应的实体类和mapper导入
      • 6.3.3 在阿里云接口前自行进行审查
      • 6.3.4 测试
  • 7 图片文字敏感词过滤
    • 7.1 文字图片识别
    • 7.2 Tesseract-OCR
    • 7.3 Tess4j案例
      • 7.3.1 导入依赖
      • 7.3.2 将训练好的分类器放入资源中
      • 7.3.3 demo
      • 7.3.4 结果
    • 7.4 图片文字敏感词过滤实现
      • 7.4.1 创建工具类
      • 7.4.2 工具类被其他微服务使用
      • 7.4.3 在微服务中配置
      • 7.4.4 添加实现
  • 8 静态文件生成
    • 8.1 实现思路
      • 8.1.1 生成minio接口和实现,并且异步调用
      • 8.1.2 修改saveArticle逻辑
      • 8.1.3 开启异步调用
      • 8.1.4 测试


day4学习内容

自媒体文章自动审核

在这里插入图片描述

今日内容

在这里插入图片描述

1 自媒体文章自动审核

1.1 审核流程

在这里插入图片描述

在这里插入图片描述

1.2 内容安全第三方接口

在这里插入图片描述

在这里插入图片描述

1.3 引入阿里云内容安全接口

在这里插入图片描述

1.3.1 添加依赖

在heima-leadnews-common包下引入依赖

<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-core</artifactId><version>4.1.1</version>
</dependency>
<dependency><groupId>com.aliyun</groupId><artifactId>aliyun-java-sdk-green</artifactId><version>3.6.6</version>
</dependency>
<dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.9</version>
</dependency>
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>2.8.3</version>
</dependency>

1.3.2 导入aliyun模块

放入heima-leadnews-common模块下的com.heima.common

哪个微服务使用,就在哪个微服务的nacos中配置

在heima-leadnews-wemedia中的nacos配置中心添加以下配置:

aliyun:accessKeyId: LTAI5tCWHCcfvqQzu8k2oKmXsecret: auoKUFsghimbfVQHpy7gtRyBkoR4vc
#aliyun.scenes=porn,terrorism,ad,qrcode,live,logoscenes: terrorism

1.3.3 注入Bean测试

在resource中META-INF的spring-factories中自动配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.heima.common.exception.ExceptionCatch,\com.heima.common.aliyun.GreenTextScan,\com.heima.common.aliyun.GreenImageScan

在测试类中进行测试

@SpringBootTest(classes = WemediaApplication.class)
@RunWith(SpringRunner.class)
public class AliyunTest {@Autowiredprivate GreenTextScan greenTextScan;@Autowiredprivate GreenImageScan greenImageScan;@Autowiredprivate FileStorageService fileStorageService;@Testpublic void testScanText() throws Exception {Map map = greenTextScan.greeTextScan("我是一个好人,冰毒");System.out.println(map);}@Testpublic void testScanImage() throws Exception {byte[] bytes = fileStorageService.downLoadFile("http://192.168.200.130:9000/leadnews/2021/04/26/ef3cbe458db249f7bd6fb4339e593e55.jpg");Map map = greenImageScan.imageScan(Arrays.asList(bytes));System.out.println(map);}
}

2 app端文章保存接口

2.1 表结构说明

在这里插入图片描述

2.2 分布式id

在这里插入图片描述

2.2.1 分布式id-技术选型

在这里插入图片描述

2.2.2 雪花算法

在这里插入图片描述

2.2.3 配置雪花算法

第一:在实体类中的id上加入如下配置,指定类型为id_worker

@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;

第二:在application.yml文件中配置数据中心id和机器id

在文章的微服务的nacos配置中leadnews-article中添加

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/leadnews_article?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=falseusername: rootpassword: 123sjbsjb# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径,通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.article.pojos#雪花算法global-config:datacenter-id: 1workerId: 1
minio:accessKey: miniosecretKey: minio123bucket: leadnewsendpoint: http://192.168.204.129:9000readPath: http://192.168.204.129:9000

在这里插入图片描述

2.3 保存app端文章-思路分析

在这里插入图片描述

2.4 实现接口

在这里插入图片描述

2.4.1 实现步骤

在这里插入图片描述

2.4.2 定义feign接口

2.4.2.1 导入feign远程调用依赖

在heima-leadnews-feign-api的pom.xml中导入依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.4.2.2 定义文章端远程接口

heima-leadnews-feign-api定义com.heima.apis.article.IArticleClient接口

@FeignClient(value = "leadnews-article")

@FeignClient指定文章远程调用接口名称

@FeignClient(value = "leadnews-article")
public interface IArticleClient {@PostMapping("/api/v1/article/save")public ResponseResult saveArticle(@RequestBody ArticleDto dto) ;
}
2.4.2.3 导入ArticleDto

在heima-leadnews-model模块下com.heima.model.article.dto中导入ArticleDto类

@Data
public class ArticleDto  extends ApArticle {/*** 文章内容*/private String content;
}

2.4.3 实现feign接口

在heima-leadnews-service模块下的heima-leadnews-article模块下创建com.heima.article.feign.ArticleClient类

@RestController
public class ArticleClient implements IArticleClient {@Autowiredprivate ApArticleService apArticleService;@PostMapping("/api/v1/article/save")@Overridepublic ResponseResult saveArticle(@RequestBody ArticleDto dto) {return apArticleService.saveArticle(dto);}
}

2.4.4 创建mapper

在heima-leadnews-service模块下的heima-leadnews-article模块下创建com.heima.article.mapper.ApArticleConfigMapper接口

@Mapper
public interface ApArticleConfigMapper extends BaseMapper<ApArticleConfig> {
}

2.4.5 为AparticleConfig设置默认参数

添加@NoArgsConstructor

public ApArticleConfig(Long articleId) {this.articleId = articleId;this.isDelete = false;this.isDown = false;this.isForward = true;this.isComment = true;
}

添加有参构造

2.4.6 在ApArticleService的实现类ApArticleServiceImpl中实现方法

ApArticleService接口

public interface ApArticleService extends IService<ApArticle>{/*** 加载文章列表* @param dto* @param type 1 加载更多 2 加载最新* @return*/public ResponseResult load(ArticleHomeDto dto, Short type);/*** 保存文章* @param dto* @return*/public ResponseResult saveArticle(ArticleHomeDto dto);
}

实现类,实现saveArticle方法

@Autowired
private ApArticleConfigMapper apArticleConfigMapper;
@Autowired
private ApArticleContentMapper apArticleContentMapper;
/*** 保存文章* @param dto* @return*/
@Override
public ResponseResult saveArticle(ArticleDto dto) {//1.参数检查if(dto == null){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}ApArticle apArticle = new ApArticle();//org.springframework.beansBeanUtils.copyProperties(dto, apArticle);//2.判断是否存在idif(dto.getId() == null) {//2.1 不存在id ,新增 文章、内容、配置save(apArticle);//2.1.2 保存文章配置ApArticleConfig apArticleConfig = new ApArticleConfig(apArticle.getId());apArticleConfigMapper.insert(apArticleConfig);//2.1.3 保存文章内容ApArticleContent apArticleContent = new ApArticleContent();apArticleContent.setArticleId(apArticle.getId());apArticleContent.setContent(dto.getContent());apArticleContentMapper.insert(apArticleContent);}else {//2.2 存在id,更新 文章、内容//2.2.1 更新文章updateById(apArticle);//2.2.2 更新文章内容ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, dto.getId()));apArticleContent.setContent(dto.getContent());apArticleContentMapper.updateById(apArticleContent);}//3.返回结果 文章的idreturn ResponseResult.okResult(apArticle.getId());
}

2.4.7 启动ArticleApplication

在这里插入图片描述

在这里插入图片描述

刚刚是新增,如果是修改。

就会在json中传入id

在这里插入图片描述

在这里插入图片描述

成功修改

3 自媒体文章审核实现

3.1 创建审核接口

在heima-leadnews-service中heima-leadnews-wemedia中的service新增WmNewAutoScanService接口

public interface WmNewAutoScanService {/*** 自动审核媒体文章*/public void  autoScanMediaNews(Integer id);
}

3.2 实现审核接口

@Service
@Slf4j
@Transactional
public class WmNewAutoScanServiceImpl implements WmNewAutoScanService {@Autowiredprivate WmNewsMapper wmNewsMapper;@Qualifier("com.heima.apis.article.IArticleClient")@Autowiredprivate IArticleClient iArticleClient;@Autowiredprivate WmChannelMapper wmChannelMapper;@Autowiredprivate WmUserMapper wmUserMapper;@Overridepublic void autoScanMediaNews(Integer id) {//1.查询自媒体文章WmNews wmNews = wmNewsMapper.selectById(id);if (wmNews == null) {throw new RuntimeException("自媒体文章不存在");}if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){Map<String,List<String>> scanMaterialsList = extractImageAndContent(wmNews);//2.调用阿里云接口审核文本内容List<String> contentTexts =scanMaterialsList.get("contentTexts");boolean isTextScan =true;if(!isTextScan)return;//3.调用阿里云接口审核图片内容List<String> imagesUrls =scanMaterialsList.get("imagesUrls");boolean isImageScan =true;if(!isImageScan)return;if(isTextScan && isImageScan) {//审核通过wmNews.setStatus((short) 9);wmNews.setReason("审核通过");}}//4.审核成功保存app端的相关文章数据ArticleDto dto=new ArticleDto();BeanUtils.copyProperties(wmNews,dto);//布局dto.setLayout(wmNews.getType());//频道dto.setChannelId(wmNews.getChannelId());//频道名称WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());if(wmChannel!=null){dto.setChannelName(wmChannel.getName());}//作者dto.setAuthorId(Long.valueOf(wmNews.getUserId()));//作者名称WmUser wmUser= wmUserMapper.selectById(wmNews.getUserId());if(wmUser!=null){dto.setAuthorName(wmUser.getName());}//设置文章idif(wmNews.getArticleId()!=null){dto.setId(wmNews.getArticleId());}dto.setCreatedTime(new Date());ResponseResult responseResult = iArticleClient.saveArticle(dto);if(responseResult.getCode().equals(200)){//保存成功wmNews.setArticleId((Long)responseResult.getData());wmNewsMapper.updateById(wmNews);}else{//保存失败throw new RuntimeException("保存app端文章失败");}}private Map<String,List<String>> extractImageAndContent(WmNews wmNews) {//提取文章内容String content = wmNews.getContent();List<String> imagesUrls =new ArrayList<>();List<String> contentTexts =new ArrayList<>();Map<String,List<String>> scanMaterialsList =new HashMap<>();List<Map> maps = JSON.parseArray(content, Map.class);//提取文章图片for (Map map : maps) {if(map.get("type").equals("image")){String imgUrl = (String) map.get("value");imagesUrls.add(imgUrl);}if(map.get("type").equals("text")){String text = (String) map.get("value");contentTexts.add(text);}}scanMaterialsList.put("imagesUrls",imagesUrls);scanMaterialsList.put("contentTexts",contentTexts);return scanMaterialsList;}
}

3.3 启动类扫描feign

调用Feign远程接口时,要在启动类中加入@EnableFeignClients(basePackages = “com.heima.apis”)来对feign的api进行扫描,同时也要引入feign-api模块的依赖

<dependency><groupId>com.heima</groupId><artifactId>heima-leadnews-feign-api</artifactId>
</dependency>
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.wemedia.mapper")
@EnableFeignClients(basePackages = "com.heima.apis")
public class WemediaApplication {public static void main(String[] args) {SpringApplication.run(WemediaApplication.class,args);}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

3.4 测试

转到WmNewAutoScanService接口中,ctrl+shift+T创建测试类

在这里插入图片描述

@SpringBootTest(classes = WemediaApplication.class)
@RunWith(SpringRunner.class)
class WmNewAutoScanServiceTest {@Autowiredprivate WmNewAutoScanService wmNewAutoScanService;@Testvoid autoScanMediaNews() {wmNewAutoScanService.autoScanMediaNews(6236);}
}

4 自媒体调用文章微服务feign远程调用服务降级

在这里插入图片描述

4.1 feign远程调用服务降级处理的逻辑

在这里插入图片描述

4.2 编写降级逻辑

在heima-leadnews-feign-api模块下编写降级逻辑com.heima.apis.article.fallback.IArticleClientFallback类,实现IArticleClient接口

@Component
public class IArticleClientFallback implements IArticleClient {@Overridepublic ResponseResult saveArticle(ArticleDto dto) {return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR,"获取数据失败");}
}

4.3 指定IArticleClient接口指向Feign降级逻辑

@FeignClient(value = "leadnews-article",fallback = IArticleClientFallback.class)

@FeignClient(value = "leadnews-article",fallback = IArticleClientFallback.class)
public interface IArticleClient {@PostMapping("/api/v1/article/save")public ResponseResult saveArticle(@RequestBody ArticleDto dto) ;
}

4.4 加载feign降级逻辑

因为IArticleClientFallback是在com.heima.apis.article.fallback包下,并不能被spring通过@Component直接加载

因此需要在使用的微服务中加载feign

如使用的微服务是heima-leadnews-wemedia,所以要在com.heima.wemedia.config下创建InitConfig类加载feign降级策略

@Configuration
@ComponentScan("com.heima.apis.article.fallback")
public class InitConfig {
}

4.5 配置降级策略

要么在bootstrap中开启,要么在nacos中实现热更新

这里采用nacos热更新

feign:# 开启feign对hystrix熔断降级的支持hystrix:enabled: true# 修改调用超时时间client:config:default:connectTimeout: 2000readTimeout: 2000

在这里插入图片描述

4.6 测试

当前设置超时2s进行降级,测试一下

在com.heima.article.service.impl.ApArticleServiceImpl类中的saveArticle方法添加睡眠3秒进行测试

@Override
public ResponseResult saveArticle(ArticleDto dto) {try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}//1.参数检查if(dto == null){

这次审核6239

@SpringBootTest(classes = WemediaApplication.class)
@RunWith(SpringRunner.class)
class WmNewAutoScanServiceTest {@Autowiredprivate WmNewAutoScanService wmNewAutoScanService;@Testvoid autoScanMediaNews() {wmNewAutoScanService.autoScanMediaNews(6239);}
}

在这里插入图片描述

在这里插入图片描述

5 文章审核异步调用

在这里插入图片描述

在这里插入图片描述

5.1 在自动审核的方法加上@Async注解

Springboot集成异步线程调用

@Override
@Async//表明这是一个异步方法
public void autoScanMediaNews(Integer id) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}

5.2 在文章发布后调用自动审核方法

//5.审核文章
wmNewAutoScanService.autoScanMediaNews(wmNews.getId());
@Autowired
private WmNewAutoScanService wmNewAutoScanService;
@Override
public ResponseResult submitNews(WmNewsDto wmNewsDto) {// 0.参数检查if(wmNewsDto == null||wmNewsDto.getContent()==null){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}//1. 保存或修改文章WmNews wmNews = new WmNews();BeanUtils.copyProperties(wmNewsDto,wmNews);//1.1 封面if(wmNewsDto.getImages()!=null&& wmNewsDto.getImages().size()>0){String imageStr = StringUtils.join(wmNewsDto.getImages(), ",");wmNews.setImages(imageStr);}//1.2 如果封面为自动-1,则需要手动设置封面规则if(wmNewsDto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){wmNews.setType(null);}saveOrUpdateWmNews(wmNews);//2.判断是否为草稿,如果为草稿结束当前方法if(wmNews.getStatus().equals(WmNews.Status.NORMAL.getCode())){return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);}//3.不是草稿,保存文章内容与图片素材的关系//3.1 获取文章内容的图片素材List<String> imageList=extractUrlInfo(wmNewsDto.getContent());saveRelativeInfoForContent(imageList,wmNews.getId());//4.不是草稿,保存文章封面图片与图片素材的关系saveRelativeInfoForCover(wmNewsDto,wmNews,imageList);//5.审核文章wmNewAutoScanService.autoScanMediaNews(wmNews.getId());return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}

5.3 在启动类中添加注解开启异步调用

在自媒体引导类中使用@EnableAsync注解开启异步调用

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.wemedia.mapper")
@EnableFeignClients(basePackages = "com.heima.apis")
@EnableAsync//开启异步
public class WemediaApplication {public static void main(String[] args) {SpringApplication.run(WemediaApplication.class,args);}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
}

5.4 综合测试

在这里插入图片描述

5.5 使用rabbit MQ来完成异步调用

我的异步调用只要在启动类中加入@EnableAsync就报错,迫不得已采用rabbitMQ

5.5.1 引入依赖

在heima-leadnews-service中引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>

5.5.2 为微服务配置MQ

在heima-leadnews-article和wemedia的配置文件中添加配置

spring:rabbitmq:host: 192.168.204.129port: 5672virtual-host: /username: itcastpassword: 123321

5.5.3 改造方法,创建监听队列

修改heima-leadnews-wemedia下的com.heima.wemedia.service.impl.WmNewAutoScanServiceImpl类中的autoScanMediaNews方法

@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void autoScanMediaNews(Integer id) {//1.查询自媒体文章WmNews wmNews = wmNewsMapper.selectById(id);if (wmNews == null) {throw new RuntimeException("自媒体文章不存在");}if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){Map<String,List<String>> scanMaterialsList = extractImageAndContent(wmNews);//2.调用阿里云接口审核文本内容List<String> contentTexts =scanMaterialsList.get("contentTexts");boolean isTextScan =true;if(!isTextScan)return;//3.调用阿里云接口审核图片内容List<String> imagesUrls =scanMaterialsList.get("imagesUrls");boolean isImageScan =true;if(!isImageScan)return;if(isTextScan && isImageScan) {//审核通过wmNews.setStatus((short) 9);wmNews.setReason("审核通过");}}//4.审核成功保存app端的相关文章数据ArticleDto dto=new ArticleDto();BeanUtils.copyProperties(wmNews,dto);//布局dto.setLayout(wmNews.getType());//频道dto.setChannelId(wmNews.getChannelId());//频道名称WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());if(wmChannel!=null){dto.setChannelName(wmChannel.getName());}//作者dto.setAuthorId(Long.valueOf(wmNews.getUserId()));//作者名称WmUser wmUser= wmUserMapper.selectById(wmNews.getUserId());if(wmUser!=null){dto.setAuthorName(wmUser.getName());}//设置文章idif(wmNews.getArticleId()!=null){dto.setId(wmNews.getArticleId());}dto.setCreatedTime(new Date());//2.rabbitmq异步处理Map<String,Object> map=new HashMap<>();map.put("dto",dto);map.put("wmNewsId",id);rabbitTemplate.convertAndSend("article.queue", map);/*ResponseResult responseResult = iArticleClient.saveArticle(dto);if(responseResult.getCode().equals(200)){//保存成功wmNews.setArticleId((Long)responseResult.getData());wmNewsMapper.updateById(wmNews);}else{//保存失败log.error("保存app端文章失败,responseResult: {}", responseResult);throw new RuntimeException("保存app端文章失败");}*/
}
rabbitTemplate.convertAndSend("article.queue", map);

发送到article.queue队列

在heima-leadnews-article模块下创建com.heima.article.mq.ArticleMessageConsumer消费者监听类监听article.queue

@Slf4j
@Component
public class ArticleMessageConsumer {@Autowiredprivate IArticleClient iArticleClient;@Autowiredprivate RabbitTemplate rabbitTemplate;@RabbitListener(bindings =@QueueBinding(value=@Queue(name="article.queue"),exchange=@Exchange(name="article.direct",type= ExchangeTypes.FANOUT)))public void processMessage(Map<String,Object> map) {ObjectMapper objectMapper = new ObjectMapper();Object dto = map.get("dto");Integer id= (Integer) map.get("wmNewsId");LinkedHashMap<String, Object> linkedHashMap = (LinkedHashMap<String, Object>) dto;ArticleDto articleDto = objectMapper.convertValue(linkedHashMap, ArticleDto.class);// 异步处理文章数据ResponseResult responseResult = iArticleClient.saveArticle(articleDto);if(responseResult.getCode().equals(200)){WmNews wmNews = new WmNews();BeanUtils.copyProperties(dto, wmNews);wmNews.setArticleId((Long)responseResult.getData());Map<String,Object> params = new HashMap<>();params.put("id", id);params.put("wmNews", wmNews);params.put("articleId",(Long)responseResult.getData());rabbitTemplate.convertAndSend("wmNews.queue", params);log.info("发送params成功,param: {}", params);}else{//保存失败log.error("保存app端文章失败,responseResult: {}", responseResult);throw new RuntimeException("保存app端文章失败");}}
}

ResponseResult responseResult = iArticleClient.saveArticle(articleDto);回填的id发到wmNews.queue

在heima-leadnews-wemedia模块下创建com.heima.wemedia.mq.ReceiveWmNewsId消费者监听类监听wmNews.queue

@Component
@Slf4j
public class ReceiveWmNewsId {@Autowiredprivate WmNewsMapper wmNewsMapper;@RabbitListener(bindings =@QueueBinding(value=@Queue(name="wmNews.queue"),exchange=@Exchange(name="wmNews.direct",type= ExchangeTypes.FANOUT)))public void processMessage(Map<String,Object> map) {ObjectMapper objectMapper = new ObjectMapper();Integer id= (Integer)map.get("id");Object wmNews= map.get("wmNews");Long articleId= (Long)map.get("articleId");LinkedHashMap<String, Object> linkedHashMap = (LinkedHashMap<String, Object>) wmNews;WmNews articleDto = objectMapper.convertValue(linkedHashMap, WmNews.class);WmNews oldwmNews = wmNewsMapper.selectById(id);BeanUtils.copyProperties(wmNews,oldwmNews);oldwmNews.setStatus((short) 9);oldwmNews.setReason("审核通过");oldwmNews.setArticleId(articleId);int i = wmNewsMapper.updateById(oldwmNews);if(i == 0){log.error("更新自媒体文章失败,wmNews: {}", oldwmNews);throw new RuntimeException("更新自媒体文章失败");}}
}

5.5.4 序列化MQ消息

在heima-leadnews-article和wemedia的启动类中添加序列化器

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.wemedia.mapper")
@EnableFeignClients(basePackages = "com.heima.apis")
public class WemediaApplication {public static void main(String[] args) {SpringApplication.run(WemediaApplication.class,args);}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}@Beanpublic MessageConverter messageConverter(){return new Jackson2JsonMessageConverter();}@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(messageConverter);return rabbitTemplate;}
}
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.article.mapper")
public class ArticleApplication {public static void main(String[] args) {SpringApplication.run(ArticleApplication.class,args);}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}@Beanpublic MessageConverter messageConverter(){return new Jackson2JsonMessageConverter();}@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(messageConverter);return rabbitTemplate;}
}

5.5.5 加上mq后的综合测试

在这里插入图片描述

测试通过在MQ上也检测到消息

在这里插入图片描述

6 自管理敏感词过滤

在这里插入图片描述

6.1 DFA实现原理

在这里插入图片描述

6.2 DFA检索过程

在这里插入图片描述

6.3 实现步骤

在这里插入图片描述

6.3.1 创建敏感词表

在leadnews-wemedia数据库中到入wm_sensitive.sql

6.3.2 将wm_sensitive对应的实体类和mapper导入

@Data
@TableName("wm_sensitive")
public class WmSensitive implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 敏感词*/@TableField("sensitives")private String sensitives;/*** 创建时间*/@TableField("created_time")private Date createdTime;
}
@Mapper
public interface WmSensitiveMapper extends BaseMapper<WmSensitive> {
}

6.3.3 在阿里云接口前自行进行审查

boolean isSensitive= handleSensitiveWords(contentTexts,wmNews);

if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){Map<String,List<String>> scanMaterialsList = extractImageAndContent(wmNews);//2.调用阿里云接口审核文本内容List<String> contentTexts =scanMaterialsList.get("contentTexts");//2.1 敏感词过滤boolean isSensitive= handleSensitiveWords(contentTexts,wmNews);boolean isTextScan =true;if(!isTextScan)return;//3.调用阿里云接口审核图片内容List<String> imagesUrls =scanMaterialsList.get("imagesUrls");boolean isImageScan =true;
@Autowired
private WmSensitiveMapper wmSensitiveMapper;
private boolean handleSensitiveWords(List<String> contentTexts, WmNews wmNews) {boolean isSensitive = true;//1.获取所有敏感词List<WmSensitive> wmSensitiveList = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));List<String> collect = wmSensitiveList.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());//2.初始化敏感词库SensitiveWordUtil.initMap(collect);//3.遍历文章内容查看是否包含敏感词for(String contentText:contentTexts){Map<String, Integer> map = SensitiveWordUtil.matchWords(contentText);if(map.size()>0){//4.如果包含敏感词,修改文章状态wmNews.setStatus((short) 2);wmNews.setReason("文章内容包含敏感词");wmNewsMapper.updateById(wmNews);isSensitive = false;break;}}return isSensitive;
}

6.3.4 测试

在这里插入图片描述

7 图片文字敏感词过滤

7.1 文字图片识别

在这里插入图片描述

7.2 Tesseract-OCR

在这里插入图片描述

7.3 Tess4j案例

在这里插入图片描述

7.3.1 导入依赖

在heima-leadnews-test模块下的tess4j-demo的模块下导入依赖

<dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><version>4.1.1</version>
</dependency>

7.3.2 将训练好的分类器放入资源中

在这里插入图片描述

7.3.3 demo

在tess4j-demo的Applcation中

public class Application {/*** 识别图片中的文字* @param args*/public static void main(String[] args) {// 1.创建Tesseract对象Tesseract tesseract = new Tesseract();// 2.设置训练库的位置tesseract.setDatapath("D:\\Code\\JavaCode\\HeimaToutiao\\heima-leadnews\\heima-leadnews-test\\tess4j-demo\\src\\main\\resources\\tessdata");// 3.设置识别语言tesseract.setLanguage("chi_sim");// 4.设置识别图片File file = new File("D:\\Code\\JavaCode\\HeimaToutiao\\heima-leadnews\\heima-leadnews-test\\tess4j-demo\\src\\main\\resources\\testdata\\testImage.png");// 5.识别图片try {String result = tesseract.doOCR(file);System.out.println(result.replace("\\n|\\r", ""));} catch (TesseractException e) {e.printStackTrace();}}
}

7.3.4 结果

在这里插入图片描述

7.4 图片文字敏感词过滤实现

在这里插入图片描述

7.4.1 创建工具类

在heima-leadnews-common中创建com.heima.common.tess4j.Tess4jClient工具类,封装tess4j

@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "tess4j")
public class Tess4jClient {private String dataPath;private String language;public String doOCR(BufferedImage image) throws TesseractException {//创建Tesseract对象ITesseract tesseract = new Tesseract();//设置字体库路径tesseract.setDatapath(dataPath);//中文识别tesseract.setLanguage(language);//执行ocr识别String result = tesseract.doOCR(image);//替换回车和tal键  使结果为一行result = result.replaceAll("\\r|\\n", "-").replaceAll(" ", "");return result;}}

7.4.2 工具类被其他微服务使用

想让工具类被其他微服务使用就要拷贝全路径,在当前的resource中的META-INF的spring.factories中添加配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.heima.common.exception.ExceptionCatch,\com.heima.common.aliyun.GreenTextScan,\com.heima.common.aliyun.GreenImageScan,\com.heima.common.tess4j.Tess4jClient

7.4.3 在微服务中配置

在heima-leadnews-wemedia中的resource的boostrap.yml中进行配置

tess4j:data-path: D:\Code\JavaCode\HeimaToutiao\heima-leadnews\heima-leadnews-test\tess4j-demo\src\main\resources\tessdatalanguage: chi_sim

7.4.4 添加实现

在WmNewsAutoScanServiceImpl中的handleImageScan方法上添加如下代码

try {for (String image : images) {byte[] bytes = fileStorageService.downLoadFile(image);//图片识别文字审核---begin-----//从byte[]转换为butteredImageByteArrayInputStream in = new ByteArrayInputStream(bytes);BufferedImage imageFile = ImageIO.read(in);//识别图片的文字String result = tess4jClient.doOCR(imageFile);//审核是否包含自管理的敏感词boolean isSensitive = handleSensitiveScan(result, wmNews);if(!isSensitive){return isSensitive;}//图片识别文字审核---end-----imageList.add(bytes);} 
}catch (Exception e){e.printStackTrace();
}

8 静态文件生成

在这里插入图片描述

8.1 实现思路

我们在保存/修改文章时就应该同时异步的的生成静态文件,生成静态文件上传到minio中

8.1.1 生成minio接口和实现,并且异步调用

在com.heima.article.service.ArticleFreemarkerService接口

生成静态文件,上传到minio中

public interface ArticleFreemarkerService {/*** 生成静态化页面* @param apArticle* @param content*/public void buildArticleToMinio(ApArticle apArticle,String content);
}
@Service
@Slf4j
@Transactional
public class ArticleFreemarkerServiceImpl implements ArticleFreemarkerService {@Autowiredprivate ApArticleContentMapper apArticleContentMapper;@Autowiredprivate Configuration configuration;@Autowiredprivate FileStorageService fileStorageService;@Autowiredprivate ApArticleService apArticleService;/*** 生成静态化页面* @param apArticle* @param content*/@Async@Overridepublic void buildArticleToMinio(ApArticle apArticle, String content) {if(StringUtils.isNotBlank(content)){//1.文章内容通过freemarker生成静态html页面Template template = null;//2 输出流StringWriter writer = new StringWriter();try {template = configuration.getTemplate("article.ftl");//2.1 创建模型Map<String,Object> contentDataModel=new HashMap();//content是固定的,因为article.ftl中有<#if content??>${content}</#if>//因为apArticleContent.getContent()获取的是字符串,所以需要转换成对象contentDataModel.put("content", JSONArray.parseArray(content));//2.2 合成方法template.process(contentDataModel,writer);} catch (Exception e) {throw new RuntimeException(e);}//3.把静态页面上传到minio//3.1 文件流InputStream inputStream = new ByteArrayInputStream(writer.toString().getBytes());String path = fileStorageService.uploadHtmlFile("",apArticle.getId()+".html",inputStream);//4.把静态页面的路径保存到数据库apArticleService.update(Wrappers.<ApArticle>lambdaUpdate().eq(ApArticle::getId,apArticle.getId()).set(ApArticle::getStaticUrl,path));}}
}

8.1.2 修改saveArticle逻辑

修改com.heima.article.service.impl.ApArticleServiceImpl的saveArticle方法,添加buildArticleToMinio

articleFreemarkerService.buildArticleToMinio(apArticle, dto.getContent());
    @Autowiredprivate ApArticleConfigMapper apArticleConfigMapper;@Autowiredprivate ApArticleContentMapper apArticleContentMapper;@Autowiredprivate ArticleFreemarkerService articleFreemarkerService;/*** 保存文章* @param dto* @return*/@Overridepublic ResponseResult saveArticle(ArticleDto dto) {//1.参数检查if(dto == null){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}ApArticle apArticle = new ApArticle();//org.springframework.beansBeanUtils.copyProperties(dto, apArticle);//2.判断是否存在idif(dto.getId() == null) {//2.1 不存在id ,新增 文章、内容、配置save(apArticle);//2.1.2 保存文章配置ApArticleConfig apArticleConfig = new ApArticleConfig(apArticle.getId());apArticleConfigMapper.insert(apArticleConfig);//2.1.3 保存文章内容ApArticleContent apArticleContent = new ApArticleContent();apArticleContent.setArticleId(apArticle.getId());apArticleContent.setContent(dto.getContent());apArticleContentMapper.insert(apArticleContent);}else {//2.2 存在id,更新 文章、内容//2.2.1 更新文章updateById(apArticle);//2.2.2 更新文章内容ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, dto.getId()));apArticleContent.setContent(dto.getContent());apArticleContentMapper.updateById(apArticleContent);}//异步调用 生成静态文件上传到minio中articleFreemarkerService.buildArticleToMinio(apArticle, dto.getContent());//3.返回结果 文章的idreturn ResponseResult.okResult(apArticle.getId());}
}

8.1.3 开启异步调用

引导类加上@EnableAsyn

@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.article.mapper")
@EnableAsync
public class ArticleApplication {public static void main(String[] args) {SpringApplication.run(ArticleApplication.class,args);}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}@Beanpublic MessageConverter messageConverter(){return new Jackson2JsonMessageConverter();}@Beanpublic RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);rabbitTemplate.setMessageConverter(messageConverter);return rabbitTemplate;}
}

8.1.4 测试

在这里插入图片描述

查看minio有没有生成

在这里插入图片描述

生成成功,查看数据库,有html生成,说明功能成功

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1027647.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【全栈小5】我的创作纪念日

目录 前言机缘收获粉丝和原创个人成就六边形战士 回顾文章原代码代码优化 憧憬 前言 全栈小5 &#xff0c;有幸再次遇见你&#xff1a; 还记得 2019 年 03 月 29 日吗&#xff1f; 你撰写了第 1 篇技术博客&#xff1a; 《前端 - 仿动态效果 - 展开信息图标》 在这平凡的一天&…

Matlab之求直角坐标系下两直线的交点坐标

目的&#xff1a;在直角坐标系下&#xff0c;求两个直线的交点坐标 一、函数的参数说明 输入参数&#xff1a; PointA&#xff1a;直线A上的点坐标&#xff1b; AngleA&#xff1a;直线A的倾斜角&#xff0c;单位度&#xff1b; PointB&#xff1a;直线B上的点坐标&#xf…

Git命令及GUI基本操作

不习惯使用Git命令的可移步下面Git GUI基本操作 Git 常用命令 git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git branch -a 查看所有的分支 git branch -r 查看本地所有分支 git commit -am "init" 提交并且加注释 git remote add orig…

Linux根据时间删除文件或目录

《liunx根据时间删除文件》和 《Linux 根据时间删除文件或者目录》已经讲述了根据时间删除文件或目录的方法。 下面我做一些补充&#xff0c;讲述一个具体例子。以删除/home目录下的文件为例。 首先通过命令&#xff1a; ls -l --time-style"%Y-%m-%d %H:%M:%S"…

上位机图像处理和嵌入式模块部署(qmacvisual几何测量)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 几何测量是图像处理中经常遇到的一个问题&#xff0c;前面我们曾经讨论过点到直线的距离。不仅如此&#xff0c;qmacvisual还提供了另外三个常用的…

RTSP应用:实现视频流的实时推送

在实现实时视频流推送的项目中&#xff0c;RTSP&#xff08;Real Time Streaming Protocol&#xff09;协议扮演着核心角色。本文将指导你通过安装FFmpeg软件&#xff0c;下载并编译live555&#xff0c;以及配置ffmpeg进行视频流推送&#xff0c;来实现一个基本的RTSP流媒体服务…

Spring Boot 防护 XSS + SQL 注入攻击

XSS跨站脚本攻击 ① XSS漏洞介绍 跨站脚本攻击XSS是指攻击者往Web页面里插入恶意Script代码&#xff0c;当用户浏览该页之时&#xff0c;嵌入其中Web里面的Script代码会被解析执行&#xff0c;从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击&#xff01; ② XSS…

iptables添加端口映射,k8s主机查询不到端口但能访问。

研究原因&#xff1a;k8s内一台主机使用命令查询没有80端口。但通过浏览器访问又能访问到服务。 查询了资料是使用了hostport方式暴露pod端口。cni调用iptables增加了DNAT规则。访问时流量先经过iptables直接被NAT到具体服务去了。 链接: K8s罪魁祸首之"HostPort劫持了我…

单例模式如何保证实例的唯一性

前言 什么是单例模式 指一个类只有一个实例&#xff0c;且该类能自行创建这个实例的一种创建型设计模式。使用目的&#xff1a;确保在整个系统中只能出现类的一个实例&#xff0c;即一个类只有一个对象。对于频繁使用的对象&#xff0c;“忽略”创建时的开销。特点&#xff1a…

快速上手Spring Cloud 七:事件驱动架构与Spring Cloud

快速上手Spring Cloud 一&#xff1a;Spring Cloud 简介 快速上手Spring Cloud 二&#xff1a;核心组件解析 快速上手Spring Cloud 三&#xff1a;API网关深入探索与实战应用 快速上手Spring Cloud 四&#xff1a;微服务治理与安全 快速上手Spring Cloud 五&#xff1a;Spring …

基于PaddleNLP的深度学习对文本自动添加标点符号(二)

前言 基于PaddleNLP的深度学习对文本自动添加标点符号的源码版来了&#xff0c;本篇文章主要讲解如何文本自动添加标点符号的原理和相关训练方法&#xff0c;前一篇文章讲解的是使用paddlepaddle已经训练好的一些模型&#xff0c;在一些简单场景下可以通过这些模型进行预测&…

【Unity】调整Player Settings的Resolution设置无效

【背景】 Build时修改了Player Settings下的Resolution设置&#xff0c;但是再次Building时仍然不生效。 【分析】 明显是沿用了之前的分辨率设定&#xff0c;所以盲猜解决办法是Build相关的缓存文件&#xff0c;或者修改打包名称。 【解决】 实测修改版本号无效&#xf…

指针数组的有趣程序【C语言】

文章目录 指针数组的有趣程序指针数组是什么&#xff1f;指针数组的魅力指针数组的应用示例&#xff1a;命令行计算器有趣的颜色打印 结语 指针数组的有趣程序 在C语言的世界里&#xff0c;指针是一种强大的工具&#xff0c;它不仅能够指向变量&#xff0c;还能指向数组&#…

[机缘参悟-162/管理者与领导者-151] :受害者心态与受害者思维模式,如何克服受害者思维模式,管理者如何管理这种思维模式的人?

目录 一、受害者心态概述 1.1 什么是受害者心态 1.2 受害者心态的表现形式 1.3 受害者心态在职场上的表现 1.4 受害者思维模式 1.5 受害者心态的危害 二、受害者心态的成因 2.1 概述 2.2 神经网络与受害者心态 三、如何克服受害者心态 3.1 概述 3.2 职场 3.3 家庭…

verilog 从入门到看得懂---verilog 的基本语法各种语句

本篇文章主要介绍verilog里面常用的语句&#xff0c; 包括条件语句、循环语句块语句和生成语句。出了块语句和生成语句&#xff0c;其他的基本和c语言或者m语言一致。 1&#xff0c;if 语句&#xff0c;在需要判断逻辑的时候可以使用if语句&#xff0c;如 从输入a&#xff0c;…

《QT实用小工具·二》图片文字转base64编码

1、概述 源码放在文章末尾 base64编码转换类 图片转base64字符串。base64字符串转图片。字符转base64字符串。base64字符串转字符。后期增加数据压缩。Qt6对base64编码转换进行了重写效率提升至少200%。 下面是demo演示&#xff1a; 项目部分代码如下所示&#xff1a; #ifn…

解决npm init vue@latest证书过期问题:npm ERR! code CERT_HAS_EXPIRED

目录 一. 问题背景 二. 错误信息 三. 解决方案 3.1 临时解决办法 3.2 安全性考量 一. 问题背景 我在试图创建一个新的Vue.js项目时遇到了一个问题&#xff1a;npm init vuelatest命令出现了证书过期的错误。不过这是一个常见的问题&#xff0c;解决起来也简单。 二. 错误…

【aws】架构图工具推荐

碎碎念 以前以为日本冰箱论是个梗&#xff0c;结果居然是真的。用光盘传真其实还能理解&#xff08;毕竟我也喜欢电子古董2333&#xff09;&#xff0c;但是画架构图居然用的是excel&#xff0b;截图&#xff01;啊苍天呐&#xff0c;然后看到隔壁工位用excel画web原型又感觉释…

Python 从0开始 一步步基于Django创建项目(13)将数据关联到用户

在city_infos应用程序中&#xff0c;每个城市信息条目是关联到城市的&#xff0c;所以只需要将城市条目关联到用户即可。 将数据关联到用户&#xff0c;就是把‘顶层’数据关联到用户。 设计思路&#xff1a; 1、修改顶层数据模型&#xff0c;向其中添加‘用户’属性 2、根…

kubernetes K8s的监控系统Prometheus升级Grafana,来一个酷炫的Node监控界面(二)

上一篇文章《kubernetes K8s的监控系统Prometheus安装使用(一)》中使用的监控界面总感觉监控的节点数据太少&#xff0c;不能快算精准的判断出数据节点运行的状况。 今天我找一款非常酷炫的多维度数据监控界面&#xff0c;能够非常有把握的了解到各节点的数据&#xff0c;以及运…