标签:文件 web com springframework import org 上传 example
此篇指南带你遍历创建一个可以接受HTTP多部分文件(multi-part file)上传服务器程序的步骤。
What You Will Build
你将创建一个Spring Boot web应用用来接受上传的文件。你也将构建一个简单的HTML界面用来上传测试文件。
What You Need
- 大约15分钟
- 你喜欢的文本编辑器或IDE
- JDK 1.8 以上
- Graddle 4+ 或 Maven 3.2+
- 你也可以直接将代码导入进你的IDE
- Spring Tool Suite (STS)
- InteelliJ IDEA
How to complete this guide
正如Spring大多数指南一样,你可以从头开始并且完成每一个步骤或者你可以绕开你已经熟悉的基本设置。无论哪种方式,你最终都是完成代码。
为了从头开始,移步到Starting with Spring Initializr
。
为了跳过基础,做如下步骤:
- 下载并解压这篇指南的原仓库,或者使用GIt克隆
git clone https://github.com/spring-guides/gs-uploading-files.git
- 进入(cd)
gs-uploading-files/initial
- 移步到
Create an Application Class
当你完成以后,你可以再次检查你的gs-uploading-files/complete
的代码。
Starting with Spring Initializr
你可以使用预初始化项目点击Generate来下载ZIP文件。这一项目被配置为适合本篇指南。
为了手动初始化项目:
- 浏览https://start.spring.io/。这个服务拉取了你的应用所有需要的依赖并且已经为了做了多数配置。
- 选择Gradle或Maven与你想使用的语言。本文假设你选择Java。
- 点击Dependencies选择Spring Web和Thymeleaf。
- 点击Generate。
- 下载ZIP文件,这是一个为你的选择配置好的网络应用文件。
如果你的IDE整合了Spring Initializr,你可以从你的IDE完成此步骤
你也可以从GitHub中fork此项目使用你的IDE或者编辑器打开。
Create an Application Class
为了启动Spring Boot MVC应用,你首先需要一个启动器。在本篇示例,spring-boot-starter-thymeleaf
和spring-boot-starter-web
都作为依赖被添加。为了使用Servlet容器上传文件,你需要注册一个MultipartConfigElement
类(将是在web.xml中的<multipart-config>
)。由于使用Spring Boot,一切事物已经为你自动配置。
所有你需要做的事情就是开始如下所示的应用UploadingFilesApplication
类:
src/main/java/com/example/uploadingfiles/UploadingFilesApplication.java
package com.example.uploadingfiles;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UploadingFilesApplication {
public static void main(String[] args) {
SpringApplication.run(UploadingFilesApplication.class, args);
}
}
作为自动配置Spring MVC,Spring Boot将创建一个MultipartConfigElement
bean并且使其准备接受文件上传。
Create a File Upload Controller
initial中的应用已经包含一少部分的类用来处理存储和加载在硬盘中上传的文件。它们全部在com.example.uploadingfiles.storage
。你将在你的新类FileUploadController
中使用它们。如下所示为文件上传控制器:
src/main/java/com/example/uploadingfiles/FileUploadController.java
package com.example.uploadingfiles;
import java.io.IOException;
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;
import com.example.uploadingfiles.storage.StorageFileNotFoundException;
import com.example.uploadingfiles.storage.StorageService;
@Controller
public class FileUploadController {
private final StorageService storageService;
@Autowired
public FileUploadController(StorageService storageService) {
this.storageService = storageService;
}
@GetMapping("/")
public String listUploadedFiles(Model model) throws IOException {
model.addAttribute("files", storageService.loadAll().map(
path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,
"serveFile", path.getFileName().toString()).build().toUri().toString())
.collect(Collectors.toList()));
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();
}
}
FileUploadController
类使用@Controller
注解,因此Spring MVC可以用其查找路径。每一个方法使用@GetMapping
或@PostMapping
注解标记用来将路径和HTTP动作与特定的控制器动作联系起来。
在这个例子中:
GET /
:从StorageService
中查找当前上传文件的列表并且加载到Thymeleaf模板中。它使用MvcUriComponentsBuilder
计算出一个到实际资源的链接。GET /files/{filename}
:加载资源(前提存在)并且通过使用Content-Disposition
响应头发送到浏览器进行下载。POST /
:处理multi-part消息file
以及发送它到StorageService
进行保存。
在生产环境中,你很有可能将文件存储到临时位置、数据库、NoSQL存储(例如Mongo的[GridFS](https://docs.mongodb.org/manual/core/gridfs)。最好不要上传到你的应用的文件系统。
你将需要提供一个StorageService
来使得控制器可以与存储层(例如文件系统)进行交互。如下所示:
src/main/java/com/example/uploadingfiles/storage/StorageService.java
package com.example.uploadingfiles.storage;
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();
}
Creating an HTML Template
如下所示的Thymeleaf模板用来演示如何上传文件以及显示被上传的文件:
<html xmlns:th="https://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="上传" /></td></tr>
</table>
</form>
</div>
<div>
<ul>
<li th:each="file : ${files}">
<a th:href="${file}" th:text="${file}" />
</li>
</ul>
</div>
</body>
</html>
这一模板有三个部分:
- 在顶部Spring MVC写入flash-scoped meesage可选消息
- 用户上传文件的表单
- 从后端提供的文件列表
Tuning File Upload Limits
当配置文件上传的时候,一个常用的做法是设置文件的大小。想象一下尝试处理5GB的文件上传!在Spring Boot,我们可以微调它的自动配置MultipartContentElement
的某些属性配置。
添加如下所示的属性到你存在的属性配置中:
src/main/resources/application.properties
spring.servlet.multipart.max-file-size=128KB
spring.servlet.multipart.max-request-size=128KB
multipart设置被限制为:
spring.servlet.multipart.max-file-size
设置为128KB,代表着全部文件大小不可以超过128KB。spring.servlet.multipart.max-request-size
设置为128KB,代表全部请求multipart/form-data
大小不能超过128KB。
Run the Application
你想要目标目录用来上传文件,所以你需要启用由Spring Initializr创建的基本UploadingFilesApplication
类,并且添加一个BootCommandLineRunner
在启动时来删除和重新创建这个目录。如下所示:
src/main/java/com/example/uploadingfiles/UploadingFilesApplication.java
package com.example.uploadingfiles;
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;
import com.example.uploadingfiles.storage.StorageProperties;
import com.example.uploadingfiles.storage.StorageService;
@SpringBootApplication
@EnableConfigurationProperties(StorageProperties.class)
public class UploadingFilesApplication {
public static void main(String[] args) {
SpringApplication.run(UploadingFilesApplication.class, args);
}
@Bean
CommandLineRunner init(StorageService storageService) {
return (args) -> {
storageService.deleteAll();
storageService.init();
};
}
}
@SpringBootApplication
是一个添加了如下展示的所有内容的方便注解:
@Configuration
:对于应用上下文(context),将类标记为bean定义的来源。@EnableAutoConfiguration
:告诉Spring Boot开始根据类路径设置添加bean,其它bean,以及各种属性设置。例如,如果spring-webmvc
在类路径中,这一注解将应用程序标记为web应用以及激活关键行为,例如设置DispatcherServlet
。@ComponentScan
:告诉Spring寻找com.example
包下其它组件、配置以及服务,使其找到控制器。
main()
方法使用Spring Boot的SpringApplication.run()
方法来启动一个应用程序。你是否注意到没有一行的XML?也同样没有web.xml
文件。这一个应用程序是100%纯Java并且你并没有必须处理配置任何一个plumbing或infrastructure。
Build an executable JAR
你可以在命令行以Gradle或Maven运行应用程序。你也可以构建一个单一可执行的JAR包,其中包含所有必须的依赖、类以及资源并且运行。构建一个可执行jar可以易于传输、版本和部署服务作为应用,贯穿至整个开发周期,穿插于不同环境等等。
如果你使用Gradle,你可以通过使用./gradlew bootRun
来运行应用程序。或者说,你可以使用./gradlew build
来构建JAR包,然后运行JAR包,如下命令:
java -jar build/libs/gs-uploading-files-0.1.0.jar
如果你使用Maven,你可以通过./mvnw spring-boot:run
来运行应用程序。或者说,你可以使用./mvnw clean package
来构建JAR包,通过如下命令执行JAR包。
java -jar target/gs-uploading-files-0.1.0.jar
此处步骤描述了创建一个可执行JAR包。你也可以构造一个经典的WAR文件。
它运行于服务端用于接受文件上传的部分。日志输出被打印。服务应该启动运行在几秒之内。
当服务器运行,你需要打开浏览器访问http://localhost:8080/
可以看到文件上传表单。选择一个小文件之后点击上传按钮。你应该看到来自于控制器的成功页面。如果你选择一个文件太大了,你将会得到一个丑陋的错误页面。
在之后,你应该在你的浏览器窗口看到一行类似于如下的输出:
You successfully uploaded <name of your file>!
Testing Your Application
在我们的应用中,有多种方法来测试特定功能。如下所示,使用MockMvc
以便于不需要从servlet容器开始:
src/test/java/com/example/uploadingfiles/FileUploadTests.java
package com.example.uploadingfiles;
import java.nio.file.Paths;
import java.util.stream.Stream;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import com.example.uploadingfiles.storage.StorageFileNotFoundException;
import com.example.uploadingfiles.storage.StorageService;
@AutoConfigureMockMvc
@SpringBootTest
public class FileUploadTests {
@Autowired
private MockMvc mvc;
@MockBean
private StorageService storageService;
@Test
public void shouldListAllFiles() throws Exception {
given(this.storageService.loadAll())
.willReturn(Stream.of(Paths.get("first.txt"), Paths.get("second.txt")));
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(model().attribute("files",
Matchers.contains("http://localhost/files/first.txt",
"http://localhost/files/second.txt")));
}
@Test
public void shouldSaveUploadedFile() throws Exception {
MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt",
"text/plain", "Spring Framework".getBytes());
this.mvc.perform(multipart("/").file(multipartFile))
.andExpect(status().isFound())
.andExpect(header().string("Location", "/"));
then(this.storageService).should().store(multipartFile);
}
@SuppressWarnings("unchecked")
@Test
public void should404WhenMissingFile() throws Exception {
given(this.storageService.loadAsResource("test.txt"))
.willThrow(StorageFileNotFoundException.class);
this.mvc.perform(get("/files/test.txt")).andExpect(status().isNotFound());
}
}
在这些测试,你使用各种mock来设置你的控制器和StorageService
的交互,以及使用MockMultipartFile
本身与Servlet容器交互。
对于一个整合测试的例子,查看FileUploadIntegrationTests
类(在src/test/java/com/example/uploadingfiles
)。
标签:文件,web,com,springframework,import,org,上传,example 来源: https://www.cnblogs.com/geekfx/p/16209548.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。