微服务[学成在线] day08:FastDFS 实现课程图片管理

微服务项目学成在线 微服务项目学成在线,黑马2019年最新项目.开发工具采用的是idea,学习本项目相信大家可以学到很多. 立即下载

😎 知识点概览

为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。

本章节为【学成在线】项目的 day08 的内容

  • FastDFS 的 安装与基本使用流程。
  • 基于 Java Api 来操作 FastDFS
  • 结合 FastDFS 实现对课程图片的 CRUD
  • 图片删除的场景使用 Promise 解决一些问题

目录

内容会比较多,小伙伴们可以根据目录进行按需查阅。

一、FastDFS 探究

0x01 什么是fastDFS ?

1、介绍

FastDFS是用c语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。FastDFS专为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

为什么要使用 fastDFS 呢?

上边介绍的 NFS、GFS 都是通用的分布式文件系统,通用的分布式文件系统的优点的是开发体验好,但是系统复杂性高、性能一般,而专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。fastDFS 非常适合存储图片等那些小文件,fastDFS 不对文件进行分块,所以它就没有分块合并的开销,fastDFS 网络通信采用 socket,通信速度很快。

2、工作原理

FastDFS 架构包括 Tracker server 和 Storageserver。客户端请求 Tracker server 进行文件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。

1)Tracker

Tracker Server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。

FastDFS 集群中的 Tracker server 可以有多台,Tracker server 之间是相互平等关系同时提供服务,Tracker server 不存在单点故障。客户端请求 Tracker server 采用轮询方式,如果请求的 tracker 无法提供服务则换另一个 tracker。

2)Storage

Storage Server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storage server 没有实现自己的文件系统而是使用操作系统的文件系统来管理文件。可以将 storage 称为存储服务器。

Storage 集群采用了分组存储方式。storage 集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,组内的 Storage server 之间是平等关系,不同组的 Storage server 之间不会相互通信,同组内的 Storage server 之间会相互连接进行文件同步,从而保证同组内每个storage上的文件完全一致的。一个组的存储容量为该组内的存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。

采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由 tracker 进行调度选择。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。

3)Storage状态收集

Storage server 会连接集群中所有的 Tracker server,定时向他们报告自己的状态,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。

3、文件上传流程

客户端上传文件后存储服务器将 文件ID 返回给客户端,此 文件ID 用于以后访问该文件的索引信息。文件索引信息,包括:组名,虚拟磁盘路径,数据两级目录,文件名。

  • 组名:文件上传后所在的 storage组名称,在文件上传成功后有 storage服务器返回,需要客户端自行保存。
  • 虚拟磁盘路径: storage配置的虚拟路径,与磁盘选项 store_path* 对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。
  • 数据两级目录: storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
  • 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器 IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

4、文件下载流程

tracker 根据请求的文件路径即文件ID 来快速定义文件。

比如请求下边的文件:

1.通过组名tracker能够很快的定位到客户端需要访问的存储服务器组是group1,并选择合适的存储服务器提供客户端访问。

2.存储服务器根据“文件存储虚拟磁盘路径”和“数据文件两级目录”可以很快定位到文件所在目录,并根据文件名找到客户端需要访问的文件。

0x02 FastDFS入门

1、环境搭建

安装 FastDFS 流程 参考: https://www.cnblogs.com/yufeng218/p/8111961.html

2、上传、下载、查询 测试

在工程下创建 test-fastdfs 模块

1)上传测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestFastDFS {
    /**
     * 测试文件上传
     */
    @Test
    public void testFileUpload(){
        try {
            //加载配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
            //连接 Tracker
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getConnection();
            //获取 Storage
            StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
            //创建 Storage Client
            StorageClient1 storageClient1 = new StorageClient1(trackerServer, storeStorage);
            //向 Storage 服务器上传文件,拿到文件id
            String filePath = "d:/test1.html";
            String fileId = storageClient1.upload_file1(filePath, "html", null);
            System.out.println("上传成功:" + fileId);

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

在上述的代码中,我们通过访问 Tracker 将 d:/test1.html 文件上传到了 Storage 服务器中,上传完成后得到了文件的完整的储存路径,如下:

group1/M00/00/00/CgEBmF6QKa-Abjv7AAAGqbcDljA60.html

我们可以在 Storage 中的物理 fdfs_storage/data 路径找到该文件

2)文件查询
/**
 * 文件信息查询
 */
@Test
public void TestFileInfoQuery(){
    try {
        //加载配置文件
        ClientGlobal.initByProperties("config/fastdfs-client.properties");
        //连接 Tracker
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        //获取 Storage
        StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
        //创建 Storage Client
        StorageClient1 storageClient1 = new StorageClient1(trackerServer, storeStorage);

        String fileId = "group1/M00/00/00/CgEBmF6QKa-Abjv7AAAGqbcDljA60.html";
        FileInfo fileInfo = storageClient1.query_file_info1(fileId);
        System.out.println("文件信息: "+ fileInfo);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

运行结果

3)文件下载
/**
 * 文件下载
 */
@Test
public void TestFileDownload(){
    try {
        //加载配置文件
        ClientGlobal.initByProperties("config/fastdfs-client.properties");
        //连接 Tracker
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        //获取 Storage
        StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
        //创建 Storage Client
        StorageClient1 storageClient1 = new StorageClient1(trackerServer, storeStorage);

        String fileId = "group1/M00/00/00/CgEBmF6QKa-Abjv7AAAGqbcDljA60.html";
        String saveToPath = "d:/test.html";
        //下载文件
        byte[] bytes = storageClient1.download_file1(fileId);
        FileOutputStream fileOutputStream = new FileOutputStream(new File(saveToPath));
        fileOutputStream.write(bytes);
        System.out.println("下载成功! " + saveToPath);
    } catch (Exception ex){
        ex.printStackTrace();
    }
}

运行结果

3、搭建图片虚拟主机

1) 在storage上安装Nginx

在 storage server 上安装 nginx 的目的是对外通过 http 访问 storage server 上的文 件。使用 nginx 的模块 FastDFS-nginx-module 的作用是通过 http 方式访问 storage 中 的文件,当 storage 本机没有要找的文件时向源storage 主机代理请求文件。

在storage上安装nginx(安装 FastDFS-nginx-module 模块)

参考:FastDFS安装教程.pdf 进行安装

安装完成启动 storage上的 nginx:

/usr/local/nginx/sbin/nginx ‐c /usr/local/nginx/conf/nginx‐fdfs.conf
2)配置 Nginx 的图片服务的虚拟主机

图片服务虚拟主机的作用是负载均衡,将图片请求转发到 storage server 上。

1、 通过图片服务虚拟主机请求图片流程图

2、在 nginx 图片代理服务上配置图片服务器虚拟主机

修改本地的 hosts 文件,将 img.xuecheng.com 映射到本地IP 127.0.0.1

windows 的 hosts 文件路径为:C:\Windows\System32\drivers\etc

127.0.0.1 img.xuecheng.com

增加 nginx 虚拟机主机

	#图片服务
	upstream img_server_pool{
		#server 192.168.101.64:80 weight=10;
		server 10.1.1.152:80 weight=10;
	} 
	#学成网图片服务
	server {
		listen       80;    
		server_name img.xuecheng.com;    

		#个人中心    
		location /group1 {      
			proxy_pass http://img_server_pool;          
		}     
		location /group2 {      
			proxy_pass http://img_server_pool;          
		}     
	}

3、测试访问

http://img.xuecheng.com/group1/M00/00/00/CgEBmF6QKa-Abjv7AAAGqbcDljA60.html

成功映射到 storage 服务上

4、总结

通过本次课程的学习您要达到以下目标:

1)了解分布式文件系统的概念及应用场景

分布式文件系统是通过网络将单机上的文件系统组成一个网络文件系统。

分布式文件系统主要应用在大型互联网项目中,实现图片存储、音视频存储等服务。

分布式文件系统的优点:可以快速扩容存储,提高文件访问速度。

2)理解fastDFS的工作原理

fastDFS 由 tracker 和 storage 组成,它们都可以部署集群。

tracker 负责调度,storage 负责存储。

3)掌握 fastDFS 存取文件方法

客户端与 fastDFS 采用 socket 协议通信,可以采用官方提供的 java版本的 fastDSF-client快速开发。

4)能够动手搭建一个 fastDSF 文件服务器

二、上传课程图片

0x01 需求分析

在很多系统都有上传图片/上传文件的需求,比如:上传课程图片、上传课程资料、上传用户头像等,为了提供系统的可重用性专门设立文件系统服务承担图片/文件的管理,文件系统服务实现对文件的上传、删除、查询等功能进行管理。

各个子系统不再开发上传文件的请求,各个子系统通过文件系统服务进行文件的上传、删除等操作。文件系统服务最终会将文件存储到 fastDSF 文件系统中。

下图是各各子系统与文件系统服务之间的关系:

下图是课程管理中上传图片处理流程:

执行流程如下:

1、管理员进入教学管理前端,点击上传图片

2、图片上传至文件系统服务,文件系统请求 fastDFS 上传文件

3、文件系统将文件入库,存储到文件系统服务数据库中。

4、文件系统服务向前端返回文件上传结果,如果成功则包括文件的 Url 路径。

5、课程管理前端请求 课程管理 进行保存课程图片信息到课程 数据库。

6、课程管理服务将课程图片保存在 课程数据库。

0x02 创建工程

导入xc-service-base-filesystem.zip工程。

1)工程目录结构如下

image-20200410193248194

1)pom.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>xc-framework-parent</artifactId>
        <groupId>com.xuecheng</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../xc-framework-parent/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>xc-service-base-filesystem</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-service-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-model</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
    </dependencies>

</project>

2)配置文件

server:
  port: 22100
spring:
  application:
    name: xc-service-base-filesystem
#mongo配置
  data:
    mongodb:
      database: xc_fs
      uri: mongodb://root:123123@127.0.0.1:27017
#SpringMVC上传文件配置
  servlet:
    multipart:
      #默认支持文件上传.
      enabled: true
      #支持文件写入磁盘.
      file-size-threshold: 0
      # 上传文件的临时目录
      location:
      # 最大支持文件大小
      max-file-size: 1MB
      # 最大支持请求大小
      max-request-size: 30MB
xuecheng:
  fastdfs:
    connect_timeout_in_seconds: 5
    network_timeout_in_seconds: 30
    charset: UTF-8
    tracker_servers: 192.168.101.65:22122 #多个 trackerServer中间以逗号分隔

0x03 构建接口

系统的文件信息(图片、文档等小文件的信息)在mongodb中存储,下边是文件信息的模型类。

1、模型类

1)模型类如下

@Data
@ToString
@Document(collection = "filesystem")
public class FileSystem {
    @Id
    private String fileId;
    //文件请求路径
    private String filePath;
    //文件大小
    private long fileSize;
    //文件名称
    private String fileName;
    //文件类型
    private String fileType;
    //图片宽度
    private int fileWidth;
    //图片高度
    private int fileHeight;
    //用户id,用于授权暂时不用
    private String userId;
    //业务key
    private String businesskey;
    //业务标签
    private String filetag;
    //文件元信息
    private Map metadata;
}

说明:

  • fileId:fastDFS 返回的文件 ID。

  • filePath:请求fastDFS浏览文件 URL。

  • filetag:文件标签,由于文件系统服务是公共服务,文件系统服务会为使用文件系统服务的子系统分配文件标签,用于标识此文件来自哪个系统。

  • businesskey:文件系统服务为其它子系统提供的一个业务标识字段,各子系统根据自己的需求去使用,比如:课程管理会在此字段中存储课程 id 用于标识该图片属于哪个课程。

  • metadata:文件相关的元信息。

2)数据库 collection 集合

在 mongodb 创建数据库xc_fs(文件系统数据库),并创建集合 filesystem。

2、API 接口

@Api(value = "文件管理接口", description = "文件管理接口,提供对文件的CRUD")
public interface FileSystemControllerApi {

    @ApiOperation("上传文件接口")
    public UploadFileResult uploadFile(MultipartFile multipartFile,
                                       String fileTage,
                                       String businessKey,
                                       String metaData);

}

3、Dao 层

dao 层继承 Spring Data Mongodb 的 API

package com.xuecheng.filesystem.dao;

import com.xuecheng.framework.domain.filesystem.FileSystem;
import org.springframework.data.mongodb.repository.MongoRepository;

public interface FileSystemRepository extends MongoRepository<FileSystem,String> {

}

4、Service 层

package com.xuecheng.filesystem.service;

import com.alibaba.fastjson.JSON;
import com.xuecheng.filesystem.dao.FileSystemRepository;
import com.xuecheng.framework.domain.filesystem.FileSystem;
import com.xuecheng.framework.domain.filesystem.response.FileSystemCode;
import com.xuecheng.framework.domain.filesystem.response.UploadFileResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Map;

@Service
public class FileSystemService {
    @Value("${xuecheng.fastdfs.tracker_servers}")
    String tracker_servers;
    @Value("${xuecheng.fastdfs.connect_timeout_in_seconds}")
    int connect_timeout_in_seconds;
    @Value("${xuecheng.fastdfs.network_timeout_in_seconds}")
    int network_timeout_in_seconds;
    @Value("${xuecheng.fastdfs.charset}")
    String charset;

    @Autowired
    FileSystemRepository fileSystemRepository;

    /**
     * 上传文件到FastDFS
     * @param multipartFile 文件数据
     * @param fileTag 文件标签
     * @param businessKey 业务key
     * @param metaData 文件元数据
     * @return
     */
    public UploadFileResult uploadFile(MultipartFile multipartFile,
                                       String fileTag,
                                       String businessKey,
                                       String metaData){
        //验证提交的文件是否为空
        if(multipartFile == null){
            ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_FILEISNULL);
        }

        //第一步:将文件上传到 FastDFS中
        String fileId = this.fdfsUpload(multipartFile);
        if(StringUtils.isEmpty(fileId)){    //上传文件为空时抛出异常
            ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_SERVERFAIL);
        }

        //第二步:将文件储存到mongoDB内

        //设置相关的文件信息
        FileSystem fileSystem = new FileSystem();
        fileSystem.setFileId(fileId);
        fileSystem.setFileName(multipartFile.getOriginalFilename());
        fileSystem.setBusinesskey(businessKey);
        fileSystem.setFilePath(fileId); //FastDFS的fileId就是实际的物理路径
        fileSystem.setFileSize(multipartFile.getSize());
        fileSystem.setFiletag(fileTag);
        fileSystem.setFileType(multipartFile.getContentType());
        //文件元数据需要转换成Map对象
        if(StringUtils.isNotEmpty(metaData)){
            Map metaDataMap = JSON.parseObject(metaData, Map.class);
            fileSystem.setMetadata(metaDataMap);
        }
        FileSystem save = fileSystemRepository.save(fileSystem);
        return new UploadFileResult(CommonCode.SUCCESS,save);
    }

    //上传文件到FastDFS
    private String fdfsUpload(MultipartFile multipartFile){
        //初始化FastDFS的环境
        try {
            initFdfsConfig();
            TrackerClient trackerClient = new TrackerClient();
            TrackerServer trackerServer = trackerClient.getConnection();
            //得到 Storage 连接信息
            StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
            //获取 Storage 客户端
            StorageClient1 storageClient1 = new StorageClient1(trackerServer, storeStorage);

            //上传文件
            byte[] fileBytes = multipartFile.getBytes();   // 获取文件信息
            String originalFilename = multipartFile.getOriginalFilename();
            // 获取文件拓展名
            String extStr = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            //上传文件
            String fileId = storageClient1.upload_file1(fileBytes, extStr, null);
            return fileId;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //初始化FastDFS环境
    private void initFdfsConfig(){
        try {
              ClientGlobal.initByTrackers(tracker_servers);
              ClientGlobal.setG_connect_timeout(connect_timeout_in_seconds);
              ClientGlobal.setG_network_timeout(network_timeout_in_seconds);
              ClientGlobal.setG_charset(charset);
        } catch (Exception e) {
            e.printStackTrace();
            //抛出异常
            ExceptionCast.cast(FileSystemCode.FS_INITFDFS_ERROR);
        }
    }
}

5、Controller 层

package com.xuecheng.filesystem.controller;

@RestController
@RequestMapping("/filesystem")
public class FileSystemController implements FileSystemControllerApi {
    @Autowired
    FileSystemService fileSystemService;
    @Override
    @PostMapping("/upload")
    public UploadFileResult uploadFile(MultipartFile multipartFile, String fileTag, String businessKey, String metaData) {
        return fileSystemService.uploadFile(multipartFile,fileTag,businessKey,metaData);
    }
}

6、测试

在 Swagger UI 生成的接口文档内进行测试 http://localhost:22100/swagger-ui.html

0x04 前端配置

1、需求

上传图片界面如下图:

点击“加号”上传图片,图片上传成功自动显示;点击“删除”将删除图片。

2、页面

使用 Element-UI 的Upload上传组件实现上边的效果。

1) template

<el‐upload
  action="/filesystem/upload"
  list‐type="picture‐card"
  name="multipartFile" 
  :before‐upload="setbusinesskey"
  :on‐success="handleSuccess"
  :file‐list="fileList"
  :limit="picmax"
  :on‐exceed="rejectupload"
  :data="uploadval">
  <i class="el‐icon‐plus"></i>
</el‐upload>

el-upload参数说明:

  • action:必选参数,上传的地址
  • list-type:文件列表的类型(text/picture/picture-card)
  • name: 提交的文件参数名称,这里要跟后端接收的对应上
  • before-upload:上传前执行钩子方法 ,function(file)
  • on-success:上传成功 执行的钩子方法 ,function(response, file, fileList)
  • on-error:上传失败的钩子方法,function(err, file, fileList)
  • on-remove:文件删除的钩子方法,function(file, fileList)
  • file-list:文件列表,此列表为上传成功 的文件
  • limit:最大允许上传个数
  • on-exceed:文件超出个数限制时的钩子,方法为:function(files, fileList)
  • data:提交上传的额外参数,需要封装为json对象,最终提交给服务端为key/value串

2) 数据模型

<script>
  import * as sysConfig from '@/../config/sysConfig';
  import * as courseApi from '../../api/course';
  import utilApi from '../../../../common/utils';
  import * as systemApi from '../../../../base/api/system';
  export default {
    data() {
      return {
        picmax:1,
        courseid:'',
        dialogImageUrl: '',
        dialogVisible: false,
        fileList:[],
        uploadval:{filetag:"course"},
        imgUrl:sysConfig.imgUrl
      }
    },
    methods: {
      //超出文件上传个数提示信息
      rejectupload(){
        this.$message.error("最多上传"+this.picmax+"个图片");
      },
      //在上传前设置上传请求的数据
      setuploaddata(){
      },
      //删除图片
      handleRemove(file, fileList) {
        console.log(file)
        alert('删除')
      },
      //上传成功的钩子方法
      handleSuccess(response, file, fileList){
        console.log(response)
        alert('上传成功')
      },
      //上传失败执行的钩子方法
      handleError(err, file, fileList){
        this.$message.error('上传失败');
        //清空文件队列
        this.fileList = []
      }
    },
    mounted(){
      //课程id
      this.courseid = this.$route.params.courseid;
    }
  }
</script>

3、测试

1、点击“加号”测试上传图片

三、保存课程图片

0x01 需求分析

图片上传到文件系统后,其它子系统如果想使用图片可以引用图片的地址,课程管理模块使用图片的方式是将图片地址保存到课程数据库中。

业务流程如下:

1、上传图片到文件系统服务

2、保存图片地址到课程管理服务在课程管理服务创建保存课程与图片对应关系的表 course_pic。

3、在 course_pic 保存图片成功后方可查询课程图片信息。

通过查询 course_pic 表数据则查询到某课程的图片信息。

0x02 构建接口

1、API 接口

在 com.xuecheng.api.course 包下创建该接口

@ApiOperation("保存课程图片信息")
public ResponseResult saveCoursePic(String courseId, String pic);

2、Dao 层

由于是对 mysql 的单表操作,这里我们通过继承 spring data jpa 提供的接口来实现 dao

package com.xuecheng.manage_course.dao;

import com.xuecheng.framework.domain.course.CourseBase;
import com.xuecheng.framework.domain.course.CoursePic;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by Administrator.
 */
public interface CoursePicRepository extends JpaRepository<CoursePic,String> {

}

3、Service 层

在 CourseService 下新增 saveCoursePic 方法

/**
 * 保存课程图片信息到数据库
 * @param courseId 课程id
 * @param pic 图片id
 * @return
 */

@Transactional  //Mysql操作需要添加到Spring事务
public ResponseResult saveCoursePic(String courseId, String pic) {
    CoursePic coursePic = null;
    //判断该课程id是否已经存在图片
    Optional<CoursePic> byId = coursePicRepository.findById(courseId);
    if(byId.isPresent()){
        coursePic = byId.get();
    }
    //不存在则重新创建一个课程图片对象并保存信息
    if(coursePic == null){
        coursePic = new CoursePic();
    }

    coursePic.setCourseid(courseId);
    coursePic.setPic(pic);
    CoursePic save = coursePicRepository.save(coursePic);
    return new ResponseResult(CommonCode.SUCCESS);
}

4、Controller 层

在 CourseContorller 下新增 saveCoursePic 方法

/**
 * 保存课程信息与图片的对应关系
 * @param courseId 课程id
 * @param pic 图片文件id
 * @return
 */
@Override
@PostMapping("/coursepic/add")
public ResponseResult saveCoursePic(@RequestParam("courseId") String courseId, @RequestParam("pic") String pic) {
    return courseService.saveCoursePic(courseId,pic);
}

0x03 前端配置

1、需求

前端需要在上传图片成功后保存课程图片信息。

2、页面

在 course.js 下创建 ajax 请求的 api

//保存课程图片地址到课程数据 库
export const addCoursePic= (courseId,pic) => {
  return http.requestPost(apiUrl+'/course/coursepic/add?courseId='+courseId+"&pic="+pic)
}

el-upload 组件在上传成功后,会调用上传成功的钩子方法,配置如 :on-success="handleSuccess"

钩子方法如下:

//上传成功的钩子方法
handleSuccess(response, file, fileList){
    console.log(response)
    //调用课程管理的保存图片接口,将图片信息保存到课程管理数据库course_pic中
    //从response得到新的图片文件的地址
    if(response.success){
        let fileId = response.fileSystem.fileId;
        courseApi.addCoursePic(this.courseid,fileId).then(res=>{
            if(res.success){
                this.$message.success("图片上传成功")
            }else{
                this.$message.error("图片保存失败!")
            }
        })
    }
},

3、测试

上传成功

四、图片信息查询

0x01 需求分析

在进入到 课程图片 页面之前,根据当前课程的id,找到该课程对应的课程图片。

0x02 构建接口

1、API 接口

@ApiOperation("获得课程图片信息")
public CoursePic getCoursePic(String courseId);

2、Dao 层

CoursePicRepository ,在编写保存功能时已构建。

3、Service 层

/**
 * 根据课程id获得课程的图片信息
 * @param courseId
 * @return
 */
@Transactional //Mysql操作需要添加到Spring事务
public CoursePic getCoursePic(String courseId) {
    Optional<CoursePic> byId = coursePicRepository.findById(courseId);
    if(byId.isPresent()){
        CoursePic coursePic = byId.get();
        return coursePic;
    }
    return null;
}

4、Controller 层

/**
 * 根据课程id获取该课程的课程图片信息
 * @param courseId
 * @return 由于这里每个课程只有一个图片,所以只返回一个 CoursePic 对象
 */
@Override
@GetMapping("/coursepic/get/{courseId}")
public CoursePic getCoursePic(@PathVariable("courseId") String courseId) {
    return courseService.getCoursePic(courseId);
}

5、测试

0x03 前端配置

1、需求

在课程图片页面的 mounted 钩子方法 中查询课程图片信息,并将图片地址赋值给数据对象

2、页面

API 接口

//查询课程图片
export const findCoursePicList = courseId => {
  return http.requestQuickGet(apiUrl+'/course/coursepic/get/'+courseId)
}

钩子函数

mounted(){
  //课程id
  this.courseid = this.$route.params.courseid;
  //查询课程
  courseApi.findCoursePicList(this.courseid).then(res=>{
      if(res && res.pic){
          let imgUrl = this.imgUrl+res.pic;
          //将图片地址设置到
        this.fileList.push({name:'pic',url:imgUrl,fileId:res.pic})
      }
  })
}

3、测试

别忘了启动 nginx ,这里是通过 img.xuecheng.com 访问图片。

五、课程图片删除

0x01 需求分析

0x02 构建接口

1、API 接口

@ApiOperation("删除课程图片信息")
public ResponseResult deleteCoursePic(String courseId);

2、Dao 层

JPA 自带的 deleteById 方法没有返回值,所以这里我们需要在 Dao 里面再定义一个 deleteByCourseid 方法,删除后返回影响的行数。

package com.xuecheng.manage_course.dao;

import com.xuecheng.framework.domain.course.CourseBase;
import com.xuecheng.framework.domain.course.CoursePic;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by Administrator.
 */
public interface CoursePicRepository extends JpaRepository<CoursePic,String> {
    /**
     * 根据课程id删除图片信息
     * @param courseId
     * @return 返回删除影响的行,小于1则表示删除失败
     */
    long deleteByCourseid(String courseId);
}

3、Service 层

/**
 * 删除课程图片信息
 * @param courseId
 * @return
 */
@Transactional //Mysql操作需要添加到Spring事务
public ResponseResult deleteCoursePic(String courseId) {
    long byCourseid = coursePicRepository.deleteByCourseid(courseId);
    if(byCourseid > 0){
        return new ResponseResult(CommonCode.SUCCESS);
    }
    return new ResponseResult(CommonCode.FAIL);
}

4、Controller 层

/**
 * 删除课程图片信息
 * @param courseId
 * @return
 */
@Override
@DeleteMapping("/coursepic/delete")
public ResponseResult deleteCoursePic(@RequestParam("courseId") String courseId) {
    return courseService.deleteCoursePic(courseId);
}

5、测试

0x03 前端配置

1、需求

2、页面

api 接口

//删除课程图片
export const deleteCoursePic= courseId => {
  return http.requestDelete(apiUrl+'/course/coursepic/delete?courseId='+courseId)
}

before-remove钩子方法

<el‐upload
  action="/filesystem/upload"
  list‐type="picture‐card"
  :before‐remove="handleRemove">
  <i class="el‐icon‐plus"></i>
</el‐upload>

在upload组件的 before-remove钩子方法 中实现删除动作。

//删除图片
handleRemove(file, fileList) {
  console.log(file)
  //调用服务端去删除课程图片信息,如果返回false,前端停止删除
  //异步调用
  return new Promise((resolve,rejct)=>{
    courseApi.deleteCoursePic(this.courseid).then(res=>{
      if(res.success){
          //成功
        resolve()
      }else{
        this.$message.error("删除失败");
          //失败
        rejct()
      }
    })
  })
},

before-remove 说明:删除文件之前的钩子,参数为上传的文件和文件列表,若返回 false 或者返回 Promise 且被 reject,则停止删除。

3、为什么要使用 promise?

在 handleRemove 方法调用删除图片的 api 方法,删除成功时 return true,删除失败时return false;

// 删除图片
handleRemove(file, fileList) {
    console.log(file)
    //        alert('删除')
    //        return true;
    //删除图片
    courseApi.deleteCoursePic('1').then((res) => {
        if(res.success){
            this.$message.success('删除成功');
            return true;
        }else{
            this.$message.error(res.message);
            return false;
        }
    });
},

在上边代码中将提交的课程 id 故意写错,按照我们预期应该是删除失败,而测试结果却是图片在页面上删除成功。

问题原因:

通过查询 deleteCoursePic 方法的底层代码,deleteCoursePic 最终返回一个 promise 对象。

Promise 是ES6提供的用于异步处理的对象,因为axios提交是异步提交,这里使用promise作为返回值

Promise的使用方法如下:

Promise对象在处理过程中有三种状态:

  • pending:进行中

  • resolved:操作成功

  • rejected: 操作失败

Promise的构建方法如下:

const promise = new Promise(function(resolve,reject){
     //...TODO...
    if(操作成功){
        resolve(value);
    }else{
        reject(error);
    }
})

上边的构造方法function(resolve,reject)执行流程如下:

1)方法执行一些业务逻辑。

2)如果操作成功将 Promise 的状态由 pending 变为 resolved,并将操作结果传出去

3)如果操作失败会将 promise 的状态由 pending 变为 rejected,并将失败结果传出去。
上边说的操作成功将操作结果传给谁了呢?操作失败将失败结果传给谁了呢?

我们可以通过 promise 的 then、catch 来指定:

promise.then(function (result) {
    console.log('操作成功:' + result);
});
promise.catch(function (reason) {
    console.log('操作失败:' + reason);
});

例子如下:

1、定义一个方法,返回 promise 对象

testpromise(i){
  return new Promise((resolve,reject)=>{
    if(i % 2==0){
      resolve('成功了')
    }else{
      reject('拒绝了')
    }
  })
}

2、调用此方法

向方法传入偶数、奇数进行测试。

this.testpromise(3).then(res=>{// 在then中对成功结果进行处理
    alert(res)
}).catch(res=>{//在catch中对操作失败结果进行处理
    alert(res)
})

3、最终将 handleRemove 方法修改如下

handleRemove 方法返回 promise 对象,当删除成功则 resolve,删除失败则 reject。

// 删除图片
handleRemove(file, fileList) {
    console.log(file)
    return new Promise((resolve,reject)=>{
        //删除图片
 courseApi.deleteCoursePic(this.courseid).then((res) => {
            if(res.success){
                this.$message.success('删除成功');
                resolve()//通过
            }else{
                this.$message.error(res.message);
                reject()//拒绝
            }
        });
    })
}

😁 认识作者

作者:👦 LCyee ,全干型代码🐕

自建博客:https://www.codeyee.com

记录学习以及项目开发过程中的笔记与心得,记录认知迭代的过程,分享想法与观点。

优快云 博客:https://blog.youkuaiyun.com/codeyee

记录和分享一些开发过程中遇到的问题以及解决的思路。

欢迎加入微服务练习生的队伍,一起交流项目学习过程中的一些问题、分享学习心得等,不定期组织一起刷题、刷项目,共同见证成长。

PS射击游戏射线检测优化:原理、工程与全链路高性能实现 射线池:减少GC,提升批量检测效率。分层检测:先粗后细,远距离射击高效判定。批量检测:并行处理,适合大量射线场景。空间结构:进一步加速大场景检测。下面继续深入射线检测优化,补充更多实用细节和进阶技巧,包括空间分区加速、射线检测多线程/异步化、射线合并与分帧、射线池通用模板、常见性能陷阱与调优建议等。对于极端性能需求,可自定义轻量级物理系统,仅检测关键对象(如玩家、子弹),跳过复杂物理引擎。结合AABB、OBB、球体等简单碰撞体,射线-包围体检测极快。空间分区+分层检测是大场景射线优化核心。 阅读详情

相关推荐

DM-VIO论文精读:从‘延迟边缘化’到‘位姿图BA’,手把手拆解单目VIO性能超越双目的秘密

本文深入解析DM-VIO技术如何通过延迟边缘化和位姿图BA创新,解决单目视觉惯性里程计(VIO)的尺度不可观性问题,并在精度上超越传统双目系统。文章详细介绍了延迟边缘化的双因子图结构设计、位姿图BA的多级初始化策略,以及系统级优化带来的性能提升,为VIO研究与实践提供了重要参考。

weixin_30616969的博客 427

学成在线day08,FastDFS文件分布管理系统入门,课程图片的上传,和相关增删改查,课程图片删除,前端原理异步promise方法有点复杂

FastDFS文件分布管理系统入门,参考前面文档: https://blog.youkuaiyun.com/qq847196660/article/details/101950903 自己安装FatsDFS很复杂一大堆。我们直接用品优购项目,的CentOS,这个镜像什么都做好了,配置好ip:192.168.200.128 就可以使用了。 路径: \品优购项目-配置软件-工具-讲义-资料\品优购项目-配置软...

qq847196660的博客 859

Silvaco 学习笔记——物理模型:载流子产生复合模型

对载流子的复合机制进行总结

reactortiger的博客 1万+

基于Java swing的电子图片管理系统设计与实现 文档+项目源码

电子图片管理程序是一款使用方便的图片管理软件,小巧方便,功能强大,可以很方便的去让用户管理自己的图片,增删改除,放大缩小,处理图片等。它在设计时采用了缩略图形式和树形目录,方便用户查看管理,在图片查看界面时,采用了可鼠标拖拽操作、可放大缩小的功能,同时有全新的图片处理界面,提供方便操作的按钮和滑动条变化图片参数,用户可以对图片参数进行调整处理,方便用户实现对于图片心中所想的样子;(3)创造与编辑界面的流程图: 11。(4)保险柜界面的流程图: 12。(1)主界面的流程图: 10。2.杨俊杰个人感想 21。

毕业作品网站 1328

Allegro输出光绘文件规范

添加钻孔表的具体步骤为:1.通过屏幕右边的Visibility选项的Views列表,将Drill层打开2.将Visibility选项中的PIN和Via选项都选中,见下图所示: 参数设好之后关闭NC Drill/Parameters窗口,输出数控机床钻孔文件的命令菜单为:Manufacture=>NC=>NC Drill…,打开的窗口如下: 输出数控机床钻孔文件的具体步骤为: 上图是光绘输出的层控制窗口,还有一个窗口是输出参数的控制窗口,我们通过点击上图的第二个列表项General Parameters来

axingxiansen的博客 2808

基于YOLOv8深度学习的夜视行人检测系统:UI界面 + YOLOv8 + 数据集的实现

为了解决这一问题,基于深度学习的行人检测技术,尤其是YOLO(You Only Look Once)系列算法,成为了一个有效的解决方案。本文将详细介绍如何构建一个夜视行人检测系统,利用YOLOv8模型实现高效的行人检测,并设计用户友好的界面以便于使用。本博客详细介绍了如何构建一个基于深度学习的夜视行人检测系统,包括数据准备、YOLOv8模型训练、用户界面设计和实时监控模块的实现。为了将数据集转换为YOLO格式,我们需要确保每个图像文件都有一个对应的标签文件,标签文件中包含行人的边界框信息。

YOLO 1172

学成在线--day08 课程图片管理 分布式文件系统

学成在线 第8天 讲义-课程图片管理 分布式文件系 统 这个文件系统得安装在这个学成在线得系统中并没有讲解,基本上都是安装文档安装,得也是比较老得套路,提前写号得代码复制一下,基本跑通是没有任何问题得,个人觉得这个项目得可读性还有可练习性非常差,非常不建议新手学这个项目,完全浪费时间我,我个人看看后面还有什么坑没,尽量都把他显示出来,总之看这个学成在线得视频,看到后面越看越水,基本就...

zgz102928的博客 332

我的AI个人公司成立:基于Skills与Qwen大模型的智能问答平台实战开发+龙虾团队

微学AI推出数字员工矩阵,包含10个核心AI角色(总经理、秘书、工程师等),每个角色具备专属技能模块。系统采用FastAPI+Vue3技术栈,核心功能包括:基于SkillLoader的动态技能管理(支持脚本执行和文档加载)、WebSocket流式输出、多轮对话上下文管理。通过模块化架构实现AI自驱协作,可自主完成从需求分析到开发落地的全流程。项目亮点在于声明式技能配置和实时交互能力,打破传统办公壁垒,提升工作效率。

微学AI的博客 1625

微服务[学成在线] day20:项目总结

???? 写在前面 我为什么要花时间去写这个笔记? 由于在学习该项目的过程中发现了原讲义存在的一些问题,所以该笔记基于「学成在线」微服务项目 PDF 讲义进行编写,并且投入了时间去优化了笔记的格式、代码的高亮、重点的标记等。 以及一些原讲义中所描述的一些知识点使我无法理解的内容,我会对这些内容的表达方式进行修改或者提出一些问题,并且用我自己所理解的一些想法去重新的解释这个问题。 总结一下原 PDF 讲义中已知的一些问题: 从 PDF 中复制出来的代码,部分特殊符号的编码有问题,并且不易被发现,例如横杠

通往体面生活的路上 3261

Spring Boot 与 Redisson 版本适配深度解析

Spring Boot 与 Redisson 的版本适配是一个动态演进的过程。开发者需要密切关注两者官方的版本更新日志,建立完善的版本验证机制。本文提供的适配方案基于当前最新技术状态(2024年1月),建议在实际生产环境中通过灰度发布策略验证版本兼容性。只有深入理解底层技术原理,才能在分布式系统的星辰大海中稳健航行。延伸阅读Spring Boot 官方迁移指南。

fudaihb的博客 1083

SAP_SD模块更改销售订单定价简介

方式优点缺点适用场景MASS简单,无需开发不能触发重新定价逻辑修改特定字段BDC (VA02)可模拟人工操作维护复杂,速度慢少量订单批改稳定、安全需ABAP支持推荐用于批量重新定价VBOF标准重算返利仅适返利类条件返利更新通过本文,我们了解了 SAP 的[SAP_SD模块更改销售订单定价]的基本概念和应用方法。希望这些信息能帮助您在实际工作中更好地使用 SAP 系统,提高工作效率和管理水平。更多SAP文章请点击更多SAP文章更新,大家一起学习进步!!!

我小时候很黑的博客 713

微服务[学成在线] day18:基于oauth2实现RBAC认证授权、微服务间认证实现

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day18 的内容 基于方法的权限校验 基于 RBAC 进行用户权限配置以及动态查询。 根据教师所属的公司来实现课程信息查询的细粒度授权。也就是 A 公司的老师只能查询到 A 公司下的课程。 使用 Feign 拦截器实现获取前端请求中的 header 信息,并将 header 中带有

通往体面生活的路上 2004

【100%通过率】2023华为od机试C卷【围棋的气】Python 实现

围棋棋盘由纵横各19条线垂直相交组成,棋盘上一共19 x 19 = 361 个交点,对奔双方一方执白棋,一方执黑棋,落子时只能将棋子置于交点上。 “气”是围棋中很重要的一个概念,某个棋子有几口气,是指其上下左右方向四个相邻的交叉点中,有几个交叉点没有棋子,由此可知:

MISAYAONE的博客 1858

微服务[学成在线] day13:使用FFmpeg进行格式转换以及m3u8文件生成、文件分块上传接口实现

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day13 的内容 FFmpeg 的基本使用 使用 m3u8 和 video.js技术实现视频的在线播放 搭建媒资服务工程实现文件的分块储存 目录 内容会比较多,小伙伴们可以根据目录进行按需查阅。 文章目录???? 知识点概览目录一、在线学习需求分析0x01 需求描述0x02 视频点

通往体面生活的路上 1724

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

微服务[学成在线] day10:课程发布、ElasticSearch

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day10 的内容 课程发布功能开发 ElasticsSearch 安装部署 ElasticsSearch 快速入门、IK 分词器、映射、索引。 目录 内容会比较多,小伙伴们可以根据目录进行按需查阅。 文章目录???? 知识点概览目录一、课程发布0x01 需求分析0x02 CMS一键

通往体面生活的路上 1205

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

微服务[学成在线] day05:消息中间件 RabbitMQ

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day05 的内容 RabbitMQ 的基本应用场景 使用原生RabbitMQ 库构建生产者与消费者模型 整合 Springboot 实现 RabbitMQ 生产者与消费者模型 目录 内容会比较多,小伙伴们可以根据目录进行按需查阅。 文章目录???? 知识点概览目录一、需求分析二、初

通往体面生活的路上 846

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

微服务[学成在线] day20:项目部署与持续集成(DevOps)

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day20 的内容。 原讲义中对该章节的 gitlab 与 jenkins 安装步骤以及部署容器的内容和步骤描述得不够详细,在本文中做出了补充,详细的描述每个步骤。 本章节建议还是尝试看笔记来完成一次操作,然后再去看视频资料,这样能理解得更深刻。 目录 内容会比较多,可以根据目录进行按

通往体面生活的路上 812

微服务[学成在线] day16:基于Spring Security Oauth2开发认证服务

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day16 的内容 学习 Spring Security + Oauth2 基本概念以及实现过程。 学习 Oauth2 的基本应用场景,这里主要是通过 Oauth2 的密码模式来实战。 初识 JWT 令牌。 本章节的最后通过 Spring Security Oauth2 完成了认证

通往体面生活的路上 801

微服务[学成在线] day11:基于 ElasticSearch 构建搜索服务

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day11 的内容 基于 Java 客户端实现 DSL 搜索 搭建 ElasticSearch 集群环境 使用 Logstash 自动创建 ElasticSearch 的索引、数据文档 基于 ElasticSearch 开发搜索服务接口 目录 内容会比较多,小伙伴们可以根据目录进行

通往体面生活的路上 778

微服务[学成在线] day07:课程管理开发

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day07 的内容 对课程管理的CRUD 级联菜单 使用 mongoDB 储存数据字典 目录 内容会比较多,小伙伴们可以根据目录进行按需查阅。 文章目录???? 知识点概览目录一、课程查询0x01 需求分析0x02 定义API接口0x03 课程管理服务PageHelperDaoSer

通往体面生活的路上 710

微服务[学成在线] day12:基于 Nuxt.js 构建搜索前端工程

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day12 的内容 Nuxt.js 的基本使用 基于 Nuxt.js 开发搜索门户前端 目录 知识点结合实战应用会更有意义,所以这里我就不再对单个知识点进行拆分成单个笔记,内容会比较多,这里我们可以根据目录进行按需阅读。 文章目录???? 知识点概览目录一、搜索前端技术需求0x01 什

通往体面生活的路上 698

微服务[学成在线] day17:基于Zuul网关实现路由转发、过滤器

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day17 的内容 构建用户中心服务,并基于 Spring Security Oauth2 以及 jwt 令牌实现用户认证的完整流程。 完成门户网站的用户登入、登出接口、前端页面的开发以及调试。 基于 Zuul 构建网关服务,以及使用 Zuul 网关实现基本的路由转发、过滤器、身份校验

通往体面生活的路上 690

微服务[学成在线] day15:媒资管理系统集成

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day15 的内容 根据 课程ID 搜索该课程已发布的课程信息,并返回该课程的所有课程计划信息。 将指定课程 发布时 所的课程计划的媒资信息保存到 teachplan_media_publish 表中, 根据 课程计划id 搜索该课程计划所对应的媒资信息,需要用到的是该课程计划对应的

通往体面生活的路上 639

微服务[学成在线] day06:页面发布以及课程管理

???? 知识点概览 为了方便后续回顾该项目时能够清晰的知道本章节讲了哪些内容,并且能够从该章节的笔记中得到一些帮助,所以在完成本章节的学习后在此对本章节所涉及到的知识点进行总结概述。 本章节为【学成在线】项目的 day06 的内容 使用 Spring boot 集成 RabbitMQ 和 GridFS 实现基于生产者和消费者模型的页面静态化发布的流程。 在本章节的知识点中,再次复习了基于 GridFS 和 RabbitMQ 的分布式静态页面发布的知识点,深化了记忆。 使用三级菜单实现课程计

通往体面生活的路上 627

微服务[学成在线] day02:CMS前端开发

???? 写在前面 我为什么要花时间去写这个笔记? 由于在学习该项目的过程中发现了原讲义存在的一些问题,所以该笔记基于「学成在线」微服务项目 PDF 讲义进行编写,并且投入了时间去优化了笔记的格式、代码的高亮、重点的标记等。 以及一些原讲义中所描述的一些知识点使我无法理解的内容,我会对这些内容的表达方式进行修改或者提出一些问题,并且用我自己所理解的一些想法去重新的解释这个问题。 总结一下原 PDF 讲义中已知的一些问题: 从 PDF 中复制出来的代码,部分特殊符号的编码有问题,并且不易被发现,例如横杠

通往体面生活的路上 614

微服务[学成在线] day01:CMS接口开发

???? 写在前面 我为什么要花时间去写这个笔记? 由于在学习该项目的过程中发现了原讲义存在的一些问题,所以该笔记基于「学成在线」微服务项目 PDF 讲义进行编写,并且投入了时间去优化了笔记的格式、代码的高亮、重点的标记等。 以及一些原讲义中所描述的一些知识点使我无法理解的内容,我会对这些内容的表达方式进行修改或者提出一些问题,并且用我自己所理解的一些想法去重新的解释这个问题。 总结一下原 PDF 讲义中已知的一些问题: 从 PDF 中复制出来的代码,部分特殊符号的编码有问题,并且不易被发现,例如横杠

通往体面生活的路上 611
上一篇: 微服务[学成在线] day07:课程管理开发
下一篇: 微服务[学成在线] day09:Eureka、Feign、课程预览实现
cory_lin
博客等级 码龄7年 22粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值