SpringMVC - 文件上传与下载

SpringMVC实现文件的上传和下载
文件的上传和下载能够直接使用Java中的IO流,Spring MVC为文件的上传也提供了直接的支持,但须要依赖Apache提供Commons FileUpload组件jar包html

SpringMVC文件上传

SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同java

导入文件上传的jar包程序员

<dependency>            
 	<groupId>commons-fileupload</groupId>            
 	<artifactId>commons-fileupload</artifactId>            
 	<version>1.3.1</version>        
 </dependency>        
 <dependency>            
 	<groupId>commons-io</groupId>            
 	<artifactId>commons-io</artifactId>            
 	<version>2.4</version>        
 </dependency>

编写文件上传的JSP页面web

<h3>文件上传</h3>        
<form action="user/fileupload" method="post" enctype="multipart/form-data">        
	选择文件:<input type="file" name="upload"/><br/>        
	<input type="submit" value="上传文件"/>    
</form>

这里要注意spring

  • form的属性必须是multipart/form-data,会把表单分红几个部分,存储不一样的值后端

  • 必须使用post,由于使用get会把参数写在地址栏,地址栏的大小是有限制的浏览器

  • 要提供一个选择文件的文本框服务器

文件上传是项目开发中最多见的功能。为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data,只有在这样的状况下,浏览器才会把用户选择的文件以二进制数据发送给服务器app

一旦设置了enctypemultipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择框架

Servlet3.0规范已经提供方法来处理文件上传,但这种上传须要在Servlet中完成。而Spring MVC则提供了更简单的封装。
Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。所以,SpringMVC的文件上传还须要依赖Apache Commons FileUpload的组件

后端代码

/** * SpringMVC方式的文件上传 * * @param request * @return * @throws Exception */    
 @RequestMapping(value="/fileupload2")    
 public String fileupload2(HttpServletRequest request,MultipartFile upload) throws Exception {        
 	System.out.println("SpringMVC方式的文件上传...");        
 	// 先获取到要上传的文件目录 
 	String path = request.getSession().getServletContext().getRealPath("/uploads");        
 	// 建立File对象,一会向该路径下上传文件 
 	File file = new File(path);        
 	// 判断路径是否存在,若是不存在,建立该路径 
 	if(!file.exists()) {            
 		file.mkdirs();        
 	}        
 	// 获取到上传文件的名称 
 	String filename = upload.getOriginalFilename();        
 	String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();        
 	// 把文件的名称惟一化 
 	filename = uuid+"_"+filename;        
 	// 上传文件 
 	upload.transferTo(new File(file,filename));        
 	return "success";    
 }

Spring MVC会将上传的文件绑定到MultipartFile对象中。MultipartFile提供了获取上传文件内容、文件名等方法。经过transferTo()方法还能够将文件存储到硬件中,MultipartFile对象中的经常使用方法以下:

byte[] getBytes():获取文件数据
String getContentType[]:获取文件MIME类型,如image/jpeg等
InputStream getInputStream():获取文件流
String getName():获取表单中文件组件的名字
String getOriginalFilename():获取上传文件的原名
Long getSize():获取文件的字节大小,单位为byte
boolean isEmpty():是否有上传文件
void transferTo(File dest):将上传文件保存到一个目录文件中

配置文件解析器对象

<bean id="multipartResolver"  
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
    <!-- 上传文件大小上限,单位为字节(10MB) -->
    <property name="maxUploadSize">  
        <value>10485760</value>  
    </property>  
    <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
    <property name="defaultEncoding">
        <value>UTF-8</value>
    </property>
</bean>

使用对象接收上传文件

在实际项目的开发中,不少时候上传的文件会做为对象的属性被保存。SpringMVC的处理也很是的简单

registerForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户注册</title>
</head>
<body>
    <h2>用户注册</h2>
    <form action="register" enctype="multipart/form-data" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>请上传头像:</td>
                <td><input type="file" name="image"></td>
            </tr>
            <tr>
                <td><input type="submit" value="注册"></td>
            </tr>
        </table>
    </form>
</body>
</html>

user实体类

public class User implements Serializable{

    private String username;
    private MultipartFile image;

    public User() {
        super();
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public MultipartFile getImage() {
        return image;
    }

    public void setImage(MultipartFile image) {
        this.image = image;
    }   

}

Controller

@RequestMapping(value="/register")
public String register(HttpServletRequest request,@ModelAttribute User user,Model model) throws Exception {
	System.out.println(user.getUsername());
   	//若是文件不为空,写入上传路径
   	if(!user.getImage().isEmpty()) {
   	    //上传文件路径
    	String path = request.getServletContext().getRealPath("/images/");
       	//上传文件名
       	String filename = user.getImage().getOriginalFilename();
       	File filepath = new File(path,filename);
       	//判断路径是否存在,若是不存在就建立一个
       	if (!filepath.getParentFile().exists()) { 
       	    filepath.getParentFile().mkdirs();
       	}
       	//将上传文件保存到一个目标文件当中
       	user.getImage().transferTo(new File(path + File.separator + filename));
       	//将用户添加到model
       	model.addAttribute("user", user);
       	return "userInfo";
   	} else {
    	return "error";
   	}
}

文件下载

文件下载比较简单,直接在页面给出了一个超连接,该连接href的属性等于要下载文件的文件名,就能够实现文件下载了。可是若是该文件的文件名为中文文件名,在某些早起的浏览器上就会致使下载失败;若是使用最新的Firefox、Chrome、Opera、Safari则均可以正常下载文件名为中文的文件了。
SpringMVC提供了一个ResponseEntity类型,使用它能够很方便地定义返回的HttpHeadersHttpStatus。如下代码演示文件的下载功能

@RequestMapping(value="/download")
public ResponseEntity<byte[]> download(HttpServletRequest request,
        @RequestParam("filename") String filename,
        Model model)throws Exception {
   	//下载文件路径
   	String path = request.getServletContext().getRealPath("/images/");
   	File file = new File(path + File.separator + filename);
   	HttpHeaders headers = new HttpHeaders();  
   	//下载显示的文件名,解决中文名称乱码问题 
   	String downloadFielName = new String(filename.getBytes("UTF-8"),"iso-8859-1");
   	//通知浏览器以attachment(下载方式)打开图片
   	headers.setContentDispositionFormData("attachment", downloadFielName); 
   	//application/octet-stream : 二进制流数据(最多见的文件下载)。
   	headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
   	return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),    
           headers, HttpStatus.CREATED);  
}