自媒体文章发布 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)测试