Spring 随笔05 文件上传

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

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

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

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

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

 1 package cn.tiny77.guide05;
 2
 3 import java.io.IOException;
 4 import java.util.List;
 5 import java.util.stream.Collectors;
 6
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.core.io.Resource;
 9 import org.springframework.http.HttpHeaders;
10 import org.springframework.http.ResponseEntity;
11 import org.springframework.stereotype.Controller;
12 import org.springframework.ui.Model;
13 import org.springframework.web.bind.annotation.ExceptionHandler;
14 import org.springframework.web.bind.annotation.GetMapping;
15 import org.springframework.web.bind.annotation.PathVariable;
16 import org.springframework.web.bind.annotation.PostMapping;
17 import org.springframework.web.bind.annotation.RequestParam;
18 import org.springframework.web.bind.annotation.ResponseBody;
19 import org.springframework.web.multipart.MultipartFile;
20 import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
21 import org.springframework.web.servlet.mvc.support.RedirectAttributes;
22
23 @Controller
24 public class FileUploadController {
25
26     private final StorageService storageService;
27
28     @Autowired
29     public FileUploadController(StorageService storageService) {
30         this.storageService = storageService;
31     }
32
33     @GetMapping("/")
34     public String listUploadedFiles(Model model) throws IOException {
35
36         List<String> paths = storageService.loadAll().map(
37                 path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,
38                         "serveFile", path.getFileName().toString()).build().toString())
39                 .collect(Collectors.toList());
40
41         model.addAttribute("files", paths);
42
43         return "uploadForm";
44     }
45
46     @GetMapping("/files/{filename:.+}")
47     @ResponseBody
48     public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
49
50         Resource file = storageService.loadAsResource(filename);
51         return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION,
52                 "attachment; filename=\"" + file.getFilename() + "\"").body(file);
53     }
54
55     @PostMapping("/")
56     public String handleFileUpload(@RequestParam("file") MultipartFile file,
57             RedirectAttributes redirectAttributes) {
58
59         storageService.store(file);
60         redirectAttributes.addFlashAttribute("message",
61                 "You successfully uploaded " + file.getOriginalFilename() + "!");
62
63         return "redirect:/";
64     }
65
66     @ExceptionHandler(StorageFileNotFoundException.class)
67     public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
68         return ResponseEntity.notFound().build();
69     }
70
71 }

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

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

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

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

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

 1 package cn.tiny77.guide05;
 2
 3 import org.springframework.core.io.Resource;
 4 import org.springframework.web.multipart.MultipartFile;
 5
 6 import java.nio.file.Path;
 7 import java.util.stream.Stream;
 8
 9 public interface StorageService {
10
11     void init();
12
13     void store(MultipartFile file);
14
15     Stream<Path> loadAll();
16
17     Path load(String filename);
18
19     Resource loadAsResource(String filename);
20
21     void deleteAll();
22
23 }

以下是接口实现类

  1 package cn.tiny77.guide05;
  2
  3 import java.io.IOException;
  4 import java.net.MalformedURLException;
  5 import java.nio.file.Files;
  6 import java.nio.file.Path;
  7 import java.nio.file.Paths;
  8 import java.nio.file.StandardCopyOption;
  9 import java.util.stream.Stream;
 10
 11 import org.springframework.beans.factory.annotation.Autowired;
 12 import org.springframework.core.io.Resource;
 13 import org.springframework.core.io.UrlResource;
 14 import org.springframework.stereotype.Service;
 15 import org.springframework.util.FileSystemUtils;
 16 import org.springframework.util.StringUtils;
 17 import org.springframework.web.multipart.MultipartFile;
 18
 19 @Service
 20 public class FileSystemStorageService implements StorageService {
 21
 22     private final Path rootLocation;
 23
 24     @Autowired
 25     public FileSystemStorageService(StorageProperties properties) {
 26         this.rootLocation = Paths.get(properties.getLocation());
 27     }
 28
 29     @Override
 30     public void store(MultipartFile file) {
 31         String filename = StringUtils.cleanPath(file.getOriginalFilename());
 32         try {
 33             if (file.isEmpty()) {
 34                 throw new StorageException("无法保存空文件 " + filename);
 35             }
 36             if (filename.contains("..")) {
 37                 // This is a security check
 38                 throw new StorageException(
 39                         "无权访问该位置 "
 40                                 + filename);
 41             }
 42             Files.copy(file.getInputStream(), this.rootLocation.resolve(filename),
 43                     StandardCopyOption.REPLACE_EXISTING);
 44         }
 45         catch (IOException e) {
 46             throw new StorageException("无法保存文件 " + filename, e);
 47         }
 48     }
 49
 50     @Override
 51     public Stream<Path> loadAll() {
 52         try {
 53             return Files.walk(this.rootLocation, 1)
 54                     .filter(path -> !path.equals(this.rootLocation))
 55                     .map(path -> this.rootLocation.relativize(path));
 56         }
 57         catch (IOException e) {
 58             throw new StorageException("读取文件异常", e);
 59         }
 60
 61     }
 62
 63     @Override
 64     public Path load(String filename) {
 65         return rootLocation.resolve(filename);
 66     }
 67
 68     @Override
 69     public Resource loadAsResource(String filename) {
 70         try {
 71             Path file = load(filename);
 72             Resource resource = new UrlResource(file.toUri());
 73             if (resource.exists() || resource.isReadable()) {
 74                 return resource;
 75             }
 76             else {
 77                 throw new StorageFileNotFoundException(
 78                         "无法读取文件: " + filename);
 79
 80             }
 81         }
 82         catch (MalformedURLException e) {
 83             throw new StorageFileNotFoundException("无法读取文件: " + filename, e);
 84         }
 85     }
 86
 87     @Override
 88     public void deleteAll() {
 89         FileSystemUtils.deleteRecursively(rootLocation.toFile());
 90     }
 91
 92     @Override
 93     public void init() {
 94         try {
 95             Files.createDirectories(rootLocation);
 96         }
 97         catch (IOException e) {
 98             throw new StorageException("初始化存储空间出错", e);
 99         }
100     }
101 }

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}" 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、应用启动函数

 1 package cn.tiny77.guide05;
 2
 3 import org.springframework.boot.CommandLineRunner;
 4 import org.springframework.boot.SpringApplication;
 5 import org.springframework.boot.autoconfigure.SpringBootApplication;
 6 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 7 import org.springframework.context.annotation.Bean;
 8
 9
10 @SpringBootApplication
11 @EnableConfigurationProperties(StorageProperties.class)
12 public class Application {
13
14     public static void main(String[] args) {
15         SpringApplication.run(Application.class, args);
16     }
17
18     @Bean
19     CommandLineRunner init(StorageService storageService) {
20         return (args) -> {
21             storageService.deleteAll();
22             storageService.init();
23         };
24     }
25 }

5、运行结果

6.项目DEMO : https://github.com/qinrongjin/SpringGuide05

时间: 2024-10-12 19:59:21

Spring 随笔05 文件上传的相关文章

Spring MVC 多文件上传大小限制及异常处理

Spring MVC  多文件上传大小限制及异常处理 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 在 spring mvc 的默认配置文件 WEB-INF/xxx-servlet.xml 中

Ext4.2结合Spring MVC实现文件上传显示进度

1.实现原理: 在大文件上传时显示上传进度是很有必要的,不能让用户感觉到陷入无穷的等待中,或感觉程序已经卡死.为此我们可以在session中存一个上传进度的变量,在文件上传的过程中实时的去修改这个值,这就需要在后台重写Spring MVC自带的上传解析类,每上传一定的字节数就修改一下session中的进度,在前台通个AJAX请求每隔一定的时间去获取这个值显示给用户,这样就达到了显示上传进度的需求,不过这样频繁的请求服务器无疑是增加了服务器的压力,在没有使用任何第三方上传组件的情况下只能如此. 2

【Spring学习笔记-MVC-13】Spring MVC之文件上传

作者:ssslinppp       1. 摘要 Spring MVC为文件上传提供了最直接的支持,这种支持是通过即插即用的MultipartResolve实现的.Spring使用Jakarta Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver. 下面将具体讲解Spring MVC实现文件上传的具体步骤. 2. 添加Jar包 Spring MVC文件上传,需要添加如下两个jar包: commons-fil

spring mvc ajaxfileupload文件上传返回json下载问题

问题:使用spring mvc ajaxfileupload 文件上传在ie8下会提示json下载问题 解决方案如下: 服务器代码: @RequestMapping(value = "/addAnalysis", method = RequestMethod.POST) public void addAnalysisUI( HttpServletResponse response,HttpServletRequest request,HttpSession session, @Requ

Spring Boot入门——文件上传与下载

Spring Boot入门--文件上传与下载https://www.cnblogs.com/studyDetail/p/7003253.html 1.在pom.xml文件中添加依赖 复制代码 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http:/

Spring中实现文件上传

详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt110 实现图片上传  用户必须能够上传图片,因此需要文件上传的功能.比较常见的文件上传组件有Commons FileUpload(http://jakarta.apache.org/commons/fileupload/a>)和COS FileUpload(http://www.servlets.com/cos),Spring已经完全集成了这两种组件,这里我们选择Commo

spring boot实现文件上传下载

spring boot 引入”约定大于配置“的概念,实现自动配置,节约了开发人员的开发成本,并且凭借其微服务架构的方式和较少的配置,一出来就占据大片开发人员的芳心.大部分的配置从开发人员可见变成了相对透明了,要想进一步熟悉还需要关注源码.1.文件上传(前端页面): <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd&quo

spring mvc注解文件上传下载

需要两个包: 包如何导入就不介绍了,前端代码如下(一定要加enctype="multipart/form-data"让服务器知道是文件上传): <form action="upload.do" method="post" enctype="multipart/form-data"> <input type="file" id="upimage" name="f

spring test---restful与文件上传

spring提供了大量经常使用的功能測试,如文件上传.restful风格url訪问.以下介绍主要介绍下test中经常使用功能的使用方法: 首先能够静态导入类.方便在測试类中使用,导入的类有 import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; import static org.springframework.test.web.client.response.MockR