CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Trang chủHướng dẫnHướng dẫn tải tệp với Spring MVC

Hướng dẫn tải tệp với Spring MVC

CyStack blog 6 phút để đọc
CyStack blog16/10/2025
Locker Avatar

Chris Pham

Technical Writer

Locker logo social
Reading Time: 6 minutes

Việc tải lên tệp là một tính năng không thể thiếu trong hầu hết các ứng dụng web hiện đại. Từ việc tải lên ảnh đại diện, tài liệu, đến các tệp media, khả năng này đóng vai trò cực kỳ quan trọng trong trải nghiệm người dùng và chức năng của ứng dụng. Trước đây, chúng ta đã tìm hiểu qua cách xử lý tải tệp trong Servlet thuần và Struts2.

Hướng dẫn tải tệp với Spring MVC

Hôm nay, tôi sẽ dẫn bạn đi sâu vào cách triển khai tính năng này trong Spring Framework, cụ thể là Spring MVC File Upload, cho cả tệp đơn và nhiều tệp.

Upload file trong Spring MVC

Framework Spring MVC hỗ trợ mạnh mẽ việc tải lên tệp bằng cách tích hợp API Apache Commons FileUpload. Quy trình triển khai rất đơn giản, chỉ yêu cầu một vài cấu hình cơ bản. Chúng ta sẽ xây dựng một dự án Spring MVC mẫu và tập trung vào những thay đổi cốt lõi cần thiết để tận dụng khả năng tích hợp tải tệp của Spring.

Upload file trong Spring MVC

1. Maven Dependencies cho Apache Commons FileUpload

Đầu tiên, chúng ta cần thêm các dependency của Apache Commons FileUpload vào tệp pom.xml của dự án. Điều này đảm bảo rằng các tệp JAR cần thiết sẽ có mặt trong ứng dụng web của chúng ta. Dưới đây là đoạn mã dependency từ tệp pom.xml của tôi:

<!-- Apache Commons FileUpload -->
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.1</version>
</dependency>

<!-- Apache Commons IO -->
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.4</version>
</dependency>

Dependency commons-fileupload cung cấp các lớp cốt lõi để xử lý dữ liệu tệp được tải lên (multipart requests), trong khi commons-io hỗ trợ các thao tác vào/ra (I/O) hiệu quả, giúp chúng ta dễ dàng đọc và ghi tệp.

2. Spring File Upload Form Views

Tiếp theo, chúng ta sẽ tạo hai trang JSP đơn giản để cho phép người dùng tải lên một tệp hoặc nhiều tệp trong ứng dụng web Spring.

Mã JSP cho upload.jsp (tải lên tệp đơn):

<%@ taglib uri="<https://java.sun.com/jsp/jstl/core>" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Upload File Request Page</title>
</head>
<body>
	<form method="POST" action="uploadFile" enctype="multipart/form-data">
		File to upload: <input type="file" name="file"><br />
		Name: <input type="text" name="name"><br /> <br />
		<input type="submit" value="Upload"> Press here to upload the file!
	</form>
</body>
</html>

Mã JSP cho uploadMultiple.jsp (tải lên nhiều tệp):

<%@ taglib uri="<https://java.sun.com/jsp/jstl/core>" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Upload Multiple File Request Page</title>
</head>
<body>
	<form method="POST" action="uploadMultipleFile" enctype="multipart/form-data">
		File1 to upload: <input type="file" name="file"><br />
		Name1: <input type="text" name="name"><br /> <br />
		File2 to upload: <input type="file" name="file"><br />
		Name2: <input type="text" name="name"><br /> <br />
		<input type="submit" value="Upload"> Press here to upload the file!
	</form>
</body>
</html>

Hãy chú ý, các tệp này là các tệp HTML đơn giản tôi không sử dụng bất kỳ thẻ JSP hay Spring phức tạp nào để giữ cho ví dụ dễ hiểu. Điểm quan trọng cần lưu ý là thuộc tính enctype của form phải là multipart/form-data. Điều này giúp ứng dụng web Spring nhận biết rằng yêu cầu chứa dữ liệu tệp và cần được xử lý đặc biệt.

Ngoài ra, đối với việc tải lên nhiều tệp, các trường form namefile trong các thẻ input đều có cùng tên (name="file"name="name"). Điều này giúp dữ liệu được gửi dưới dạng mảng (array) đến server, và chúng ta sẽ dễ dàng xử lý các tệp theo cặp tên-tệp trên server.

3. Cấu Hình Spring MVC Multipart

Để Spring sử dụng Apache Commons FileUpload xử lý các request multipart, chúng ta chỉ cần cấu hình một bean multipartResolver với class là org.springframework.web.multipart.commons.CommonsMultipartResolver. Tệp cấu hình Spring cuối cùng của chúng ta (ví dụ: servlet-context.xml) sẽ trông như sau:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="<https://www.springframework.org/schema/mvc>"
	xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>" xmlns:beans="<https://www.springframework.org/schema/beans>"
	xmlns:context="<https://www.springframework.org/schema/context>"
	xsi:schemaLocation="<https://www.springframework.org/schema/mvc> <https://www.springframework.org/schema/mvc/spring-mvc.xsd>
		<https://www.springframework.org/schema/beans> <https://www.springframework.org/schema/beans/spring-beans.xsd>
		<https://www.springframework.org/schema/context> <https://www.springframework.org/schema/context/spring-context.xsd>">

	<!-- DispatcherServlet Context: defines this servlet's request-processing
		infrastructure -->

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving
		up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/**" location="/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources
		in the /WEB-INF/views directory -->
	<beans:bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>

	<beans:bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

		 <!-- setting maximum upload size -->
		<beans:property name="maxUploadSize" value="100000" />

	</beans:bean>

	<context:component-scan base-package="com.journaldev.spring.controller" />

</beans:beans>

Trong cấu hình này, tôi đã thiết lập giới hạn kích thước tải lên tối đa (maxUploadSize) là 100000 byte (khoảng 100KB) cho bean multipartResolver. Bạn có thể điều chỉnh giá trị này tùy theo nhu cầu của ứng dụng.

Nếu bạn xem mã nguồn của lớp DispatcherServlet, bạn sẽ thấy một biến MultipartResolver với tên multipartResolver được định nghĩa và khởi tạo trong phương thức initMultipartResolver:

private void initMultipartResolver(ApplicationContext context)
  {
    try
    {
      this.multipartResolver = ((MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class));
      if (this.logger.isDebugEnabled()) {
        this.logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
      }
    }
    catch (NoSuchBeanDefinitionException ex)
    {
      this.multipartResolver = null;
      if (this.logger.isDebugEnabled())
        this.logger.debug("Unable to locate MultipartResolver with name 'multipartResolver': no multipart request handling provided");
    }
  }

Với cấu hình này, bất kỳ request nào có enctypemultipart/form-data sẽ được multipartResolver xử lý và phân tích trước khi chuyển đến lớp Controller của chúng ta.

4. Spring File Upload Controller Class

Lớp Controller của chúng ta khá đơn giản. Chúng ta cần định nghĩa các phương thức xử lý (handler methods) cho các URI /uploadFile/uploadMultipleFile.

FileUploadController.java:

package com.journaldev.spring.controller;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

/**
 * Handles requests for the application file upload requests
 */
@Controller
public class FileUploadController {

	private static final Logger logger = LoggerFactory
			.getLogger(FileUploadController.class);

	/**
	 * Upload single file using Spring Controller
	 */
	@RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
	public @ResponseBody
	String uploadFileHandler(@RequestParam("name") String name,
			@RequestParam("file") MultipartFile file) {

		if (!file.isEmpty()) {
			try {
				byte[] bytes = file.getBytes();

				// Creating the directory to store file
				String rootPath = System.getProperty("catalina.home");
				File dir = new File(rootPath + File.separator + "tmpFiles");
				if (!dir.exists())
					dir.mkdirs();

				// Create the file on server
				File serverFile = new File(dir.getAbsolutePath()
						+ File.separator + name);
				BufferedOutputStream stream = new BufferedOutputStream(
						new FileOutputStream(serverFile));
				stream.write(bytes);
				stream.close();

				logger.info("Server File Location="
						+ serverFile.getAbsolutePath());

				return "You successfully uploaded file=" + name;
			} catch (Exception e) {
				return "You failed to upload " + name + " => " + e.getMessage();
			}
		} else {
			return "You failed to upload " + name
					+ " because the file was empty.";
		}
	}

	/**
	 * Upload multiple file using Spring Controller
	 */
	@RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST)
	public @ResponseBody
	String uploadMultipleFileHandler(@RequestParam("name") String[] names,
			@RequestParam("file") MultipartFile[] files) {

		if (files.length != names.length)
			return "Mandatory information missing";

		String message = "";
		for (int i = 0; i < files.length; i++) {
			MultipartFile file = files[i];
			String name = names[i];
			try {
				byte[] bytes = file.getBytes();

				// Creating the directory to store file
				String rootPath = System.getProperty("catalina.home");
				File dir = new File(rootPath + File.separator + "tmpFiles");
				if (!dir.exists())
					dir.mkdirs();

				// Create the file on server
				File serverFile = new File(dir.getAbsolutePath()
						+ File.separator + name);
				BufferedOutputStream stream = new BufferedOutputStream(
						new FileOutputStream(serverFile));
				stream.write(bytes);
				stream.close();

				logger.info("Server File Location="
						+ serverFile.getAbsolutePath());

				message = message + "You successfully uploaded file=" + name
						+ "<br />";
			} catch (Exception e) {
				return "You failed to upload " + name + " => " + e.getMessage();
			}
		}
		return message;
	}
}

Hãy lưu ý cách chúng ta sử dụng các annotation của Spring như @Controller, @RequestMapping, @RequestParam, và @ResponseBody. Những annotation này giúp cuộc sống của lập trình viên dễ dàng hơn và mã nguồn trở nên dễ đọc hơn nhiều.

  • Phương thức uploadFileHandler xử lý kịch bản tải lên tệp đơn.
  • Phương thức uploadMultipleFileHandler xử lý kịch bản tải lên nhiều tệp.
  • @ResponseBody chỉ ra rằng giá trị trả về của phương thức sẽ được ghi trực tiếp vào phản hồi HTTP body, thay vì phân giải thành một view.

Trên thực tế, bạn có thể tổ chức code một cách linh hoạt hơn, thậm chí có thể sử dụng một phương thức duy nhất để xử lý cả hai kịch bản tải lên tệp đơn và nhiều tệp bằng cách kiểm tra số lượng tệp nhận được.

5. Triển Khai và Kiểm Tra

 

Kết Luận

Tóm lại, việc triển khai tính năng tải lên tệp trong Spring MVC đòi hỏi chúng ta phải cấu hình đúng các dependency Maven (commons-fileupload, commons-io), thiết lập enctype="multipart/form-data" cho form HTML, định nghĩa bean multipartResolver trong cấu hình Spring với lớp CommonsMultipartResolver, và viết logic xử lý tệp trong Controller bằng cách sử dụng đối tượng MultipartFile và các phương thức lưu tệp vào hệ thống. Với những bước cơ bản nhưng mạnh mẽ này, bạn đã sẵn sàng tích hợp khả năng tải lên tệp một cách hiệu quả vào các dự án Spring của mình.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất