自媒体后台搭建
①:资料中找到heima-leadnews-wemedia.zip解压
拷贝到heima-leadnews-service工程下,并指定子模块
执行leadnews-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
图片上传的页面,首先是展示素材信息,可以点击图片上传,弹窗后可以上传图片
表结构
对应实体类:
/**
*
* 自媒体图文素材信息表
*
*/
@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;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
}
实现思路
网关进行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中新增工具类
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中新增拦截器
public class WmTokenInterceptor implements HandlerInterceptor {
/**
* 得到header中的用户信息,并且存入到当前线程中
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String userId = request.getHeader("userId");
if (userId != null) {
// 存入当前线程中
WmUser wmUser = new WmUser();
wmUser.setId(Integer.valueOf(userId));
WmThreadLocalUtil.setUser(wmUser);
}
return true;
}
/**
* 清理线程中的数据
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
WmThreadLocalUtil.clear();
}
}
接口定义
说明 | |
---|---|
接口路径 | /api/v1/material/upload_picture |
请求方式 | POST |
参数 | MultipartFile |
响应结果 | ResponseResult |
自媒体微服务集成heima-file-starter
①:导入heima-file-starter
<dependencies>
<dependency>
<groupId>com.heimagroupId>
<artifactId>heima-file-starterartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
dependencies>
②:在自媒体微服务的配置中心添加以下配置:
minio:
accessKey: minio
secretKey: minio123
bucket: leadnews
endpoint: http://192.168.200.130:9000
readPath: http://192.168.200.130:9000
实现代码
创建WmMaterialController
@RestController
@RequestMapping("/api/v1/material")
public class WmMaterialController {
@Autowired
private WmMaterialService wmMaterialService;
@PostMapping("/upload_picture")
public ResponseResult uploadPicture(MultipartFile multipartFile){
return wmMaterialService.uploadPicture(multipartFile);
}
}
创建WmMaterialMapper
@Mapper
public interface WmMaterialMapper extends BaseMapper<WmMaterial> {
}
创建WmMaterialServiceImpl,及其父类接口
@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) {
try {
// 1.检测参数
if (multipartFile == null && multipartFile.getSize() == 0) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2.上传图片到minIO中
String fileName = UUID.randomUUID().toString().replace("-", "");
// 获取图片的后缀名
String originalFilename = multipartFile.getOriginalFilename();
String postfix = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileId = fileStorageService.uploadImgFile("", fileName + postfix, multipartFile.getInputStream());
log.info("上传图片到MinIO中,field:{}", fileId);
// 3.把图片保存到数据库中
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);
} catch (IOException e) {
e.printStackTrace();
log.error("WmMaterialServiceImpl-上传文件失败");
}
return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
}
}
说明 | |
---|---|
接口路径 | /api/v1/material/list |
请求方式 | POST |
参数 | WmMaterialDto |
响应结果 | ResponseResult |
在WmMaterialController中,定义相关接口与方法
@PostMapping("/list")
public ResponseResult findList(@RequestBody WmMaterialDto dto){
return wmMaterialService.findList(dto);
}
在WmMaterialServiceImpl中,实现方法,及其父类接口
/**
* 素材列表查询
* @param dto
* @return
*/
@Override
public ResponseResult findList(WmMaterialDto dto) {
// 1.检测参数
dto.checkParam();
// 2.分页查询
IPage page = new Page(dto.getPage(), dto.getSize());
LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
// 2.1.设置查询条件
// 2.1.1.是否收藏
if (dto.getIsCollection() != null && dto.getIsCollection() == 1){
lqw.eq(WmMaterial::getIsCollection, dto.getIsCollection());
}
// 2.1.2按照用户查询
lqw.eq(WmMaterial::getUserId, WmThreadLocalUtil.getUser().getId());
// 2.1.3按照时间倒序查询
lqw.orderByDesc(WmMaterial::getCreatedTime);
page(page, lqw);
// 3.结果返回
ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
responseResult.setData(page.getRecords());
return responseResult;
}
说明 | |
---|---|
接口路径 | /api/v1/material/del_picture/{id} |
请求方式 | GET |
参数 | Integer id |
响应结果 | ResponseResult |
返回结果实例:
1.在WmMaterialController,实现相关接口方法
@GetMapping("/del_picture/{id}")
public ResponseResult deletePictureById(@PathVariable Integer id){
return wmMaterialService.deletePictureById(id);
}
2.定义WmMaterialServiceImpl,实现相关业务逻辑方法,及其父类接口
@Autowired
private WmNewsMaterialMapper wmNewsMaterialMapper;
/**
* 删除图片
* @param id
* @return
*/
@Override
public ResponseResult deletePictureById(Integer id) {
// 1.检查参数
if (id == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2.检查是否有文章在引用该图片
LambdaQueryWrapper<WmNewsMaterial> lqw = new LambdaQueryWrapper<>();
lqw.eq(WmNewsMaterial::getMaterialId, id);
List<WmNewsMaterial> wmNewsMaterials = wmNewsMaterialMapper.selectList(lqw);
if (wmNewsMaterials.size() > 0){
// 照片正在被引用,无法删除
return ResponseResult.errorResult(AppHttpCodeEnum.MATERIAL_IS_REFERENCE);
}
// 3.没有引用,可以删除
// 3.1.删除minIO中的照片数据
WmMaterial wmMaterial = getById(id);
fileStorageService.delete(wmMaterial.getUrl());
// 3.2.删除数据库中的照片数据
removeById(id);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
取消收藏
说明 | |
---|---|
接口路径 | /api/v1/material/cancel_collect/{id} |
请求方式 | GET |
参数 | Integer id |
响应结果 | ResponseResult |
收藏
说明 | |
---|---|
接口路径 | /api/v1/material/collect/{id} |
请求方式 | GET |
参数 | Integer id |
响应结果 | ResponseResult |
返回结果实例:
1.在WmMaterialController,实现相关接口方法
@GetMapping("/cancel_collect/{id}")
public ResponseResult cancelCollectPicture(@PathVariable Integer id){
return wmMaterialService.cancelCollectPicture(id);
}
@GetMapping("/collect/{id}")
public ResponseResult collectPicture(@PathVariable Integer id){
return wmMaterialService.collectPicture(id);
}
2.定义WmMaterialServiceImpl,实现相关业务逻辑方法,及其父类接口
/**
* 取消收藏照片
* @param id
* @return
*/
@Override
public ResponseResult cancelCollectPicture(Integer id) {
// 1.检查参数
if (id == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2.建立参数模型
WmMaterial wmMaterial = new WmMaterial();
wmMaterial.setId(id);
wmMaterial.setIsCollection(WemediaConstants.CANCEL_COLLECT_MATERIAL);
super.updateById(wmMaterial);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
/**
* 收藏照片
* @param id
* @return
*/
@Override
public ResponseResult collectPicture(Integer id) {
// 1.检查参数
if (id == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2.建立参数模型
WmMaterial wmMaterial = new WmMaterial();
wmMaterial.setId(id);
wmMaterial.setIsCollection(WemediaConstants.COLLECT_MATERIAL);
super.updateById(wmMaterial);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
表结构
wm_channel 频道信息表
对应实体类:
/**
* @author Kyle
* @date 2023/8/10 13:16
* 频道信息表
*/
@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;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
}
说明 | |
---|---|
接口路径 | /api/v1/channel/channels |
请求方式 | GET |
参数 | 无 |
响应结果 | ResponseResult |
1.定义controller,实现相关接口方法
@RestController
@RequestMapping("/api/v1/channel")
public class WmChannelController {
@Autowired
private WmChannelService wmChannelService;
@GetMapping("/channels")
public ResponseResult findAll(){
return wmChannelService.findAll();
}
}
2.定义WmChannelMapper
@Mapper
public interface WmChannelMapper extends BaseMapper<WmChannel> {
}
3.定义WmChannelServiceImpl,实现相关业务逻辑方法,及其父类接口
@Service
@Slf4j
@Transactional
public class WmChannelServiceImpl extends ServiceImpl<WmChannelMapper, WmChannel> implements WmChannelService {
/**
* 查询所有频道
* @return
*/
@Override
public ResponseResult findAll() {
return ResponseResult.okResult(list());
}
}
表结构分析
wm_news 自媒体文章表
对应实体类:
@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;
/**
* 创建时间
*/
@TableField("created_time")
private Date createdTime;
/**
* 提交时间
*/
@TableField("submited_time")
private Date submitedTime;
/**
* 当前状态
0 草稿
1 提交(待审核)
2 审核失败
3 人工审核
4 人工审核通过
8 审核通过(待发布)
9 已发布
*/
@TableField("status")
private Short status;
/**
* 定时发布时间,不定时则为空
*/
@TableField("publish_time")
private Date publishTime;
/**
* 拒绝理由
*/
@TableField("reason")
private String reason;
/**
* 发布库文章ID
*/
@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;
}
}
}
** ** | 说明 |
---|---|
接口路径 | /api/v1/news/list |
请求方式 | POST |
参数 | WmNewsPageReqDto |
响应结果 | ResponseResult |
WmNewsPageReqDto :
@Data
public class WmNewsPageReqDto extends PageRequestDto {
/**
* 状态
*/
private Short status;
/**
* 开始时间
*/
private Date beginPubDate;
/**
* 结束时间
*/
private Date endPubDate;
/**
* 所属频道ID
*/
private Integer channelId;
/**
* 关键字
*/
private String keyword;
}
1.定义controller,实现相关接口方法
@RestController
@RequestMapping("/api/v1/news")
public class WmNewsController {
@Autowired
private WmNewsService wmNewsService;
@PostMapping("/list")
public ResponseResult findList(@RequestBody WmNewsPageReqDto dto){
return wmNewsService.findList(dto);
}
}
2.定义WmNewsMapper
@Mapper
public interface WmNewsMapper extends BaseMapper<WmNews> {
}
3.定义WmNewsServiceImpl,实现相关业务逻辑方法,及其父类接口
@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
/**
* 条件查询文章列表
* @param dto
* @return
*/
@Override
public ResponseResult findList(WmNewsPageReqDto dto) {
// 1.检查参数
// 分页检查
dto.checkParam();
// 2.分页的条件查询
IPage page = new Page(dto.getPage(), dto.getSize());
LambdaQueryWrapper<WmNews> lqw = new LambdaQueryWrapper<>();
// 查询当前登录人的文章
lqw.eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId());
// 状态精确查询
lqw.eq(dto.getStatus() != null, WmNews::getStatus, dto.getStatus());
// 频道精确查询
lqw.eq(dto.getChannelId() != null, WmNews::getChannelId, dto.getChannelId());
// 时间范围查询
if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null){
lqw.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
}
// 关键字模糊查询
lqw.like(StringUtils.isNotBlank(dto.getKeyword()), WmNews::getTitle, dto.getKeyword());
// 按照发布时间倒序查询
lqw.orderByDesc(WmNews::getPublishTime);
page = page(page, lqw);
// 3.结果返回
ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
responseResult.setData(page.getRecords());
return responseResult;
}
}
表结构分析
wm_material 素材表
wm_news_material 文章素材关系表
wm_news_material表对应的实体类:
@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;
}
该功能为保存、修改(是否有id)、保存草稿的共有方法
1.前端提交发布或保存为草稿
2.后台判断请求中是否包含了文章id
3.如果不包含id,则为新增
3.1 执行新增文章的操作
3.2 关联文章内容图片与素材的关系
3.3 关联文章封面图片与素材的关系
4.如果包含了id,则为修改请求
4.1 删除该文章与素材的所有关系
4.2 执行修改操作
4.3 关联文章内容图片与素材的关系
4.4 关联文章封面图片与素材的关系
说明 | |
---|---|
接口路径 | /api/v1/news/submit |
请求方式 | POST |
参数 | WmNewsDto |
响应结果 | ResponseResult |
WmNewsDto 实体类
@Data
public class WmNewsDto {
private Integer id;
/**
* 标题
*/
private String title;
/**
* 频道id
*/
private Integer channelId;
/**
* 标签
*/
private String labels;
/**
* 发布时间
*/
private Date publishTime;
/**
* 文章内容
*/
private String content;
/**
* 文章封面类型 0 无图 1 单图 3 多图 -1 自动
*/
private Short type;
/**
* 提交时间
*/
private Date submitedTime;
/**
* 状态 提交为1 草稿为0
*/
private Short status;
/**
* 封面图片列表 多张图以逗号隔开
*/
private List<String> images;
}
1.定义WmNewsController,实现相关接口方法
@PostMapping("/submit")
public ResponseResult submitNews(@RequestBody WmNewsDto dto){
return wmNewsService.submitNews(dto);
}
2.定义WmNewsMaterialMapper,批量保存文章信息关系
@Mapper
public interface WmNewsMaterialMapper extends BaseMapper<WmNewsMaterial> {
/**
* 批量保存文章信息关系
* @param materialIds
* @param newsId
* @param type
*/
void saveRelations(@Param("materialIds") List<Integer> materialIds,@Param("newsId") Integer newsId, @Param("type")Short type);
}
3.创建WmNewsMaterialMapper.xml文件,动态SQL实现 批量保存文章信息关系
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>
4.定义 Wemedia常量类
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;
}
5.在WmNewsServiceImpl,实现相关业务逻辑方法,及其父类接口
@Autowired
private WmNewsMaterialMapper wmNewsMaterialMapper;
@Autowired
private WmMaterialMapper wmMaterialMapper;
/**
* 发布修改文章或保存为草稿
*
* @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){
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 = extractUrlInfo(dto.getContent());
saveRelativeInfoForContent(materials, wmNews.getId());
// 4.不是草稿,保存文章封面图片与素材的关系:如果当前布局是自动的,需要匹配封面图片
saveRelativeInfoForCover(dto, wmNews, materials);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
/**
* 第一个功能:如果当前封面类型为自动,则设置封面类型的数据
* 匹配规则:
* 1. 如果内容图片大于等于1,小于3 单图 type 1
* 2. 如果内容图片大于等于3 多图 type 3
* 2. 如果内容没有图片 无图 type 0
* 第二个功能:保存封面图片与素材的关系
* @param dto
* @param wmNews
* @param materials
*/
private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {
List<String> images = dto.getImages();
// 1.如果当前封面类型为自动,则设置封面类型的数据
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);
}
// 2.保存封面图片与素材的关系
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);
}
/**
* 保存文章图片与素材的关系到数据库中
* @param materials
* @param newsId
* @param type
*/
private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
if (materials == null && materials.isEmpty()){
throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
}
// 通过图片的url查询素材的id
LambdaQueryWrapper<WmMaterial> lqw = new LambdaQueryWrapper<>();
lqw.in(WmMaterial::getUrl, materials);
List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(lqw);
// 判断素材是否有效
if (dbMaterials == null || dbMaterials.size() == 0){
// 手动抛出异常
throw new CustomException(AppHttpCodeEnum.MATERIAL_REFERENCE_FAIL);
}
// 传递参数的数量 与 数据库查询的数量 不匹配
if (materials.size() != dbMaterials.size()){
// 手动抛出异常
throw new CustomException(AppHttpCodeEnum.MATERIAL_REFERENCE_FAIL);
}
List<Integer> idList = dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());
// 批量保存
wmNewsMaterialMapper.saveRelations(idList, newsId, type);
}
/**
* 提前文章内容中的图片信息
* @param content
* @return
*/
private List<String> extractUrlInfo(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;
}
/**
* 保存或修改文章
* @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 {
// 修改文章
// 删除文章图片与素材的关系
LambdaQueryWrapper<WmNewsMaterial> lqw = new LambdaQueryWrapper<>();
lqw.eq(WmNewsMaterial::getNewsId, wmNews.getId());
wmNewsMaterialMapper.delete(lqw);
updateById(wmNews);
}
}
接口描述
说明 | |
---|---|
接口路径 | /api/v1/news/one/{id} |
请求方式 | GET |
参数 | 文章id |
响应结果 | ResponseResult |
返回结果实例:
1.定义WmNewsController,实现相关接口方法
@GetMapping("/one/{id}")
public ResponseResult selectNewsById(@PathVariable Integer id){
return wmNewsService.selectNewsById(id);
}
2.在WmNewsServiceImpl,实现相关业务逻辑方法,及其父类接口
/**
* 查看文章详细
* @param id
* @return
*/
@Override
public ResponseResult selectNewsById(Integer id) {
// 检查参数
if (id == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
WmNews wmNews = getById(id);
return ResponseResult.okResult(wmNews);
}
接口描述
说明 | |
---|---|
接口路径 | /api/v1/news/del_news/{id} |
请求方式 | GET |
参数 | 文章id |
响应结果 | ResponseResult |
1.定义WmNewsController,实现相关接口方法
@GetMapping("/del_news/{id}}")
public ResponseResult deleteNewsById(@PathVariable Integer id){
return wmNewsService.deleteNewsById(id);
}
2.在WmNewsServiceImpl,实现相关业务逻辑方法,及其父类接口
/**
* 根据id删除文章
* @param id
* @return
*/
@Override
public ResponseResult deleteNewsById(Integer id) {
// 1.检查参数
if (id == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
WmNews wmNews = getById(id);
// 2.判断文章是否存在
if (wmNews == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
}
// 3.判断文章是否已发布
if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED)){
// 已发布文章,不能删除
return ResponseResult.errorResult(AppHttpCodeEnum.MATERIAL_IS_PUBLISHED);
}
// 4.可以删除文章
// 4.1.删除wm_news数据库
removeById(id);
// 4.2.删除wm_news_material数据库
LambdaQueryWrapper<WmNewsMaterial> lqw = new LambdaQueryWrapper<>();
lqw.eq(WmNewsMaterial::getNewsId, id);
wmNewsMaterialMapper.delete(lqw);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}
接口描述
说明 | |
---|---|
接口路径 | /api/v1/news/down_or_up |
请求方式 | POST |
参数 | WmNewsDto |
响应结果 | ResponseResult |
WmNewsDto
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DyDxyDFZ-1691677688774)(C:\Users\captaindeng\AppData\Roaming\Typora\typora-user-images\image-20230810172336769.png)]
1.定义WmNewsController,实现相关接口方法
@PostMapping("/down_or_up")
public ResponseResult newsDownOrUp(@RequestBody WmNewsDto dto){
return wmNewsService.newsDownOrUp(dto);
}
2.在WmNewsServiceImpl,实现相关业务逻辑方法,及其父类接口
/**
* 上下架文章
* @param dto
* @return
*/
@Override
public ResponseResult newsDownOrUp(WmNewsDto dto) {
// 1.检查参数
if (dto == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
// 2.判断文章是否存在
WmNews wmNews = getById(dto.getId());
if (wmNews == null) {
return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
}
// 3.文章存在,判断是否是发布状态:正在发布状态,不能操作上下架
if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED)){
return ResponseResult.errorResult(AppHttpCodeEnum.MATERIAL_IS_PUBLISHED);
}
// 4.可以操作上下架
wmNews.setEnable(dto.getEnable());
updateById(wmNews);
return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
}