2024/9/6黑马头条跟学笔记(三)

D3

内容介绍

image-20240905084455825

jdk8新特性,stream流,lambda表达式

自媒体前后端搭建

image-20240905084636308

步骤

image-20240905084700309

sql——

实体——

微服务拷贝,配置nacos——

image-20240905090609759
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.233.136:3306/leadnews_wemedia?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: 123456
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:mapper-locations: classpath*:mapper/*.xml# 设置别名包扫描路径,通过该属性可以给包中的类注册别名type-aliases-package: com.heima.model.media.pojos

自媒体微服务网关,nacos注册服务

image-20240905095136893
spring:cloud:gateway:globalcors:cors-configurations:'[/**]': # 匹配所有请求allowedOrigins: "*" #跨域处理 允许所有的域allowedMethods: # 支持的方法- GET- POST- PUT- DELETEroutes:# 平台管理- id: wemediauri: lb://leadnews-wemediapredicates:- Path=/wemedia/**filters:- StripPrefix= 1

启动自媒体微服务也网关微服务,进行测试

成功启动

image-20240905103254052

前端页面

nginx虚拟主机server 反代到服务器,和跳转静态资源 8802

下载前端压缩包放入文件夹

配置文件

upstream  heima-wemedia-gateway{server localhost:51602;
}server {listen 8802;location / {root  E:\区块链比赛\区块链赛前B站笔记++++\Spring系列\培训班项目文件\黑马头条\D1\资料\D1\前端项目\wemedia-web\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;   # 记录真实发出请求的客户端IPproxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息}
}

改完记得 nginx -s reload

http://localhost:8802/ 访问测试

image-20240905104141760

素材管理

图片上传

效果图
image-20240905104305264
表结构
image-20240905104337930
拷贝实体类
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;/*** 创建时间*/@TableField("created_time")private Date createdTime;}
思路

image-20240905104715430

前端请求——》网关拦截获取token存header——》拦截器将header信息存thread线程——》minio存文件拿url——》db记录url

为什么不在网关存threa? 不同微服务的上下文是隔离的 gateway和wemedia

编码思路

  1. 自媒体网关服务 从token里获取claimbody的id值,存到header

  2. 发送请求携带header到wemedia服务,设置拦截器,获取header存线程

    • 静态方法生成线程,设置set,clear,get 线程对象的静态方法,外部拦截器调用
    • 存完线程当拦截器的请求执行完毕也就是postHandle方法被触发时要清除线程,否则一个请求一个线程,100个用户每个用户发100个请求,100*100内存溢出
    • 拦截器要在webmvc里注册,拦截所有请求
  3. 上传图片接口

网关服务AuthorizeFilter过滤器
//获取用户id
Object userId = claimsBody.get("id");
//将用户id放到请求头中
ServerHttpRequest httpRequest = request.mutate().header("userId", userId.toString()).build();
// 1. 更新请求信息
// 在处理请求时,您可能需要在请求头中添加或修改某些信息(例如用户 ID)。
// 通过重置请求,您确保后续的处理逻辑(如过滤器、拦截器或控制器)能够获取到这些更新后的请求头。
exchange.mutate().request(httpRequest).build();
Utils模块新增工具类

新建thread包

image-20240905113340623

package com.heima.wemedia.interceptor;import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
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 {@Overridepublic 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;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("清理threadlocal...");WmThreadLocalUtil.clear();}
}

新建interceptor包

image-20240905113414769

package com.heima.wemedia.interceptor;import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
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 {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//得到header中的信息String userId = request.getHeader("userId");if(userId!=null){//把用户id存入threadloacl中WmUser wmUser = new WmUser();wmUser.setId(Integer.valueOf(userId));WmThreadLocalUtil.setUser(wmUser);log.info("wmTokenFilter设置用户信息到threadlocal中...");}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info("清理threadlocal...");WmThreadLocalUtil.clear();}
}
添加拦截器在webconfig

image-20240905113834647

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 {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new WmTokenInterceptor()).addPathPatterns("/**");}
}
上传接口+mapper+service

  • 前端传递过来的mutilparfile参数名不能修改为file或其他,不然报凑

  • 成功则回显url图片地址给img src get渲染访问

引入minio 依赖

wemedia服务

<dependencies><dependency><groupId>com.heima</groupId><artifactId>heima-file-starter</artifactId><version>1.0-SNAPSHOT</version></dependency>
</dependencies>

nacos登记minio的配置文件

minio:accessKey: miniosecretKey: minio123bucket: leadnewsendpoint: http://192.168.233.136:9000readPath: http://192.168.233.136:9000

image-20240905115058860

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> {
}
service
package com.heima.wemedia.service;public interface WmMaterialService extends IService<WmMaterial> {/*** 图片上传* @param multipartFile* @return*/public ResponseResult uploadPicture(MultipartFile multipartFile);}
impl
  1. 检查文件大小
  2. 上传minio(文件名字重写)
  3. 保存数据库
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 {@Autowiredprivate FileStorageService fileStorageService;/*** 图片上传* @param multipartFile* @return*/@Overridepublic ResponseResult uploadPicture(MultipartFile multipartFile) {//1.检查参数if(multipartFile == null || multipartFile.getSize() == 0){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}//2.上传图片到minIO中String fileName = UUID.randomUUID().toString().replace("-", "");//aa.jpgString 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.保存到数据库中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);}}
接口
package com.heima.wemedia.controller.v1;import com.heima.model.common.dtos.ResponseResult;
import com.heima.wemedia.service.WmMaterialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;@RestController
@RequestMapping("/api/v1/material")
public class WmMaterialController {@Autowiredprivate WmMaterialService wmMaterialService;@PostMapping("/upload_picture")public ResponseResult uploadPicture(MultipartFile multipartFile){return wmMaterialService.uploadPicture(multipartFile);}}

重启wemedia服务

启动前端项目进行测试

http://localhost:8802/

image-20240905190334399

图片查询

效果图

image-20240905190715221

接口定义

image-20240905190727885

实体

文件自带的,pageDto,后续用来给继承然后传达分页信息 list,默认值为page(1) size(10)

image-20240905191903089

model下的wemedia的dto增加

@Data
public class WmMaterialDto extends PageRequestDto {/*** 1 收藏* 0 未收藏*/private Short isCollection;
}
实现
  1. 核对前端传来的分页参数
  2. mp分页查询
  3. 返回结果
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.file.service.FileStorageService;
import com.heima.model.common.dtos.PageRequestDto;
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.WmMaterialDto;
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 {@Autowiredprivate FileStorageService fileStorageService;/*** 图片上传** @param multipartFile* @return*/@Overridepublic ResponseResult uploadPicture(MultipartFile multipartFile) {// 1.检查参数if (multipartFile == null || multipartFile.getSize() == 0) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}// 2.上传图片到minIO中String fileName = UUID.randomUUID().toString().replace("-", "");// aa.jpgString 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.保存到数据库中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);}@Overridepublic ResponseResult findList(WmMaterialDto dto) {// 1. 核对前端传来的分页参数dto.checkParam();// 2. mp分页查询IPage page = new Page(dto.getPage(), dto.getSize());// 判断是否收藏是收藏则 条件为所有为收藏的图片LambdaQueryWrapper<WmMaterial> wrapper = new LambdaQueryWrapper<>();if (dto.getIsCollection() != null && dto.getIsCollection() == 1) {wrapper.eq(WmMaterial::getIsCollection, dto.getIsCollection());}// 如果不是收藏则以用户来展示所有图片// 如果两种结果都需要以用户id查询,不同的是 是否查询收藏的条件,那么把共同条件放后,额外条件放前// 过五关斩六将思维wrapper.eq(WmMaterial::getUserId, WmThreadLocalUtil.getUser().getId());// 时间倒叙wrapper.orderByDesc(WmMaterial::getCreatedTime);page = page(page, wrapper);// 3. 返回结果// 多态,向上转型,获取更多可选字段,构建返回值对象ResponseResult result = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());result.setData(page.getRecords());return  result;}}
复制mp分页拦截器到引导类
   @Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}

image-20240905195947830

接口类
   @PostMapping("list")public ResponseResult list(@RequestBody WmMaterialDto wmMaterialDto){return wmMaterialService.findList(wmMaterialDto);}

byd token应该设置久一点的,还得重新登录

image-20240905200506122

频道列表查询

image-20240905200711287

表结构

image-20240905200811048

频道名,描述,默认,排序

实体

拷贝频道实体到model

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;/*** 创建时间*/@TableField("created_time")private Date createdTime;}

接口定义

image-20240905201122456

直接把所有频道给查出来,一点不带分页的噢

老规矩了,接口,service,impl,mapper 接着拷贝咯

接口

package com.heima.wemedia.controller.v1;import com.heima.model.common.dtos.ResponseResult;
import com.heima.wemedia.service.WmChannelService;
import org.checkerframework.checker.units.qual.A;
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 {@Autowiredprivate WmChannelService wmchannelService;@GetMapping("/channels")public ResponseResult findAll() {return wmchannelService.findAll();}
}

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();}

impl

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*/@Overridepublic ResponseResult findAll() {return ResponseResult.okResult(list());}
}

联调测试

刷新查看

image-20240905202400930 image-20240905202349732

文章列表

image-20240905202618474

表结构

image-20240905202640784

image-20240905202729549

image-20240905202755035

type,布局状态

status,文章状态

实体类

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;/*** 创建时间*/@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;}}}
知识点

image-20240905203007763

由于状态太多,1,2,3,4,5记不住对应啥属性,因此我们设置一个枚举类,属性code,,类似于NORMAL= new Status,有点像孙悟空,分身出来了多个,每个都有各自的code值

Dto前端查询类
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;/*** 所属频道ID*/private Integer channelId;/*** 关键字*/private String keyword;
}

接口定义

就是前端查询的表单参数

接口


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);}

impl

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*/@Overridepublic ResponseResult findAll(WmNewsPageReqDto dto) {//1.检查参数if(dto == null){return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);}//分页参数检查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<>();//状态精确查询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);//3.结果返回ResponseResult responseResult = new PageResponseResult(dto.getPage(),dto.getSize(),(int)page.getTotal());responseResult.setData(page.getRecords());return responseResult;}}

参数非空检验,分页初始化,获取登陆人信息,分页lambda构造器,状态频道精准——时间范围——关键字模糊查like查,发布时间倒序查,结果返回 分页三要素,和data

以上代码直接copy了,写吐了

联调测试

又得退出重登了,这里图片没有是以为minio是黑马的url

image-20240905210642100

发布文章

需求分析

image-20240905211023922

点T图标,文本编辑, 点图标图标,上传图片,还开源进行修改

定时发布

封面图

存草稿0,提交1

表结构

关系表存在的意义为,删除素材前先得把所有文章图片都删了,草稿就没事,直接删

思路

image-20240905212254347

有id是修改,删除关联关系,修改后判断是否是草稿,草稿直接存,不是就将内容里的新素材关联该文章

没id则新增,草稿保存,非草稿关联多素材,同时关联用户设置的封面素材,如果没设置则默认规则(推荐文章的第一张图)

接口定义

image-20240905212709380

接口定义-响应

image-20240905213036181

实体类

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;/*** 发布时间*/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;
}
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;}

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>

image-20240905215944332

mid素材id nid文章id

常量

common包

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;
}

AppHttpEnum增加如下

    // 自媒体文章错误 3501~3600MATERIASL_REFERENCE_FAIL(3501,"素材引用失效");

service

增加

    /*** 发布修改文章或保存为草稿* @param dto* @return*/public ResponseResult submitNews(WmNewsDto dto);

impl

  1. 内容为空返回错误

  2. 判断保存还是修改

  3. 判断是不是草稿,草稿则不提交,结束方法

  4. 不是草稿,保存素材与文章的关系

  5. 不是草稿,保存封面图片与文章的关系

具体内容为

  • 内容空值校验
  • 拷贝前端残缺内容(BeanUtils,相同属性名&&类型拷贝)
  • 存news的images封面用字符串。转前端LIst为String
  • 封面类型自动(-1) 根据内容的图片数量来设置封面类型 3张就三图,1,2张就单图,0张就无图类型
  • 根据id 来设置保存或修改,并额外的数据,userId,publishTime…
  • 草稿就结束,不是草稿就开始保存封面图或者内容图的引用关系
  • 抽取content内所有的内容图,根据文章id依次对应设置关系,当然要看素材库里有无该素材,失效或者素材与数据库不匹配则抛异常,最后根据素材对象获取id集合,依次添加关系
  • 封面图关系类型,同时由于前面删除了所有封面,将新的封面string 串也就是 url1,url2,url3保存,最后调用修改方法
  • 以上就是为了设置封面图片类型type,最后一个判断只要封面图片大于0则设置关系图,不大于0说明是无图,不管
/*** 发布修改文章或保存为草稿* @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---> stringif(dto.getImages() != null && dto.getImages().size() > 0){//[1dddfsd.jpg,sdlfjldk.jpg]-->   1dddfsd.jpg,sdlfjldk.jpgString imageStr = StringUtils.join(dto.getImages(), ",");wmNews.setImages(imageStr);}//如果当前封面类型为自动 -1if(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);}/*** 第一个功能:如果当前封面类型为自动,则设置封面类型的数据* 匹配规则:* 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();//如果当前封面类型为自动,则设置封面类型的数据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;/*** 保存文章图片与素材的关系到数据库中* @param materials* @param newsId* @param type*/
private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {if(materials!=null && !materials.isEmpty()){//通过图片的url查询素材的idList<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);}}/*** 提取文章内容中的图片信息* @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);}}

接口新增

@PostMapping("/submit")
public ResponseResult submitNews(@RequestBody WmNewsDto dto){return  wmNewsService.submitNews(dto);
}

联调测试

image-20240905234534497

image-20240905234613892

1为单图,3为多图 0为无图

image-202409052346440601

1为主图封面引用 0为内容引用

  • 设置引用类型type(封面主图,内容图)

  • 提前保存(没id增加,有id修改并删除所有关系(后续在根据修改后的内容增加关系))

  • 设置对应关系(素材未丢失情况,根据内容有几张,自动几张)

    (这里有两个setImage的操作好像一个是为了直接给草稿设置封面图,一个是为了给提交设置封面图,草稿的话直接返回所有封面图,提交的话只设置了根据内容摘取的前X张)
    然后再次进行修改图片即可(第二次是给提交而不是草稿内容去修改的)

  • saveRelativeInfo 校验素材库,保存关系图

  • saveRelativeInfoForContent 无业务操作,指定引用类型为内容引用

  • saveRelativeInfoForCover 自动/非自动 非自动就本来有type了, 自动就根据内容图片设置type,
    最后根据传上来的封面(非自动) 或是内容里扒出来的自动进行关系保存(自动)

  • 由于加了Transaction注解,一旦中途一个错,直接回滚

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/418892.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的火车订票管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JAVA语言 Spring Boot框架 工具&#xff1a;IDEA/Eclipse、Navicat、Tomcat 系统展示 首页 管理…

Android Jetpact Lifecycle 解析

认识 Lifecycle Lifecycle 是什么 Lifecycle 是 Jetpack 组件库中的一个生命周期感知型组件。在 Lifecycle 出现之前&#xff0c;需要手动从外部宿主&#xff08;如 Activity、Fragment 或自定义宿主&#xff09;中将生命周期事件分发到功能组件内部&#xff0c;这势必会造成…

SAM 2:分割图像和视频中的任何内容

文章目录 摘要1 引言2 相关工作3 任务&#xff1a;可提示视觉分割4 模型5 数据5.1 数据引擎5.2 SA-V数据集 6 零样本实验6.1 视频任务6.1.1 提示视频分割6.1.2 半监督视频对象分割6.1.3 公平性评估 6.2 图像任务 7 与半监督VOS的最新技术的比较8 数据和模型消融8.1 数据消融8.2…

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本 1.2 认识Nano版本 2 STM32F446U上移植RT-Thread 2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet 2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码 2.2.3.2 匹配端口 2.2.4 移植FinSH…

时间同步服务

多主机协作工作时&#xff0c;各个主机的时间同步很重要&#xff0c;时间不一致会造成很多重要应用的故障&#xff0c;如&#xff1a;加密协 议&#xff0c;日志&#xff0c;集群等。 利用NTP&#xff08;Network Time Protocol&#xff09; 协议使网络中的各个计算机时间达到…

OceanBase 4.x 存储引擎解析:如何让历史库场景成本降低50%+

据国际数据公司&#xff08;IDC&#xff09;的报告显示&#xff0c;预计到2025年&#xff0c;全球范围内每天将产生高达180ZB的庞大数据量&#xff0c;这一趋势预示着企业将面临着更加严峻的海量数据处理挑战。随着数据日渐庞大&#xff0c;一些存储系统会出现诸如存储空间扩展…

AF透明模式/虚拟网线模式组网部署

透明模式组网 实验拓扑 防火墙基本配置 接口配置 eth1 eth3 放通策略 1. 内网用户上班时间&#xff08;9:00-17:00&#xff09;不允许看视频、玩游戏及网上购物&#xff0c;其余时 间访问互联网不受限制&#xff1b;&#xff08;20 分&#xff09; 应用控制策略 2. 互联…

IBM Storwize V7000存储控制器故障节点报错574

背景&#xff1a;由于客户机房搬迁&#xff0c;需要下电迁移设备。该存储自2016年投入生产使用后&#xff0c;从未关过机&#xff0c;已正常运行七八年时间&#xff0c;期间只更换过硬盘&#xff0c;无其他硬件故障。 在GUI界面点击关闭系统后&#xff0c;大概等了40分钟&…

说一下解除docker限制内存警告

有时候docker要对容器使用的内存做出限制&#xff0c;通常的做法是使用参数 -m 例如&#xff1a; docker run -m 512M表示容器内存最大不能超过512M。 但这样做&#xff0c;在ubuntu会看到以下警告 WARNING: Your kernel does not support swap limit capabilitiesdocker官方…

从监控到智能:EasyCVR视频汇聚平台助力加油站安全监管升级转型

随着科技的不断进步&#xff0c;视频监控技术在各个行业的应用日益广泛&#xff0c;尤其在加油站这一关键领域&#xff0c;视频智能监管系统的应用显得尤为重要。TSINGSEE青犀视频EasyCVR视频汇聚平台作为一款基于“云-边-端”一体化架构的视频融合与AI智能分析平台&#xff0c…

JAVA读写Excel(jxl,poi,easyExcel)

目录 一、需求描述 二、具体操作Excel的常用方法 方法一&#xff1a; 使用jxl 方法二&#xff1a; POI 方法三&#xff1a;EasyExcel 三、总结 一、需求描述 前端有时候会传送 Excel 文件给后端&#xff08;Java&#xff09;去解析&#xff0c;那我们作为后端该如何实现…

Jenkins+Svn+Vue自动化构建部署前端项目(保姆级图文教程)

目录 介绍 准备工作 配置jenkins 构建部署任务 常见问题 介绍 在平常开发前端vue项目时,我们通常需要将vue项目进行打包构建,将打包好的dist目录下的静态文件上传到服务器上,但是这种繁琐的操作是比较浪费时间的,可以使用jenkins进行自动化构建部署前端vue 准备工作 准备…

AI模型的未来之路:全能与专精的博弈与共生

人工智能(AI)领域正迅速发展,伴随着技术的不断进步,AI模型的应用范围也在不断扩展。当前,AI模型的设计和使用面临两个主要趋势:全能型模型和专精型模型。这两者之间的博弈与共生将塑造未来的AI技术格局。本文将从以下七个方面探讨AI模型的未来之路,并提供实用的代码示例…

ROS1 + Realsense d455 固件安装+读取rostopic数据

目录 安装固件&#xff08;一定要匹配&#xff09;ROS1 wrapper 安装方法Realsense SDK 安装方法Realsense Firmware 安装方法 修改roslaunch配置文件&#xff0c;打开双目图像和IMU数据其他坑点参考链接 安装固件&#xff08;一定要匹配&#xff09; 如果你是使用ROS1获取rea…

Python数据分析-绘制图表

示例1&#xff1a; from pyecharts.charts import Bar # 柱状图 from pyecharts import options as optsfrom pyecharts.render import make_snapshotbar Bar() bar.add_xaxis([一月, 二月, 三月, 四月, 五月]) bar.add_yaxis("销售额", [10, 20, 15, 25, 30])# 配…

安卓framework单屏幕Display秒双/多屏互动相关需求改进-wms实战开发

背景 前面已经给学员朋友们分享过单屏秒变双屏的成果展示&#xff0c;具体详情可以点击这里&#xff1a; https://mp.weixin.qq.com/s/KdYTLMuXiBdjM0kZmYKzPg 一些vip学员朋友也纷纷求助马哥的实现patch代码&#xff0c;想用于公司的实战项目实现。但是在公司需求实现要求和…

Python(TensorFlow)和MATLAB及Java光学像差导图

&#x1f3af;要点 几何光线和波前像差计算入瞳和出瞳及近轴光学计算波前像差特征矩阵方法计算光谱反射率、透射率和吸光度透镜像差和绘制三阶光线像差图和横向剪切干涉图分析瞳孔平面焦平面和大气湍流建模神经网络光学像差计算透镜光线传播几何偏差计算像差和像散色差纠正对齐…

八、Maven总结

1.为什么要学习Maven&#xff1f; 2.Maven 也可以配华为云和腾讯云等。 3.IDEA整合Maven 4.IDEA基于Maven进行工程的构建 5.基于Maven进行依赖管理&#xff08;重点&#xff09; 6. Maven的依赖传递和依赖冲突 7. Maven工程继承和聚合 8.仓库及查找顺序

应用层协议Http

Http协议 1.1 什么是http协议 在进行网络通信时&#xff0c;应用层协议一般都是程序员自己写的&#xff0c;但是有一些大佬其实已经定义出了一些现成的应用层协议&#xff0c;例如&#xff1a;HTTP&#xff08;超文本传输协议&#xff09;、FTP&#xff08;文件传输协议&#…

SAP学习笔记 - 开发04 - Fiori UI5 开发环境搭建

上一章学习了 CDSView开发环境的搭建&#xff0c;以及CDSView相关的知识。 SAP学习笔记 - 开发03 - CDSView开发环境搭建&#xff0c;Eclipse中连接SAP&#xff0c;CDSView创建-CSDN博客 本章继续学习SAP开发相关的内容&#xff0c; - Fiori UI5的开发环境搭建 - 安装VSCode …