springboot文件上传

news2024/11/16 11:35:55

1.新建文件上传页面

在static目录中新建upload-test.html,上传页面代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>springboot文件上传测试</title>
</head>
<body>
<form action="/uploadFile" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" value="文件上传" />
</form>
</body>
</html>

其中后端处理文件上传的请求地址为/uploadFile,请求方法为POST。在文件上传时需要设置form表单的enctype属性为“multipart/form-data”。
效果图如下:
在这里插入图片描述

2.新建文件上传处理Controller类

在controller包下新建UploadController类并编写实际的文件上传逻辑代码,如下所示:

package ltd.newbee.mall.controller;

import ltd.newbee.mall.util.PageResult;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

@Controller
public class UploadController {
    //文件保存路径为在D盘下的upload文件夹,可以按照自己的习惯修改
    private final static String FILE_UPLOAD_PATH = "D:\\upload\\";
    @RequestMapping(value = "/uploadFile",method = RequestMethod.POST)
    @ResponseBody
    public String uploadFile(@RequestParam("file") MultipartFile file){
        if (file.isEmpty()){
            return "文件上传失败";
        }
        String fileName = file.getOriginalFilename();
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        //生成文件名称通用方法
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
        Random r = new Random();
        StringBuilder tempName = new StringBuilder();
        tempName.append(sdf.format(new Date())).append(r.nextInt(100)).append(suffixName);
        String newFileName = tempName.toString();
        try {
            //保存文件
            byte[] bytes = file.getBytes();
            Path path = Paths.get(FILE_UPLOAD_PATH+newFileName);
            Files.write(path,bytes);
        }catch (IOException e){
            e.printStackTrace();
        }
        return "上传成功";
    }
}

由于Spring Boot已经自动配置了StandardServletMultipartResolver类来处理文件上传请求,因此能够直接在控制器方法中使用MultipartFile读取文件信息。 @RequestParam中文件名称属性需要与前端页面中input文件输入框设置的name属性一致。如果文件为空则返回上传失败,如果不为空则根据日期生成一个新的文件名,读取文件流程并写入指定的路径中,最后返回上传成功的提示信息。
需要注意的是文件上传路径的设置。在上述代码中设置的文件保存路径为D:\upload\,即在D盘下的upload文件夹。如果项目部署在Linux系统中的话,写法与此不同。比如想要把文件上传到/opt/newbee/upload目录下,就需要把路径设置的代码改为private final static String FILE_UPLOAD_PATH = “/opt/newbee/upload/”。这一点需要注意,两种系统的写法存在一些差异。如果文件存储目录还没有创建的话,首先需要创建该目录,然后启动项目进行文件上传测试。

3.文件上传功能测试

在编码完成后,启动Spring Boot项目。在启动成功后,打开浏览器并输入测试页面地址:

http://localhost:8080/upload-test.html

打开后选择上传的文件,然后上传,显示成功。
在这里插入图片描述
检查本机upload目录下是否有改文件(注意这里需要在对应的位置建立好upload文件夹)
在这里插入图片描述
另外,在Spring Boot项目中支持单个文件的最大值默认为1MB,支持单个请求最大值默认10 MB。如果选择了大于默认值的文件进行上传,比如一个1.2MB的文件或者一个11MB的请求,就会报错。

4.文件上传路径回显

Spring Boot项目与普通Spring项目的目录结构不同,并没有webapp目录,因此无法与普通的Java Web项目一样,上传文件到webapp目录中并直接根据目录进行访问。Spring Boot项目中通常使用自定义静态资源映射目录,以此来实现文件上传整个流程的闭环。比如在前文文件上传案例中,在文件上传到upload目录后,会增加一个自定义静态资源映射配置,使得在upload下的静态资源可以通过该映射地址被访问到。
新建config包并在config包中新增SpringBootWebMvcConfigurer类,实现代码如下所示:

package ltd.newbee.mall.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class SpringBootWebMvcConfigurer implements WebMvcConfigurer {
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/upload/**").addResourceLocations("file:D:\\upload\\");
    }

}

通过以上代码配置,所有以“/upload/”开头的静态资源在请求时都会映射到D盘的upload目录下。路径的设置与前文中上传文件的设置目录类似,不同系统的文件路径的写法不同(比如Linux和Windows)。同时需要注意在设置静态资源映射路径时,路径前需要添加“file:”前缀。
最后修改一下在文件上传时的返回信息,把路径拼装好并返回到页面上,以便于功能测试,UploadController代码的修改如下所示:

        return "上传成功,地址为:/upload/"+newFileName;

最后启动项目进行测试
在这里插入图片描述
检查对应目录下是否有文件
在这里插入图片描述
上传成功完成。

5.多文件上传功能实现

首先,在static目录中新建upload-same-file-name.html,页面代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多文件上传测试(文件名相同)</title>
</head>
<body>
<form action="/uploadFilesBySameName" method="post" enctype="multipart/form-data">
    <input type="file" name="files"/><br><br>
    <input type="file" name="files"/><br><br>
    <input type="file" name="files"/><br><br>
    <input type="file" name="files"/><br><br>
    <input type="file" name="files"/><br><br>
    <input type="submit" value="文件上传"/>
</form>
</body>
</html>

多文件上传页面与单文件上传页面类似,不同点是新增了4个文件输入框,文件输入框的name属性统一命名为files,文件名完全一致。后端处理文件上传的请求地址为/uploadFilesBySameName,请求方法为POST。
在UploadController类中新增uploadFilesBySameName()方法,用于处理在文件名相同时的多文件上传问题,新增代码如下所示:

    @RequestMapping(value = "/uploadFileBySameName",method = RequestMethod.POST)
    @ResponseBody
    public String uploadFileBySameName(@RequestPart MultipartFile[] files){
        if (files == null|| files.length==0){
            return "参数错误";
        }
        if (files.length>5){
            return "文件最多上传5个";
        }
        String uploadResult = "上传成功,地址为:<br>";
        for (MultipartFile file:files){
            String fileName = file.getOriginalFilename();
            if (StringUtils.isEmpty(fileName)){
                //表示无文件信息,跳出当前循环
                continue;
            }
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            //生成文件名称的通用方法
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
            Random r = new Random();
            StringBuilder tempName = new StringBuilder();
            tempName.append(sdf.format(new Date())).append(r.nextInt(100)).append(suffixName);
            String newFileName = tempName.toString();
            try {
                //保存文件
                byte[] bytes = file.getBytes();
                Path path = Paths.get(FILE_UPLOAD_PATH+newFileName);
                Files.write(path,bytes);
                uploadResult += "/upload/" + newFileName + "<br>";
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return uploadResult;
    }

与单文件在上传时的uploadFile()方法相比,多文件上传有两处改动。
第一,文件参数在接收时的代码改动。在多文件上传并接收参数时使用的是@RequestPart注解,且接收的文件参数是一个数组MultipartFile。而单文件在上传时使用的是@RequestParam注解,接收的文件是单个对象。
第二,文件在保存时增加循环逻辑。多文件保存的处理方式与单文件在上传时比较类似,只是增加了循环逻辑,对接收的MultipartFile数组中每一个文件进行存储操作,最后拼接文件的地址信息并返回。
另外一个需要注意的知识点,多文件上传在接收参数时,参数名称files需要完全对应input框中的name属性。比如本次演示,在upload-same-file-name.html文件中所有文件输入框的name属性都是files;在后端处理时,uploadFilesBySameName()方法的参数名称也定义为files,两个名称是对应的。如果所有文件输入框的name属性都改为uploadFiles,那么uploadFilesBySameName()方法的参数名称也需要改为uploadFiles,否则接收的文件对象数组为空。
在编码完成后,启动Spring Boot项目。在在启动成功后打开浏览器并输入多图上传的测试页面地址:

http://localhost:8080/upload-same-file-name.html

实际效果:
在这里插入图片描述
在这里插入图片描述

6.文件名不同时的多文件上传处理

首先,在static目录中新建upload-different-file-name.html,页面代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多文件上传测试(文件名不同)</title>
</head>
<body>
<form action="/uploadFilesByDifferentName" method="post" enctype="multipart/form-data">
    <input type="file" name="files1"/><br><br>
    <input type="file" name="files2"/><br><br>
    <input type="file" name="files3"/><br><br>
    <input type="file" name="files4"/><br><br>
    <input type="file" name="files5"/><br><br>
    <input type="submit" value="文件上传"/>
</form>
</body>
</html>

然后,在UploadController类中新增uploadFilesByDifferentName()方法,用于处理文件名在不相同时的多文件上传,新增代码如下所示:

    @RequestMapping(value = "/uploadFilesByDifferentName",method = RequestMethod.POST)
    @ResponseBody
    public String uploadFilesByDifferentName(HttpServletRequest httpServletRequest Request){
        List<MultipartFile> multipartFiles = new ArrayList<>(8);
        //如果不是文件上传请求则不处理
        if (!standardServletMultipartResolver.isMultipart(httpServletRequest)){
            return "请选择文件";
        }
        //将HttpServletRequest 对象转换为MultipartHttpServletRequest对象,并读取文件
        MultipartHttpServletRequest multiRequest =(MultipartHttpServletRequest)httpServletRequest;
        Iterator<String> iter = multiRequest.getFileNames();
        int total=0;
        while (iter.hasNext()){
            if (total>5) {
                return "最多上传5个文件";
            }
            total+=1;
            MultipartFile file = multiRequest.getFile(iter.next());
            multipartFiles.add(file);
        }
        if (CollectionUtils.isEmpty(multipartFiles)) {
            return "请选择文件";
        }
        if (multipartFiles != null && multipartFiles.size()>5){
            return "文件最多上传5个";
        }
        String uploadResult = "上传成功,地址为:<br>";
        for(int i=0;i<multipartFiles.size();i++){
            String fileName = multipartFiles.get(i).getOriginalFilename();
            if (StringUtils.isEmpty(fileName)){
                //表示无文件信息,跳出当前循环
                continue;
            }
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            //生成文件名称的通用方法
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
            Random r = new Random();
            StringBuilder tempName = new StringBuilder();
            tempName.append(sdf.format(new Date())).append(r.nextInt(100)).append(suffixName);
            String newFileName = tempName.toString();
            try {
                //保存文件
                byte[] bytes = multipartFiles.get(i).getBytes();
                Path path = Paths.get(FILE_UPLOAD_PATH+newFileName);
                Files.write(path,bytes);
                uploadResult += "/upload/" + newFileName + "<br>";
            }catch (IOException e){
                e.printStackTrace();
            }
        }
        return uploadResult;
    }

与文件名相同时的多文件上传的uploadFilesBySameName()方法相比,文件名不同时的改动只有一处,即文件参数在接收时的代码做了改动。在读取文件信息时的逻辑是自行实现的代码逻辑,首先调用isMultipart()方法判断当前请求是否为文件上传请求,如果不是则不进行处理,如果是文件上传请求,则HttpServletReques对象转换为MultipartHttpServletRequest对象,并读取文件数据,在读取完成后再依次进行存储。存储文件的过程与之前的逻辑一致,最后拼接文件的地址信息并返回。
另外,需要判断当前请求是否为文件上传请求时要用到StandardServletMultipart Resolver类isMultipart()方法。前文中提到的StandardServletMultipartResolver类已经自动配置,所以可以直接在UploadController类中使用@Autowired注解注入,代码如下所示:

    @Autowired
    private StandardServletMultipartResolver standardServletMultipartResolver;

测试成功
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/442630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

编译时报Clang SA is not enabled问题解决

报此问题应该是swap不足导致的&#xff0c;原因是用的虚拟机&#xff0c;改为16G内存问题排除 具体解决如下&#xff1a; 1.free -h 查看当前分区大小和使用情况 2.扩展分区大小 2.1首先删除系统默认分区 sudo swapoff /swapfile sudo rm /swapfile 2.2新建swap分区&#xf…

ROS学习第十六节—— 头文件与源文件

https://download.csdn.net/download/qq_45685327/87708569 1.自定义头文件调用 新建功能包 在该路径下创建头文件 /home/xiaoming/demo0/src/hello_head/include/hello_head 编写以下代码 #ifndef _HELLO_H #define _HELLO_Hnamespace hello_ns{class HelloPub {public:vo…

分享10个值得推荐的技巧,提升JavaScript 的性能

JavaScript 在网页开发中非常重要&#xff0c;它控制了大部分网页上的活动和动画效果。但是&#xff0c;如果代码编写不当&#xff0c;JavaScript 可能会导致网站速度变慢。代码的不足可能导致网页加载缓慢&#xff0c;渲染速度也会变慢。 按照以下策略来提高您网站的速度和性能…

基于web的病号康复训练系统asp.net+sqlserver+C#

本系统主要内容分为病号管理模块,康复师管理模块,管理员管理模块等三大模块 1,病号管理模块主要分为:用户管理,在线问答,在线预约,用户中心,信息查询. 2. 康复师管理模块主要有:康复师信息管理,病人信息管理&#xff0c;预约信息管理&#xff0c;留言信息管理&#xff0c;训练计…

自然语言处理实战项目3-利用CNN做语义分析任务

大家好&#xff0c;我是微学AI&#xff0c;今天给大家带来自然语言处理实战项目3-利用CNN做语义分析任务&#xff0c;深度学习在自然语言处理领域中的应用越来越广泛&#xff0c;其中语义分析是其中一个重要的应用。本文将为读者介绍语义分析的任务以及如何用深度学习方法实现该…

​​2021遥感应用组二等奖:基于机器学习回归算法的鄱阳湖水质遥感定量反演及时序变化监测研究

作品介绍 一、作品背景 鄱阳湖是中国第一大淡水湖&#xff0c;也是中国第二大湖&#xff0c;它在调节长江水位、涵养水源、改善当地气候等方面起着重大的作用。但近年来受围垦、环境污染等人类活动影响&#xff0c;鄱阳湖湿地退化严重&#xff0c;同时使鄱阳湖的容量减少&…

JdbcTemplate总结

JdbcTemplate总结 JdbcTemplate技术是 Spring技术里面提供的一种数据库访问技术。之前学习的数据库技术是 JdbcUtils类完成的&#xff0c;现在用JdbcTemplate新技术了。 使用JdbcTemplate技术的本质就是&#xff1a;通过 IOC容器配置一个 JdbcTemplate对象&#xff0c;使用它来…

choco-slover安装

一. 基础知识 1. 起步资料 choco-slover github源代码以及工具下载网址:https://github.com/chocoteam/choco-solverchoco-slover 官网文档:https://choco-solver.org/choco-slover安装eclipse视频:https://www.youtube.com/watch?v=qz6ATkEI_F8视频所采用的资源网址:htt…

C learning_5

数组相关问题 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {int arr[] { 1,2,3 };//数组如果初始化的话&#xff0c;可以不指定大小&#xff0c;会根据初始化的内容自动确定大小/*c99标准之前数组的大小不能是变量的但是在c99标准之后引入了变长数…

( “树” 之 BST) 235. 二叉搜索树的最近公共祖先 ——【Leetcode每日一题】

二叉查找树&#xff08;BST&#xff09;&#xff1a;根节点大于等于左子树所有节点&#xff0c;小于等于右子树所有节点。 二叉查找树中序遍历有序。 235. 二叉搜索树的最近公共祖先 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定…

考验大家指针功底的时候到了:请问如何理解 (int*)1 + 1 ?

来&#xff0c;猜猜看&#xff0c;这里的执行结果是什么&#xff1f; 这是今天课上的一道理解题&#xff0c;给大家一点点思考时间。 &#xff08;心里有答案了再往下滑哦&#xff09; 5 4 3 2 1 . 答案是&#xff0c;报warning&#xff01;因为%d不是用来输出指针的哈…

ntlm hash加密方式学习

文章目录 一、ntlm hash二、LM hash加密三 、NTLM Hash 加密 一、ntlm hash 什么是ntlm hash&#xff0c;当windows进行本地用户密码认证时不是以用户输入的明文密码与系统密码直接比较&#xff0c;而是经过某种方式加密之后进行比较。所以windows中的用户密码凭证不是以明文的…

哪个洗脱一体机好用?好用的洗拖一体机推荐

洗地机是一款使用非常方便的清洁工具&#xff0c;通常可以实现吸、拖、洗三个功能&#xff0c;对于各类家庭污渍都有着不错的处理能力&#xff0c;无论是干燥垃圾还是潮湿垃圾一律可以有效清理。不过很多新手朋友在选购洗地机时会因为看不懂参数而频繁踩雷。本文为大家整理了洗…

图像分割(Segmentation)

文章目录 图像分割FCNU-NetSegNetDeepLab图像分割常用数据集 图像分割 图像分割是预测图像中每一个像素所属的类别或者物体。基于深度学习的图像分割算法主要分为两类&#xff1a; 语义分割&#xff08;Semantic Segmentation&#xff09; 为图像中的每个像素分配一个类别。 …

基于Bert的知识库智能问答系统

项目完整地址&#xff1a; 可以先看一下Bert的介绍。 Bert简单介绍 一.系统流程介绍。 知识库是指存储大量有组织、有结构的知识和信息的仓库。这些知识和信息被存储为实体和实体关系的形式&#xff0c;通常用于支持智能问答系统。在一个知识库中&#xff0c;每个句子通常来说…

用Morss获取全文RSS摘要

什么是 Morss &#xff1f; Morss 工具的目标是从互联网上常见的 RSS 摘要中获取全文 RSS 摘要。Morss 能打开来自 RSS的链接&#xff0c;然后从网站下载整篇文章并将其放回 RSS 摘要中&#xff0c;还可以将摘要导出为 RSS/JSON/CSV/HTML。 Morss 需配合其他 RSS 阅读器使用&am…

人工智能AI图像风格迁移(StyleTransfer),基于双层ControlNet(Python3.10)

图像风格迁移&#xff08;Style Transfer&#xff09;是一种计算机视觉技术&#xff0c;旨在将一幅图像的风格应用到另一幅图像上&#xff0c;从而生成一幅新图像&#xff0c;该新图像结合了两幅原始图像的特点&#xff0c;目的是达到一种风格化叠加的效果&#xff0c;本次我们…

神经影像分析的统计学方法

线性模型概述 模型是对现实的一种数学近似&#xff0c;其中给定输入变量集的某个函数旨在重建一个输出变量。以fMRI范式为例&#xff0c;在这个范式中&#xff0c;给受试者呈现面孔和房屋的图像。该模型的目标是利用体素对面孔和房屋反应时的预期时间进程&#xff0c;并产生与…

基于html+css的图片展示20

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

Mybatis(十)级联映射与懒加载

一、Mybatis的级联映射 使用Mybatis的级联映射&#xff0c;我们可以轻松的实现一对一、一对多或者多对多关联查询&#xff0c;甚至可以利用级联映射实现懒加载。 所谓的懒加载&#xff0c;就是我们在一个实体对象中关联了其他对象&#xff0c;如果不需要获取被关联的对象&…