文章审核以及APP端保存文章
业务流程:
App端保存接口:
数据库表详情
文章的基本信息表:id,标题,作者id,频道id......
文章的权限/配置表:存储文章是否可以评论,是否上架,是否转发,是否下架
文章的内容表:为文章的内容数据量大,所以被分库分表出来,记录文章的内容
分布式ID的技术选型:雪花算法
MybatisPlus中已经集成了雪花算法,所以只需要在id上配置类型为id_worker。并且可以在配置文件中配置机器id和服务id
@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;
业务流程
①首先将文章的信息作为参数传过来,然后判断文章是否已经存在,因为不知道是保存新的文章还是修改之前的文章。②然后如果是新的文章,就要保存文章,保存文章的配置和保存文章的内容。③如果是修改已经存在的文章,则先把文章修改成新的数据,然后再保存文章的内容。
第一步:在heima-leadnews-fegin-api中定义Feign的接口
@FeignClient(value = "leadnews_article")
public interface IArticleClient {
@PostMapping("/api/v1/article/save")
public ResponseResult saveArticle(@RequestBody ArticleDto dto);
}
第二步:在heima-leadnews-article中实现Feign的接口
@RestController
public class ArticleClient implements IArticleClient {
@Autowired
private ApArticleService apArticleService;
@PostMapping("/api/v1/article/save")
@Override
public ResponseResult saveArticle(@RequestBody ArticleDto dto) {
return apArticleService.saveArticle(dto);
}
}
第三步:实现类,保存文章的内容,包括配置和内容
@Autowired
private ApArticleConfigMapper apArticleConfigMapper;
@Autowired
private ApArticleContentMapper apArticleContentMapper;
/**
* 保存app端的文章
* @param dto
* @return
*/
@Override
public ResponseResult saveArticle(ArticleDto dto) {
//检查参数
if(dto == null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//创建文章的对象,并且拷贝过来
ApArticle article = new ApArticle();
BeanUtils.copyProperties(dto,article);
//判断是否文章是否存在id
if(dto.getId() == null){
//不存在id 则需要保存文章
save(article);
//保存配置
ApArticleConfig apArticleConfig = new ApArticleConfig(article.getId());
apArticleConfigMapper.insert(apArticleConfig);
//保存内容
ApArticleContent apArticleContent = new ApArticleContent();
apArticleContent.setArticleId(article.getId());
apArticleContent.setContent(dto.getContent());
apArticleContentMapper.insert(apArticleContent);
}else{
//存在id 修改 文章 文章内容
updateById(article);
//修改文章内容
ApArticleContent apArticleContent = apArticleContentMapper.selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, dto.getId()));
apArticleContent.setContent(dto.getContent());
apArticleContentMapper.updateById(apArticleContent);
}
//结果返回 文章id
return ResponseResult.okResult(article.getId());
}
文章内容审核:
数据库表详情
status字段:0 草稿 1 待审核 2 审核失败 3 人工审核 4 人工审核通过 8 审核通过(待发布) 9 已发布
业务流程
首先根据传过来的参数去查询文章,如果文章不存在则会报错,如果存在则将文章并且判断文章是处于待审核状态。就把内容中的图片和文本提取出来。再把图片和文本通过阿里官方接口进行审核,并且修改文章的状态,设置审核失败或者需要人工审核。当所有的准备都完成后就可以远程调用Fegin接口去实现文章审核通过保存文章的操作
media微服务要远程调用article微服务,需要在启动类上添加扫描类
@Service
@Transactional
@Slf4j
public class WmNewsAutoScanServiceimpl implements WmNewsAutoScanService {
@Autowired
private WmNewsMapper wmNewsMapper;
/**
* 自媒体文章审核
* @param id 参数是文章的id
*/
@Override
public void autoScanWmnews(Integer id) {
//1.查询目标文章
WmNews wmNews = wmNewsMapper.selectById(id);
if(wmNews == null){
throw new RuntimeException("文章不存在");
}
//判断文章是否处于待审核阶段,如果在就进行内容审核
if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())){
//调用方法从内容中提取纯文本内容和图片,去用于审核
Map<String,Object> textAndImages = handleTextAndImages(wmNews);
//2.审核文本内容 //直接默认通过,不使用阿里云的验证
//3.审核图片 //直接默认通过,不使用阿里云的验证
//4.审核成功调用方法去保存APP端的相关数据
ResponseResult responseResult = saveAppArticle(wmNews);
if(!responseResult.getCode().equals(200)){
throw new RuntimeException("文章审核保存app端失败");
}
//回填articleid
wmNews.setArticleId((Long) responseResult.getData());
//状态设置成功状态
updateWmNews(wmNews, (short) 9,"审核成功");
}
}
@Autowired
private IArticleClient iArticleClient;
@Autowired
private WmChannelMapper wmChannelMapper;
@Autowired
private WmUserMapper wmUserMapper;
//更新文章的状态
private void updateWmNews(WmNews wmNews, short status, String reason) {
wmNews.setStatus(status);
wmNews.setReason(reason);
wmNewsMapper.updateById(wmNews);
}
//保存app端相关的文章数据
private ResponseResult saveAppArticle(WmNews wmNews) {
//创建对象
ArticleDto articleDto = new ArticleDto();
BeanUtils.copyProperties(wmNews,articleDto);
//设置文章布局
articleDto.setLayout(wmNews.getType());
//设置频道信息
WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
if(wmChannel != null){
articleDto.setChannelName(wmChannel.getName());
}
//设置作者信息
articleDto.setAuthorId(wmNews.getUserId().longValue());
WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
if(wmUser != null){
articleDto.setAuthorName(wmUser.getName());
}
//设置文章id
if(wmNews.getArticleId() != null){
articleDto.setId(wmNews.getArticleId());
}
//设置时间
articleDto.setCreatedTime(new Date());
//远程调用
ResponseResult responseResult = iArticleClient.saveArticle(articleDto);
//返回数据
return responseResult;
}
//从文章内容中提取文章内容和图片
private Map<String, Object> handleTextAndImages(WmNews wmNews) {
//存储纯文本内容
StringBuilder stringBuilder = new StringBuilder();
//存储图片信息
List<String> images = new ArrayList<>();
//当亲内容不为空
if(StringUtils.isNotBlank(wmNews.getContent())){
List<Map> maps = JSONArray.parseArray(wmNews.getContent(), Map.class);
for (Map map : maps) {
if(map.get("type").equals("text")){
stringBuilder.append(map.get("value"));
}
if(map.get("type").equals("images")){
images.add((String) map.get("value"));
}
}
}
//提取封面图片
if(StringUtils.isNotBlank(wmNews.getImages())){
String[] split = wmNews.getImages().split(",");
images.addAll(Arrays.asList(split));
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("content",stringBuilder.toString());
resultMap.put("images",images);
return resultMap;
}
}
Fegin远程调用服务降级
由于上级的微服务的服务异常不可用,最终会蔓延到下游所有的服务,导致下游的服务都崩掉,所以这里使用hystrix实现降级
文章审核的异步调用
第一步:
@Override
@Async //表名方法为异步方法
public void autoScanWmnews(Integer id)
第二步:
//保存文章封面图片与素材的关系
saveRelativeInfoForCover(dto,wmNews,materials);
//审核文章
wmNewsAutoScanService.autoScanWmnews(wmNews.getId());
第三步:
@SpringBootApplication
@EnableDiscoveryClient
@MapperScan("com.heima.wemedia.mapper")
@EnableFeignClients(basePackages = "com.heima.apis")
@EnableAsync//开启异步调用
public class WemediaApplication {