Spring 中的檔案上傳與下載控制
阿新 • • 發佈:2018-11-09
- 先建立根應用上下文配置,WebDemo/src/main/java/com/seliote/webdemo/config/RootContextConfig.java
package com.seliote.webdemo.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; // 配置類必須標註 @Configuration 註解 @Configuration // 設定註解掃描,預設掃描所有標註了 @Component 的類(@Component 標註的標註也算),都將變為 Spring 管理的 bean(自動例項化與注入依賴) @ComponentScan( // 註解掃描的起始包 basePackages = "com.seliote.webdemo", // 排除對標註了 @Configuration 與 @Controller 類的例項化 excludeFilters = @ComponentScan.Filter({Configuration.class, Controller.class}) ) public class RootContextConfig { }
- 建立 Servlet 上下文配置,注意其中註冊了一個 MultipartResolver 用於 Servlet 3.0- 的檔案下載,WebDemo/src/main/java/com/seliote/webdemo/config/ServletContextConfig.java
package com.seliote.webdemo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.support.StandardServletMultipartResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @Configuration // 啟用註解驅動的控制器請求對映 @EnableWebMvc @ComponentScan( basePackages = "com.seliote.webdemo", // 忽略預設掃描模式 useDefaultFilters = false, // 僅對標註了 @Controller 的類進行掃描 includeFilters = @ComponentScan.Filter(Controller.class) ) public class ServletContextConfig { // 啟用檔案上傳,如果不是 Servlet 3.0+ 就使用第三方工具 @Bean public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); } }
- 編寫啟動項,注意其中註冊 DispatcherServlet 時所呼叫的
dynamic.setMultipartConfig(new MultipartConfigElement(...))
方法用於開啟檔案上傳,WebDemo/src/main/java/com/seliote/webdemo/config/Bootstrap.java
package com.seliote.webdemo.config; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; // ServletContainerInitializer 介面的實現將在應用程式啟動時(所有監聽器啟動之前)呼叫 onStartup() 方法(應用可用的最早時間點), // 但是直接實現 ServletContainerInitializer 過於麻煩,所以提供了一個 SpringServletContainerInitializer 橋介面, // 它會在應用程式啟動時掃描應用中所有 WebApplicationInitializer 介面的實現並呼叫其 onStartup() 方法 public class Bootstrap implements WebApplicationInitializer { public void onStartup(ServletContext aServletContext) throws ServletException { // 允許 Servlet 容器提供靜態檔案 aServletContext.getServletRegistration("default").addMapping("/resource/*"); // 配置根應用上下文 AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(RootContextConfig.class); // 通過監聽器啟動根上下文(ContextLoaderListener 將在 Web 應用程式啟動時初始化 aServletContext.addListener(new ContextLoaderListener(rootContext)); // 配置 Servlet 上下文 AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext(); servletContext.register(ServletContextConfig.class); // 動態註冊一個 DispatcherServlet,注意是 new DispatcherServlet(ApplicationContext) // 並傳入上文建立的 AnnotationConfigWebApplicationContext,而非傳入 DispatcherServlet.class ServletRegistration.Dynamic dynamic = aServletContext.addServlet("dispatcherServlet", new DispatcherServlet(servletContext)); // 啟用檔案上傳 dynamic.setMultipartConfig(new MultipartConfigElement("/tmp", 20_971_520L, 41_943_040L, 512_000)); // 設定 DispatcherServlet 的對映 dynamic.addMapping("/"); // 設定應用程式部署後即啟動 dynamic.setLoadOnStartup(1); } }
- 兩個 JSP 用於上傳和下載
WebDemo/web/upload.jsp
<%@ page contentType="text/html" pageEncoding="UTF-8" language="java" %>
<html>
<head>
<title>Upload</title>
</head>
<body>
<h2>Select a file:</h2><br /><br />
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="userFile" /><br />
<input type="submit" value="Submit" />
</form>
</body>
</html>
WebDemo/web/download.jsp
<%@ page contentType="text/html" pageEncoding="UTF-8" language="java" %>
<html>
<head>
<title>Download</title>
</head>
<body>
<a href="/download">
<button type="button">Download</button>
</a>
</body>
</html>
- 最後編寫控制器即可,WebDemo/src/main/java/com/seliote/webdemo/controller/FileController.java
package com.seliote.webdemo.controller;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@Controller
public class FileController {
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@RequestMapping("/upload")
public String upload(@RequestPart("userFile") Part aPart) throws IOException {
if (aPart == null) {
return "Part is null";
}
InputStream inputStream = aPart.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int readLength = -1;
while ((readLength = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, readLength);
}
int length = byteArrayOutputStream.size();
byteArrayOutputStream.close();
return "Success!" + length;
}
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@RequestMapping("/download")
public void download(HttpServletRequest aHttpServletRequest, HttpServletResponse aHttpServletResponse) throws IOException {
File file = new File("/home/seliote/Temp/grub.cfg");
// 設定響應頭,說明是檔案下載
aHttpServletResponse.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
aHttpServletResponse.setContentType("application/octet-stream");
// 為響應手動寫入檔案
InputStream inputStream = new FileInputStream(file);
ServletOutputStream servletOutputStream = aHttpServletResponse.getOutputStream();
byte[] buffer = new byte[1024];
int readLength = -1;
while ((readLength = inputStream.read(buffer)) != -1) {
servletOutputStream.write(buffer, 0, readLength);
}
inputStream.close();
}
}