1. 程式人生 > 其它 >黑馬頭條專案[修改版]-第七天

黑馬頭條專案[修改版]-第七天

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

測試動作:在自媒體前端進行釋出文章