基于Spring实现文件上传功能

发布时间 - 2026-01-11 03:03:29    点击率:

本小节你将建立一个可以接受HTTP multi-part 文件的服务。

你将建立一个后台服务来接收文件以及前台页面来上传文件。

要利用servlet容器上传文件,你要注册一个MultipartConfigElement类,以往需要在web.xml 中配置<multipart-config>,
而在这里,你要感谢SpringBoot,一切都为你自动配置好了。

1、新建一个文件上传的Controller:

应用已经包含一些 存储文件 和 从磁盘中加载文件 的类,他们在cn.tiny77.guide05这个包下。我们将会在FileUploadController中用到这些类。

package cn.tiny77.guide05;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
public class FileUploadController {

 private final StorageService storageService;

 @Autowired
 public FileUploadController(StorageService storageService) {
  this.storageService = storageService;
 }

 @GetMapping("/")
 public String listUploadedFiles(Model model) throws IOException {
  
  List<String> paths = storageService.loadAll().map(
    path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,
      "serveFile", path.getFileName().toString()).build().toString())
    .collect(Collectors.toList());

  model.addAttribute("files", paths);

  return "uploadForm";
 }

 @GetMapping("/files/{filename:.+}")
 @ResponseBody
 public ResponseEntity<Resource> serveFile(@PathVariable String filename) {

  Resource file = storageService.loadAsResource(filename);
  return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
    "attachment; filename=\"" + file.getFilename() + "\"").body(file);
 }

 @PostMapping("/")
 public String handleFileUpload(@RequestParam("file") MultipartFile file,
   RedirectAttributes redirectAttributes) {

  storageService.store(file);
  redirectAttributes.addFlashAttribute("message",
    "You successfully uploaded " + file.getOriginalFilename() + "!");

  return "redirect:/";
 }

 @ExceptionHandler(StorageFileNotFoundException.class)
 public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
  return ResponseEntity.notFound().build();
 }

}

该类用@Controller注解,因此SpringMvc可以基于它设定相应的路由。每一个@GetMapping和@PostMapping注解将绑定对应的请求参数和请求类型到特定的方法。

GET / 通过StorageService 扫描文件列表并 将他们加载到 Thymeleaf 模板中。它通过MvcUriComponentsBuilder来生成资源文件的连接地址。

GET /files/{filename} 当文件存在时候,将加载文件,并发送文件到浏览器端。通过设置返回头"Content-Disposition"来实现文件的下载。

POST / 接受multi-part文件并将它交给StorageService保存起来。

你需要提供一个服务接口StorageService来帮助Controller操作存储层。接口大致如下

package cn.tiny77.guide05;

import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;

import java.nio.file.Path;
import java.util.stream.Stream;

public interface StorageService {

 void init();

 void store(MultipartFile file);

 Stream<Path> loadAll();

 Path load(String filename);

 Resource loadAsResource(String filename);

 void deleteAll();

}

以下是接口实现类

package cn.tiny77.guide05;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

@Service
public class FileSystemStorageService implements StorageService {

 private final Path rootLocation;

 @Autowired
 public FileSystemStorageService(StorageProperties properties) {
  this.rootLocation = Paths.get(properties.getLocation());
 }

 @Override
 public void store(MultipartFile file) {
  String filename = StringUtils.cleanPath(file.getOriginalFilename());
  try {
   if (file.isEmpty()) {
    throw new StorageException("无法保存空文件 " + filename);
   }
   if (filename.contains("..")) {
    // This is a security check
    throw new StorageException(
      "无权访问该位置 "
        + filename);
   }
   Files.copy(file.getInputStream(), this.rootLocation.resolve(filename),
     StandardCopyOption.REPLACE_EXISTING);
  }
  catch (IOException e) {
   throw new StorageException("无法保存文件 " + filename, e);
  }
 }

 @Override
 public Stream<Path> loadAll() {
  try {
   return Files.walk(this.rootLocation, 1)
     .filter(path -> !path.equals(this.rootLocation))
     .map(path -> this.rootLocation.relativize(path));
  }
  catch (IOException e) {
   throw new StorageException("读取文件异常", e);
  }

 }

 @Override
 public Path load(String filename) {
  return rootLocation.resolve(filename);
 }

 @Override
 public Resource loadAsResource(String filename) {
  try {
   Path file = load(filename);
   Resource resource = new UrlResource(file.toUri());
   if (resource.exists() || resource.isReadable()) {
    return resource;
   }
   else {
    throw new StorageFileNotFoundException(
      "无法读取文件: " + filename);

   }
  }
  catch (MalformedURLException e) {
   throw new StorageFileNotFoundException("无法读取文件: " + filename, e);
  }
 }

 @Override
 public void deleteAll() {
  FileSystemUtils.deleteRecursively(rootLocation.toFile());
 }

 @Override
 public void init() {
  try {
   Files.createDirectories(rootLocation);
  }
  catch (IOException e) {
   throw new StorageException("初始化存储空间出错", e);
  }
 }
}

2、建立一个Html页面

这里使用Thymeleaf模板

<html xmlns:th="http://www.thymeleaf.org">
<body>

 <div th:if="${message}">
  <h2 th:text="${message}"/>
 </div>

 <div>
  <form method="POST" enctype="multipart/form-data" action="/">
   <table>
    <tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr>
    <tr><td></td><td><input type="submit" value="Upload" /></td></tr>
   </table>
  </form>
 </div>

 <div>
  <ul>
   <li th:each="file : ${files}">
    <a th:href="${file}" rel="external nofollow" th:text="${file}" />
   </li>
  </ul>
 </div>

</body>
</html>

页面主要分为三部分分

- 顶部展示SpringMvc传过来的信息
- 一个提供用户上传文件的表单
- 一个后台提供的文件列表

3、限制上传文件的大小

在文件上传的应用中通常要设置文件大小的,想象一下后台处理的文件如果是5GB,那得多糟糕!在SpringBoot中,我们可以通过属性文件来控制。
新建一个application.properties,代码如下:
spring.http.multipart.max-file-size=128KB #文件总大小不能超过128kb
spring.http.multipart.max-request-size=128KB #请求数据的大小不能超过128kb

4、应用启动函数

package cn.tiny77.guide05;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;


@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class Application {

 public static void main(String[] args) {
  SpringApplication.run(Application.class, args);
 }

 @Bean
 CommandLineRunner init(StorageService storageService) {
  return (args) -> {
   storageService.deleteAll();
   storageService.init();
  };
 }
} 

5、运行结果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Spring  # 文件上传  # SpringMVC文件上传 多文件上传实例  # Spring实现文件上传(示例代码)  # 详解SpringBoot文件上传下载和多文件上传(图文)  # jquery.form.js框架实现文件上传功能案例解析(springmvc)  # SpringMVC 文件上传配置  # 多文件上传  # 使用的MultipartFile的实例  # 使用jQuery.form.js/springmvc框架实现文件上传功能  # MyBatis与SpringMVC相结合实现文件上传、下载功能  # springMVC配置环境实现文件上传和下载  # SpringMVC文件上传的配置实例详解  # Spring Boot实现文件上传示例代码  # 上传文件  # 你要  # 加载  # 文件列表  # 你将  # 不能超过  # 新建一个  # 好了  # 为你  # 一切都  # 而在  # 会在  # 我们可以  # 得多  # 将它  # 提供一个  # 建立一个  # 表单  # 来实现 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 百度输入法ai面板怎么关 百度输入法ai面板隐藏技巧  Laravel Blade模板引擎语法_Laravel Blade布局继承用法  Laravel安装步骤详细教程_Laravel环境搭建指南  Laravel如何实现多级无限分类_Laravel递归模型关联与树状数据输出【方法】  微信h5制作网站有哪些,免费微信H5页面制作工具?  网站制作企业,网站的banner和导航栏是指什么?  Laravel用户密码怎么加密_Laravel Hash门面使用教程  如何自定义建站之星网站的导航菜单样式?  javascript基于原型链的继承及call和apply函数用法分析  如何正确选择百度移动适配建站域名?  Linux虚拟化技术教程_KVMQEMU虚拟机安装与调优  使用豆包 AI 辅助进行简单网页 HTML 结构设计  Laravel如何生成和使用数据填充?(Seeder和Factory示例)  Midjourney怎么调整光影效果_Midjourney光影调整方法【指南】  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  nodejs redis 发布订阅机制封装实现方法及实例代码  Win11搜索栏无法输入_解决Win11开始菜单搜索没反应问题【技巧】  打开php文件提示内存不足_怎么调整php内存限制【解决方案】  购物网站制作费用多少,开办网上购物网站,需要办理哪些手续?  如何在服务器上配置二级域名建站?  iOS验证手机号的正则表达式  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  Laravel如何获取当前登录用户信息_Laravel Auth门面使用与Session用户读取【技巧】  Laravel如何使用Facades(门面)及其工作原理_Laravel门面模式与底层机制  如何快速搭建高效服务器建站系统?  Edge浏览器怎么启用睡眠标签页_节省电脑内存占用优化技巧  如何用免费手机建站系统零基础打造专业网站?  如何快速查询网址的建站时间与历史轨迹?  如何解决hover在ie6中的兼容性问题  利用 Google AI 进行 YouTube 视频 SEO 描述优化  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  Edge浏览器如何截图和滚动截图_微软Edge网页捕获功能使用教程【技巧】  Laravel如何集成Inertia.js与Vue/React?(安装配置)  如何快速使用云服务器搭建个人网站?  php485函数参数是什么意思_php485各参数详细说明【介绍】  如何构建满足综合性能需求的优质建站方案?  js代码实现下拉菜单【推荐】  如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  Laravel怎么实现支付功能_Laravel集成支付宝微信支付  Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例  米侠浏览器网页背景异常怎么办 米侠显示修复  在线制作视频网站免费,都有哪些好的动漫网站?  bootstrap日历插件datetimepicker使用方法  如何快速配置高效服务器建站软件?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  Laravel如何发送邮件_Laravel Mailables构建与发送邮件的简明教程  Laravel Debugbar怎么安装_Laravel调试工具栏配置指南  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法