Spring Web文件上传功能简述

toc

正文

在日常项目开发过程中,文件上传是一个非常常见的功能,当然正规项目都有专门的文件服务器保存上传的文件,实际只需要保存文件路径链接到数据库中即可,但在小型项目中可能没有专门的文件服务器用来存储这些文件,这时就需要我们自己手动实现文件上传功能了。

简单文件上传

在SpringWeb项目中要想实现文件上传也很简单,通过接收 MultipartFile类型的文件即可接收到文件参数,一个简单的文件上传Controller接口代码如下

java 复制代码
@RestController
@RequestMapping("/test")
public class TestController {
    @CrossOrigin
    @PostMapping("/file")
    public String testFileUpload(MultipartFile file){
        String oriName = file.getOriginalFilename();
        return "已收到上传文件:"+oriName;
    }
}

这时只需要前端通过<input type="file"/>标签获取文件并使用FormData的方式上传即可,简单代码如下

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FileUploadDoc</title>
    <style>
        .contain{
            margin-left: 300px;
            margin-top: 100px;
            border: blanchedalmond solid;
            width: 310px;
            padding: 10px;
        }
    </style>
</head>
<body>
<div class="contain">
    <input id="uploadedInput" type="file" name="uploadedFile">
    <button id="submitBtn">提交</button>
</div>
</body>
<script>
    let btn = document.getElementById("submitBtn")
    let fileInput = document.getElementById("uploadedInput")
    btn.addEventListener("click",()=>{
        let fileData=fileInput.files[0]
        let formData = new FormData()
        formData.append("file",fileData)
        //注意:这里不需要设置Content-Type参数
        let xhr = new XMLHttpRequest();
        xhr.open("POST","http://localhost:18080/test/file")
        xhr.send(formData)
        xhr.onreadystatechange=()=>{
            if (xhr.status===200){
                console.log(xhr.responseText)
            }
        }
    })
</script>
</html>

效果如下

选择文件后,通过点击提交按钮即可将所选文件上传到后端服务器。

这里有一个问题需要注意,如果上传失败报错,需要设置

  1. 最大文件大小,参数名spring.servlet.multipart.max-file-size,默认值1MB

  2. 单个请求最大值 ,参数名spring.servlet.multipart.max-request-size,默认值10MB

这两个参数,在SpringBoot项目中由于存在默认配置,可以不设置,若需要修改默认值则需根据实际情况设置这两个参数。

如果超出尺寸大小的限制会抛出这两个异常

  1. 文件大小超出限制异常为 FileSizeLimitExceededException
  2. 请求内容超出限制异常为 SizeLimitExceededException

文件写入

一般情况下的上传业务,需要将文件写入到固定的文件夹下,而当遇到同名文件时需要覆盖原来的文件。面对这种业务逻辑需要修改代码如下

java 复制代码
@CrossOrigin
@PostMapping("/file")
public String testFileUpload(MultipartFile file) throws IOException {
    if (file == null) {
        return "上传文件不能为空";
    }

    //获取文件名
    String oriName = file.getOriginalFilename();
    //文件保存文件夹
    String dirPath = "D:\\Activities\\temp_files";
    File serverFile = new File(dirPath, oriName);
    //判断文件是否存在
    if (serverFile.exists()) {
        serverFile.delete();
    } else {
        serverFile.createNewFile();
    }
    //读取文件并上传
    try (InputStream input = file.getInputStream();
         BufferedInputStream bIn = new BufferedInputStream(input);
         OutputStream output = new FileOutputStream(serverFile);
         BufferedOutputStream bOut = new BufferedOutputStream(output)) {
        byte[] byteArr = new byte[1024];
        int len = 0;
        while ((len = bIn.read(byteArr)) > 0) {
            bOut.write(byteArr, 0, len);
        }
    }

    return "已收到上传文件:" + oriName;
}

另一种常见的业务逻辑是,校验文件格式(如:只支持txt文件格式)后,对其进行重命名后返回一个网络地址,这时可使用以下代码

java 复制代码
@CrossOrigin
@PostMapping("/file")
public String testFileUpload(MultipartFile file) throws IOException {
    if (file == null) {
        return "上传文件不能为空";
    }

    StringBuffer fileNameBuf = new StringBuffer();
    fileNameBuf.append(System.currentTimeMillis()).append(UUID.randomUUID());
    String oriName = file.getOriginalFilename();
    //校验.txt和.TXT文件格式
    Pattern pattern = Pattern.compile("^.+[.txt|.TXT]$");
    if(pattern.matcher(oriName).matches()) {
        fileNameBuf.append(".txt");
    }else{
        return "文件格式错误,只支持txt文件";
    }

    String dirPath = "D:\\Activities\\temp_files";
    File serverFile = new File(dirPath, fileNameBuf.toString());
    if (serverFile.exists()) {
        return "文件上传失败,请重试";
    } else {
        serverFile.createNewFile();
    }
    try (InputStream input = file.getInputStream();
         BufferedInputStream bIn = new BufferedInputStream(input);
         OutputStream output = new FileOutputStream(serverFile);
         BufferedOutputStream bOut = new BufferedOutputStream(output)) {
        byte[] byteArr = new byte[1024];
        int len = 0;
        while ((len = bIn.read(byteArr)) > 0) {
            bOut.write(byteArr, 0, len);
        }
    }

    //生成网络链接
    StringBuffer webPath = new StringBuffer("文件上传成功,文件访问链接为:");
    webPath.append("https://img.sunyog.top/temp_files/").append(fileNameBuf);
    return webPath.toString();
}

总结

本文简单介绍了在Spring Web项目中文件上传相关的业务,在Spring中文件上传通过接收 MultipartFile类型的参数即可实现,获取到文件后可根据具体的业务逻辑进行相应处理。而在JavaScript中需要做的仅仅是获取所选文件,并通过FormData传输数据即可。


📩 联系方式

掘金: 我的掘金

CSDN: 我的CSDN

❗版权声明

本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问我的个人中心

相关推荐
拾光拾趣录16 分钟前
for..in 和 Object.keys 的区别:从“遍历对象属性的坑”说起
前端·javascript
OpenTiny社区27 分钟前
把 SearchBox 塞进项目,搜索转化率怒涨 400%?
前端·vue.js·github
编程猪猪侠1 小时前
Tailwind CSS 自定义工具类与主题配置指南
前端·css
qhd吴飞1 小时前
mybatis 差异更新法
java·前端·mybatis
YGY Webgis糕手之路1 小时前
OpenLayers 快速入门(九)Extent 介绍
前端·经验分享·笔记·vue·web
患得患失9491 小时前
【前端】【vueDevTools】使用 vueDevTools 插件并修改默认打开编辑器
前端·编辑器
ReturnTrue8681 小时前
Vue路由状态持久化方案,优雅实现记住表单历史搜索记录!
前端·vue.js
UncleKyrie2 小时前
一个浏览器插件帮你查看Figma设计稿代码图片和转码
前端
遂心_2 小时前
深入解析前后端分离中的 /api 设计:从路由到代理的完整指南
前端·javascript·api
你听得到112 小时前
Flutter - 手搓一个日历组件,集成单日选择、日期范围选择、国际化、农历和节气显示
前端·flutter·架构