zoukankan      html  css  js  c++  java
  • Day08_课程图片管理与分布式文件系统

    1 FastDFS研究

    参考链接:https://www.cnblogs.com/artwalker/p/13502534.html

    2 上传图片开发

    1.1.1 需求分析

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

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

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

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

    执行流程如下:

    1、管理员进入教学管理前端,点击上传图片
    2、图片上传至文件系统服务,文件系统请求fastDFS上传文件
    3、文件系统将文件入库,存储到文件系统服务数据库中。
    4、文件系统服务向前端返回文件上传结果,如果成功则包括文件的Url路径。
    5、课程管理前端请求课程管理进行保存课程图片信息到课程数据库。
    6、课程管理服务将课程图片保存在课程数据库。
    

    1.1.2 创建文件系统服务工程

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

    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)配置文件

    原测试程序中fastdfs-client.properties的配置信息统一放在application.yml

    server:
      port: 22100
    spring:
      application:
        name: xc-service-base-filesystem
      #mongo配置
      data:
        mongodb:
          database: xc_fs
          uri:  mongodb://localhost: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: 10.211.55.13:22122 #多个 trackerServer中间以逗号分隔
    

    1.1.3 API接口

    1.1.3.1 模型类

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

    1. 模型如下:
    package com.xuecheng.framework.domain.filesystem;
    
    import lombok.Data;
    import lombok.ToString;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.mongodb.core.mapping.Document;
    
    import java.util.Map;
    
    /**
     * Created by mrt on 2018/2/5.
     */
    @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:文件相关的元信息。
    
    1. collection

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

    1.1.3.2 Api接口

    在api工程下创建com.xuecheng.api.filesystem包,

    package com.xuecheng.api.filesystem;
    
    import com.xuecheng.framework.domain.filesystem.response.UploadFileResult;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.web.multipart.MultipartFile;
    
    @Api(value="文件管理接口",description = "文件管理接口,提供文件的增、删、改、查")
    public interface FileSystemControllerApi {
        /**
         * 上传文件
         * @param multipartFile 文件
         * @param filetag   文件标签
         * @param businesskey 业务key
         * @param metadata 元信息,json格式
         * @return
         */
        @ApiOperation("上传文件接口")
        public UploadFileResult upload(MultipartFile multipartFile,
                                       String filetag,
                                       String businesskey,
                                       String metadata);
    }
    
    1.1.2.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.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.util.Map;
    
    /**
     * @author Administrator
     * @version 1.0
     **/
    @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;
    
        //上传文件
        public UploadFileResult upload( MultipartFile multipartFile,
                                       String filetag,
                                       String businesskey,
                                       String metadata){
            if(multipartFile ==null){
                ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_FILEISNULL);
            }
            //第一步:将文件上传到fastDFS中,得到一个文件id
            String fileId = fdfs_upload(multipartFile);
            if(StringUtils.isEmpty(fileId)){
                ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_SERVERFAIL);
            }
            //第二步:将文件id及其它文件信息存储到mongodb中。
            FileSystem fileSystem = new FileSystem();
            fileSystem.setFileId(fileId);
            fileSystem.setFilePath(fileId);
            fileSystem.setFiletag(filetag);
            fileSystem.setBusinesskey(businesskey);
            fileSystem.setFileName(multipartFile.getOriginalFilename());
            fileSystem.setFileType(multipartFile.getContentType());
            if(StringUtils.isNotEmpty(metadata)){
                try {
                    Map map = JSON.parseObject(metadata, Map.class);
                    fileSystem.setMetadata(map);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            fileSystemRepository.save(fileSystem);
            return new UploadFileResult(CommonCode.SUCCESS,fileSystem);
        }
    
        //上传文件到fastDFS
    
        /**
         *
         * @param multipartFile 文件
         * @return 文件id
         */
        private String fdfs_upload(MultipartFile multipartFile){
             //初始化fastDFS的环境
             initFdfsConfig();
             //创建trackerClient
            TrackerClient trackerClient = new TrackerClient();
            try {
                TrackerServer trackerServer = trackerClient.getConnection();
                //得到storage服务器
    
                StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
                //创建storageClient来上传文件
                StorageClient1 storageClient1 = new StorageClient1(trackerServer,storeStorage);
                //上传文件
                //得到文件字节
                byte[] bytes = multipartFile.getBytes();
                //得到文件的原始名称
                String originalFilename = multipartFile.getOriginalFilename();
                //得到文件扩展名
                String ext = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
                String fileId = storageClient1.upload_file1(bytes, ext, null);
                return fileId;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        //初始化fastDFS环境
        private void initFdfsConfig(){
            //初始化tracker服务地址(多个tracker中间以半角逗号分隔)
            try {
                ClientGlobal.initByTrackers(tracker_servers);
                ClientGlobal.setG_charset(charset);
                ClientGlobal.setG_network_timeout(network_timeout_in_seconds);
                ClientGlobal.setG_connect_timeout(connect_timeout_in_seconds);
            } catch (Exception e) {
                e.printStackTrace();
                //抛出异常
                ExceptionCast.cast(FileSystemCode.FS_INITFDFSERROR);
            }
        }
    }
    
    1.1.2.5 Controller
    package com.xuecheng.filesystem.controller;
    
    import com.xuecheng.api.filesystem.FileSystemControllerApi;
    import com.xuecheng.filesystem.service.FileSystemService;
    import com.xuecheng.framework.domain.filesystem.response.UploadFileResult;
    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;
    
    /**
     * @author Administrator
     * @version 1.0
     **/
    @RestController
    @RequestMapping("/filesystem")
    public class FileSystemController implements FileSystemControllerApi {
        @Autowired
        FileSystemService fileSystemService;
    
    
        @Override
        @PostMapping("/upload")
        public UploadFileResult upload(MultipartFile multipartFile, String filetag, String businesskey, String metadata) {
    
            return fileSystemService.upload(multipartFile, filetag, businesskey, metadata);
        }
    }
    
    1.1.2.6 测试

    使用swagger-ui或postman进行测试。

    下图是使用swagger-ui进行测试的界面:

    1.1.3 上传课程图片前端

    1.1.3.1 需求

    上传图片界面如下图:

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

    1.1.3.2 页面

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

    1. template (course_picture.vue)
    <template>
      <div>
        <el-upload
          action="/api/filesystem/upload"
          list-type="picture-card"
          :before-upload="setuploaddata"
          :on-success="handleSuccess"
          :file-list="fileList"
          :limit="picmax"
          :on-exceed="rejectupload"
          :before-remove="handleRemove"
          :data="uploadval">
          <i class="el-icon-plus"></i>
        </el-upload>
      </div>
    </template>
    

    el-upload参数说明:

    action:必选参数,上传的地址
    list-type:文件列表的类型(text/picture/picture-card)
    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"},//上传提交的额外的数据,将uploadval转成key/value提交给服务器
            imgUrl:sysConfig.imgUrl
          }
        },
        methods: {
          //超出文件上传个数提示信息
          rejectupload(){
            this.$message.error("最多上传"+this.picmax+"个图片");
          },
          //在上传前设置上传请求的数据
          setuploaddata(){
    
          },
          //删除图片
          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()
                }
    
              })
            })
    
          },
          //上传成功的钩子方法
          handleSuccess(response, file, fileList){
            console.log(response)
    //        alert('上传成功')
            //调用课程管理的保存图片接口,将图片信息保存到课程管理数据库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(res.message)
                  }
    
              })
            }
    
          },
          //上传失败执行的钩子方法
          handleError(err, file, fileList){
            this.$message.error('上传失败');
            //清空文件队列
            this.fileList = []
          },
          //promise 有三种状态:
          //进行中pending
          //执行成功 resolve
          //执行失败 reject
          testPromise(i){
    
              return new Promise((resolve,reject)=>{
                  if(i<2){
                      //成功了
                    resolve('成功了');
                  }else{
                      //失败了
                    reject('失败了');
                  }
    
              })
          }
        },
        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})
              }
    
          })
        }
      }
    </script>
    
    1.1.3.3 测试

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

    3 保存课程图片

    1.2.1 需求分析

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

    业务流程如下:

    1、上传图片到文件系统服务
    2、保存图片地址到课程管理服务
    3、在course_pic保存图片成功后方可查询课程图片信息
    

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

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

    1.2.2 课程管理服务端开发(在xc-service-manage-course下)

    1.2.2.1 API

    课程管理需要使用图片,则在课程管理服务中提供保存课程图片的api。

    @Api(value = "课程管理接口", description = "课程管理接口,提供课程的增、删、改、查")
    public interface CourseControllerApi {
        @ApiOperation("添加课程图片")
        public ResponseResult addCoursePic(String courseId, String pic);
    }
    
    1.2.2.2 Dao

    模型:

    package com.xuecheng.framework.domain.course;
    
    import lombok.Data;
    import lombok.ToString;
    import org.hibernate.annotations.GenericGenerator;
    
    import javax.persistence.*;
    import java.io.Serializable;
    
    /**
     * Created by admin on 2018/2/10.
     */
    @Data
    @ToString
    @Entity
    @Table(name="course_pic")
    @GenericGenerator(name = "jpa-assigned", strategy = "assigned")
    public class CoursePic implements Serializable {
        private static final long serialVersionUID = -916357110051689486L;
    
        @Id
        @GeneratedValue(generator = "jpa-assigned")
        private String courseid;
        private String pic;
    
    }
    

    Dao如下:

    package com.xuecheng.filesystem.dao;
    
    import com.xuecheng.framework.domain.course.CoursePic;
    
    /**
     * @author HackerStar
     * @create 2020-08-14 16:43
     */
    public interface CoursePicRepository extends JpaRepository<CoursePic, String> {
    }
    
    
    1.2.3.3 Service
    //添加课程图片
        @Transactional
        public ResponseResult saveCoursePic(String courseId, String pic) {
            //查询课程图片
            Optional<CoursePic> picOptional = coursePicRepository.findById(courseId);
            CoursePic coursePic = null;
            if (picOptional.isPresent()) {
                coursePic = picOptional.get();
            }
            //没有课程图片则新建对象
            if (coursePic == null) {
                coursePic = new CoursePic();
            }
            coursePic.setCourseid(courseId);
            coursePic.setPic(pic);
            //保存课程图片
            coursePicRepository.save(coursePic);
            return new ResponseResult(CommonCode.SUCCESS);
        }
    
    1.2.3.4 Controller
    		@Override
        public ResponseResult addCoursePic(String courseId, String pic) {
            //保存课程图片
            return courseService.saveCoursePic(courseId,pic);
        }
    

    1.2.4 前端开发

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

    1.2.4.1 Api方法 (course.js)
    //添加课程图片 
    export const addCoursePic = (courseId, pic) => {
      return http.requestPost(apiUrl + '/course/coursepic/add?courseId=' + courseId + "&pic=" + pic)
    }
    
    1.2.4.2 页面

    1)添加上传成功的钩子 :on-success="handleSuccess"

    <el-upload
          action="/api/filesystem/upload"
          list-type="picture-card"
          :before-upload="setuploaddata"
          :on-success="handleSuccess"
          :file-list="fileList"
          :limit="picmax"
          :on-exceed="rejectupload"
          :before-remove="handleRemove"
          :data="uploadval">
          <i class="el-icon-plus"></i>
    </el-upload>
    

    2)在钩子方法 中保存课程图片信息

    如果保存图片失败则上传失败,清除文件列表。

    //上传成功的钩子方法
          handleSuccess(response, file, fileList){
            console.log(response)
    //        alert('上传成功')
            //调用课程管理的保存图片接口,将图片信息保存到课程管理数据库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(res.message)
                  }
    
              })
            }
          },
    //上传失败执行的钩子方法
          handleError(err, file, fileList){
            this.$message.error('上传失败');
            //清空文件队列
            this.fileList = []
          },
    

    4 图片查询

    1.3.1 需求分析

    课程图片上传成功,再次进入课程上传页面应该显示出来已上传的图片。

    1.3.2 API

    在课程管理服务定义查询方法

    @Api(value = "课程管理接口", description = "课程管理接口,提供课程的增、删、改、查")
    public interface CourseControllerApi {
        @ApiOperation("获取课程基础信息")
        public CoursePic findCoursePic(String courseId);
    }
    

    1.3.2 课程管理服务开发

    1.3.2.1 Dao

    使用CoursePicRepository即可,无需再开发。

    1.3.2.2 Service

    根据课程id查询课程图片

    		//查询课程图片
        public CoursePic findCoursePic(String courseId) {
            //查询课程图片
            Optional<CoursePic> picOptional = coursePicRepository.findById(courseId);
            if(picOptional.isPresent()){
                CoursePic coursePic = picOptional.get();
                return coursePic;
            }
            return null;
        }
    
    1.3.2.3 Controller
    		@Override
        @GetMapping("/coursepic/list/{courseId}")
        public CoursePic findCoursePic(@PathVariable("courseId") String courseId) {
            return courseService.findCoursePic(courseId);
        }
    

    1.3.3 前端开发

    1.3.3.1 API方法
    //查询课程图片
    export const findCoursePicList = courseId => {
      return http.requestQuickGet(apiUrl + '/course/coursepic/list/' + courseId)
    }
    
    1.3.3.2 页面

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

    1、定义图片查询方法

    //查询图片
          list() {
            courseApi.findCoursePicList(this.courseid).then((res) => {
              console.log(res);
              if (res.pic) {
                let name = '图片';
                let url = this.imgUrl + res.pic;
                let fileId = res.courseid; //先清空文件列表,再将图片放入文件列表
                this.fileList = [];
                this.fileList.push({name: name, url: url, fileId: fileId});
              }
              console.log(this.fileList);
            });
          },
    

    2)mounted钩子方法

    在mounted钩子方法中调用服务端查询文件列表并绑定到数据对象。

    mounted() {
          //课程id
          this.courseid = this.$route.params.courseid;
          //查询图片 
          this.list();
          //查询课程
          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})
            }
          })
        }
    
    1.3.3.3 测试

    测试流程:

    1、上传图片成功
    2、进入上传图片页面,点到其他信息,再返回,观察图片是否显示
    

    资料给的代码前端代码有问题,上传图片时,总是显示没有上传图片,导入课上代码,是有用的。

    5 课程图片删除

    1.4.1 需求分析

    课程图片上传成功后,可以重新上传,方法是先删除现有图片再上传新图片。

    注意:此删除只删除课程数据库的课程图片信息,不去删除文件数据库的文件信息及文件系统服务器上的文件,由于课程图片来源于该用户的文件库,所以此图片可能存在多个地方共用的情况,所以要删除文件系统中的文件,需要到图片库由用户确认后再删除。

    1.4.2 课程管理服务端开发

    1.4.2.1 API
    @Api(value = "课程管理接口", description = "课程管理接口,提供课程的增、删、改、查")
    public interface CourseControllerApi {
        @ApiOperation("删除课程图片")
        public ResponseResult deleteCoursePic(String courseId);
    }
    
    1.4.2.2 Dao

    CoursePicRepository父类提供的delete方法没有返回值,无法知道是否删除成功,这里我们在CoursePicRepository下边自定义方法:

    //删除成功返回1否则返回0 
    long deleteByCourseid(String courseid);
    
    1.4.2.3 Service
    //删除课程图片
        @Transactional
        public ResponseResult deleteCoursePic(String courseId) {
            //执行删除,返回1表示删除成功,返回0表示删除失败
            long result = coursePicRepository.deleteByCourseid(courseId);
            if (result > 0) {
                return new ResponseResult(CommonCode.SUCCESS);
            }
            return new ResponseResult(CommonCode.FAIL);
        }
    
    1.4.2.4 Controller
    		@Override
        @DeleteMapping("/coursepic/delete")
        public ResponseResult deleteCoursePic(@RequestParam("courseId") String courseId) {
            return courseService.deleteCoursePic(courseId);
        }
    

    1.4.3 前端开发

    1.4.3.1 API 调用
    //删除课程图片
    export const deleteCoursePic = courseId => {
      return http.requestDelete(apiUrl + '/course/coursepic/delete?courseId=' + courseId)
    }
    
    1.4.3.2 页面测试

    1)before-remove钩子方法

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

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

    定义handleRemove方法进行测试:

    handleRemove 返回true则删除页面的图片,返回false则停止删除页面的图片。

    //删除图片
          handleRemove(file, fileList) {
            console.log(file)
            alert('删除成功')
    				return true;
          },
    
    1.4.3.3 promise异步调用

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

    //删除图片
          handleRemove(file, fileList) {
            console.log(file)
             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("删除失败");
                  //失败
                 reject();
                }
              })
            })
          },
    
    1.4.3.4 测试

  • 相关阅读:
    numpy函数库中一些常用函数的记录
    python 中的tile函数,shape函数,sum函数
    数据挖掘十大经典算法(详解)
    逻辑回归
    17个新手常见Python运行时错误
    5.3.4 Hadoop序列化框架
    5.3.3 自定义writable和RawComparatorWritable
    Qt5.11.2 VS2015编译activemq发送程序 _ITERATOR_DEBUG_LEVEL错误和崩溃解决
    @ConfigurationProperties实现配置注入到实体类
    C++微信网页协议实现和应用
  • 原文地址:https://www.cnblogs.com/artwalker/p/13507634.html
Copyright © 2011-2022 走看看