Spring的文件上传与下载详解

文件上传

多数文件上传都是通过表单形式提交给后台服务器的,因此,要实现文件上传功能,就需要提供一个文件上传的表单,而该表单必须满足以下3个条件:

  • form表单的method属性设置为post;
  • form表单的enctype属性设置为multipart/form-data;
  • 提供的文件上传输入框
 <form action="uploadUrl" method="post" enctype="multipart/form-data">
          <input type="file" name="filename" multiple="multiple" />
          <input type="submit" value="文件上传" />
     </form>

当form表单的enctype属性为multipart/form-data时,浏览器就会采用二进制流来处理表单数据,服务器端就会对文件上传的请求进行解析处理。Spring MVC通过MultipartResolver实现文件上传功能。MultipartResolver是一个接口对象,需要通过它的实现类CommonsMultipartResolver来完成文件上传工作。MultipartResolver配置示例如下:

  <bean id="multipartResolver"          	     
            class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <!--设置请求编码格式,必须与JSP中的pageEncoding属性一致,默认为ISO-8859-1-->
             <property name="defaultEncoding" value="UTF-8" />
             <!--设置允许上传文件的最大值(2M),单位为字节-->
             <property name="maxUploadSize" value="2097152" />
             ...
     </bean>

在前面的配置代码中,除配置了CommonsMultipartResolver类外,还通过元素配置了编码格式以及允许上传文件的大小。通过元素可以对文件解析器类CommonsMultipartResolver的如下属性进行配置:

  • maxUploadSize:上传文件最大长度(以字节为单位)
  • maxInMemorySize:缓存中的最大尺寸
  • defaultEncoding:默认编码格式;
  • resolveLazily:推迟文件解析,以便在Controller中捕获文件大小异常。

注意点: 因为MultipartResolver接口的实现类CommonsMultipartResolver内部是引用multipartResolver字符串获取该实现类对象并完成文件解析的,所以在配置CommonsMultipartResolver时必须指定该Bean的id为multipartResolver。

由于CommonsMultipartResolver是Spring MVC内部通过Apache Commons FileUpload技术实现的,所以Spirng MVC的文件上传还需要依赖Apache Commons FileUpload的组件,即需要导入支持文件上传的相关JAR包。下载地址:单击前往

  • commons-fileupload-1.4.jar
  • commons-io-2.7.jar

代码实现

第一步,最基本的添加web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
			xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
			xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
			http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
			id="WebApp_ID" version="3.1">
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
    	org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

第二步:添加springmvc-config.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
  http://www.springframework.org/schema/mvc
  http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
  http://www.springframework.org/schema/context 
  http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	<!-- 定义组件扫描器,指定需要扫描的包 -->
	<context:component-scan base-package="com.lzq.controller" />
	<!--配置注解驱动  -->
	<mvc:annotation-driven />
	<!-- 定义视图解析器 -->
	<bean id="viewResolver" class=
    "org.springframework.web.servlet.view.InternalResourceViewResolver">
	     <!-- 设置前缀 -->
	     <property name="prefix" value="/WEB-INF/jsp/" />
	     <!-- 设置后缀 -->
	     <property name="suffix" value=".jsp" />
	</bean>
	<!-- 配置文件上传解析器 MultipartResolver -->
	<bean id="multipartResolver" class=
   "org.springframework.web.multipart.commons.CommonsMultipartResolver">
          <!-- 设置请求编码格式-->
          <property name="defaultEncoding" value="UTF-8" />
	</bean>
</beans> 

第三步,在前面当中对com.lza.controller包进行扫描,定义一个对应的包,在包中添加Controller类,代码当中表示获取到上传的文件,并且对文件进行重命名。

package com.lzq.controller;
import java.io.File;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class FileUpLoadController {
	@RequestMapping("/fileUpload")
	public String handleFormUpload(@RequestParam("name") String name,
			@RequestParam("uploadfile") List<MultipartFile> uploadfile, 
			HttpServletRequest request) {
		System.out.println("name = "+name);
		if (!uploadfile.isEmpty() && uploadfile.size() > 0) {
			// 循环输出上传的文件
			for (MultipartFile file : uploadfile) {
				String filename = file.getOriginalFilename();
				String DirPath = request.getServletContext().getRealPath("/upload/");
				File filepath = new File(DirPath);
				// 地址不存在先创建
				if (!filepath.exists()) {
					filepath.mkdir();
				}
				String newFilename = name+ "_"+ UUID.randomUUID() +"_"+filename;
				try {
					file.transferTo(new File(DirPath + newFilename));
				} catch (Exception e) {
					e.printStackTrace();
					return "error";
				}
			}
			return "success";
		}else {
			return "error";
		}
	}
}

第四步,上传文件的jsp页面,在WebContext下。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
<script>
	// 判断是否填写上传人并已选择上传文件
	function check() {
		var name = document.getElementById("name").value;
		var file = document.getElementById("file").value;
		if (name == "") {
			alert("填写上传人");
			return false;
		}
		if (file.length == 0 || file == "") {
			alert("请选择上传文件");
			return false;
		}
		return true;
	}
</script>
</head>
<body>
	<form action="${pageContext.request.contextPath }/fileUpload"
		method="post" enctype="multipart/form-data" onsubmit="return check()">
		上传人:<input id="name" type="text" name="name" /><br /> 
		请选择文件:<input
			id="file" type="file" name="uploadfile" multiple="multiple" /><br />
		
		<input type="submit" value="上传/提交" />
	</form>
</body>
</html>

第五步,在WEB-INF下新建一个jsp文件夹,里面添加success.jsp与error.jsp文件,文件内容自定义
运行项目,查看效果:
Spring的文件上传与下载详解_第1张图片
上传的文件可以在下面的路径当中查看,
项目的工作区间的\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\SpringFileUpLoad\upload下进行查看

文件下载

在原先的基础上添加一个a标签,使用链接指向Controller控制器类,在类当中编写方法。
先添加标签,直接传递一个参数,带上文件名1.jpg,所以需要提前在文件下新增一个文件。

<a href="${pageContext.request.contextPath }/download?filename=1.jpg">
		文件下载 </a>

添加java代码;

	@RequestMapping("/download")
	public ResponseEntity<byte[]> fileDownload(HttpServletRequest request , String filename)throws Exception{
		String path = request.getServletContext().getRealPath("/upload");
		
		//创建文件对象
		File file = new File(path+File.separator+filename);
		
		//设置响应头
		HttpHeaders headers = new HttpHeaders();
		
		//通知浏览器以下载的方式打开文件
		headers.setContentDispositionFormData("attachment", filename);
		//定义流的方式下载
		headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
		
		//使用ResponseEntity对象封装返回下载数据
		return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.OK);
	}

直接运行项目,点击超链接。

在这里就会有一个问题,那就是在进行下载的时候只能使用英文和数字组成的文件,而要下载以中文命令的文件该怎么办呢?

为了解决浏览器中文件下载时中文名称的乱码问题,可以在前端页面发送请求前先对中文名进行统一编码,然后在后台控制器类中对文件名称进行相应的转码,其具体实现步骤如下

  1. 在下载页面中对中文文件名编码 可以使用 Servlet API 中提供的 URLEncoder 类中的encoder(String s, String enc) 方法将中文转为 UTF-8 编码 衷方法中第一个参数表示需要转码
    的字符串,第二个参数表示编码格式。进行下载一个壁纸.jpg的文件。
<%@page import="java.net.URLEncoder"%>

。。。。中间省略

	<a
		href="${pageContext.request.contextPath }/download
			?filename <%=URLEncoder.encode("壁纸 .jpg" , "UTF-8")%>">
		文件下载 </a>
  1. 随后修改控制器类 FileUploadController 中的 fileDownloadO 法,并增加对文件名进行编码的方法,调用这个方法:
    Spring的文件上传与下载详解_第2张图片
	//根据浏览器的不同进行编码设置.返回编码的文件名
	private String getFilename(HttpServletRequest request, String filename)throws Exception {
		//ie
		String [] IE = {"MSIE","Trident","Edge"};
		
		//获取请求头信息
		String userAgent = request.getHeader("User-Agent");
		for (String keyword : IE) {
			if (userAgent.contains(keyword)) {
				return URLEncoder.encode(filename,"UTF-8");
			}
		}
		//火狐等其他浏览器
		return new String (filename.getBytes("UTF-8"),"ISO-8859-1");
	}

你可能感兴趣的:(#,SSM(JAVA框架))