黑馬頭條專案[修改版]-第七天
0.黑馬頭條-學習目標
- 能夠掌握自媒體文章稽核的流程
- 能夠使用阿里雲安全服務檢測文章內容
- 能夠完成自媒體文章稽核的功能
- 能夠完成自媒體釋出文章與稽核對接
1.自媒體文章自動稽核
1.1.自動稽核流程介紹
做為內容類產品,內容安全非常重要,所以需要進行對自媒體使用者釋出的文章進行稽核以後才能到app端展示給使用者。
稽核的流程如下:也可以檢視當前講義資料夾下:自媒體文章釋出時序圖.pdf
1.當自媒體使用者提交發布文章之後,會發訊息給kafka提交稽核,平臺運營端接收文章資訊 2.根據自媒體文章id查詢文章資訊 3.如果當前文章的狀態為4(人工稽核通過),則無需再進行自動稽核稽核,儲存app文章相關資料即可 4.文章狀態為8,釋出時間小於等於當前時間,則直接儲存app文章相關資料 5.文章狀態為1,則進行自動稽核 5.1 呼叫阿里雲文字反垃圾服務,進行文字稽核,如果稽核不成功或需要人工稽核,修改自媒體文章狀態 5.2 呼叫阿里雲圖片稽核服務,如果稽核不通過或需要人工稽核,修改自媒體文章狀態 5.3 文章內容中是否有自管理的敏感詞,如果有則稽核不通過,修改自媒體文章狀態 5.4 自媒體文章釋出時間大於當前時間,修改自媒體文章狀態為8(稽核通過待發布狀態) 5.5 稽核通過,修改自媒體文章狀態為 9 (稽核通過) 6.儲存app相關資料 ap_article_config 文章配置 ap_article 文章 ap_article_content 文章內容 ap_author 文章作者 7.建立索引(為後續app端的搜尋功能做資料準備)
1.2.相關表結構介紹
自媒體庫:leadnews_wemedia資料庫,自媒體文章表:wm_news
建立對應的實體類(之前已經建立)
文章庫:leadnews_article資料庫,文章作者表:ap_author
建立對應的實體類(之前已經建立)
文章庫:leadnews_article資料庫,文章資訊表:ap_article
- layout 文章佈局 0 無圖文章 1 單圖文章 2 多圖文章
- flag 文章標記 0 普通文章 1 熱點文章 2 置頂文章 3 精品文章 4 大V 文章
- images 文章圖片 多張逗號分隔
在heima-leadnews-model中建立ApArticle實體類
/** * <p> * 文章資訊表,儲存已釋出的文章 * </p> * * @author itheima */ @Data @TableName("ap_article") public class ApArticle { @TableId(value = "id",type = IdType.ID_WORKER) private Long id; /** * 標題 */ private String title; /** * 作者id */ @TableField("author_id") private Long authorId; /** * 作者名稱 */ @TableField("author_name") private String authorName; /** * 頻道id */ @TableField("channel_id") private Integer channelId; /** * 頻道名稱 */ @TableField("channel_name") private String channelName; /** * 文章佈局 0 無圖文章 1 單圖文章 2 多圖文章 */ private Short layout; /** * 文章標記 0 普通文章 1 熱點文章 2 置頂文章 3 精品文章 4 大V 文章 */ private Byte flag; /** * 文章封面圖片 多張逗號分隔 */ private String images; /** * 標籤 */ private String labels; /** * 點贊數量 */ private Integer likes; /** * 收藏數量 */ private Integer collection; /** * 評論數量 */ private Integer comment; /** * 閱讀數量 */ private Integer views; /** * 省市 */ @TableField("province_id") private Integer provinceId; /** * 市區 */ @TableField("city_id") private Integer cityId; /** * 區縣 */ @TableField("county_id") private Integer countyId; /** * 建立時間 */ @TableField("created_time") private Date createdTime; /** * 釋出時間 */ @TableField("publish_time") private Date publishTime; /** * 同步狀態 */ @TableField("sync_status") private Boolean syncStatus; /** * 來源 */ private Boolean origin; }
文章庫:leadnews_article資料庫,文章內容表:ap_article_content
在heima-leadnews-model中建立ApArticleContent實體類
@Data
@TableName("ap_article_content")
public class ApArticleContent {
@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;
/**
* 文章id
*/
@TableField("article_id")
private Long articleId;
/**
* 文章內容
*/
private String content;
}
文章庫:leadnews_article資料庫,文章配置表:ap_article_config
在heima-leadnews-model中建立ApArticleConfig實體類
/**
* <p>
* APP已釋出文章配置表
* </p>
*
* @author itheima
*/
@Data
@TableName("ap_article_config")
public class ApArticleConfig {
@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;
/**
* 文章id
*/
@TableField("article_id")
private Long articleId;
/**
* 是否可評論
*/
@TableField("is_comment")
private Boolean isComment;
/**
* 是否轉發
*/
@TableField("is_forward")
private Boolean isForward;
/**
* 是否下架
*/
@TableField("is_down")
private Boolean isDown;
/**
* 是否已刪除
*/
@TableField("is_delete")
private Boolean isDelete;
}
1.3.自媒體微服務遠端介面準備
1.3.1.自媒體Feign介面
1.需求說明和feign介面定義
在自動稽核的時候需要自媒體的遠端介面,如下:
1 根據文章id查詢自媒體文章的資料
2 在稽核的過程中,稽核失敗或者成功需要修改自媒體文章的狀態
3 在文章進行儲存的時候需要查詢作者資訊,需要通過自媒體使用者關聯查詢作者資訊
2.在heima-leadnews-admin的pom.xml檔案中引入Feign的依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
3.在heima-leadnews-admin中建立WemediaFeign
@FeignClient("leadnews-wemedia")
public interface WemediaFeign {
/**
* 根據文章id查詢自媒體文章的資料
* @param id
* @return
*/
@GetMapping("/api/v1/news/findOne/{id}")
public WmNews findById(@PathVariable("id") Integer id);
/**
* 在稽核的過程中,稽核失敗或者成功需要修改自媒體文章的狀態
* @param wmNews
* @return
*/
@PostMapping("/api/v1/news/update")
public ResponseResult updateWmNews(WmNews wmNews);
/**
* 在文章進行儲存的時候需要查詢作者資訊,需要通過自媒體使用者關聯查詢作者資訊
* @param id
* @return
*/
@GetMapping("/api/v1/user/findOne/{id}")
public WmUser findWmUserById(@PathVariable("id") Integer id);
}
4.在heima-leadnews-apis中的WmNewsControllerApi介面中新增方法
/**
* 根據id查詢文章資訊
* @param id
* @return
*/
public WmNews findById(Integer id);
/**
* 修改文章
* @param wmNews
* @return
*/
public ResponseResult updateWmNews(WmNews wmNews);
5.在heima-leadnews-apis中的WmUserControllerApi介面中新增方法
/**
* 根據id查詢使用者
* @param id
* @return
*/
public WmUser findWmUserById(Integer id);
6.在heima-leadnews-wemedia中的WmNewsController實現方法
/**
* 根據id查詢文章資訊
* @param id
* @return
*/
@GetMapping("/findOne/{id}")
@Override
public WmNews findById(@PathVariable("id") Integer id) {
return wmNewsService.getById(id);
}
/**
* 修改文章
* @param wmNews
* @return
*/
@PostMapping("/update")
@Override
public ResponseResult updateWmNews(@RequestBody WmNews wmNews) {
boolean b = wmNewsService.updateById(wmNews);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
7.在heima-leadnews-wemedia中的WmUserController實現方法
/**
* 根據id查詢使用者
* @param id
* @return
*/
@GetMapping("/findOne/{id}")
@Override
public WmUser findWmUserById(@PathVariable("id") Integer id) {
return wmUserService.getById(id);
}
8.啟動heima-leadnews-wemedia,使用postman測試
根據id查詢文章資訊測試
修改文章
根據id查詢使用者
1.3.2.文章feign介面
1.3.2.1.分散式id
隨著業務的增長,文章表可能要佔用很大的物理儲存空間,為了解決該問題,後期使用資料庫分片技術。將一個數據庫進行拆分,通過資料庫中介軟體連線。如果資料庫中該表選用ID自增策略,則可能產生重複的ID,此時應該使用分散式ID生成策略來生成ID。
雪花演算法實現
snowflake是Twitter開源的分散式ID生成演算法,結果是一個long型的ID。其核心思想是:使用41bit作為毫秒數,10bit作為機器的ID(5個bit是資料中心,5個bit的機器ID),12bit作為毫秒內的流水號(意味著每個節點在每毫秒可以產生 4096 個 ID),最後還有一個符號位,永遠是0
mybatis-plus已經集成了雪花演算法,完成以下兩步即可在專案中整合雪花演算法
1.在heima-leadnews-article的application.yml檔案中進行分散式id的設定
mybatis-plus:
......
global-config:
datacenter-id: 1 #資料中心id
worker-id: 1 #機器中心id
注意:如果當前專案做叢集了,那資料中心id和機器中心id至少其中一個要不一致,比如:
叢集伺服器1
datacenter-id: 1 #資料中心id
worker-id: 1 #機器中心id
叢集伺服器2
datacenter-id: 1 #資料中心id
worker-id: 2 #機器中心id
2.在heima-leadnews-model的ApArticle、ApArticleConfig、ApArticleContent實體類中的id屬性中設定分散式id的標識
/*
IdType.AUTO : 資料庫自增
IdType.INPUT : 自行輸入ID
IdType.NONE : 未設定主鍵型別,這是預設值
IdType.UUID : 32位UUID字串,只有當插入物件ID為空,才自動填充。
IdType.ID_WORKER : 分散式全域性唯一ID,長整型型別,只有當插入物件ID為空,才自動填充。
IdType.ID_WORKER_STR:分散式全域性唯一ID,字串型別,只有當插入物件ID為空,才自動填充。
*/
@TableId(value = "id",type = IdType.ID_WORKER)
private Long id;
1.3.2.2.文章微服務遠端呼叫介面準備
在文章稽核成功以後需要在app的article庫中新增文章資料
1.儲存文章資訊 ap_article,需要返回當前文章,並且需要獲取儲存後獲取到的主鍵
2.儲存文章配置資訊 ap_article_config
3.儲存文章內容 ap_article_content
4.在儲存文章的時候需要關聯作者,需要根據名稱查詢作者資訊
1.在heima-leadnews-admin中建立ArticleFeign
@FeignClient("leadnews-article")
public interface ArticleFeign {
/**
* 儲存文章資訊 ap_article,需要返回當前文章,並且需要獲取儲存後獲取到的主鍵
* @param apArticle
* @return
*/
@PostMapping("/api/v1/article/save")
public ApArticle saveAparticle(ApArticle apArticle);
/**
* 儲存文章配置資訊 ap_article_config
* @param apArticleConfig
* @return
*/
@PostMapping("/api/v1/article_config/save")
public ResponseResult saveArticleConfig(ApArticleConfig apArticleConfig);
/**
* 儲存文章內容 ap_article_content
* @param apArticleContent
* @return
*/
@PostMapping("/api/v1/article_content/save")
public ResponseResult saveArticleContent(ApArticleContent apArticleContent);
/**
* 在儲存文章的時候需要關聯作者,需要根據名稱查詢作者資訊
* @param name
* @return
*/
@GetMapping("/api/v1/author/findByName/{name}")
public ApAuthor selectAuthorByName(@PathVariable("name") String name);
}
1.3.2.3.文章微服務遠端呼叫功能實現
1.將資料中的ApArticleConfigControllerApi、ApArticleContentControllerApi、ApArticleControllerApi拷貝到heima-leadnews-apis中
public interface ApArticleConfigControllerApi {
/**
* 儲存app端文章配置
* @param apArticleConfig
* @return
*/
ResponseResult saveArticleConfig(ApArticleConfig apArticleConfig);
}
public interface ApArticleContentControllerApi {
/**
* 儲存app端文章內容
* @param apArticleContent
* @return
*/
ResponseResult saveArticleContent(ApArticleContent apArticleContent);
}
public interface ApArticleControllerApi {
/**
* 儲存app文章
* @param apArticle
* @return
*/
ApArticle saveArticle(ApArticle apArticle);
}
2.在heima-leadnews-apis的AuthorControllerApi新增介面
public interface AuthorControllerApi {
......
/**
* 根據名稱查詢作者
* @param name
* @return
*/
public ApAuthor selectAuthorByName(String name);
}
3.將資料中的ApArticleConfigMapper、ApArticleContentMapper、ApArticleMapper拷貝到heima-leadnews-article中
@Mapper
public interface ApArticleConfigMapper extends BaseMapper<ApArticleConfig> {
}
@Mapper
public interface ApArticleContentMapper extends BaseMapper<ApArticleContent> {
}
@Mapper
public interface ApArticleMapper extends BaseMapper<ApArticle> {
}
4.將資料中的ApArticleConfigService、ApArticleContentService、ApArticleService拷貝到heima-leadnews-article中
public interface ApArticleConfigService extends IService<ApArticleConfig> {
}
public interface ApArticleContentService extends IService<ApArticleContent> {
}
public interface ApArticleService extends IService<ApArticle> {
}
5.將資料中ApArticleConfigServiceImpl、ApArticleContentServiceImpl、ApArticleServiceImpl拷貝到heima-leadnews-article中
@Service
public class ApArticleConfigServiceImpl extends ServiceImpl<ApArticleConfigMapper, ApArticleConfig> implements ApArticleConfigService {
}
@Service
public class ApArticleContentServiceImpl extends ServiceImpl<ApArticleContentMapper,ApArticleContent> implements ApArticleContentService {
}
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
}
6.在heima-leadnews-article的AuthorController中實現介面方法
@RestController
@RequestMapping("/api/v1/author")
public class AuthorController implements AuthorControllerApi {
@Autowired
AuthorService authorService;
.......
/**
* 根據名稱查詢作者
* @param name
* @return
*/
@GetMapping("/findByName/{name}")
@Override
public ApAuthor selectAuthorByName(@PathVariable("name") String name) {
ApAuthor apAuthor = authorService.getOne(Wrappers.<ApAuthor>lambdaQuery().eq(ApAuthor::getName, name));
return apAuthor;
}
}
7.在heima-leadnews-article中建立ApArticleConfigController、ApArticleContentController、ApArticleController
@RestController
@RequestMapping("/api/v1/article_config")
public class ApArticleConfigController implements ApArticleConfigControllerApi {
@Autowired
private ApArticleConfigService apArticleConfigService;
/**
* 儲存app端文章配置
* @param apArticleConfig
* @return
*/
@PostMapping("/save")
@Override
public ResponseResult saveArticleConfig(@RequestBody ApArticleConfig apArticleConfig) {
apArticleConfigService.save(apArticleConfig);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
@RestController
@RequestMapping("/api/v1/article_content")
public class ApArticleContentController implements ApArticleContentControllerApi {
@Autowired
private ApArticleContentService apArticleContentService;
/**
* 儲存app端文章內容
* @param apArticleContent
* @return
*/
@PostMapping("/save")
@Override
public ResponseResult saveArticleContent(@RequestBody ApArticleContent apArticleContent) {
apArticleContentService.save(apArticleContent);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
}
@RestController
@RequestMapping("/api/v1/article")
public class ApArticleController implements ApArticleControllerApi {
@Autowired
private ApArticleService articleService;
/**
* 儲存app文章
* @param apArticle
* @return
*/
@PostMapping("/save")
@Override
public ApArticle saveArticle(@RequestBody ApArticle apArticle) {
articleService.save(apArticle);
return apArticle;
}
}
8.啟動當前專案,使用postman進行測試
儲存文章資訊測試
儲存文章配置資訊測試
儲存文章內容測試
根據名稱查詢作者資訊
1.4.自媒體文章稽核準備-自管理敏感詞查詢
1.在heima-leadnews-admin的AdSensitiveMapper中新增介面
@Mapper
public interface AdSensitiveMapper extends BaseMapper<AdSensitive> {
public List<String> findAllSensitive();
}
2.在heima-leadnews-admin中建立對映配置檔案
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.heima.admin.mapper.AdSensitiveMapper">
<select id="findAllSensitive" resultType="string">
select sensitives from ad_sensitive
</select>
</mapper>
1.5.文章稽核功能
1.5.1.業務層介面定義
1.在heima-leadnews-admin中建立WemediaNewsAutoScanService
public interface WemediaNewsAutoScanService {
/**
* 自媒體文章稽核
* @param id
*/
public void autoScanByMediaNewsId(Integer id);
}
2.在heima-leadnews-admin中建立WemediaNewsAutoScanServiceImpl
具體是實現思路如下
1.5.2.業務邏輯實現-抽取內容和圖片
在heima-leadnews-admin中的WemediaNewsAutoScanServiceImpl進行程式碼編寫
@Service
@Log4j2
public class WemediaNewsAutoScanServiceImpl implements WemediaNewsAutoScanService {
@Autowired
private WemediaFeign wemediaFeign;
@GlobalTransactional
@Override
public void autoScanByMediaNewsId(Integer id) {
if (id == null) {
log.error("當前的稽核id空");
return;
}
//1.根據id查詢自媒體文章資訊
WmNews wmNews = wemediaFeign.findById(id);
if (wmNews == null) {
log.error("稽核的自媒體文章不存在,自媒體的id:{}", id);
return;
}
//2.文章狀態為4(人工稽核通過)直接儲存資料和建立索引
if (wmNews.getStatus() == 4) {
//儲存資料
saveAppArticle(wmNews);
return;
}
//3.文章狀態為8 釋出時間>當前時間 直接儲存資料
if (wmNews.getStatus() == 8 && wmNews.getPublishTime().getTime() <= System.currentTimeMillis()) {
//儲存資料
saveAppArticle(wmNews);
return;
}
//4.文章狀態為1,待稽核
if (wmNews.getStatus() == 1) {
//抽取文章內容中的純文字和圖片
Map<String, Object> contentAndImagesResult = handleTextAndImages(wmNews);
//4.1 文字稽核
//4.2 圖片稽核
//4.3 自管理的敏感詞稽核
//4.4 釋出時間大於當前時間,
//5.稽核通過,修改自媒體文章狀態為9 儲存app端相關文章資訊
}
}
/**
* 儲存app文章相關的資料
*
* @param wmNews
*/
private void saveAppArticle(WmNews wmNews) {
}
/**
* 提取文字內容和圖片
*
* @param wmNews
* @return
*/
private Map<String, Object> handleTextAndImages(WmNews wmNews) {
//文章的內容
String content = wmNews.getContent();
//儲存純文字內容
StringBuilder sb = new StringBuilder();
//儲存圖片
List<String> images = new ArrayList<>();
List<Map> contentList = JSONArray.parseArray(content, Map.class);
for (Map map : contentList) {
if (map.get("type").equals("text")) {
sb.append(map.get("value"));
}
if (map.get("type").equals("image")) {
images.add((String) map.get("value"));
}
}
if (wmNews.getImages() != null && wmNews.getType() != 0) {
String[] split = wmNews.getImages().split(",");
images.addAll(Arrays.asList(split));
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("content", sb.toString());
resultMap.put("images", images);
return resultMap;
}
1.5.3.業務邏輯實現-文字稽核
@GlobalTransactional
@Override
public void autoScanByMediaNewsId(Integer id) {
........
//4.文章狀態為1,待稽核
if (wmNews.getStatus() == 1) {
......
//4.1 文字稽核
boolean textScanBoolean = handleTextScan((String) contentAndImagesResult.get("content"), wmNews);
if (!textScanBoolean) return;
........
}
}
/**
* 文字稽核
*
* @param content
* @param wmNews
* @return
*/
private boolean handleTextScan(String content, WmNews wmNews) {
boolean flag = true;
try {
Map map = greeTextScan.greeTextScan(content);
//稽核不通過
if (!map.get("suggestion").equals("pass")) {
//稽核失敗
if (map.get("suggestion").equals("block")) {
//修改自媒體文章的狀態,並告知稽核失敗原因
updateWmNews(wmNews, (short) 2, "文章內容中有敏感詞彙");
flag = false;
}
//人工稽核
if (map.get("suggestion").equals("review")) {
//修改自媒體文章的狀態,並告知稽核失敗原因
updateWmNews(wmNews, (short) 3, "文章內容中有不確定詞彙");
flag = false;
}
}
} catch (Exception e) {
e.printStackTrace();
flag = false;
}
return flag;
}
/**
* 修改自媒體文章
*
* @param wmNews
* @param status
* @param msg
*/
private void updateWmNews(WmNews wmNews, short status, String msg) {
wmNews.setStatus(status);
wmNews.setReason(msg);
wemediaFeign.updateWmNews(wmNews);
}
1.5.4.業務邏輯實現-圖片稽核
@GlobalTransactional
@Override
public void autoScanByMediaNewsId(Integer id) {
......
//4.文章狀態為1,待稽核
if (wmNews.getStatus() == 1) {
.......
//4.2 圖片稽核
boolean imagesScanBoolean = handleImagesScan((List<String>) contentAndImagesResult.get("images"), wmNews);
if (!imagesScanBoolean) return;
.......
}
}
@Autowired
private GreenImageScan greenImageScan;
@Autowired
private FastDFSClient fastDFSClient;
@Value("${fdfs.url}")
private String fileServerUrl;
/**
* 稽核圖片
*
* @param images
* @param wmNews
* @return
*/
private boolean handleImagesScan(List<String> images, WmNews wmNews) {
if (images == null) {
return true;
}
boolean flag = true;
List<byte[]> imageList = new ArrayList<>();
try {
for (String image : images) {
String imageName = image.replace(fileServerUrl, "");
int index = imageName.indexOf("/");
String groupName = imageName.substring(0, index);
String imagePath = imageName.substring(index + 1);
byte[] imageByte = fastDFSClient.download(groupName, imagePath);
imageList.add(imageByte);
}
//阿里雲圖片稽核
Map map = greenImageScan.imageScan(imageList);
//稽核不通過
if (!map.get("suggestion").equals("pass")) {
//稽核失敗
if (map.get("suggestion").equals("block")) {
//修改自媒體文章的狀態,並告知稽核失敗原因
updateWmNews(wmNews, (short) 2, "文章中圖片有違規");
flag = false;
}
//人工稽核
if (map.get("suggestion").equals("review")) {
//修改自媒體文章的狀態,並告知稽核失敗原因
updateWmNews(wmNews, (short) 3, "文章圖片有不確定元素");
flag = false;
}
}
} catch (Exception e) {
e.printStackTrace();
flag = false;
}
return flag;
}
1.5.5.業務邏輯實現-自管理敏感詞稽核
@GlobalTransactional
@Override
public void autoScanByMediaNewsId(Integer id) {
.......
//4.文章狀態為1,待稽核
if (wmNews.getStatus() == 1) {
.......
//4.3 自管理的敏感詞稽核
boolean sensitiveScanBoolean = handleSensitive((String) contentAndImagesResult.get("content"), wmNews);
if (!sensitiveScanBoolean) return;
//4.4 釋出時間大於當前時間,
if (wmNews.getPublishTime().getTime() > System.currentTimeMillis()) {
//修改文章狀態為8
updateWmNews(wmNews, (short) 8, "稽核通過,待發布");
return;
}
//5.稽核通過,修改自媒體文章狀態為9 儲存app端相關文章資訊
saveAppArticle(wmNews);
}
}
@Autowired
private AdSensitiveMapper adSensitiveMapper;
/**
* 敏感詞稽核
*
* @param content
* @param wmNews
* @return
*/
private boolean handleSensitive(String content, WmNews wmNews) {
boolean flag = true;
List<String> allSensitive = adSensitiveMapper.findAllSensitive();
//初始化敏感詞
SensitiveWordUtil.initMap(allSensitive);
//文章內容自管理敏感詞過濾
Map<String, Integer> resultMap = SensitiveWordUtil.matchWords(content);
if (resultMap.size() > 0) {
log.error("敏感詞過濾沒有通過,包含了敏感詞:{}", resultMap);
//找到了敏感詞,稽核不通過
updateWmNews(wmNews, (short) 2, "文章中包含了敏感詞");
flag = false;
}
return flag;
}
/**
* 儲存app文章相關的資料
*
* @param wmNews
*/
private void saveAppArticle(WmNews wmNews) {
}
1.5.6.業務邏輯實現-儲存app端文章資料
@Autowired
ArticleFeign articleFeign;
/**
* 儲存app文章相關的資料
*
* @param wmNews
*/
private void saveAppArticle(WmNews wmNews) {
//儲存app文章
ApArticle apArticle = saveArticle(wmNews);
......
}
@Autowired
AdChannelMapper adChannelMapper;
/**
* 儲存文章
* @param wmNews
* @return
*/
private ApArticle saveArticle(WmNews wmNews) {
ApArticle apArticle = new ApArticle();
apArticle.setTitle(wmNews.getTitle());
apArticle.setLayout(wmNews.getType());
apArticle.setImages(wmNews.getImages());
apArticle.setCreatedTime(new Date());
//獲取作者相關資訊
Integer wmUserId = wmNews.getUserId();
WmUser wmUser = wemediaFeign.findWmUserById(wmUserId);
if(wmUser != null){
String wmUserName = wmUser.getName();
ApAuthor apAuthor = articleFeign.selectAuthorByName(wmUserName);
if(apAuthor != null){
apArticle.setAuthorId(apAuthor.getId().longValue());
apArticle.setAuthorName(apAuthor.getName());
}
}
//獲取頻道相關資訊
Integer channelId = wmNews.getChannelId();
AdChannel channel = adChannelMapper.selectById(channelId);
if(channel != null){
apArticle.setChannelId(channel.getId());
apArticle.setChannelName(channel.getName());
}
return articleFeign.saveAparticle(apArticle);
}
1.5.7.業務邏輯實現-儲存app端文章配置和內容
/**
* 儲存app文章相關的資料
*
* @param wmNews
*/
private void saveAppArticle(WmNews wmNews) {
....
//儲存app文章配置
saveArticleConfig(apArticle);
//儲存app文章內容
saveArticleContent(apArticle,wmNews);
//修改自媒體文章的狀態為9
wmNews.setArticleId(apArticle.getId());
updateWmNews(wmNews,(short)9,"稽核通過");
//TODO es索引建立
}
/**
* 建立app端文章配置資訊
* @param apArticle
*/
private void saveArticleConfig(ApArticle apArticle) {
ApArticleConfig apArticleConfig = new ApArticleConfig();
apArticleConfig.setArticleId(apArticle.getId());
apArticleConfig.setIsForward(true);
apArticleConfig.setIsDelete(false);
apArticleConfig.setIsDown(true);
apArticleConfig.setIsComment(true);
articleFeign.saveArticleConfig(apArticleConfig);
}
/**
* 建立app端文章內容資訊
* @param apArticle
* @param wmNews
*/
private void saveArticleContent(ApArticle apArticle, WmNews wmNews) {
ApArticleContent apArticleContent = new ApArticleContent();
apArticleContent.setArticleId(apArticle.getId());
apArticleContent.setContent(wmNews.getContent());
articleFeign.saveArticleContent(apArticleContent);
}
1.5.8.測試
在heima-leadnews-admin中編寫單元測試類
@SpringBootTest(classes = AdminApplication.class)
@RunWith(SpringRunner.class)
public class WemediaNewsAutoScanServiceTest {
@Autowired
private WemediaNewsAutoScanService wemediaNewsAutoScanService;
@Test
public void testScanNews(){
wemediaNewsAutoScanService.autoScanByMediaNewsId(6219);
}
}
1.5.9.文章稽核功能-釋出文章提交稽核定義監聽接受訊息
在稽核文章流程的第一步,當自媒體人釋出一篇文章後會馬上進行稽核,這個時候是通過訊息中介軟體進行資料的傳遞的。所以說需要配置生產者和消費者。目前自媒體微服務就是生產者,admin就是消費者
1.5.9.1.生產者編寫
1.在heima-leadnews-common專案中引入kafka 的依賴
<!-- kafkfa -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
</dependency>
<!--kafka stream-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams</artifactId>
</dependency>
2.在heima-leadnews-wemedia的application.yml中配置
spring:
.....
kafka:
bootstrap-servers: 192.168.200.130:9092
producer:
retries: 10
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
3.修改heima-leadnews-wemedia的WmNewsServiceImpl
/**
* 儲存或修改文章
*
* @param wmNews
* @param isSubmit
*/
private void saveWmNews(WmNews wmNews, Short isSubmit) {
wmNews.setStatus(isSubmit);
wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
wmNews.setCreatedTime(new Date());
wmNews.setSubmitedTime(new Date());
wmNews.setEnable((short) 1);
boolean flag = false;
if (wmNews.getId() == null) {
flag = save(wmNews);
} else {
//如果是修改,則先刪除素材與文章的關係
LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(WmNewsMaterial::getNewsId, wmNews.getId());
wmNewsMaterialMapper.delete(queryWrapper);
flag = updateById(wmNews);
}
//傳送訊息
if(flag){
kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC,JSON.toJSONString(wmNews.getId()));
}
}
4.在heima-leadnews-common建立常量類
public class NewsAutoScanConstants {
public static final String WM_NEWS_AUTO_SCAN_TOPIC="wm.news.auto.scan.topic";
}
1.5.9.2.消費者編寫
1.在heima-leadnews-admin中建立WemediaNewsAutoListener
@Component
public class WemediaNewsAutoListener {
@Autowired
WemediaNewsAutoScanService wemediaNewsAutoScanService;
@KafkaListener(topics = NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC)
public void recevieMessage(ConsumerRecord<?,?> record){
Optional<? extends ConsumerRecord<?, ?>> optional = Optional.ofNullable(record);
if(optional.isPresent()){
Object value = record.value();
wemediaNewsAutoScanService.autoScanByMediaNewsId(Integer.valueOf((String) value));
}
}
}
2.在heima-leadnews-admin的application.yml檔案中配置kafka
spring:
.....
kafka:
bootstrap-servers: 192.168.200.130:9092
consumer:
group-id: ${spring.application.name}-kafka-group
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
3.在heima-leadnews-admin的pom.xml中引入seata依賴
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-leadnews-seata</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
4.將file.conf和registry.conf拷貝到heima-leadnews-admin的resources目錄下,並修改file.conf的內容
5.在heima-leadnews-admin的application.yml檔案中配置
spring:
......
cloud:
......
alibaba:
seata:
tx-service-group: ${spring.application.name}_tx_group
6.在heima-leadnews-admin中建立SeataConfig
@Configuration
@ComponentScan("com.heima.seata.config")
public class SeataConfig {
}
7.在heima-leadnews-admin的WemediaNewsAutoScanServiceImpl的autoScanByMediaNewsId()方法上新增@GlobalTransactional
@GlobalTransactional
@Override
public void autoScanByMediaNewsId(Integer id) {
}
1.6.綜合測試
服務啟動列表:
1,nacos
2,seata
3,fastdfs
4,zookeeper&kafka
5,article微服務
6,wemedia微服務
7,啟動wemedia閘道器微服務
8,admin微服務
9,啟動前端系統wemedia
測試動作:在自媒體前端進行釋出文章