华为云OBS文件上传和下载

华为云Obs文件上传和下载

使用的技术

  1. 前端是Vue框架,element-ui
  2. 后端是Springboot项目
  3. 服务器是华为云
  4. 文件上传下载地方是华为云Obs对象存储服务

1、前端上传代码

el-upload组件:

<el-upload
    class="upload-demo"
    ref="upload"
    action
    :limit="limitNum"
    :before-upload="beforeAvatarUpload"
    :on-remove="handleRemove"
    :http-request="myUpload"
    :file-list="fileList"
    :auto-upload="false">
    <el-button slot="trigger" size="small" type="primary">选择文件</el-button>
    <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">上传到服务器</el-button>
    <div slot="tip" class="el-upload__tip">服务器容量有限,尽量不要上传大文件!</div>
  </el-upload>

方法:

methods: {
      // 手动上传操作
      submitUpload() {
        // 触发自定义的上传方法 myUpload
        this.$refs.upload.submit();
      },
      // 覆盖默认的上传行为,自定义上传的实现,有几个文件就会调用这个方法几次
      myUpload(fileObj) {
        let formData = new FormData();
        formData.set('file', fileObj.file);
        this.$api.fileUpload(formData)
          .then(response => {
            if (response.data.success === true) {
              this.$notify({
                title: '上传成功',
                message: response.data.re.name + '上传成功!',
                type: 'success'
              });
              // 清空已上传的文件列表
              this.$refs.upload.clearFiles();
            } else {
              this.$notify.error({
                title: '上传失败',
                message: '上传失败,请重试!'
              });
            }
          })
          .catch(error => {
            this.$message('发生错误了!');
          });
      },
      // 上传前的钩子函数
      beforeAvatarUpload(file) {
        // 文件格式
        const extension = file.name.substring(file.name.lastIndexOf('.') + 1);
        // 文件大小
        const size = file.size / 1024 / 1024;
        if (size > 100) {
          this.$notify({
            title: '警告',
            message: '文件大小不得超过100MB!',
            type: 'warning'
          });
        }
      },
      handleRemove(file, fileList) {
        let fileLists = [];
        fileList.forEach(function (elem) {
          let item = {
            name: elem.name,
            url: ''
          };
          fileLists.push(item);
        });
        this.fileList = fileLists;
      }
    }

2、前端下载代码

方法:

	// 本地下载
	localDownload() {
		let fileName = '2.jpeg';
        this.$api.fileDownload(fileName)
          .then(res => {
            const blob = new Blob([res.data], {type: 'text/plain;charset=UTF-8'});
            const filename = decodeURI(res.headers['content-disposition'].split('filename=')[1]);
            // IE
            if (window.navigator && window.navigator.msSaveOrOpenBlob) {
              window.navigator.msSaveOrOpenBlob(blob, filename)
            } else {
              let href = window.URL.createObjectURL(blob);
              this.simulateDownloadByA(href, filename);
            }
          })
          .catch(error => {
            this.$message('发生错误了!');
          })
      },
	// 通过a标签模拟下载
	simulateDownloadByA(href, filename) {
        const a = document.createElement('a');
        a.download = filename;
        a.style.display = 'none';
        a.href = href;
        document.body.appendChild(a);
        a.click();
        a.remove();
        window.URL.revokeObjectURL(href);
      }

3、前端请求方法:

import instance from './http'

// 上传文件
function fileUpload (data) {
  return instance.post(process.env.API_HOST + '/ziyuan/file/fileUpload', data, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  })
}

// 下载文件
function fileDownload (data) {
  return instance.post(process.env.API_HOST + '/ziyuan/file/fileDownload', {
    date: new Date().getTime(),
    fileName: JSON.stringify(data)
  }, {
    responseType: "blob"
  })
}

注意:

  1. instance是我封装在http.js中的实例
  2. 上传文件时传参不能序列化,否则传递的就不是文件(file),导致上传无法成功
  3. 下载文件方法要设置responseType为“blob”或者“arraybuffer”,要不然会乱码

3、后端端代码

pom文件引入依赖:

<dependency>
	<groupId>com.huaweicloud</groupId>
	<artifactId>esdk-obs-java</artifactId>
	<version>3.19.7</version>
</dependency>

上传:

@RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
    public Result fileUpload(@RequestParam(value = "file", required = false) MultipartFile multipartFile) {
        try {
            // 创建ObsClient实例
            ObsClient obsClient = new ObsClient(FileConstant.AK, FileConstant.SK, FileConstant.END_POINT);
            // 上传文件,注意:上传内容大小不能超过5GB
            String objectKey = multipartFile.getOriginalFilename();
            InputStream inputStream = multipartFile.getInputStream();
            PutObjectResult putObjectResult = obsClient.putObject(FileConstant.BUCKET_NAME, objectKey, inputStream);
            String url = "https://" + putObjectResult.getObjectUrl();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name", objectKey);
            jsonObject.put("url", url);
            inputStream.close();
            obsClient.close();
            return Result.success("文件上传成功!", jsonObject);
        } catch (Exception e) {
            log.error("{}文件上传失败!", multipartFile.getOriginalFilename());
            return Result.fail("文件上传失败!");
        }
    }

下载:

@RequestMapping(value = "/fileDownload", method = RequestMethod.POST)
    public Result fileDownload(HttpServletRequest request, HttpServletResponse response, @RequestBody String jsonString) {
        JSONObject jsonObject = JSON.parseObject(jsonString);
        String fileName = JSON.parseObject((String) jsonObject.get("fileName"), String.class);
        try {
            // 创建ObsClient实例
            ObsClient obsClient = new ObsClient(FileConstant.AK, FileConstant.SK, FileConstant.END_POINT);
            ObsObject obsObject = obsClient.getObject(FileConstant.BUCKET_NAME, fileName);
            InputStream inputStream = obsObject.getObjectContent();
            // 缓冲文件输出流
            BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            // 为防止 文件名出现乱码
            final String userAgent = request.getHeader("USER-AGENT");
            // IE浏览器
            if (StringUtils.contains(userAgent, "MSIE")) {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } else {
                // google,火狐浏览器
                if (StringUtils.contains(userAgent, "Mozilla")) {
                    fileName = new String(fileName.getBytes(), "ISO8859-1");
                } else {
                    // 其他浏览器
                    fileName = URLEncoder.encode(fileName, "UTF-8");
                }
            }
            response.setContentType("application/x-download");
            // 设置让浏览器弹出下载提示框,而不是直接在浏览器中打开
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            IOUtils.copy(inputStream, outputStream);
            outputStream.flush();
            outputStream.close();
            inputStream.close();
            return null;
        } catch (IOException | ObsException e) {
            log.error("文件下载失败:{}", e.getMessage());
            return Result.fail("文件下载失败!");
        }
    }

注意:

  1. end-point、ak、sk是华为云Obs提供的,bucketName是你创建的桶名,都写在常量类里了
  2. Result是自己封装的后端返回类

4、遇到的问题

  1. end-point、ak、sk的获取
    地址:https://support.huaweicloud.com/qs-obs/obs_qs_0005.html
    华为云OBS文件上传和下载_第1张图片
    获取AK和SK,桶是自己创建,end-point我的是 https://obs.cn-north-4.myhuaweicloud.com
    华为云OBS文件上传和下载_第2张图片
  2. 上传文件时
    上传文件要设置请求头,请求参数放文件,后端可以以 MultipartFile 类型接收
    华为云OBS文件上传和下载_第3张图片
    在这里插入图片描述
    在这里插入图片描述
  3. 下载文件时
    1、下载文件传递的参数文件名要序列化,后端以String来接收,转化为JSONObject,再获取参数
    在这里插入图片描述
    注意不能写成:String fileName1 = (String) jsonObject.get("fileName");不然获取ObsObject的时候会报错
    2、 成功返回前端的时候要return null;不然会报一个重复提交的错误:
    Cannot call sendError() after the response has been committed
    3、下载文件的请求要设置请求头,不然会乱码

---------------------------20200619-------------------------------------
我看有小伙伴说 http.js 的代码不太清楚怎么封装,我把主要的写出来

import axios from 'axios'
// 创建axios实例
const instance = axios.create({timeout: 1000 * 60})
// 设置post请求头
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
export default instance

当然在这文件中能做的事情还有很多,比如说请求拦截、响应拦截、错误统一处理、路由跳转等等

贴两个不错的关于axios封装文章:
https://blog.csdn.net/qq_38145702/article/details/81558816#commentBox
https://blog.csdn.net/qq_40128367/article/details/82735310#commentBox

你可能感兴趣的:(java,vue,javascript,js,post)