iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > JAVA >Spring Boot实现文件上传的两种方式
  • 852
分享到

Spring Boot实现文件上传的两种方式

springbootservletjava 2023-09-02 22:09:15 852人浏览 独家记忆
摘要

最近的一个小项目里使用到了文件上传、下载功能,今天我打算梳理一下文件上传所涉及的技术及实现。 内容主要包括两部分,如何通过纯 Servlet 的形式进行文件上传、保存(不通过 spring 框架);另一部分是如何在 Spring WEB m

最近的一个小项目里使用到了文件上传、下载功能,今天我打算梳理一下文件上传所涉及的技术及实现。 内容主要包括两部分,如何通过纯 Servlet 的形式进行文件上传、保存(不通过 spring 框架);另一部分是如何在 Spring WEB mvc 中进行文件上传。

01-从 Http 协议角度分析文件上传

HTTP 协议传输文件一般都遵循 RFC 1867 规范,即客户端通过 POST 请求,Context-Type 为 "multipart/fORM-data"。 前端提交页面一般为:

Choose a file:

通过 Wireshark 对 POST 请求进行抓包,发现发送的请求格式为:

POST /upload HTTP/1.1Host: localhost:8080Content-Length: 197624Content-Type: multipart/form-data; boundary=----WebKitFormBoundarynIbwtdWznj6QLu52First boundary: ------WebKitFormBoundarynIbwtdWznj6QLu52Encapsulated multipart part:  (image/png)    Content-Disposition: form-data; name="image"; filename="Snipaste_2023-01-05_13-35-11.png"    Content-Type: image/png    Portable Network GraphicsBoundary: ------WebKitFormBoundarynIbwtdWznj6QLu52Encapsulated multipart part:  (image/png)    Content-Disposition: form-data; name="image"; filename="Snipaste_2023-01-05_13-35-12.png"    Content-Type: image/png    Portable Network GraphicsLast boundary: ------WebKitFormBoundarynIbwtdWznj6QLu52--

对上述过程有了基本的理解后,就可以动手来写上传功能(本文以图片为例,当然你也可以实现支持上传其他类型的文件的版本)。 接下来我会展示两种实现文件上传功能的代码,第一种是使用纯 Servlet api 实现,不依赖 Spring 框架,当你的程序是一个简单的基于 Servlet 的应用时,可以参考这种方式。 第二种,借助了 Spring 提供的 MultipartFile 以及 MultipartResolver 实现的文件上传。

02-Servlet 处理上传请求

首先,需要先实现一个 Servlet。

@MultipartConfig(fileSizeThreshold = 5 * 1024 * 1024,        maxFileSize = 1024 * 1024 * 5,        maxRequestSize = 1024 * 1024 * 5)@WebServlet(name = "MultipartServlet", urlPatterns = "/servlet-upload")public class MultipartServlet extends httpservlet {    private File uploadDir = null;    @Override    public void init(ServletConfig config) throws ServletException {        super.init(config);        // 检查存储文件的路径是否存在,若不存在,则创建一个        String uploadPath = System.getProperty("user.dir") + File.separator + "uploads";        uploadDir = new File(uploadPath);        if (!uploadDir.exists()) {            uploadDir.mkdir();        }    }    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        // 第一节中介绍过,文件上传是通过 POST 方法完成的,所以这里我们要重写 doPost 方法        try {            final Collection parts = req.getParts();   // 从请求中获取 multipart 内容            for (Part part : parts) {                if (part.getSize() <= 0) {                  // 判断上传的内容是否空文件                    System.out.println("part is empty, skip it!");                    continue;                }                String fileName = getFileName(part);       // 从请求中获取文件的名                // or                //final String fileName = part.getSubmittedFileName();                // fileName 是前端提供的,并不十分可靠                // 后端应该自己生成一个文件名                fileName = genNewFileName(fileName);                String uploadedFilePath = uploadDir + File.separator + fileName;                part.write(uploadedFilePath);   // 存储到指定目录                System.out.println("saved to " + uploadedFilePath);                resp.getWriter().write("saved to "  + uploadedFilePath);            }        } catch (ServletException se) {            // request is not of type multipart/form-data        }        resp.setStatus(HttpServletResponse.SC_OK);        resp.getWriter().flush();        resp.getWriter().close();    }    private String getFileName(Part part) {        for (String s : part.getHeader("Content-Disposition").split(";")) {            if (s.trim().startsWith("filename")) {                return s.substring(s.indexOf("=") + 2, s.length() - 1);            }        }        // 默认文件名        return "foo.txt";    }    private String genNewFileName(String filename) {        String filenameFormat = "%s.%s";        return String.format(filenameFormat,                UUID.randomUUID().toString().replace("-", "").substring(8),                FilenameUtils.getExtension(filename)        );    }}

这里面有几个地方需要解释一下;

  • 其一,getFileName 为什么要这么实现?参考第一节给出的 HTTP 报文,发现每个 Part,即两个 boundary 之间的内容,通过 Content-Disposition 给出了内容类型、文件名等信息。 getFileName 中的逻辑就是从这个格式里获得文件名的。 不过,这个文件名是由前端提供的,它其实也可以不提供,所以这个值就不是那么可靠。 所以,在我们将上传文件保存到磁盘上时,最好重新生成一个文件名,这就使 genNewFileName 的动机。
  • 其二,根据 HttpServletRequest 接口的文档,getParts 方法在请求不是 multipart 类型时会抛异常。 而且,Part 的内容有可能是为空的,如果我们不做判断,可能会在服务端创建一个空文件。
  • Servlet 类上的注解,@WebServlet 不再介绍,@MultipartConfig 是对请求、请求中文件大小的限制条件,当请求或文件超过这个限制时会抛对应的异常。

有了上面的定义,我们就可以测试下上传功能了。 

服务启动后,访问 页面能够得到上传页面。 选择文件,提交后,服务端响应成功,并将新名字传给前端。例如:

注:这里 会返回 Thymeleaf 实现的上传界面。

 @GetMapping("/servlet-upload-page")public String uploadImageByServlet(Model model) {    model.addAttribute("message", "please choose file to be uploaded");    return "upload/servlet-upload";}

界面内容为:

Upload Image Example

其中,@{/servlet-upload} 指向的是 @WebServlet(name = "MultipartServlet", urlPatterns = "/servlet-upload") 中将 Servlet 注册到的 url。

03-通过 Spring Boot 中的 MultipartFile 处理上传请求

通过 Spring Boot 来实现文件上传功能会更简单,它的自动化配置机制已经做了大部分的工作。 开发人员的工作就是定义一个 Controller,处理文件上传请求就可以了。

@Controllerpublic class UploadController {    public static String UPLOAD_DIRECTORY = System.getProperty("user.dir") + File.separator + "uploads";    @GetMapping("/upload")   // 主要返回文件上传页面    public String uploadImage(Model model) {        model.addAttribute("message", "please choose file to be uploaded");        return "upload/index";    }        @PostMapping("/upload")  // 处理文件上传 POST 请求    public String upload(@RequestParam("image")MultipartFile[] files,                         Model model)            throws IOException {        StringBuilder sb = new StringBuilder();        for (MultipartFile file : files) {            if (file.getSize() <= 0) {                continue;            }            final String newFileName = save(file);            final String msg = String.format("uploaded file %s, and new filename is %s%n", file.getOriginalFilename(), newFileName);            sb.append(msg);        }        model.addAttribute("msg", sb.toString());        return "upload/index";    }    private String save(MultipartFile file) throws IOException{        String newFileName = genNewFileName(file.getOriginalFilename());        final Path filePath = Paths.get(UPLOAD_DIRECTORY, newFileName);        Files.write(filePath, file.getBytes());        System.out.println("file saved to: " + filePath);        return newFileName;    }}

Spring Boot 中,文件上传请求(multipart request)被 StandardServletMultipartResolver 进一步封装为 StandardMultipartHttpServletRequest。 解析原请求的过程与我在前面介绍 Servlet 的方式时基本类似:

private void parseRequest(HttpServletRequest request) {    try {        Collection parts = request.getParts();        this.multipartParameterNames = new LinkedHashSet<>(parts.size());        MultiValueMap files = new LinkedMultiValueMap<>(parts.size());        for (Part part : parts) {              String headerValue = part.getHeader(HttpHeaders.CONTENT_DISPOSITION);            ContentDisposition disposition = ContentDisposition.parse(headerValue);            String filename = disposition.getFilename();            if (filename != null) {                // 把文件添加到 files                if (filename.startsWith("=?") && filename.endsWith("?=")) {                    filename = MimeDelegate.decode(filename);                }                // part 被封装为 StandardMultipartFile,它是 MultipartFile 的一个实现类                files.add(part.getName(), new StandardMultipartFile(part, filename));            }            else {                // 把不是文件的属性添加到 multipartParameterNames 中                this.multipartParameterNames.add(part.getName());            }        }        setMultipartFiles(files);    }    catch (Throwable ex) {        handleParseFailure(ex);    }}

通过上面的代码可以了解到,Client 提交的 POST 请求中,上传的文件被封装称 MultipartFile。 所以,我们在 Controller 中的处理方法中,可以通过 @RequestParam 的方式拿到这个文件列表进行处理,就像我们的 UploadController 实现的那样。

04-总结

在今天的文章中,我介绍了文件上传的两种实现方式,从纯 Servlet 实现,到基于 Spring Boot MVC 实现。 并且分析了 Spring Boot 中对 Multipart 请求的封装过程。

 

来源地址:https://blog.csdn.net/ww2651071028/article/details/129255059

--结束END--

本文标题: Spring Boot实现文件上传的两种方式

本文链接: https://www.lsjlt.com/news/391545.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring Boot实现文件上传的两种方式
    最近的一个小项目里使用到了文件上传、下载功能,今天我打算梳理一下文件上传所涉及的技术及实现。 内容主要包括两部分,如何通过纯 Servlet 的形式进行文件上传、保存(不通过 Spring 框架);另一部分是如何在 Spring Web M...
    99+
    2023-09-02
    spring boot servlet java
  • Spring boot实现文件上传实例(多文件上传)
    文件上传主要分以下几个步骤:(1)新建maven java project;(2)在pom.xml加入相应依赖;(3)新建一个表单页面(这里使用thymleaf);(4)编写controller;(5)测试;(6)对上传的文件做一些限制;(...
    99+
    2023-05-31
    spring boot 文件上传
  • jsp 实现上传文件的两种方法
    在用Java开发企业器系统的使用,特别是涉及到与办公相关的软件开发的时候,文件的上传是客户经常要提到的要求.因此有 一套很好文件上传的解决办法也能方便大家在这一块的开发.........[@more@]在用Java开发企业器系统的使用,特别...
    99+
    2023-06-03
  • Spring Boot使用GridFS实现文件的上传和下载方式
    目录使用GridFS实现文件的上传和下载首先了解一下怎么用命令操作GridFS使用Spring Boot操作GridFSSpring Boot中使用GridFS什么是GridFS在S...
    99+
    2024-04-02
  • Spring Boot实现文件上传和下载
    实现Spring Boot文件上传和下载的步骤: 1.文件上传 在pom.xml文件中添加依赖:spring-boot-starter-web和spring-boot-starter-thymelea...
    99+
    2023-09-06
    spring boot java servlet
  • Spring boot实现热部署的两种方式详解
    热部署是什么大家都知道在项目开发过程中,常常会改动页面数据或者修改数据结构,为了显示改动效果,往往需要重启应用查看改变效果,其实就是重新编译生成了新的 Class 文件,这个文件里记录着和代码等对应的各种信息,然后 Class 文件将被虚拟...
    99+
    2023-05-31
    springboot 热部署 spring boo
  • Spring Boot简单实现文件上传功能
    目录前言后端处理物理路径和虚拟路径映射前言 前端处理 通过form表单来上传文件提交方式为postenctype格式为"multipart/form-data"i...
    99+
    2024-04-02
  • spring boot ajax跨域的两种方式
    前言 java语言在多数时,会作为一个后端语言,为前端的php,node.js等提供API接口。前端通过ajax请求去调用java的API服务。今天以node.js为例,介绍两种跨域方式:CrossOrigin和反向代理。&nbs...
    99+
    2023-05-31
    spring boot ajax
  • SpringMVC上传文件的两种方法
    在该示例中,阐述了SpringMVC如何上传文件。1、上传页面upload.jsp<body> <form action="/TestSpringMVC3/data/uploadfile" enctype="multi...
    99+
    2023-05-30
    springmvc 上传 sprin
  • 详解Spring-boot中读取config配置文件的两种方式
    了解过spring-Boot这个技术的,应该知道Spring-Boot的核心配置文件application.properties,当然也可以通过注解自定义配置文件的信息。Spring-Boot读取配置文件的方式:一.读取核心配置文件信息ap...
    99+
    2023-05-31
    spring boot config
  • Spring Boot项目搭建的两种方式
    目录什么是Spring Boot使用 Spring Boot有什么好处Spring Boot开发环境搭建方式1:官网配置生成方式2:IDEA中生成什么是Spring Boot Spr...
    99+
    2024-04-02
  • Spring Boot文件上传最新解决方案
    一、创建一个简单的包含WEB依赖的SpringBoot项目 pom.xml内容: <!-- Spring Boot web启动器 --> <dependency...
    99+
    2024-04-02
  • vue实现上传按钮的样式的两种方法
    目录1、铜通过纯html css实现2、通过js实现1、铜通过纯html css实现 html代码 <div class="file-upload"> <d...
    99+
    2022-12-24
    vue 上传按钮的样式 vue 按钮样式
  • 详解Spring boot操作文件的多种方式
    目录一、获取文件路径1、class.getResource(path)2、ClassLoader.getResource(path)3、项目路径二、操作文件的三种方式1、ClassP...
    99+
    2024-04-02
  • django上传文件的三种方式
    目录Django文件上传需要考虑的重要事项Django文件上传的3种常见方式项目创建与设置创建模型URLConf配置使用一般表单上传文件使用ModelForm上传文件GitHub源码...
    99+
    2024-04-02
  • Spring Boot 项目启动自动执行方法的两种实现方式
    目录实际应用场景:第一种实现ApplicationRunner接口第二种实现CommandLineRunner接口对比:注意:实际应用场景: springboot项目启动成功后执行一...
    99+
    2024-04-02
  • Spring boot实现上传文件至本地或服务器
    大家好 我是程序猿小张 图片文件上传是项目中必不可少的一个功能,上传的地址也当然是优先选择第三方的对象存储,例如七牛云、阿里云等等,但是当中的话只有七牛云是有一个免费额度的,其他都是要收钱的。所以就想...
    99+
    2023-09-01
    spring boot 服务器 后端
  • java实现文件下载的两种方式
    本文实例为大家分享了java实现文件下载的具体代码,供大家参考,具体内容如下public HttpServletResponse download(String path, HttpServletResponse response) { ...
    99+
    2023-05-30
    java 文件下载 ava
  • Spring Boot实现热部署的五种方式
    1.模板热部署 在 Spring Boot 中,模板引擎的页面默认是开启缓存的,如果修改了页面的内容,则刷新页面是得不到修改后的页面的,因此我们可以在application.prop...
    99+
    2024-04-02
  • Node.js实现下载文件的两种实用方式
    目录第一种方式:使用原生的http模块第二种方式:使用Express+Axios下载文件总结设置响应头返回数据流第一种方式:使用原生的http模块 我们仅需要用到fs和http两个n...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作