自媒体文章发布 1)自媒体前后端搭建 1.1)后台搭建 
①:资料中找到heima-leadnews-wemedia.zip解压
 拷贝到heima-leadnews-service工程下,并指定子模块
 执行leadnews-wemedia.sql脚本
 添加对应的nacos配置
1 2 3 4 5 6 7 8 9 10 11 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  mybatis-plus:   mapper-locations:  classpath*:mapper/*.xml       type-aliases-package:  com.heima.model.media.pojos  
 
②:资料中找到heima-leadnews-wemedia-gateway.zip解压
 拷贝到heima-leadnews-gateway工程下,并指定子模块
 添加对应的nacos配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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  
 
③:在资料中找到类文件夹
 拷贝wemedia文件夹到heima-leadnews-model模块下的com.heima.model
1.2)前台搭建 
通过nginx的虚拟主机功能,使用同一个nginx访问多个项目
搭建步骤:
①:资料中找到wemedia-web.zip解压
②:在nginx中leadnews.conf目录中新增heima-leadnews-wemedia.conf文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 upstream  heima-wemedia-gateway{     server localhost:51602 ; } server { 	listen 8802 ; 	location / { 		root D:/workspace/ wemedia-web/; 		index index.html; 	} 	 	location ~/wemedia/ MEDIA/(.*) { 		proxy_pass http: 		proxy_set_header HOST $host;  # 不改变源请求头的值 		proxy_pass_request_body on;  #开启获取请求体 		proxy_pass_request_headers on;  #开启获取请求头 		proxy_set_header X-Real-IP $remote_addr;   # 记录真实发出请求的客户端IP 		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息 	} } 
 
③:启动nginx,启动自媒体微服务和对应网关
④:联调测试登录功能
2)自媒体素材管理 2.1)素材上传 2.2.1)需求分析 
图片上传的页面,首先是展示素材信息,可以点击图片上传,弹窗后可以上传图片
2.2.2)素材管理-图片上传-表结构 媒体图文素材信息表wm_material
对应实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 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;@Data @TableName("wm_material") public  class  WmMaterial  implements  Serializable   {    private  static  final  long  serialVersionUID = 1L ;          @TableId(value = "id", type = IdType.AUTO)      private  Integer id;          @TableField("user_id")      private  Integer userId;          @TableField("url")      private  String url;          @TableField("type")      private  Short type;          @TableField("is_collection")      private  Short isCollection;          @TableField("created_time")      private  Date createdTime; } 
 
2.2.3)实现思路 
①:前端发送上传图片请求,类型为MultipartFile
②:网关进行token解析后,把解析后的用户信息存储到header中
1 2 3 4 5 6 7 8 Object userId = claimsBody.get("id" ); ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {     httpHeaders.add("userId" , userId + "" ); }).build(); exchange.mutate().request(serverHttpRequest).build(); 
 
③:自媒体微服务使用拦截器获取到header中的的用户信息,并放入到threadlocal中
在heima-leadnews-utils中新增工具类
注意:需要从资料中找出WmUser实体类拷贝到model工程下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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<>();          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中新增拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 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  {                  String userId = request.getHeader("userId" );         Optional<String> optional = Optional.ofNullable(userId);         if (optional.isPresent()){                          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();     } } 
 
配置使拦截器生效,拦截所有的请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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查看具体功能实现)
⑤:把用户id和图片上的路径保存到素材表中——(2.2.5查看具体功能实现)
2.2.4)接口定义 
 
说明  
 
 
接口路径 
/api/v1/material/upload_picture 
 
请求方式 
POST 
 
参数 
MultipartFile 
 
响应结果 
ResponseResult 
 
MultipartFile  :Springmvc指定的文件接收类型
ResponseResult  :
成功需要回显图片,返回素材对象
1 2 3 4 5 6 7 8 9 10 11 12 13 {   "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"    } } 
 
失败:
2.2.5)自媒体微服务集成heima-file-starter ①:导入heima-file-starter
1 2 3 4 5 6 7 <dependencies >     <dependency >          <groupId > com.heima</groupId >          <artifactId > heima-file-starter</artifactId >          <version > 1.0-SNAPSHOT</version >      </dependency >  </dependencies > 
 
②:在自媒体微服务的配置中心添加以下配置:
1 2 3 4 5 6 minio:   accessKey:  minio    secretKey:  minio123    bucket:  leadnews    endpoint:  http://192.168.200.130:9000    readPath:  http://192.168.200.130:9000  
 
2.2.6)具体实现 ①:创建WmMaterialController
1 2 3 4 5 6 7 8 9 10 11 @RestController @RequestMapping("/api/v1/material") public  class  WmMaterialController   {    @PostMapping("/upload_picture")      public  ResponseResult uploadPicture (MultipartFile multipartFile)  {         return  null ;     } } 
 
②:mapper
1 2 3 4 5 6 7 8 9 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 >  {} 
 
③:业务层:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package  com.heima.wemedia.service;public  interface  WmMaterialService  extends  IService <WmMaterial >  {         public  ResponseResult uploadPicture (MultipartFile multipartFile)  ; } 
 
业务层实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 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;          @Override      public  ResponseResult uploadPicture (MultipartFile multipartFile)   {                  if (multipartFile == null  || multipartFile.getSize() == 0 ){             return  ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);         }                  String fileName = UUID.randomUUID().toString().replace("-" , "" );                  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-上传文件失败" );         }                  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);                  return  ResponseResult.okResult(wmMaterial);     } } 
 
④:控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RestController @RequestMapping("/api/v1/material") public  class  WmMaterialController   {    @Autowired      private  WmMaterialService wmMaterialService;     @PostMapping("/upload_picture")      public  ResponseResult uploadPicture (MultipartFile multipartFile)  {         return  wmMaterialService.uploadPicture(multipartFile);     } } 
 
⑤:测试
启动自媒体微服务和自媒体网关,使用前端项目进行测试
2.2)素材列表查询 2.2.1)接口定义 
 
说明  
 
 
接口路径 
/api/v1/material/list 
 
请求方式 
POST 
 
参数 
WmMaterialDto 
 
响应结果 
ResponseResult 
 
WmMaterialDto  :
1 2 3 4 5 6 7 8 9 @Data public  class  WmMaterialDto  extends  PageRequestDto   {         private  Short isCollection; } 
 
ResponseResult  :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 {   "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)功能实现 ①:在WmMaterialController类中新增方法
1 2 3 4 @PostMapping("/list") public  ResponseResult findList (@RequestBody  WmMaterialDto dto)  {    return  null ; } 
 
②:mapper已定义
③:业务层
在WmMaterialService中新增方法
1 2 3 4 5 6 public  ResponseResult findList ( WmMaterialDto dto)  ;
 
实现方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override public  ResponseResult findList (WmMaterialDto dto)   {         dto.checkParam();          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);          ResponseResult responseResult = new  PageResponseResult(dto.getPage(),dto.getSize(),(int )page.getTotal());     responseResult.setData(page.getRecords());     return  responseResult; } 
 
④:控制器:
1 2 3 4 @PostMapping("/list") public  ResponseResult findList (@RequestBody  WmMaterialDto dto)  {    return  wmMaterialService.findList(dto); } 
 
⑤:在自媒体引导类中天mybatis-plus的分页拦截器
1 2 3 4 5 6 @Bean public  MybatisPlusInterceptor mybatisPlusInterceptor ()   {    MybatisPlusInterceptor interceptor = new  MybatisPlusInterceptor();     interceptor.addInnerInterceptor(new  PaginationInnerInterceptor(DbType.MYSQL));     return  interceptor; } 
 
3)自媒体文章管理 3.1)查询所有频道 3.1.1)需求分析 
3.1.2)表结构 wm_channel 频道信息表
对应实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 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;@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;          @TableField("is_default")      private  Boolean isDefault;          @TableField("status")      private  Boolean status;          @TableField("ord")      private  Integer ord;          @TableField("created_time")      private  Date createdTime; } 
 
3.1.3)接口定义 
 
说明  
 
 
接口路径 
/api/v1/channel/channels 
 
请求方式 
POST 
 
参数 
无 
 
响应结果 
ResponseResult 
 
ResponseResult  :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 {   "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)功能实现 接口定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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
1 2 3 4 5 6 7 8 9 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 >  {         public  ResponseResult findAll ()  ; } 
 
实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 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   {         @Override      public  ResponseResult findAll ()   {         return  ResponseResult.okResult(list());     } } 
 
控制层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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)测试 3.2)查询自媒体文章 3.2.1)需求说明 
3.2.2)表结构分析 wm_news 自媒体文章表
对应实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 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;@Data @TableName("wm_news") public  class  WmNews  implements  Serializable   {    private  static  final  long  serialVersionUID = 1L ;          @TableId(value = "id", type = IdType.AUTO)      private  Integer id;          @TableField("user_id")      private  Integer userId;          @TableField("title")      private  String title;          @TableField("content")      private  String content;          @TableField("type")      private  Short type;          @TableField("channel_id")      private  Integer channelId;     @TableField("labels")      private  String labels;          @TableField("created_time")      private  Date createdTime;          @TableField("submited_time")      private  Date submitedTime;          @TableField("status")      private  Short status;          @TableField("publish_time")      private  Date publishTime;          @TableField("reason")      private  String reason;          @TableField("article_id")      private  Long articleId;          @TableField("images")      private  String images;     @TableField("enable")      private  Short enable;                @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 
 
参数 
WmNewsPageReqDto 
 
响应结果 
ResponseResult 
 
WmNewsPageReqDto  :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 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   {         private  Short status;          private  Date beginPubDate;          private  Date endPubDate;          private  Integer channelId;          private  String keyword; } 
 
ResponseResult  :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 {   "host" : "null" ,   "code" : 0 ,   "errorMessage" : "操作成功" ,   "data" : [     Object { ... },     Object { ... },     Object { ... }        ],   "currentPage" :1 ,   "size" :10 ,   "total" :21  } 
 
3.2.4)功能实现 ①:新增WmNewsController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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
1 2 3 4 5 6 7 8 9 10 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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 >  {         public  ResponseResult findAll (WmNewsPageReqDto dto)  ; } 
 
实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 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   {         @Override      public  ResponseResult findAll (WmNewsPageReqDto dto)   {                  if (dto == null ){             return  ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);         }                  dto.checkParam();                  WmUser user = WmThreadLocalUtil.getUser();         if (user == null ){             return  ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);         }                  IPage page = new  Page(dto.getPage(),dto.getSize());         LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new  LambdaQueryWrapper<>();                  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());                  lambdaQueryWrapper.orderByDesc(WmNews::getCreatedTime);         page = page(page,lambdaQueryWrapper);                  ResponseResult responseResult = new  PageResponseResult(dto.getPage(),dto.getSize(),(int )page.getTotal());         responseResult.setData(page.getRecords());         return  responseResult;     }     } 
 
④:控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 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)测试 启动后端自媒体微服务和自媒体网关微服务,测试文章列表查询
3.3)文章发布 3.3.1)需求分析 
3.3.2)表结构分析 保存文章,除了需要wm_news表以外,还需要另外两张表
wm_material 素材表
wm_news_material 文章素材关系表
其中wm_material和wm_news表的实体类已经导入到了项目中,下面是wm_news_material表对应的实体类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 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;@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;          @TableField("material_id")      private  Integer materialId;          @TableField("news_id")      private  Integer newsId;          @TableField("type")      private  Short type;          @TableField("ord")      private  Short ord; } 
 
3.3.3)实现思路分析 
1.前端提交发布或保存为草稿
2.后台判断请求中是否包含了文章id
3.如果不包含id,则为新增
    3.1 执行新增文章的操作
    3.2 关联文章内容图片与素材的关系
    3.3 关联文章封面图片与素材的关系
4.如果包含了id,则为修改请求
    4.1 删除该文章与素材的所有关系
    4.2 执行修改操作
    4.3 关联文章内容图片与素材的关系
    4.4 关联文章封面图片与素材的关系
3.3.4)接口定义 
 
说明  
 
 
接口路径 
/api/v1/channel/submit 
 
请求方式 
POST 
 
参数 
WmNewsDto 
 
响应结果 
ResponseResult 
 
WmNewsDto  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 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;           private  Integer channelId;           private  String labels;           private  Date publishTime;           private  String content;           private  Short type;           private  Date submitedTime;            private  Short status;                 private  List<String> images; } 
 
前端给传递过来的json数据格式为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 {     "title" :"黑马头条项目背景" ,     "type" :"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":" 随着智能手机的普及,人们更加习惯于通过手机来看新闻。由于生活节奏的加快,很多人只能利用碎片时间来获取信息,因此,对于移动资讯客户端的需求也越来越高。黑马头条项目正是在这样背景下开发出来。黑马头条项目采用当下火热的微服务+大数据技术架构实现。本项目主要着手于获取最新最热新闻资讯,通过大数据分析用户喜好精确推送咨询新闻"     },     {         " type":" image",         " value":" http:    } ]"  } 
 
ResponseResult:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 {     “code”:501 ,     “errorMessage”:“参数失效"  } {     “code”:200,     “errorMessage”:“操作成功" } {     “code”:501 ,     “errorMessage”:“素材引用失效"  } 
 
3.3.5)功能实现 ①:在新增WmNewsController中新增方法
1 2 3 4 @PostMapping("/submit" ) public ResponseResult submitNews(@RequestBody WmNewsDto dto){     return null; } 
 
②:新增WmNewsMaterialMapper类,文章与素材的关联关系需要批量保存,索引需要定义mapper文件和对应的映射文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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 > 
 
③:常量类准备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 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中新增方法
1 2 3 4 5 6 public  ResponseResult submitNews (WmNewsDto dto)  ;
 
实现方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 @Override public  ResponseResult submitNews (WmNewsDto dto)   {         if (dto == null  || dto.getContent() == null ){         return  ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);     }          WmNews wmNews = new  WmNews();          BeanUtils.copyProperties(dto,wmNews);          if (dto.getImages() != null  && dto.getImages().size() > 0 ){                  String imageStr = StringUtils.join(dto.getImages(), "," );         wmNews.setImages(imageStr);     }          if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){         wmNews.setType(null );     }     saveOrUpdateWmNews(wmNews);          if (dto.getStatus().equals(WmNews.Status.NORMAL.getCode())){         return  ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);     }               List<String> materials =  ectractUrlInfo(dto.getContent());     saveRelativeInfoForContent(materials,wmNews.getId());          saveRelativeInfoForCover(dto,wmNews,materials);     return  ResponseResult.okResult(AppHttpCodeEnum.SUCCESS); } private  void  saveRelativeInfoForCover (WmNewsDto dto, WmNews wmNews, List<String> materials)   {    List<String> images = dto.getImages();          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);     } } private  void  saveRelativeInfoForContent (List<String> materials, Integer newsId)   {    saveRelativeInfo(materials,newsId,WemediaConstants.WM_CONTENT_REFERENCE); } @Autowired private  WmMaterialMapper wmMaterialMapper;private  void  saveRelativeInfo (List<String> materials, Integer newsId, Short type)   {    if (materials!=null  && !materials.isEmpty()){                  List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));                  if (dbMaterials==null  || dbMaterials.size() == 0 ){                          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);     } } 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;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);     } } 
 
④:控制器
1 2 3 4 @PostMapping("/submit") public  ResponseResult submitNews (@RequestBody  WmNewsDto dto)  {    return   wmNewsService.submitNews(dto); } 
 
3.3.6)测试