文件的上传和下载
文件上传
多数文件的上传都是通过表单的形式提交给后台服务起的,因此,要实现一个文件的上传功能,就需要提供一个文件上传的表单,该表单需要满足的条件时:
- form表单的属性method属性设置为post
- form表单enctype属性设置为multipart/form-data
- 提供了的文件上传输入框
<form action="#" method="post" enctype="multipart/form-data">
<%--multiple="multiple"是HTML5中的新特性,可以实现文件上传--%>
<input type="file" name="filename" multiple="multiple"><br/>
<input type="submit" value="文件上传">
</form>
what
当from表单的enctype属性为multipart/form-data时,浏览器就会采用二进制流来处理表单数据,服务器端就会对文件上传的请求进行解析处理,Spring MVC通过MultipartResovler实现文件上传功能,MultipartResoler是一个接口对象,需要通过它的实现类CommonsMultipartResolver来实现文件的上传工作。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--文件上传的默认编码-->
<property name="defaultEncoding" value="UTF-8"/>
<!--上传文件的最大长度-->
<property name="maxUploadSize" value="2097152"/>
<!--推迟文件解析,一边在Controller中捕获大小-->
<property name="resolveLazily" value="true"/>
<!--文件缓存中的最大尺寸-->
<property name="maxInMemorySize" value="1024"/>
<!--因为MultipartResolver接口的实现类CommonsMultipartResovler是引用multipartRseolver字符串
获取该实现类对象并完成文件解析的,所以在文件的内部必须要配置CommonsMultipartResvoler时必须指定该Bean的id值为mulitpartResolver-->
</bean>
- commonsMultipartResolver是Spring MVC内部通过Apache Commons FileUpload技术实现的,所以SpringMVC需要依赖Apache Commons FileUpload的组件,
- commons-fileupload
- commons-io
参数MultipartFile
package com.yzb.chapter16.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.MultipartFile;
@Controller
public class FileUploadController {
@RequestMapping("/fileUpload")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("filename")MultipartFile file){
if(!file.isEmpty()){
.......;
return "uploadSuccess";
}
return "uploadFailure";
}
}
- 上面使用了MultipartFile参数,使用这个参数来接受上传文件
- 进行判断上传文件是否为空,不为空,则进行解析存放处理
- @@@ multipartFile参数的属性
- byte[] getBytes():以字节数组的形式返回文件内容
- String getContentType():返回内容类型
- InputStream getInputStream():读取文件内容,得到一个InputStream流
- String getName():得到多部件表单的参数名称
- String getOrigianlFilename():获取文件上传的初始名
- long getSize():获取上传文件的大小
- boolean isEmpty():判断上传文件是否为空
- void transferTo(File file):将上传文件保存到目标目录下。
代码
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
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.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件上传</title>
<script type="text/javascript">
function check() {
const name = document.getElementById("name").valueOf();
const filename = document.getElementById("file").valueOf();
if(name == ""){
alert("请输入用户名");
return false;
}
if(filename.length==0){
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/>
<%--multiple="multiple"是HTML5中的新特性,可以实现文件上传--%>
上传文件:<input id="file" type="file" name="filename" multiple="multiple"><br/>
<input type="submit" value="文件上传">
</form>
</body>
</html>
springmvc.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/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<context:component-scan base-package="com.yzb.chapter16"></context:component-scan>
<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>
<mvc:resources mapping="/js/**" location="/js/"/>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--文件上传的默认编码-->
<property name="defaultEncoding" value="UTF-8"/>
<!--上传文件的最大长度-->
<property name="maxUploadSize" value="2097152"/>
<!--<!–推迟文件解析,一边在Controller中捕获大小–>
<property name="resolveLazily" value="true"/>
<!–文件缓存中的最大尺寸–>
<property name="maxInMemorySize" value="1024"/>-->
<!--因为MultipartResolver接口的实现类CommonsMultipartResovler是引用multipartRseolver字符串
获取该实现类对象并完成文件解析的,所以在文件的内部必须要配置CommonsMultipartResvoler时必须指定该Bean的id值为mulitpartResolver-->
</bean>
</beans>
FileUploadController
package com.yzb.chapter16.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.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
/*
* 文件上传页面
* */
@Controller
public class FileUploadController {
@RequestMapping("/fileUpload")
public String handleFormUpload(@RequestParam("name") String name,
@RequestParam("filename") List<MultipartFile> file,
HttpServletRequest request){
//判断文件是否存在
if(!file.isEmpty()){
for (MultipartFile multipartFile : file) {
//得到文件的原始名称
String originalFilename = multipartFile.getOriginalFilename();
//设置文件的上传路径
String realPath = request.getServletContext().getRealPath("/upload/");
//判断路径是否存在,不在就进行创建
File filePath = new File(realPath);
if(!filePath.exists()){
filePath.mkdirs();
}
//设置新的文件名
String fielName = name +"_" + UUID.randomUUID() +"_"+ originalFilename;
try {
//上传文件,
multipartFile.transferTo(new File(realPath+fielName));
System.out.println(realPath+fielName);
} catch (IOException e) {
//跳转错误页面
return "error";
}
}
//跳转到成功页面
return "success";
}else {
//跳转到错误页面
return "error";
}
}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
上传文件成功
</body>
</html>
error.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
上传文件失败
</body>
</html>
文件下载
文件下载就是将文件服务器中的文件下载到本机上,在spring MVCzhong ,分为两个步骤:
- 在客户端页面使用一个文件下载的超链接,该链接的href属性要制定后台文件下载的方法,以及文件名,
<a href="${pageContext.request.contextPath}/download?filename=1.jpg">文件下载</a>
- 在后台方法中使用Spring MVC提供的ResponseEntity<>类型对象完成文件下载,使用它可以方便的定义返回的HttpHeards对象,和HttpStatus对象,返回的数据类型是json的形式(相当于@ResponseBody,直接返回结果对象),在以前下载文件时,一个文件流,两个头,在这里还需要两个头,流使用提供包装类就可以了
- 响应头信息中的MdiaType 代表的是Interner Media Type(即互联网媒体类型),也叫做MIME类型,MediaType.APPLICATION_OCTET_STREAM的值是application/octet-stream.即表示以二进制流的形式下载数据。
- HttpStatus类型:代表的是Http协议中的状态,
DownloadController
package com.yzb.chapter16.controller;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
@Controller
public class DownloadController {
@RequestMapping("download")
public ResponseEntity<byte[]> download(String filename, HttpServletRequest request) throws IOException {
//指定文件下载的路径
String realPath = "F:\\download";
File file = new File(realPath + File.separator +filename);
//设置消息头
HttpHeaders httpHeaders = new HttpHeaders();
//通知浏览器以下载的形式打开文件
httpHeaders.setContentDispositionFormData("attachment",filename);
//定义以流的形式下载返回文件数据
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),httpHeaders, HttpStatus.OK);
}
}
download.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>文件下载</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download?filename=1.jpg">文件上传</a>
</body>
</html>
中文名的下载
因为前端页面的对中文名的编码格式和后台控制类对于文件名称进行响应的转码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@page import="java.net.URLEncoder" %>
<html>
<head>
<title>文件下载</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/download?filename=1.jpg">文件下载</a><br/>
<a href="${pageContext.request.contextPath}/download?filename=<%=URLEncoder.encode("壁纸.jpg","UTF-8")%>>">中文文件下载</a>
</body>
</html>
package com.yzb.chapter16.controller;
import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
@Controller
public class DownloadController {
@RequestMapping("download")
public ResponseEntity<byte[]> download(String filename, HttpServletRequest request) throws Exception {
//指定文件下载的路径
String realPath = request.getServletContext().getRealPath("/upload/");
File file = new File(realPath + File.separator +filename);
filename = this.getFilename(request,filename);
//设置消息头
HttpHeaders httpHeaders = new HttpHeaders();
//通知浏览器以下载的形式打开文件
httpHeaders.setContentDispositionFormData("attachment",filename);
//定义以流的形式下载返回文件数据
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),httpHeaders, HttpStatus.OK);
}
//解决中文下载问题
public String getFilename(HttpServletRequest request, String filename) throws Exception {
//ie浏览器的编码格式
String[] IEBrowserWords = {"MSIE","Trident","Edge"};
String userAgent = request.getHeader("User-Agent");
for (String ieBrowserWord : IEBrowserWords) {
if(userAgent.contains(ieBrowserWord)){
return URLEncoder.encode(filename,"UTF-8");
}
}
//其他浏览器就采用这种编码格式
return new String(filename.getBytes("UTF-8"),"ISO-8859-1");
}
}