File 文件上传 — 前后端实现

项目中通常会涉及到图片上传以便于各种业务场景,复用率高就会封装为模块进行使用,此文章主要针对前端封装文件做详细介绍。

文件

场景

        用户资料、审核资料、文件库等场景。

以下会以图片、PDF文档等类型进行演示。

在代码中其实就是 FromData 对象包含 File 对象~。

前端

此处前端以 Vue + ElementPlus 举例。

Vue 组件中定义 Upload 组件

<template>
    <el-upload
            multiple
            action="#"
            class="upload-demo"
            :auto-upload="false"
            :on-change="change"
    >
         <el-button type="primary">select file</el-button>
    </el-upload>
<template>

后端接收文件格式需为 FormData 对象,将 File 对象 append 至 FormData 对象里,以下只是简单示例,axios url 需替换为自己服务器地址,并且需参考下方修改 headers。

const change = (data) => {
      let formData = new FormData();
      formData.append('file', data.raw);
      axios({
          method:"POST",
          data:formData,
          url: 'http://192.168.0.111:8888/upload/files',
          headers:{
              'Content-Type':'multipart/form-data',
          },
      }).then(res=>{
          console.log(res)
      }).catch(err=>{
          console.log(err)
      })
}

后端

此处以 Java Spring Boot 为示例。

下方代码过于简单就是普通接收 FormData 对象并设置 File 信息保存至本地指定文件夹。

@PostMapping("files")
@ResponseBody
@TokenCheck
public Result<Object> upload(MultipartFile file) {
		System.out.println(file);
        if (file.isEmpty()) {
            return Result.error("文件上传失败");
        }
        
        
        // 获取文件名
        String originalFilename = file.getOriginalFilename();

        // 获取文件后缀名
        String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));

        // 设置文件上传绝对路径
        String filePath = "D:\\java\\workspace\\java-bookstore\\src\\main\\resources\\static\\images\\";

        // 获取UUID名称
        String fileName = UUidUtil.getUUID() + suffixName;

        // 获取上传文件的File对象
        File dest = new File(filePath + fileName);
        System.out.println(dest);
        // 开始上传
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
        	file.transferTo(dest);
            return Result.success("操作成功");
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
        
        return Result.error("上传失败");
    }

在上方代码中,我仅是将前端传入的文件保存至本地了,在平常项目中通常是一个 http / https 路径地址保存至数据库中,下方就以文件上传至 oss 举例。

Oss 

前端 > Oss

在前端直接调用 Oss 方法并采用分片形式上传文件。

优点:减少请求服务器压力(无),直接上传至 Oss 省去了后端再去调用 Oss,增加响应速度。

缺点:在前端暴露了 Oss 密钥信息,恶意抓包并请求会导致 Oss 储存被恶意损坏,安全性降低。

结合以上两点,请谨慎考虑选择使用以下哪种方式,因为本人公司自研项目,并不会提供外网客户访问。

以下是我在 Vue 项目中对 Oss 上传进行了封装,包括上传进度条、回调。

import {uuid} from "vue-uuid";

const OSS = require("ali-oss");
const multipartUpload = ( async (file,callback) => {
    //阿里云oss配置
    let client = new OSS({
        region: 'XXX',//根据那你的Bucket地点来填写
        accessKeyId: "XXX",
        accessKeySecret: "XXX",
        bucket: 'XXX',//bucket名字
    });
    /* uploadFiles 百分比进度 */
    const progress = (p) => {
        // Object的上传进度。
        let name = String(p)
        let index = name.indexOf('.')
        let r = ''
        if(index !== -1){
           let ress = name.substr(index + 1,2)
            if(ress.length >= 2){
                ress[0] == 0 ? r = ress.substr(1,1) : r = ress
            }else if(ress.length <= 1){
                r = ress + '0'
            }else {
                r = ress
            }
            callback(r,{res:{status:0}})
        }
    };
    try {
        let fileIndex = file.name.indexOf('.')
        let fileType = file.name.substr(fileIndex)
        const result = await client.multipartUpload('XXX' + uuid.v1() + fileType, file, {
            progress, partSize:10 * 1024 * 1024,
        });
        if(result.res.status === 200){
            result.file = file;
            callback(100,result);
        }
    } catch (e) {
        // 捕获超时异常。
        if (e.code === 'ConnectionTimeoutError') {
            console.log('TimeoutError');
        }
    }
})

export {
    multipartUpload
}

Java > Oss

@RestController
public class FileUploadController {

    // 设置OSS相关参数
    private static final String endpoint = "your-endpoint"; //根据那你的Bucket地点来填写
    private static final String accessKeyId = "your-access-key-id";
    private static final String accessKeySecret = "your-access-key-secret";
    private static final String bucketName = "your-bucket-name"; // 储存空间名称

    @PostMapping("/upload")
    public String uploadFileToOSS(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            return "文件为空";
        }

        try {
            // 获取文件名
            String originalFilename = file.getOriginalFilename();
            // 生成唯一文件名
            String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
            // 创建OSSClient实例
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            // 上传文件至OSS
            // 此处 file.getInputStream 为文件流
            PutObjectResult putObjectResult = ossClient.putObject(new PutObjectRequest(bucketName, fileName, file.getInputStream()));
            // 关闭OSSClient
            ossClient.shutdown();

            return putObjectResult.getETag();
        } catch (IOException e) {
            e.printStackTrace();
            return "Upload failed";
        }
    }
}

以上是将文件上传至 Oss 进行储存,当然你可以在上传成功之后再将文件保持至数据库中。

​String httpPath = "http://" + bucketName + "." + endpoint + "/" + fileName;

其中 bucketNameendpointfileName分别为你的OSS存储桶名称、OSS服务的访问域名和文件在OSS中的路径(路径及文件名称)。

以上就是前后端上传文件实现方案了。

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值