2024.3.26 Tuesday
Contents
10. File Upload and Download
10.1. Preparation
- File upload is one of the most common features in project development. Spring MVC supports file upload well, but the Spring MVC context does not assemble MultipartResolver by default, so it cannot handle file uploads by default. If you want to use Spring’s file upload function, you need to configure MultipartResolver in the context.
- Requirements for the front-end form: To upload files, the form’s method must be set to POST, and enctype must be set to multipart/form-data. Only in this case, the browser will send the user-selected files as binary data to the server.
- Detailed explanation of the enctype attribute in the form:
- application/x-www=form-urlencoded: The default way, it only processes the value attribute in the form fields, and the form fields’ values are processed into URL encoding.
- multipart/form-data: This encoding method will handle form data in a binary stream manner. This method will encapsulate the content of the file specified by the file field into the request parameters, without character encoding.
- text/plain: Other than converting spaces to “+” signs, other characters are not encoded. This method is suitable for sending emails directly through the form.
- Once the enctype is set to multipart/form-data, the browser will process the form data in a binary stream manner. The processing of file uploads involves parsing the original HTTP response on the server side. In 2003, the Apache Software Foundation released the open-source Commons FileUpload component, which quickly became the best choice for Servlet/JSP programmers to upload files.
- The Servlet 3.0 specification already provides methods to handle file uploads, but this type of upload needs to be completed in the Servlet.
- Spring MVC provides a simpler encapsulation.
- Spring MVC provides direct support for file uploads, implemented by a plug-and-play MultipartResolver.
- Spring MVC uses the Apache Commons FileUpload technology to implement a MultipartResolver implementation class: CommonsMultipartResolver. Therefore, Spring MVC’s file upload still depends on the Apache Commons FileUpload component.
10.2. Basic Configuration
10.2.1. Create a module named springmvc-08-file
Add web support, modify web.xml (same as in springmvc-07-interceptor), modify Tomcat configuration
These operations have been repeated multiple times, so this time only the modified parts are detailed.
10.2.2. Create a controller folder, applicationContext.xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- Automatically scan the specified package, all annotated classes are managed by the IOC container -->
<context:component-scan base-package="P29.controller"/>
<!-- Static resource filtering -->
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<!-- View Resolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- Prefix -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- Suffix -->
<property name="suffix" value=".jsp" />
</bean>
<!-- File upload configuration -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- Request encoding format, must be consistent with the JSP's pageEncoding attribute to correctly read the form's content, default is ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- Upload file size limit, in bytes (10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
</beans>
- Common methods of CommonsMultipartFile:
- String getOriginalFilename(): Gets the original name of the uploaded file
- InputStream getInputStream(): Gets the file stream
- void transferTo(File dest): Saves the uploaded file to a directory file
10.3. File Upload
10.3.1. Import the jar package for file upload: commons-fileupload in this module’s pom.xml
Maven will automatically import its dependency package, commons-io package
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringMVC_try1</artifactId>
<groupId>com.kuang</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>P29</groupId>
<artifactId>springmvc-08-file</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- File Upload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- Import a higher version of servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
</dependencies>
</project>
Import the lib directory in project structure
10.3.2. Modify index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%--Submit a file in binary stream form--%>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit" value="upload">
</form>
</body>
</html>
10.3.3. Create FileController.java
package P29.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
// Use CommonsMultipartFile to receive files
//@RequestParam("file") encapsulates the file obtained from the name=file control into a CommonsMultipartFile object
// For bulk upload, CommonsMultipartFile would be an array
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
// Get the file name: file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
// If the file name is empty, go directly back to the homepage!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("Upload file name: " + uploadFileName);
// Save the upload path settings
String path = request.getServletContext().getRealPath("/upload");
// If the path does not exist, create one
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("Upload file save address: " + realPath);
InputStream is = file.getInputStream(); // File input stream
OutputStream os = new FileOutputStream(new File(realPath, uploadFileName)); // File output stream
// Read and write
int len = 0;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1){
os.write(buffer, 0, len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
}
10.3.4. Using file.TransferTo to Save Uploaded Files
Modify FileController.java
by adding the fileUpload2 method
package P29.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
@Controller
public class FileController {
//CommonsMultipartFile to receive files
//@RequestParam("file") encapsulates the file obtained from the file control into a CommonsMultipartFile object
//For batch upload, CommonsMultipartFile can be an array
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//Get file name: file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//If the file name is empty, go directly back to the homepage!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("Upload file name : "+uploadFileName);
//Setting up the save path for upload
String path = request.getServletContext().getRealPath("/upload");
//If the path does not exist, create one
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("Upload file save address:"+realPath);
InputStream is = file.getInputStream(); //File input stream
OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //File output stream
//Reading and writing (through IO)
int len=0;
byte[] buffer = new byte[1024];
while ((len=is.read(buffer))!=-1){
os.write(buffer,0,len);
os.flush();
}
os.close();
is.close();
return "redirect:/index.jsp";
}
/*
* Using file.TransferTo to save uploaded files
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//Setting up the save path for upload
//Not getting the file name of the uploaded file, directly save the file
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//Upload file address
System.out.println("Upload file save address:"+realPath);
//Directly write files through CommonsMultipartFile's method (not through IO) (note at this time)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
}
10.3.5. Running
http://localhost:8080/springmvc_08_file_war_exploded/
The uploaded files can be found in the specified location.
10.4. File Download
10.4.1. Steps for File Download
- Set the response header.
- Read the file — InputStream.
- Write out the file — OutputStream.
- Perform the operation.
- Close the streams (open last, close first).
10.4.2. Code Implementation (Modify FileController.java)
package P29.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@Controller
public class FileController {
// Below is the code for downloading images
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
// The image's download path (here, we hope to download an image named "Screenshot1.png" from /upload)
String path = request.getServletContext().getRealPath("/upload");
String fileName = "Screenshot1.png";
//1. Set response header
response.reset(); // Set the page to not cache, clear buffer
response.setCharacterEncoding("UTF-8"); // Character encoding
response.setContentType("multipart/form-data"); // Binary data transfer
// Set the response header
response.setHeader("Content-Disposition",
"attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path, fileName);
//2. Read the file — input stream
InputStream input=new FileInputStream(file);
//3. Write out the file — output stream
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4. Perform the write-out operation
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
}
10.4.3. Run
http://localhost:8080/springmvc_08_file_war_exploded/download
The file is downloaded to the browser’s specified save location.