SpringCloud微服务项目实战 - 4.自媒体平台(博主后台)

news2025/4/8 13:20:56

“我读过很多书,但后来大部分都忘记了,你说这样的阅读究竟有什么意义?”
“当我还是个孩子时,我吃过很多食物,现在已经记不起来吃过什么了。但可以肯定的是,它们中的一部分已经长成我的骨头和肉。”

在这里插入图片描述



系列文章目录

  1. 项目搭建
  2. App登录及网关
  3. App文章
  4. 自媒体平台(博主后台)

文章目录

  • 系列文章目录
  • 一、前后端搭建
    • 1. 后台搭建
      • ⑴. 导入文章数据库
      • ⑵. 实体类
        • ①. 自媒体用户信息
        • ②. 自媒体登录
      • ⑶. 导入媒体微服务
      • ⑷. Nacos配置
      • ⑸. 导入媒体网关
      • ⑹. Nacos配置
    • 2. 前台搭建
      • ⑴. 导入nginx
      • ⑵. 配置nginx.conf文件
      • ⑶. 测试
  • 二、自媒体素材管理
    • 1. 图片上传
      • ⑴. 实体类
      • ⑵. 网关
      • ⑶. 拦截器
        • ①. 线程公共方法
        • ②. 过滤器
        • ③. 自定义拦截器
      • ⑷. 接口定义
        • ①. 基础搭建
          • Ⅰ. Controller
          • Ⅱ. Mapper
          • Ⅲ. Service
          • Ⅳ. Impl
        • ②. 业务层
        • ③. 配置
          • Ⅰ. 引入minio
          • Ⅱ. Nacos配置
        • ④. 业务层实现类
        • ⑤. Controller
      • ⑸. 测试
    • 2. 图片列表
      • ⑴. Dto
      • ⑵. Controller
      • ⑶. Service
      • ⑷. ServiceImpl
      • ⑸. 引入 MyBatisPlus 插件
      • ⑹. Controller
      • ⑺. 测试
  • 三、文章管理
    • 1. 频道列表查询
      • ⑴. 接口定义
      • ⑵. 实体类
      • ⑶. 基础搭建
        • ①. Controller
        • ②. Mapper
        • ③. Service
        • ④. ServiceImpl
      • ⑷. Service
      • ⑸. ServiceImpl
      • ⑹. Controller
      • ⑺. 测试
    • 2. 文章列表查询
      • ⑴. 表结构分析
      • ⑵. 接口定义
        • ①. 接口说明
        • ②. Dto
      • ⑶. 基础搭建
        • ①. Controller
        • ②. Mapper
        • ③. Service
        • ④. ServiceImpl
      • ⑷. Service
      • ⑸. ServiceImpl
      • ⑹. Controller
      • ⑺. 测试
    • 3. 文章发布
      • ⑴. 需求分析
      • ⑵. 表结构分析
        • ①. 表关系
        • ②. 实体类
      • ⑶. 思路分析
      • ⑷. 接口定义
        • ①. 接口说明
        • ②. Dto
      • ⑸. 基础搭建
        • ①. Controller
        • ②. Mapper
        • ③. Mapper配置文件
        • ④. Service
        • ⑤. ServiceImpl
      • ⑹. 定义常量
      • ⑺. 自定义提示信息
      • ⑻. ServiceImpl(内容图片与素材)
      • ⑼. Controller
      • ⑽. 测试
        • ①. 单图
          • Ⅰ. 发布文章
          • Ⅱ. 内容列表
          • Ⅲ. 数据库
        • ②. 草稿
          • Ⅰ. 发布文章
          • Ⅱ. 内容列表
          • Ⅲ. 数据库
        • ③. 自动
          • Ⅰ. 发布文章
          • Ⅱ. 内容列表
          • Ⅲ. 数据库


一、前后端搭建

1. 后台搭建

⑴. 导入文章数据库

sql链接: https://pan.baidu.com/s/18xmuhipX1EKuPLa3clC47g?pwd=abcd
在这里插入图片描述

创建同名空数据库 => localhost右键 => 运行SQL文件 => 刷新
在这里插入图片描述


⑵. 实体类

①. 自媒体用户信息

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/pojos/WmUser.java 文件:

/**
 * <p>
 * 自媒体用户信息表
 * </p>
 *
 * @author itheima
 */
@Data
@TableName("wm_user")
public class WmUser implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @TableField("ap_user_id")
    private Integer apUserId;

    @TableField("ap_author_id")
    private Integer apAuthorId;

    /**
     * 登录用户名
     */
    @TableField("name")
    private String name;

    /**
     * 登录密码
     */
    @TableField("password")
    private String password;

    /**
     * 盐
     */
    @TableField("salt")
    private String salt;

    /**
     * 昵称
     */
    @TableField("nickname")
    private String nickname;

    /**
     * 头像
     */
    @TableField("image")
    private String image;

    /**
     * 归属地
     */
    @TableField("location")
    private String location;

    /**
     * 手机号
     */
    @TableField("phone")
    private String phone;

    /**
     * 状态
            0 暂时不可用
            1 永久不可用
            9 正常可用
     */
    @TableField("status")
    private Integer status;

    /**
     * 邮箱
     */
    @TableField("email")
    private String email;

    /**
     * 账号类型
            0 个人 
            1 企业
            2 子账号
     */
    @TableField("type")
    private Integer type;

    /**
     * 运营评分
     */
    @TableField("score")
    private Integer score;

    /**
     * 最后一次登录时间
     */
    @TableField("login_time")
    private Date loginTime;

    /**
     * 创建时间
     */
    @TableField("created_time")
    private Date createdTime;

}

②. 自媒体登录

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/dtos/WmLoginDto.java 文件:

@Data
public class WmLoginDto {

    /**
     * 用户名
     */
    private String name;
    /**
     * 密码
     */
    private String password;
}

⑶. 导入媒体微服务

微服务资源: https://pan.baidu.com/s/1JfRzXiawYo1Iixf8b2gaTw?pwd=abcd
在这里插入图片描述

解压至 leadnews-heima-service 目录下

编辑 heima-leadnews-service/pom.xml pom依赖:

    <modules>
        <module>heima-leadnews-user</module>
        <!--文章模块-->
        <module>heima-leadnews-article</module>
        <!--自媒体模块-->
        <module>heima-leadnews-wemedia</module>
    </modules>

刷新Maven

⑷. Nacos配置

新建 leadnews-wemedia 配置:

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: 123456
# 设置Mapper接口所对应的XML文件位置,如果你在Mapper接口中有自定义方法,需要进行该配置
mybatis-plus:
  mapper-locations: classpath*:mapper/*.xml
  # 设置别名包扫描路径,通过该属性可以给包中的类注册别名
  type-aliases-package: com.heima.model.media.pojos

⑸. 导入媒体网关

微服务资源: https://pan.baidu.com/s/1PusVjATzWk-Z299PTcQAAQ?pwd=abcd
在这里插入图片描述
解压至 heima-leadnews-gateway 目录下

编辑 heima-leadnews-gateway/pom.xml pom依赖:

    <modules>
        <module>heima-leadnews-app-gateway</module>
        <module>heima-leadnews-wemedia-gateway</module>
    </modules>

刷新Maven

⑹. Nacos配置

新建 leadnews-wemedia-gateway 配置:

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

2. 前台搭建

⑴. 导入nginx

资源链接: https://pan.baidu.com/s/1TAwwtNcO7gWOUQOIvpgU3w?pwd=abcd

解压至 nginx 目录下(同APP端nginx)


⑵. 配置nginx.conf文件

(nginx包中)新建 D:\code\hm\leadnews\config\nginx-1.18.0\conf\leadnews.conf\heima-leadnews-wemedia.conf 文件:

upstream  heima-wemedia-gateway{
    server localhost:51602; # 根据网关去做的请求
}

server {
	listen 8802;
	location / {
		root D:/code/hm/leadnews/config/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;   # 记录真实发出请求的客户端IP
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  #记录代理信息
	}
}

⑶. 测试

启动nginx,启动自媒体微服务和自媒体网关,自媒体地址: http://localhost:8802/#/login
在这里插入图片描述




二、自媒体素材管理

1. 图片上传

⑴. 实体类

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/pojos/WmMaterial.java 文件:

/**
 * <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;

}

⑵. 网关

编辑 heima-leadnews-gateway/heima-leadnews-wemedia-gateway/src/main/java/com/heima/wemedia/gateway/filter/AuthorizeFilter.java 文件:

        //5.判断token是否有效
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            //是否是过期
            int result = AppJwtUtil.verifyToken(claimsBody);
            if(result == 1 || result  == 2){
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

            // 网关: 进行token解析后,把解析后的用户信息存储到header中
            // 获取用户信息
            Object userId = claimsBody.get("id");

            // 存放到header中
            ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
                httpHeaders.add("userId", userId + "");
            }).build();

            // 重置请求
            exchange.mutate().request(serverHttpRequest);

        } catch (Exception e) {
            e.printStackTrace();
        }

⑶. 拦截器

①. 线程公共方法

新建 heima-leadnews-utils/src/main/java/com/heima/utils/thread/WmThreadLocalUtils.java 文件:

public class WmThreadLocalUtils {

    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-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/interceptor/WmTokenInterceptor.java 文件:

public class WmTokenInterceptor implements HandlerInterceptor {

    /**
     * 前置处理器: 得到hedaer中的用户信息, 并且存入到当前线程中
     * @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));
            WmThreadLocalUtils.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 {
        WmThreadLocalUtils.clear();
    }
}

③. 自定义拦截器

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/config/WebMvcConfig.java 文件:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    /**
     * 添加自定义拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new WmTokenInterceptor()).addPathPatterns("/**");
    }
}

⑷. 接口定义

说明
接口路径/api/v1/material/upload_picture
请求方式POST
参数MultipartFile
响应结果ResponseResult

①. 基础搭建

Ⅰ. Controller

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmMaterialController.java 文件:

@RestController
@RequestMapping("/api/v1/material")
public class WmMaterialController {

    @PostMapping("upload_picture")
    public ResponseResult uploadPicture(MultipartFile multipartFile) {
        return null;
    }
}
Ⅱ. Mapper

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/mapper/WmMaterialMapper.java 文件:

@Mapper
public interface WmMaterialMapper extends BaseMapper<WmMaterial> {
}
Ⅲ. Service

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmMaterialService.java 文件:

public interface WmMaterialService extends IService<WmMaterial> {
}
Ⅳ. Impl

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmMaterialServiceImpl.java 文件:

@Slf4j
@Service
@Transactional
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {
}

②. 业务层

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmMaterialService.java 文件:

public interface WmMaterialService extends IService<WmMaterial> {

    /**
     * 图片上传
     * @param multipartFile
     * @return
     */
    public ResponseResult uploadPicture(MultipartFile multipartFile);
}

③. 配置

Ⅰ. 引入minio

编辑 heima-leadnews-service/heima-leadnews-wemedia/pom.xml 配置文件:

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

编辑 leadnews-wemedia 配置:

minio:
  accessKey: minio
  secretKey: minio123
  bucket: leadnews
  endpoint: http://192.168.200.130:9000
  readPath: http://192.168.200.130:9000

④. 业务层实现类

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmMaterialServiceImpl.java 文件:

@Slf4j
@Service
@Transactional
public class WmMaterialServiceImpl extends ServiceImpl<WmMaterialMapper, WmMaterial> implements WmMaterialService {

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 图片上传
     * @param multipartFile
     * @return
     */
    @Override
    public ResponseResult uploadPicture(MultipartFile multipartFile) {

        // 1. 检查参数
        if(multipartFile == null || multipartFile.getSize() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID); // 无效参数
        }

        // 2. 上传图片到minio中
        String fileName = UUID.randomUUID().toString().replace("-", "");
        // aa.kpg
        String originalFilename = multipartFile.getOriginalFilename();
        String postfix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileId = null;
        try {
            fileId = fileStorageService.uploadImgFile("", fileName + postfix, multipartFile.getInputStream());
            log.info("上传图片到minio中, fileId{}", fileId);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("WmMaterialServiceImpl-上传图片失败");
        }

        // 3. 储存到数据库中
        WmMaterial wmMaterial = new WmMaterial();
        wmMaterial.setUserId(WmThreadLocalUtils.getUser().getId());
        wmMaterial.setUrl(fileId);
        wmMaterial.setIsCollection((short)0);
        wmMaterial.setType((short)0);
        wmMaterial.setCreatedTime(new Date());
        save(wmMaterial);

        // 4. 返回结果
        return ResponseResult.okResult(wmMaterial);
    }
}


⑤. Controller

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmMaterialServiceImpl.java 文件:

@RestController
@RequestMapping("/api/v1/material")
public class WmMaterialController {

    @Autowired
    private WmMaterialService wmMaterialService;

    @PostMapping("upload_picture")
    public ResponseResult uploadPicture(MultipartFile multipartFile) {
        return wmMaterialService.uploadPicture(multipartFile);
    }
}

⑸. 测试

启动nginx,启动自媒体微服务和自媒体网关,自媒体地址: http://localhost:8802/#/login
在这里插入图片描述

查看 数据库,新增了上传的素材图片
在这里插入图片描述



2. 图片列表

说明
接口路径/api/v1/material/list
请求方式POST
参数WmMaterialDto
响应结果ResponseResult

⑴. Dto

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/dtos/WmMaterialDto.java 文件:

@Data
public class WmMaterialDto extends PageRequestDto {

    /**
     * 0 未收藏 1 已收藏
     */
    private Short isCollection;
}

⑵. Controller

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmMaterialController.java 文件:

    @PostMapping("/list")
    public ResponseResult findList(@RequestBody WmMaterialDto dto) {
        return null;
    }

⑶. Service

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmMaterialService.java 文件:

    /**
     * 图片列表
     * @param dto
     * @return
     */
    public ResponseResult findList(WmMaterialDto dto);

⑷. ServiceImpl

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmMaterialServiceImpl.java 文件:

    /**
     * 素材列表查询
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(WmMaterialDto dto) {

        // 1. 检查参数
        dto.checkParam();

        // 2. 分页查询
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmMaterial> lambdaQueryWrapper = new LambdaQueryWrapper<>();

        // 是否收藏
        if(dto.getIsCollection() != null && dto.getIsCollection() == 1) {
            lambdaQueryWrapper.eq(WmMaterial::getIsCollection, dto.getIsCollection());
        }

        // 按照用户查询
        lambdaQueryWrapper.eq(WmMaterial::getUserId, WmThreadLocalUtils.getUser().getId());

        // 按时间倒序
        lambdaQueryWrapper.orderByDesc(WmMaterial::getCreatedTime);

        page = page(page, lambdaQueryWrapper);

        // 3. 返回结果
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());
        return responseResult;
    }

⑸. 引入 MyBatisPlus 插件

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/WemediaApplication.java 文件:

    // myBatisPlus插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

⑹. Controller

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmMaterialController.java 文件:

    @PostMapping("/list")
    public ResponseResult findList(@RequestBody WmMaterialDto dto) {
        return wmMaterialService.findList(dto);
    }

⑺. 测试

启动nginx,启动自媒体微服务和自媒体网关,自媒体地址: http://localhost:8802/#/login
在这里插入图片描述
在这里插入图片描述




三、文章管理

1. 频道列表查询

⑴. 接口定义

说明
接口路径/api/v1/channel/channels
请求方式POST
参数
响应结果ResponseResult

ResponseResult :

{
  "host": "null",
  "code": 0,
  "errorMessage": "操作成功",
  "data": [
    {
      "id": 4,
      "name": "java",
      "description": "java",
      "isDefault": true,
      "status": false,
      "ord": 3,
      "createdTime": "2019-08-16T10:55:41.000+0000"
    },
    Object {  ... },
    Object {  ... }
  ]
}

⑵. 实体类

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/pojos/WmChannel.java 文件:

/**
 * <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;

}

⑶. 基础搭建

①. Controller

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmChannelController.java 文件:

@RestController
@RequestMapping("/api/v1/channel")
public class WmChannelController {

    @GetMapping("/channels")
    public ResponseResult findAll() {
        return null;
    }
}

②. Mapper

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/mapper/WmChannelMapper.java 文件:

@Mapper
public interface WmChannelMapper extends BaseMapper<WmChannel> {
}

③. Service

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmChannelService.java 文件:

public interface WmChannelService extends IService<WmChannel> {
}

④. ServiceImpl

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmChannelServiceImpl.java 文件:

@Service
@Transactional
@Slf4j
public class WmChannelServiceImpl extends ServiceImpl<WmChannelMapper, WmChannel> implements WmChannelService {
}

⑷. Service

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmChannelService.java 文件:

public interface WmChannelService extends IService<WmChannel> {

    /**
     * 查询所有频道
     * @return
     */
    public ResponseResult findAll();
}

⑸. ServiceImpl

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmChannelServiceImpl.java 文件:

@Service
@Transactional
@Slf4j
public class WmChannelServiceImpl extends ServiceImpl<WmChannelMapper, WmChannel> implements WmChannelService {

    /**
     * 查询所有频道
     * @return
     */
    @Override
    public ResponseResult findAll() {
        return ResponseResult.okResult(list());
    }
}

⑹. Controller

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmChannelController.java 文件:

@RestController
@RequestMapping("/api/v1/channel")
public class WmChannelController {

    @Autowired
    private WmChannelService wmChannelService;

    @GetMapping("/channels")
    public ResponseResult findAll() {
        return wmChannelService.findAll();
    }
}

⑺. 测试

启动nginx,启动自媒体微服务和自媒体网关,自媒体地址: http://localhost:8802/#/login
在这里插入图片描述



2. 文章列表查询

⑴. 表结构分析

在这里插入图片描述

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/pojos/WmNews.java 对应实体类:

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

}

⑵. 接口定义

①. 接口说明

说明
接口路径/api/v1/news/list
请求方式POST
参数WmNewsPageReqDto
响应结果ResponseResult

ResponseResult :

{
  "host": "null",
  "code": 0,
  "errorMessage": "操作成功",
  "data": [
    Object { ... },
    Object { ... },
    Object { ... }
    
  ],
  "currentPage":1,
  "size":10,
  "total":21
}

②. Dto

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/dtos/WmNewsPageReqDto.java 文件:

@Data
public class WmNewsPageReqDto extends PageRequestDto {

    /**
     * 状态
     */
    private Short status;
    /**
     * 开始时间
     */
    private Date beginPubDate;
    /**
     * 结束时间
     */
    private Date endPubDate;
    /**
     * 所属频道ID
     */
    private Integer channelId;
    /**
     * 关键字
     */
    private String keyword;
}

⑶. 基础搭建

①. Controller

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmNewsController.java 文件:

@RestController
@RequestMapping("/api/v1/news")
public class WmNewsController {

    @PostMapping("/list")
    public ResponseResult findList(@RequestBody WmNewsPageReqDto dto) {
        return null;
    }
}

②. Mapper

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/mapper/WmNewsMapper.java 文件:

@Mapper
public interface WmNewsMapper extends BaseMapper<WmNews> {
}

③. Service

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmNewsService.java 文件:

public interface WmNewsService extends IService<WmNews> {
}

④. ServiceImpl

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmNewsServiceImpl.java 文件:

@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
}

⑷. Service

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmNewsService.java 文件:

    /**
     * 条件查询文章列表
     * @param dto
     * @return
     */
    public ResponseResult findList(WmNewsPageReqDto dto);

⑸. ServiceImpl

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmNewsServiceImpl.java 文件:

@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> lambdaQueryWrapper = new LambdaQueryWrapper();

        // 2.1 状态精准查询
        if(dto.getStatus() != null) {
            lambdaQueryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }

        // 2.2 频道精准查询
        if(dto.getChannelId() != null) {
            lambdaQueryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }

        // 2.3 时间范围查询
        if(dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            lambdaQueryWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }

        // 2.4 关键词的模糊查询
        if(StringUtils.isNoneBlank(dto.getKeyword())) {
            lambdaQueryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }

        // 2.5 查询当前登录人的文章
        lambdaQueryWrapper.eq(WmNews::getUserId, WmThreadLocalUtils.getUser().getId());

        // 2.6 发布时间倒序查询
        lambdaQueryWrapper.orderByDesc(WmNews::getPublishTime);

        page = page(page, lambdaQueryWrapper);

        // 3. 返回结果
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());
        return responseResult;
    }
}

⑹. Controller

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/controller/v1/WmNewsController.java 文件:

@RestController
@RequestMapping("/api/v1/news")
public class WmNewsController {

    @Autowired
    private WmNewsService wmNewsService;

    @PostMapping("/list")
    public ResponseResult findList(@RequestBody WmNewsPageReqDto dto) {
        return wmNewsService.findList(dto);
    }
}

⑺. 测试

启动nginx,启动自媒体微服务和自媒体网关,自媒体地址: http://localhost:8802/#/login
在这里插入图片描述



3. 文章发布

⑴. 需求分析

在这里插入图片描述


⑵. 表结构分析

①. 表关系

wm_material 素材表
在这里插入图片描述

wm_news_material 文章素材关系表
在这里插入图片描述

②. 实体类

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/pojos/WmNewsMaterial.java 文件:

/**
 * <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;

}

⑶. 思路分析

该功能为保存、修改(是否有id)、保存草稿的共有方法
在这里插入图片描述

  1. 前端提交发布或保存为草稿
  2. 后台判断请求中是否包含了文章id
  3. 如果不包含id,则为新增
    3.1. 执行新增文章的操作
    3.2 关联文章内容图片与素材的关系
    3.3 关联文章封面图片与素材的关系
  4. 如果包含了id,则为修改请求
    4.1 删除该文章与素材的所有关系
    4.2 执行修改操作
    4.3 关联文章内容图片与素材的关系
    4.4 关联文章封面图片与素材的关系

⑷. 接口定义

①. 接口说明

说明
接口路径/api/v1/channel/submit
请求方式POST
参数WmNewsDto
响应结果ResponseResult

ResponseResult:

{
    “code”:501,
    “errorMessage”:“参数失效"
}

{
    “code”:200,
    “errorMessage”:“操作成功"
}

{
    “code”:501,
    “errorMessage”:“素材引用失效"
}

②. Dto

新建 heima-leadnews-model/src/main/java/com/heima/model/wemedia/dtos/WmNewsDto.java 文件:

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

⑸. 基础搭建

①. Controller

编辑 heima-leadnews-model/src/main/java/com/heima/model/wemedia/dtos/WmNewsPageReqDto.java 文件:

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

②. Mapper

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/mapper/WmNewsMaterialMapper.java 文件:

@Mapper
public interface WmNewsMaterialMapper extends BaseMapper<WmNewsMaterial> {

    // 批量保存文章素材的方法
    void saveRelations(@Param("materialIds") List<Integer> materialIds, @Param("newsId") Integer newsId, @Param("type") Short type);
}

③. Mapper配置文件

新建 heima-leadnews-service/heima-leadnews-wemedia/src/main/resources/mapper/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>

④. Service

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/WmNewsService.java 文件:

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

⑤. ServiceImpl

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmNewsServiceImpl.java 文件:

    /**
     * 发布/修改文章或发布为草稿
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        return null;
    }

⑹. 定义常量

新建 heima-leadnews-common/src/main/java/com/heima/common/constants/WemediaConstants.java 文件:

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

⑺. 自定义提示信息

编辑 heima-leadnews-model/src/main/java/com/heima/model/common/enums/AppHttpCodeEnum.java 文件:

    NEED_ADMIND(3001,"需要管理员权限"),

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

⑻. ServiceImpl(内容图片与素材)

编辑 heima-leadnews-service/heima-leadnews-wemedia/src/main/java/com/heima/wemedia/service/impl/WmNewsServiceImpl.java 文件:

@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    /**
     * 条件查询文章列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findList(WmNewsPageReqDto dto) {
        // 1. 检查参数
        dto.checkParam(); // 分页检查

        // 2. 分页条件查询
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper();

        // 2.1 状态精准查询
        if(dto.getStatus() != null) {
            lambdaQueryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }

        // 2.2 频道精准查询
        if(dto.getChannelId() != null) {
            lambdaQueryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }

        // 2.3 时间范围查询
        if(dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
            lambdaQueryWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }

        // 2.4 关键词的模糊查询
        if(StringUtils.isNoneBlank(dto.getKeyword())) {
            lambdaQueryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }

        // 2.5 查询当前登录人的文章
        lambdaQueryWrapper.eq(WmNews::getUserId, WmThreadLocalUtils.getUser().getId());

        // 2.6 发布时间倒序查询
        lambdaQueryWrapper.orderByDesc(WmNews::getPublishTime);

        page = page(page, lambdaQueryWrapper);

        // 3. 返回结果
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());
        return responseResult;
    }

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

        // 1. 参数校验
        if(dto == null || dto.getContent() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 2. 保存或修改文章

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

        // 3. 判断是否为草稿, 如果是草稿, 结束当前方法
        if(dto.getStatus().equals(WmNews.Status.NORMAL.getCode())) {
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        // 4. 保存文章内容图片和素材的关系
        // 提取文章内容中的图片信息
        List<String> materials = ectractUrlInfo(dto.getContent());

        saveRelativeInfoForContent(materials, wmNews.getId());

        // 5. 保存文章封面图片和素材的关系, 如果当然布局是自动, 需要匹配封面图片
        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);
    }

    /**
     * 保存文章图片与素材的关系到数据库中
     * @param materials
     * @param newsId
     * @param type
     */
    private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
        // 参数校验
        if(materials != null && !materials.isEmpty()) {
            // 通过图片的url查询素材的id
            List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));

            // 判断素材是否有效
            if(dbMaterials == null ||dbMaterials.size() == 0) {
                // 提示调用者素材失效(还可以进行数据回滚)
                throw new CustomException(AppHttpCodeEnum.MATERIAL_REFERENCE_FAIL);
            }

            // 判断素材和数据库素材是否一致
            if(dbMaterials.size() != materials.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> 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;
    }

    /**
     * 保存或修改文章
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews) {
        // 属性补全
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 0); // 默认上架

        if(wmNews.getId() == null) {
            // 保存文章
            save(wmNews);
        } else {
            // 修改文章
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            updateById(wmNews);
        }
    }
}

⑼. Controller

编辑 heima-leadnews-model/src/main/java/com/heima/model/wemedia/dtos/WmNewsPageReqDto.java 文件:

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

⑽. 测试

启动nginx,启动自媒体微服务和自媒体网关,自媒体地址: http://localhost:8802/#/login

①. 单图

Ⅰ. 发布文章

在这里插入图片描述
在这里插入图片描述

Ⅱ. 内容列表

在这里插入图片描述

Ⅲ. 数据库

在这里插入图片描述

②. 草稿

Ⅰ. 发布文章

在这里插入图片描述

Ⅱ. 内容列表

在这里插入图片描述

Ⅲ. 数据库

数据库有文章,但是图片和素材未关联
在这里插入图片描述
在这里插入图片描述


③. 自动

Ⅰ. 发布文章

在这里插入图片描述

Ⅱ. 内容列表

在这里插入图片描述

Ⅲ. 数据库

数据库有文章,内容、封面图片和素材已关联
在这里插入图片描述
在这里插入图片描述



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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LaoCat带你认识容器与镜像(三【上】)

有道是每逢佳节倍惰怠 ~&#xff0c;春节期间随缘更新吧 ~ 本章内容 Docker挂载数据卷相关。 本文实操全部基于Ubuntu 20.04 宿主机 > linux服务器本身 前边章节就介绍过Docker数据卷相关的知识点&#xff0c;也特别强调了生产环境一定要记得挂载数据卷&#xff0c;编程的小…

【前端】Vue项目:旅游App-(11)city:添加热门数据、动态修改索引栏、点击跳转、显示城市

文章目录目标过程与代码添加热门数据热门数据样式索引栏索引监听点击、保存数据、回退首页跳转到city页、显示城市效果总代码修改的文件city.jscurrentGroupCity.vuehome.vue目标 上一篇以indexBar的形式显示了数据&#xff1a;【前端】Vue项目&#xff1a;旅游App-&#xff0…

【Kubernetes 企业项目实战】01、使用 kubeadm 安装 K8s-v1.23 高可用集群

目录 K8s-v1.23 安装环境规划 kubeadm 和二进制安装 k8s 适用场景分析 一、初始化安装 k8s 集群的环境 1.1 初步的环境初始化 1.2 配置主机之间无密码登录 1.3 关闭交换分区 swap 提升性能 1.4 修改机器内核参数 1.5 配置阿里云的 repo 源 1.6 配置安装 k8s 组件需要…

python调试器 ipdb

文章目录1. 介绍1.1 常用调试方式1.2 安装 ipdb2. 用法3. 命令3.1、查看源代码3.2、添加断点3.3 添加临时断点3.4 清除断点3.5、打印变量值3.6、逐行调试命令3.7、非逐行调试命令3.8 跳出函数&#xff0c;跳入函数3.9、查看当前函数所有参数3.10 打印变量的值3.11、打印变量类型…

11. 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例…

【openGauss】在openEuler(ARM架构)上安装openGauss(单机版)

一、系统版本介绍 当前案例中的openGauss安装&#xff0c;底层操作系统为openEuler-20.03-LTS版本&#xff0c;当前openGauss对Python版本兼容性最好的是Python 3.6版本与Python 3.7版本&#xff0c;该实验使用的openEuler版本自带Python 3.7.4&#xff0c;不需要再自行安装 二…

光电探测器怎么选

想要挑选光电探测器&#xff0c;首先应该理解探测器的重要的几个指标。 实际看一个光电探测器吧 输入输出接口三个部分&#xff0c;光纤输入&#xff0c;射频输出&#xff0c;电源供电 数据手册 捡几个难理解的说说&#xff0c;详细推导解释这里不赘述了&#xff0c;难理解的…

【二】Netty 搭建简单的http服务

Netty 搭建简单的http服务Netty 简介代码展示netty 依赖NettyServer netty 服务端启动类MyChannelInitializer 设置编码解码器&#xff0c;并添加自己的业务方法MyClientHandler 实现自己的业务方法。主要方法 是读取到数据后处理效果展示服务端打印截图采用Postman 测试 截图N…

JDBC 实现增删改查的实际操作,很简单

大家好&#xff0c;今天给大家分享一下JDBC 实现增删改查的实际操作 我们还是使用的Maven的方式&#xff0c; 首先要创建一个干净的Maven webapps项目 看这个就可以了 要导入相关的依赖 <dependencies><!-- https://mvnrepository.com/artifact/mysql/mysql-connec…

如何使用 HTML5 Web 连接到 VMware vSphere Hypervisor

本文将向你展示如何在计算机上连接 VMware vSphere Hypervisor 7.0.3,VMware vSphere Hypervisor 7.0.3 也称为 ESXi 7.0.3。 连接 ESXi 7.0.3 下载工具以管理 ESXi 主机服务器连接 ESXi 7.0.3 服务器下载工具以管理 ESXi 主机服务器 现在不需要任何工具来管理 ESXi 7.0.3,从…

1.8周报

SourceURL:file:///home/mrl/文档/1.8周报.docx 周报 代码行数&#xff1a; 周一 611 周二 672 周三 524 周四 528 周五 450 周六 545 周日 564 遇到的问题&#xff1a; 系统配置问题&#xff1a; 在升级安装python3时&#xff0c;由于操作失误&#xff0c;导…

数据脱敏实战经验

1. 创建隐私数据类型枚举&#xff1a;PrivacyTypeEnum2. 创建自定义隐私注解&#xff1a;PrivacyEncrypt3. 创建自定义序列化器&#xff1a;PrivacySerializer4. 隐私数据隐藏工具类&#xff1a;PrivacyUtil5. 注解使用这两天在整改等保测出的问题&#xff0c;里面有一个“用户…

如何将.md文件转换为pdf

目录 1.step1&#xff1a; 安装Visual Studio Code&#xff08;简称VScode&#xff09; 2.step2&#xff1a; 安装定制化插件 3.step3&#xff1a; 进入预览窗口模式 4.step4&#xff1a; 进行格式转换 1.step1&#xff1a; 安装Visual Studio Code&#xff08;简称VScode&a…

【实战篇】39 # 如何实现世界地图的新冠肺炎疫情可视化?

说明 【跟月影学可视化】学习笔记。 世界地图新冠肺炎疫情可视化 下面将实现世界地图新冠肺炎疫情可视化。数据用的是从 2020 年 1 月 22 日到 3 月 19 日这些天的新冠肺炎疫情进展。效果类似下图&#xff1a;https://covid19.who.int/ 步骤一&#xff1a;准备世界地图可视化…

[ 数据结构 ] 迪杰斯特拉算法(最短路径问题)

0 最短路径问题 战争时期&#xff0c;胜利乡有 7 个村庄(A, B, C, D, E, F, G) &#xff0c;现在有六个邮差&#xff0c;从 G 点出发&#xff0c;需要分别把邮件分别送到 A, B, C , D, E, F 六个村庄各个村庄的距离用边线表示(权) &#xff0c;比如 A – B 距离 5 公里问&#…

不透明度和填充的区别

提纲 1、不透明度和填充的相同之处 2、不透明度和填充的不同之处 3、从字面意思理解不透明度和填充 1、不透明度和填充的相同之处 在初学PS时&#xff0c;一定对“不透明度”和“填充”非常迷惑&#xff0c;它们在图层面板的这个位置 这篇就来详细聊聊这两个滑块&#xff0…

SSR是什么?Vue中怎么实现?

一、是什么 Server-Side Rendering 称其为SSR&#xff0c;意为服务端渲染 指由服务侧完成页面的 HTML 结构拼接的页面处理技术&#xff0c;发送到浏览器&#xff0c;然后为其绑定状态与事件&#xff0c;成为完全可交互页面的过程 先来看看Web3个阶段的发展史&#xff1a; 传…

Dart基础

一、dart概述 Dart简介 Dart 是谷歌开发的&#xff0c;类型安全的&#xff0c;面向对象的编程语言&#xff0c;被应用于Web、服务器、移动应用和物联网等领域。Dart 诞生于 2011 年 10 月 10 日Dart简单易学(类似TypeScript, 是强类型的语言)运行方式 原生虚拟机(Dart 代码可…

从执行者到管理者的角色转变

前言 在职场中因为岗位职责的差异&#xff0c;我们通过被分为两种角色&#xff0c;即执行者和管理者&#xff1b;大部分管理者也是从执行者晋升来的。 因为思维的惯性&#xff0c;导致我们会很容易带着执行者的意识去做管理&#xff0c;遇到问题就会想着自己动手去做&#xff0…

智慧防雷+智能防雷的综合应用方案

随着物联网时代的到来&#xff0c;信息共享成为社会运转的动力&#xff0c;伴随着现代建筑、交通、医疗以及工业制造等行业的智能化&#xff0c;大量微电子网络、自动化设备、计算机等投入使用&#xff0c;其集成度高、工作电压小、工作电流低、绝缘强度低、耐过电压和过电流能…