自媒體文章發(fā)布
1.自媒體前后端搭建
1.1 后臺搭建
①:資料中找到heima-leadnews-wemedia.zip解壓
拷貝到heima-leadnews-service工程下,并指定子模塊
執(zhí)行l(wèi)eadnews-wemedia.sql腳本
添加對應的nacos配置
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/leadnews_wemedia?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
# 設置Mapper接口所對應的XML文件位置,如果你在Mapper接口中有自定義方法,需要進行該配置
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
# 設置別名包掃描路徑,通過該屬性可以給包中的類注冊別名
type-aliases-package: com.heima.model.media.pojos
②:資料中找到heima-leadnews-wemedia-gateway.zip解壓
拷貝到heima-leadnews-gateway工程下,并指定子模塊
添加對應的nacos配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有請求
allowedOrigins: "*" #跨域處理 允許所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
routes:
# 平臺管理
- id: wemedia
uri: lb://leadnews-wemedia
predicates:
- Path=/wemedia/**
filters:
- StripPrefix= 1
這里要注意redis要配置,不然啟動會報錯
③:在資料中找到類文件夾
拷貝wemedia文件夾到heima-leadnews-model模塊下的com.heima.model
1.2 前臺搭建
通過nginx的虛擬主機功能,使用同一個nginx訪問多個項目
搭建步驟:
①:資料中找到wemedia-web.zip解壓
②:在nginx中l(wèi)eadnews.conf目錄中新增heima-leadnews-wemedia.conf文件
-
網(wǎng)關地址修改(localhost:51602)
-
前端項目目錄修改(wemedia-web解壓的目錄)
-
訪問端口修改(8802)
upstream heima-wemedia-gateway{
server localhost:51602;
}
server {
listen 8802;
location / {
root F:/javawebwork/heima-leadnews-html/wemedia-web/;
index index.html;
}
location ~/wemedia/MEDIA/(.*) {
proxy_pass http://heima-wemedia-gateway/$1;
proxy_set_header HOST $host; # 不改變源請求頭的值
proxy_pass_request_body on; #開啟獲取請求體
proxy_pass_request_headers on; #開啟獲取請求頭
proxy_set_header X-Real-IP $remote_addr; # 記錄真實發(fā)出請求的客戶端IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #記錄代理信息
}
}
③:啟動nginx,啟動自媒體微服務和對應網(wǎng)關
④:聯(lián)調測試登錄功能
訪問:http://localhost:8802/
賬號:admin
密碼:123456
登錄后界面如下:
2.自媒體素材管理
2.1 素材上傳
2.2.1 需求分析
圖片上傳的頁面,首先是展示素材信息,可以點擊圖片上傳,彈窗后可以上傳圖片
2.2.2 素材管理-圖片上傳-表結構
媒體圖文素材信息表wm_material
對應實體類:
package com.heima.model.wemedia.pojos;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 自媒體圖文素材信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("wm_material")
public class WmMaterial implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主鍵
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 自媒體用戶ID
*/
@TableField("user_id")
private Integer userId;
/**
* 圖片地址
*/
@TableField("url")
private String url;
/**
* 素材類型
0 圖片
1 視頻
*/
@TableField("type")
private Short type;
/**
* 是否收藏
*/
@TableField("is_collection")
private Short isCollection;
/**
* 創(chuàng)建時間
*/
@TableField("created_time")
private Date createdTime;
}
思考:
2.2.3 實現(xiàn)思路
①:前端發(fā)送上傳圖片請求,類型為MultipartFile
②:網(wǎng)關進行token解析后,把解析后的用戶信息存儲到header中
//獲得token解析后中的用戶信息
Object userId = claimsBody.get("id");
//在header中添加新的信息
ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
httpHeaders.add("userId", userId + "");
}).build();
//重置header
exchange.mutate().request(serverHttpRequest).build();
③:自媒體微服務使用攔截器獲取到header中的的用戶信息,并放入到threadlocal中
在heima-leadnews-utils中新增工具類
注意:需要從資料中找出WmUser實體類拷貝到model工程下
package com.heima.utils.thread;
import com.heima.model.wemedia.pojos.WmUser;
public class WmThreadLocalUtil {
private final static ThreadLocal<WmUser> WM_USER_THREAD_LOCAL = new ThreadLocal<>();
/**
* 添加用戶
* @param wmUser
*/
public static void setUser(WmUser wmUser){
WM_USER_THREAD_LOCAL.set(wmUser);
}
/**
* 獲取用戶
*/
public static WmUser getUser(){
return WM_USER_THREAD_LOCAL.get();
}
/**
* 清理用戶
*/
public static void clear(){
WM_USER_THREAD_LOCAL.remove();
}
}
在heima-leadnews-wemedia中新增攔截器
package com.heima.wemedia.interceptor;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;
@Slf4j
public class WmTokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//得到header中的信息
String userId = request.getHeader("userId");
Optional<String> optional = Optional.ofNullable(userId);
if(optional.isPresent()){
//把用戶id存入threadloacl中
WmUser wmUser = new WmUser();
wmUser.setId(Integer.valueOf(userId));
WmThreadLocalUtils.setUser(wmUser);
log.info("wmTokenFilter設置用戶信息到threadlocal中...");
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("清理threadlocal...");
WmThreadLocalUtils.clear();
}
}
配置使攔截器生效,攔截所有的請求
package com.heima.wemedia.config;
import com.heima.wemedia.interceptor.WmTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new WmTokenInterceptor()).addPathPatterns("/**");
}
}
④:先把圖片上傳到minIO中,獲取到圖片請求的路徑——(2.2.5查看具體功能實現(xiàn))
⑤:把用戶id和圖片上的路徑保存到素材表中——(2.2.5查看具體功能實現(xiàn))
2.2.4 接口定義
說明 | |
---|---|
接口路徑 | /api/v1/material/upload_picture |
請求方式 | POST |
參數(shù) | MultipartFile |
響應結果 | ResponseResult |
MultipartFile :Springmvc指定的文件接收類型
ResponseResult :
成功需要回顯圖片,返回素材對象
{
"host":null,
"code":200,
"errorMessage":"操作成功",
"data":{
"id":52,
"userId":1102,
"url":"http://192.168.200.130:9000/leadnews/2021/04/26/a73f5b60c0d84c32bfe175055aaaac40.jpg",
"type":0,
"isCollection":0,
"createdTime":"2021-01-20T16:49:48.443+0000"
}
}
失敗:
- 參數(shù)失效
- 文章上傳失敗
2.2.5 自媒體微服務集成heima-file-starter
①:在heima-leadnews-wemedia子模塊中導入heima-file-starter
<dependencies>
<dependency>
<groupId>com.heima</groupId>
<artifactId>heima-file-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
②:在自媒體微服務的配置中心添加以下配置:
minio:
accessKey: minio
secretKey: minio123
bucket: leadnews
endpoint: http://192.168.200.130:9000
readPath: http://192.168.200.130:9000
2.2.6 具體實現(xiàn)
①:創(chuàng)建WmMaterialController
@RestController
@RequestMapping("/api/v1/material")
public class WmMaterialController {
@PostMapping("/upload_picture")
public ResponseResult uploadPicture(MultipartFile multipartFile){
return null;
}
}
②:mapper
package com.heima.wemedia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.wemedia.pojos.WmMaterial;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface WmMaterialMapper extends BaseMapper<WmMaterial> {
}
③:業(yè)務層:
package com.heima.wemedia.service;
public interface WmMaterialService extends IService<WmMaterial> {
/**
* 圖片上傳
* @param multipartFile
* @return
*/
public ResponseResult uploadPicture(MultipartFile multipartFile);
}
業(yè)務層實現(xiàn)類:
package com.heima.wemedia.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.file.service.FileStorageService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.service.WmMaterialService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Date;
import java.util.UUID;
@Slf4j
@Service
@Transactional
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {
@Autowired
private FileStorageService fileStorageService;
/**
* 圖片上傳
* @param multipartFile
* @return
*/
@Override
public ResponseResult uploadPicture(MultipartFile multipartFile) {
//1.檢查參數(shù)
if(multipartFile == null || multipartFile.getSize() == 0){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//2.上傳圖片到minIO中
String fileName = UUID.randomUUID().toString().replace("-", "");
//aa.jpg
String originalFilename = multipartFile.getOriginalFilename();
String postfix = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileId = null;
try {
fileId = fileStorageService.uploadImgFile("", fileName + postfix, multipartFile.getInputStream());
log.info("上傳圖片到MinIO中,fileId:{}",fileId);
} catch (IOException e) {
e.printStackTrace();
log.error("WmMaterialServiceImpl-上傳文件失敗");
}
//3.保存到數(shù)據(jù)庫中
WmMaterial wmMaterial = new WmMaterial();
wmMaterial.setUserId(WmThreadLocalUtil.getUser().getId());
wmMaterial.setUrl(fileId);
wmMaterial.setIsCollection((short)0);
wmMaterial.setType((short)0);
wmMaterial.setCreatedTime(new Date());
save(wmMaterial);
//4.返回結果
return ResponseResult.okResult(wmMaterial);
}
}
④:控制器
@RestController
@RequestMapping("/api/v1/material")
public class WmMaterialController {
@Autowired
private WmMaterialService wmMaterialService;
@PostMapping("/upload_picture")
public ResponseResult uploadPicture(MultipartFile multipartFile){
return wmMaterialService.uploadPicture(multipartFile);
}
}
⑤:測試
這里測試的時候要注意,一定要重新訪問
http://localhost:8802/
啟動自媒體微服務和自媒體網(wǎng)關,使用前端項目進行測試
上傳后,顯示成功,表示功能實現(xiàn)
上傳成功后,數(shù)據(jù)庫多了2條數(shù)據(jù)
2.2 素材列表查詢
2.2.1 接口定義
說明 | |
---|---|
接口路徑 | /api/v1/material/list |
請求方式 | POST |
參數(shù) | WmMaterialDto |
響應結果 | ResponseResult |
WmMaterialDto :
@Data
public class WmMaterialDto extends PageRequestDto {
/**
* 1 收藏
* 0 未收藏
*/
private Short isCollection;
}
ResponseResult :
{
"host":null,
"code":200,
"errorMessage":"操作成功",
"data":[
{
"id":52,
"userId":1102,
"url":"http://192.168.200.130:9000/leadnews/2021/04/26/ec893175f18c4261af14df14b83cb25f.jpg",
"type":0,
"isCollection":0,
"createdTime":"2021-01-20T16:49:48.000+0000"
},
....
],
"currentPage":1,
"size":20,
"total":0
}
2.2.2 功能實現(xiàn)
①:在WmMaterialController類中新增方法
@PostMapping("/list")
public ResponseResult findList(@RequestBody WmMaterialDto dto){
return null;
}
②:mapper已定義
③:業(yè)務層
在WmMaterialService中新增方法
/**
* 素材列表查詢
* @param dto
* @return
*/
public ResponseResult findList( WmMaterialDto dto);
實現(xiàn)方法:
/**
* 素材列表查詢
* @param dto
* @return
*/
@Override
public ResponseResult findList(WmMaterialDto dto) {
//1.檢查參數(shù)
dto.checkParam();
//2.分頁查詢
IPage page = new Page(dto.getPage(),dto.getSize());
LambdaQueryWrapper<WmMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//是否收藏
if(dto.getIsCollection() != null && dto.getIsCollection() == 1){
lambdaQueryWrapper.eq(WmMaterial::getIsCollection,dto.getIsCollection());
}
//按照用戶查詢
lambdaQueryWrapper.eq(WmMaterial::getUserId,WmThreadLocalUtil.getUser().getId());
//按照時間倒序
lambdaQueryWrapper.orderByDesc(WmMaterial::getCreatedTime);
page = page(page,lambdaQueryWrapper);
//3.結果返回
ResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),(int)page.getTotal());
responseResult.setData(page.getRecords());
return responseResult;
}
④:控制器:
@PostMapping("/list")
public ResponseResult findList(@RequestBody WmMaterialDto dto){
return wmMaterialService.findList(dto);
}
⑤:在自媒體heima-leadnews-wemedia模塊中引導類中天mybatis-plus的分頁攔截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
重啟一下兩個項目,上傳的圖片已經(jīng)可以看到了
分頁測試一下也是正常無誤的
我們手動修改2條數(shù)據(jù),更改為收藏
收藏后如下:
3.自媒體文章管理
3.1 查詢所有頻道
3.1.1 需求分析
3.1.2 表結構
wm_channel 頻道信息表
對應實體類:
package com.heima.model.wemedia.pojos;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 頻道信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("wm_channel")
public class WmChannel implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 頻道名稱
*/
@TableField("name")
private String name;
/**
* 頻道描述
*/
@TableField("description")
private String description;
/**
* 是否默認頻道
* 1:默認 true
* 0:非默認 false
*/
@TableField("is_default")
private Boolean isDefault;
/**
* 是否啟用
* 1:啟用 true
* 0:禁用 false
*/
@TableField("status")
private Boolean status;
/**
* 默認排序
*/
@TableField("ord")
private Integer ord;
/**
* 創(chuàng)建時間
*/
@TableField("created_time")
private Date createdTime;
}
3.1.3 接口定義
說明 | |
---|---|
接口路徑 | /api/v1/channel/channels |
請求方式 | GET |
參數(shù) | 無 |
響應結果 | ResponseResult |
ResponseResult :
{
"host": "null",
"code": 0,
"errorMessage": "操作成功",
"data": [
{
"id": 4,
"name": "java",
"description": "java",
"isDefault": true,
"status": false,
"ord": 3,
"createdTime": "2019-08-16T10:55:41.000+0000"
},
Object { ... },
Object { ... }
]
}
3.1.4 功能實現(xiàn)
接口定義:
package com.heima.wemedia.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/channel")
public class WmchannelController {
@GetMapping("/channels")
public ResponseResult findAll(){
return null;
}
}
mapper
package com.heima.wemedia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.wemedia.pojos.WmChannel;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface WmChannelMapper extends BaseMapper<WmChannel> {
}
service
package com.heima.wemedia.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
public interface WmChannelService extends IService<WmChannel> {
/**
* 查詢所有頻道
* @return
*/
public ResponseResult findAll();
}
實現(xiàn)類
package com.heima.wemedia.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.service.WmChannelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
@Slf4j
public class WmChannelServiceImpl extends ServiceImpl<WmChannelMapper, WmChannel> implements WmChannelService {
/**
* 查詢所有頻道
* @return
*/
@Override
public ResponseResult findAll() {
return ResponseResult.okResult(list());
}
}
控制層
package com.heima.wemedia.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.wemedia.service.WmChannelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/channel")
public class WmchannelController {
@Autowired
private WmChannelService wmChannelService;
@GetMapping("/channels")
public ResponseResult findAll(){
return wmChannelService.findAll();
}
}
3.1.5 測試
重啟網(wǎng)關和管理文章的子模塊,發(fā)現(xiàn)列表加載出來了
3.2 查詢自媒體文章
3.2.1 需求說明
3.2.2 表結構分析
wm_news 自媒體文章表
對應實體類:
package com.heima.model.wemedia.pojos;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.apache.ibatis.type.Alias;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 自媒體圖文內容信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("wm_news")
public class WmNews implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主鍵
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 自媒體用戶ID
*/
@TableField("user_id")
private Integer userId;
/**
* 標題
*/
@TableField("title")
private String title;
/**
* 圖文內容
*/
@TableField("content")
private String content;
/**
* 文章布局
0 無圖文章
1 單圖文章
3 多圖文章
*/
@TableField("type")
private Short type;
/**
* 圖文頻道ID
*/
@TableField("channel_id")
private Integer channelId;
@TableField("labels")
private String labels;
/**
* 創(chuàng)建時間
*/
@TableField("created_time")
private Date createdTime;
/**
* 提交時間
*/
@TableField("submited_time")
private Date submitedTime;
/**
* 當前狀態(tài)
0 草稿
1 提交(待審核)
2 審核失敗
3 人工審核
4 人工審核通過
8 審核通過(待發(fā)布)
9 已發(fā)布
*/
@TableField("status")
private Short status;
/**
* 定時發(fā)布時間,不定時則為空
*/
@TableField("publish_time")
private Date publishTime;
/**
* 拒絕理由
*/
@TableField("reason")
private String reason;
/**
* 發(fā)布庫文章ID
*/
@TableField("article_id")
private Long articleId;
/**
* //圖片用逗號分隔
*/
@TableField("images")
private String images;
@TableField("enable")
private Short enable;
//狀態(tài)枚舉類
@Alias("WmNewsStatus")
public enum Status{
NORMAL((short)0),SUBMIT((short)1),FAIL((short)2),ADMIN_AUTH((short)3),ADMIN_SUCCESS((short)4),SUCCESS((short)8),PUBLISHED((short)9);
short code;
Status(short code){
this.code = code;
}
public short getCode(){
return this.code;
}
}
}
3.2.3 接口定義
說明 | |
---|---|
接口路徑 | /api/v1/news/list |
請求方式 | POST |
參數(shù) | WmNewsPageReqDto |
響應結果 | ResponseResult |
WmNewsPageReqDto :
package com.heima.model.wemedia.dtos;
import com.heima.model.common.dtos.PageRequestDto;
import lombok.Data;
import java.util.Date;
@Data
public class WmNewsPageReqDto extends PageRequestDto {
/**
* 狀態(tài)
*/
private Short status;
/**
* 開始時間
*/
private Date beginPubDate;
/**
* 結束時間
*/
private Date endPubDate;
/**
* 所屬頻道ID
*/
private Integer channelId;
/**
* 關鍵字
*/
private String keyword;
}
ResponseResult :
{
"host": "null",
"code": 0,
"errorMessage": "操作成功",
"data": [
Object { ... },
Object { ... },
Object { ... }
],
"currentPage":1,
"size":10,
"total":21
}
3.2.4 功能實現(xiàn)
①:新增WmNewsController
package com.heima.wemedia.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/news")
public class WmNewsController {
@PostMapping("/list")
public ResponseResult findAll(@RequestBody WmNewsPageReqDto dto){
return null;
}
}
②:新增WmNewsMapper
package com.heima.wemedia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.wemedia.pojos.WmNews;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface WmNewsMapper extends BaseMapper<WmNews> {
}
③:新增WmNewsService
package com.heima.wemedia.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmNews;
public interface WmNewsService extends IService<WmNews> {
/**
* 查詢文章
* @param dto
* @return
*/
public ResponseResult findAll(WmNewsPageReqDto dto);
}
實現(xiàn)類:
package com.heima.wemedia.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
/**
* 查詢文章
* @param dto
* @return
*/
@Override
public ResponseResult findAll(WmNewsPageReqDto dto) {
//1.檢查參數(shù)
if(dto == null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//分頁參數(shù)檢查
dto.checkParam();
//獲取當前登錄人的信息
WmUser user = WmThreadLocalUtil.getUser();
if(user == null){
return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
}
//2.分頁條件查詢
IPage page = new Page(dto.getPage(),dto.getSize());
LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//狀態(tài)精確查詢
if(dto.getStatus() != null){
lambdaQueryWrapper.eq(WmNews::getStatus,dto.getStatus());
}
//頻道精確查詢
if(dto.getChannelId() != null){
lambdaQueryWrapper.eq(WmNews::getChannelId,dto.getChannelId());
}
//時間范圍查詢
if(dto.getBeginPubDate()!=null && dto.getEndPubDate()!=null){
lambdaQueryWrapper.between(WmNews::getPublishTime,dto.getBeginPubDate(),dto.getEndPubDate());
}
//關鍵字模糊查詢
if(StringUtils.isNotBlank(dto.getKeyword())){
lambdaQueryWrapper.like(WmNews::getTitle,dto.getKeyword());
}
//查詢當前登錄用戶的文章
lambdaQueryWrapper.eq(WmNews::getUserId,user.getId());
//發(fā)布時間倒序查詢
lambdaQueryWrapper.orderByDesc(WmNews::getCreatedTime);
page = page(page,lambdaQueryWrapper);
//3.結果返回
ResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),(int)page.getTotal());
responseResult.setData(page.getRecords());
return responseResult;
}
}
④:控制器
package com.heima.wemedia.controller.v1;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.wemedia.service.WmNewsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/news")
public class WmNewsController {
@Autowired
private WmNewsService wmNewsService;
@PostMapping("/list")
public ResponseResult findAll(@RequestBody WmNewsPageReqDto dto){
return wmNewsService.findAll(dto);
}
}
3.2.5 測試
啟動后端自媒體微服務和自媒體網(wǎng)關微服務,測試文章列表查詢
3.3 文章發(fā)布
3.3.1 需求分析
3.3.2 表結構分析
保存文章,除了需要wm_news表以外,還需要另外兩張表
wm_material 素材表
wm_news_material 文章素材關系表
其中wm_material和wm_news表的實體類已經(jīng)導入到了項目中,下面是wm_news_material表對應的實體類:
package com.heima.model.wemedia.pojos;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* <p>
* 自媒體圖文引用素材信息表
* </p>
*
* @author itheima
*/
@Data
@TableName("wm_news_material")
public class WmNewsMaterial implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主鍵
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 素材ID
*/
@TableField("material_id")
private Integer materialId;
/**
* 圖文ID
*/
@TableField("news_id")
private Integer newsId;
/**
* 引用類型
0 內容引用
1 主圖引用
*/
@TableField("type")
private Short type;
/**
* 引用排序
*/
@TableField("ord")
private Short ord;
}
3.3.3 實現(xiàn)思路分析
1.前端提交發(fā)布或保存為草稿
2.后臺判斷請求中是否包含了文章id
3.如果不包含id,則為新增
? 3.1 執(zhí)行新增文章的操作
? 3.2 關聯(lián)文章內容圖片與素材的關系
? 3.3 關聯(lián)文章封面圖片與素材的關系
4.如果包含了id,則為修改請求
? 4.1 刪除該文章與素材的所有關系
? 4.2 執(zhí)行修改操作
? 4.3 關聯(lián)文章內容圖片與素材的關系
? 4.4 關聯(lián)文章封面圖片與素材的關系
3.3.4 接口定義
說明 | |
---|---|
接口路徑 | /api/v1/channel/submit |
請求方式 | POST |
參數(shù) | WmNewsDto |
響應結果 | ResponseResult |
WmNewsDto
package com.heima.model.wemedia.dtos;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
public class WmNewsDto {
private Integer id;
/**
* 標題
*/
private String title;
/**
* 頻道id
*/
private Integer channelId;
/**
* 標簽
*/
private String labels;
/**
* 發(fā)布時間
*/
private Date publishTime;
/**
* 文章內容
*/
private String content;
/**
* 文章封面類型 0 無圖 1 單圖 3 多圖 -1 自動
*/
private Short type;
/**
* 提交時間
*/
private Date submitedTime;
/**
* 狀態(tài) 提交為1 草稿為0
*/
private Short status;
/**
* 封面圖片列表 多張圖以逗號隔開
*/
private List<String> images;
}
前端給傳遞過來的json數(shù)據(jù)格式為:
{
"title":"黑馬頭條項目背景",
"type":"1",//這個 0 是無圖 1 是單圖 3 是多圖 -1 是自動
"labels":"黑馬頭條",
"publishTime":"2020-03-14T11:35:49.000Z",
"channelId":1,
"images":[
"http://192.168.200.130/group1/M00/00/00/wKjIgl5swbGATaSAAAEPfZfx6Iw790.png"
],
"status":1,
"content":"[
{
"type":"text",
"value":"隨著智能手機的普及,人們更加習慣于通過手機來看新聞。由于生活節(jié)奏的加快,很多人只能利用碎片時間來獲取信息,因此,對于移動資訊客戶端的需求也越來越高。黑馬頭條項目正是在這樣背景下開發(fā)出來。黑馬頭條項目采用當下火熱的微服務+大數(shù)據(jù)技術架構實現(xiàn)。本項目主要著手于獲取最新最熱新聞資訊,通過大數(shù)據(jù)分析用戶喜好精確推送咨詢新聞"
},
{
"type":"image",
"value":"http://192.168.200.130/group1/M00/00/00/wKjIgl5swbGATaSAAAEPfZfx6Iw790.png"
}
]"
}
ResponseResult:
{
“code”:501,
“errorMessage”:“參數(shù)失效"
}
{
“code”:200,
“errorMessage”:“操作成功"
}
{
“code”:501,
“errorMessage”:“素材引用失效"
}
3.3.5 功能實現(xiàn)
①:在新增WmNewsController中新增方法
@PostMapping("/submit")
public ResponseResult submitNews(@RequestBody WmNewsDto dto){
return null;
}
②:新增WmNewsMaterialMapper類,文章與素材的關聯(lián)關系需要批量保存,索引需要定義mapper文件和對應的映射文件
package com.heima.wemedia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface WmNewsMaterialMapper extends BaseMapper<WmNewsMaterial> {
void saveRelations(@Param("materialIds") List<Integer> materialIds,@Param("newsId") Integer newsId, @Param("type")Short type);
}
WmNewsMaterialMapper.xml
<?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.wemedia.mapper.WmNewsMaterialMapper">
<insert id="saveRelations">
insert into wm_news_material (material_id,news_id,type,ord)
values
<foreach collection="materialIds" index="ord" item="mid" separator=",">
(#{mid},#{newsId},#{type},#{ord})
</foreach>
</insert>
</mapper>
③:常量類準備
package com.heima.common.constants;
public class WemediaConstants {
public static final Short COLLECT_MATERIAL = 1;//收藏
public static final Short CANCEL_COLLECT_MATERIAL = 0;//取消收藏
public static final String WM_NEWS_TYPE_IMAGE = "image";
public static final Short WM_NEWS_NONE_IMAGE = 0;
public static final Short WM_NEWS_SINGLE_IMAGE = 1;
public static final Short WM_NEWS_MANY_IMAGE = 3;
public static final Short WM_NEWS_TYPE_AUTO = -1;
public static final Short WM_CONTENT_REFERENCE = 0;
public static final Short WM_COVER_REFERENCE = 1;
}
④:在WmNewsService中新增方法
/**
* 發(fā)布文章或保存草稿
* @param dto
* @return
*/
public ResponseResult submitNews(WmNewsDto dto);
實現(xiàn)方法:
/**
* 發(fā)布修改文章或保存為草稿
* @param dto
* @return
*/
@Override
public ResponseResult submitNews(WmNewsDto dto) {
//0.條件判斷
if(dto == null || dto.getContent() == null){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//1.保存或修改文章
WmNews wmNews = new WmNews();
//屬性拷貝 屬性名詞和類型相同才能拷貝
BeanUtils.copyProperties(dto,wmNews);
//封面圖片 list---> string
if(dto.getImages() != null && dto.getImages().size() > 0){
//[1dddfsd.jpg,sdlfjldk.jpg]--> 1dddfsd.jpg,sdlfjldk.jpg
String imageStr = StringUtils.join(dto.getImages(), ",");
wmNews.setImages(imageStr);
}
//如果當前封面類型為自動 -1
if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
wmNews.setType(null);
}
saveOrUpdateWmNews(wmNews);
//2.判斷是否為草稿 如果為草稿結束當前方法
if(dto.getStatus().equals(WmNews.Status.NORMAL.getCode())){
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
//3.不是草稿,保存文章內容圖片與素材的關系
//獲取到文章內容中的圖片信息
List<String> materials = ectractUrlInfo(dto.getContent());
saveRelativeInfoForContent(materials,wmNews.getId());
//4.不是草稿,保存文章封面圖片與素材的關系,如果當前布局是自動,需要匹配封面圖片
saveRelativeInfoForCover(dto,wmNews,materials);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
/**
* 第一個功能:如果當前封面類型為自動,則設置封面類型的數(shù)據(jù)
* 匹配規(guī)則:
* 1,如果內容圖片大于等于1,小于3 單圖 type 1
* 2,如果內容圖片大于等于3 多圖 type 3
* 3,如果內容沒有圖片,無圖 type 0
*
* 第二個功能:保存封面圖片與素材的關系
* @param dto
* @param wmNews
* @param materials
*/
private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {
List<String> images = dto.getImages();
//如果當前封面類型為自動,則設置封面類型的數(shù)據(jù)
if(dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
//多圖
if(materials.size() >= 3){
wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
images = materials.stream().limit(3).collect(Collectors.toList());
}else if(materials.size() >= 1 && materials.size() < 3){
//單圖
wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
images = materials.stream().limit(1).collect(Collectors.toList());
}else {
//無圖
wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
}
//修改文章
if(images != null && images.size() > 0){
wmNews.setImages(StringUtils.join(images,","));
}
updateById(wmNews);
}
if(images != null && images.size() > 0){
saveRelativeInfo(images,wmNews.getId(),WemediaConstants.WM_COVER_REFERENCE);
}
}
/**
* 處理文章內容圖片與素材的關系
* @param materials
* @param newsId
*/
private void saveRelativeInfoForContent(List<String> materials, Integer newsId) {
saveRelativeInfo(materials,newsId,WemediaConstants.WM_CONTENT_REFERENCE);
}
@Autowired
private WmMaterialMapper wmMaterialMapper;
/**
* 保存文章圖片與素材的關系到數(shù)據(jù)庫中
* @param materials
* @param newsId
* @param type
*/
private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
if(materials!=null && !materials.isEmpty()){
//通過圖片的url查詢素材的id
List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));
//判斷素材是否有效
if(dbMaterials==null || dbMaterials.size() == 0){
//手動拋出異常 第一個功能:能夠提示調用者素材失效了,第二個功能,進行數(shù)據(jù)的回滾
throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
}
if(materials.size() != dbMaterials.size()){
throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
}
List<Integer> idList = dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
//批量保存
wmNewsMaterialMapper.saveRelations(idList,newsId,type);
}
}
/**
* 提取文章內容中的圖片信息
* @param content
* @return
*/
private List<String> ectractUrlInfo(String content) {
List<String> materials = new ArrayList<>();
List<Map> maps = JSON.parseArray(content, Map.class);
for (Map map : maps) {
if(map.get("type").equals("image")){
String imgUrl = (String) map.get("value");
materials.add(imgUrl);
}
}
return materials;
}
@Autowired
private WmNewsMaterialMapper wmNewsMaterialMapper;
/**
* 保存或修改文章
* @param wmNews
*/
private void saveOrUpdateWmNews(WmNews wmNews) {
//補全屬性
wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
wmNews.setCreatedTime(new Date());
wmNews.setSubmitedTime(new Date());
wmNews.setEnable((short)1);//默認上架
if(wmNews.getId() == null){
//保存
save(wmNews);
}else {
//修改
//刪除文章圖片與素材的關系
wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,wmNews.getId()));
updateById(wmNews);
}
}
④:控制器文章來源:http://www.zghlxwxcb.cn/news/detail-542287.html
@PostMapping("/submit")
public ResponseResult submitNews(@RequestBody WmNewsDto dto){
return wmNewsService.submitNews(dto);
}
3.3.6 測試
上傳一篇文章
文章新增成功
數(shù)據(jù)庫查詢成功
保存草稿,在關系表中并沒有生成數(shù)據(jù),無誤
測試一下自動,多圖
多圖無誤文章來源地址http://www.zghlxwxcb.cn/news/detail-542287.html
到了這里,關于2023黑馬頭條.微服務項目.跟學筆記(三)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!