SpringMVC 文件上传下载
@
文件上传
文件上传是项目开发中最常见的功能。为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。
一旦设置了enctype为multipart/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的组件。
MultipartFile对象
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):将上传文件保存到一个目录文件中
文件下载
在页面给出了一个超链接,该链接href的属性等于要下载文件的文件名,就可以实现文件下载了。
接收页面传递的文件名filename后,使用Apache Commons FileUpload组件的FileUtils读取项目的上传文件,并将其构建成ResponseEntity对象返回客户端下载。
使用ResponseEntity对象,可以很方便的定义返回的HttpHeaders和HttpStatus。上面代码中的MediaType,代表的是Internet Media Type,即互联网媒体类型,也叫做MIME类型。在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。HttpStatus类型代表的是Http协议中的状态。有关MediaType和HttpStatus类可以参考Spring MVC的API文档。
上传下载示例
pom.xml增加
<!-- 文件上传组件 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3</version>
</dependency>
创建uploadForm.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="${pageContext.request.contextPath}/mvc/upload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="description"></td>
</tr>
<tr>
<td>请选择文件:</td>
<td><input type="file" name="file"></td>
</tr>
<tr>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
</body>
</html>
创建uploadForm2.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="${pageContext.request.contextPath}/mvc/upload2" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="name"></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>
创建userInfo.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>
<h3>文件下载</h3>
<a href="download?filename=${requestScope.user.image.originalFilename}"> ${requestScope.user.image.originalFilename }</a>
<a href="download?filename=${user.name}"> ${user.name}</a>
</body>
</html>
springmvc-servlet.xml添加
SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver
<!-- 文件上传的配置 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1048576" /><!-- 上传文件大小上限,单位为字节(1MB) -->
<property name="defaultEncoding" value="UTF-8" /><!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
</bean>
创建User2.java对象
使用对象接受接收上传文件,必须要实现序列化接口
package com.xc.entity;
import java.io.Serializable;
import org.springframework.web.multipart.MultipartFile;
public class User2 implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private MultipartFile image;
public User2() {
super();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MultipartFile getImage() {
return image;
}
public void setImage(MultipartFile image) {
this.image = image;
}
}
创建UploadController.java
package com.xc.controller;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
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.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
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.multipart.MultipartFile;
import com.xc.entity.User2;
@Controller
@RequestMapping("/mvc")
public class UploadController {
// 上传文件会自动绑定到MultipartFile中
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public String upload(HttpServletRequest request, @RequestParam("description") String description,
@RequestParam("file") MultipartFile multipartFile) throws Exception {
System.out.println(description);
if (!multipartFile.isEmpty()) {// 是否有上传文件
// 上传文件路径
// String path = request.getServletContext().getRealPath("/upload/");
// 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String path = request.getServletContext().getRealPath("/WEB-INF/upload");
System.out.println(path);
String filename = multipartFile.getOriginalFilename();// 获取上传文件的原名
File filepath = new File(path, filename);
System.out.println(filepath);
// 判断路径是否存在,如果不存在就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
multipartFile.transferTo(new File(path + File.separator + filename));// 将上传文件保存到一个目标文件当中
return "success";
} else {
return "error";
}
}
@RequestMapping(value = "/upload2")
public String register(HttpServletRequest request, @ModelAttribute User2 user, Model model) throws Exception {
System.out.println(user.getName());
// 如果文件不为空,写入上传路径
if (!user.getImage().isEmpty()) {
// 上传文件路径
String path = request.getServletContext().getRealPath("/WEB-INF/upload");
// 上传文件名
String filename = user.getImage().getOriginalFilename();
String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);// 得到上传文件的扩展名
System.out.println("上传文件的扩展名:" + fileExtName);
String filenamePre = filename.substring(0, filename.lastIndexOf("."));
System.out.println("上传文件的文件名:" + filenamePre);
String saveFilename = makeFileName(filenamePre, fileExtName);
System.out.println("saveFilename:" + saveFilename);
Map<String, Object> pathMap = makePath(saveFilename, path);
String dir1 = pathMap.get("dir1").toString();
String dir2 = pathMap.get("dir2").toString();
System.out.println("pathMap:" + pathMap);
String realSavePath = pathMap.get("dir").toString();
System.out.println("realSavePath:" + realSavePath);
File filepath = new File(realSavePath, saveFilename);
// 判断路径是否存在,如果不存在就创建一个
if (!filepath.getParentFile().exists()) {
filepath.getParentFile().mkdirs();
}
// 将上传文件保存到一个目标文件当中
user.getImage().transferTo(new File(realSavePath + File.separator + saveFilename));
user.setName("" + dir1 + "/" + dir2 + "/" + saveFilename);
// 将用户添加到model
model.addAttribute("user", user);
return "userInfo";
} else {
return "error";
}
}
/**
* @Method: makeFileName
* @Description: 生成上传文件的文件名,文件的原始名称+"_"+uuid
* @param filename
* 文件的原始名称
* @param fileExtName
* @return 文件的原始名称+"_"+uuid
*/
private String makeFileName(String filenamePre, String fileExtName) { // 2.jpg
// 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
return filenamePre + "_" + UUID.randomUUID().toString() + "."+ fileExtName;
}
/**
* 为防止一个目录下面出现太多文件,要使用hash算法打散存储
*
* @Method: makePath
* @param filename
* 文件名,要根据文件名生成存储目录
* @param savePath
* 文件存储路径
* @return 新的存储目录
*/
private Map<String, Object> makePath(String filename, String savePath) {
// 得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
int hashcode = filename.hashCode();
int dir1 = hashcode & 0xf; // 0--15
int dir2 = (hashcode & 0xf0) >> 4; // 0-15
// 构造新的保存目录
String dir = savePath + "\\" + dir1 + "\\" + dir2; // upload\2\3 upload\3\5
// File既可以代表文件也可以代表目录
File file = new File(dir);
// 如果目录不存在
if (!file.exists()) {
// 创建目录
file.mkdirs();
}
Map<String, Object> map = new HashMap<String, Object>();
map.put("dir", dir);
map.put("dir1", dir1);
map.put("dir2", dir2);
return map;
}
@RequestMapping(value = "/download")
public ResponseEntity<byte[]> download(HttpServletRequest request, @RequestParam("filename") String filename, Model model) throws Exception {
// 下载文件路径
String path = request.getServletContext().getRealPath("/WEB-INF/upload/");
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);
}
}
文件上传的细节
上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题,以下列出的几点需要特别注意的
- 为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
- 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
- 为防止一个目录下面出现太多文件,要使用hash算法打散存储。
- 要限制上传文件的最大值。
- 要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
参考文章:
Spring MVC 实现文件的上传和下载
SpringMVC 文件上传下载的更多相关文章
- springmvc文件上传下载简单实现案例(ssm框架使用)
springmvc文件上传下载实现起来非常简单,此springmvc上传下载案例适合已经搭建好的ssm框架(spring+springmvc+mybatis)使用,ssm框架项目的搭建我相信你们已经搭 ...
- SpringMVC文件上传下载(单文件、多文件)
前言 大家好,我是bigsai,今天我们学习Springmvc的文件上传下载. 文件上传和下载是互联网web应用非常重要的组成部分,它是信息交互传输的重要渠道之一.你可能经常在网页上传下载文件,你可能 ...
- SpringMVC文件上传下载
在Spring MVC的基础框架搭建起来后,我们测试了spring mvc中的返回值类型,如果你还没有搭建好springmvc的架构请参考博文->http://www.cnblogs.com/q ...
- SpringMVC——文件上传下载
一.单文件上传 1.导入依赖 <dependency> <groupId>commons-io</groupId> <artifactId>common ...
- SpringMVC整合fastdfs-client-java实现web文件上传下载
原文:http://blog.csdn.net/wlwlwlwl015/article/details/52682153 本篇blog主要记录一下SpringMVC整合FastDFS的Java客户端实 ...
- SpringMVC ajax技术无刷新文件上传下载删除示例
参考 Spring MVC中上传文件实例 SpringMVC结合ajaxfileupload.js实现ajax无刷新文件上传 Spring MVC 文件上传下载 (FileOperateUtil.ja ...
- SpringMVC(三) RESTful架构和文件上传下载
RESTful架构 REST全名为:Representational State Transfer.资源表现层状态转化.是目前最流行的一种互联网软件架构. 它结构清晰.符合标准.易于理解.扩展方便,所 ...
- SpringMVC——返回JSON数据&&文件上传下载
--------------------------------------------返回JSON数据------------------------------------------------ ...
- SpringMVC文件上传 Excle文件 Poi解析 验证 去重 并批量导入 MYSQL数据库
SpringMVC文件上传 Excle文件 Poi解析并批量导入 MYSQL数据库 /** * 业务需求说明: * 1 批量导入成员 并且 自主创建账号 * 2 校验数据格式 且 重复导入提示 已被 ...
随机推荐
- 倒计时5S秒自动关闭弹窗
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Web后端 JAVAWeb面试考查知识点
面试知识点:1:简单讲一下Java的跨平台原理答:由于非跨平台的情况下,对于不同的操作系统,那么就需要开发几套不同程序代码.为了解决这个问题,java通过不同系统,不同版本,不同位数的JVM来屏蔽不同 ...
- phpStudy2018安装与配置步骤详解
phpStudy 2018是一款非常强大的php环境调试工具,一次性安装,无须配置即可使用,是非常方便.好用的PHP调试环境.对学习PHP的新手来说,WINDOWS下环境配置是一件很困难的事:对老手来 ...
- android - TextView单行显示...或者文字左右滚动(走马灯效果)
条件 TextView单行显示,文字左右滚动(走马灯效果)实现条件: 实现单行设置固定宽度或者设置权重都行 代码 TextView滚动必须写下面几个属性 android:singleLine=&quo ...
- 从APP跳转到微信指定联系人聊天页面功能的实现与采坑之旅
起因: 最近做的APP中有一个新功能:已知用户微信号,可点击直接跳转到当前用户微信聊天窗口页面. 当时第一想法是使用无障碍来做,并且觉得应该不难,只是逻辑有点复杂.没想到最终踩了好多坑,特地把踩过的坑 ...
- 三星5.0以上设备最完美激活XPOSED框架的经验
对于喜欢钻研手机的小伙伴来说,常常会接触到Xposed框架以及种类繁多功能强大的模块,对于5.0以下的系统版本,只要手机能获得Root权限,安装和激活Xposed框架是异常简易的,但随着系统版本的不断 ...
- 小米5.0以上系统如何没ROOT激活xposed框架的经验
在较多企业的引流或者业务操作中,大多数需要使用安卓的黑高科技术xposed框架,这段时间,我们企业购买了一批新的小米5.0以上系统,大多数都是基于7.0以上版本,大多数不能够获取Root的su超级权限 ...
- Linux使用wget、安装Python
原文:https://blog.csdn.net/ghost_chou/article/details/81905302 1.指定需要安装的目录或创建并访问到该选择的目录下. mkdir /data/ ...
- Jenkins 配置 Git 错误解决:CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt
错误信息: Failed to connect to repository : Command "C:/tools/Git/bin/git.exe ls-remote -h https:/X ...
- 我的Windows日常——Win7完美兼容tsmmc.msc的方法
操作步骤 32位操作系统: 1.将2003系统C:\WINDOWS\system32目录下的mstsmhst.dll.mstsmmc.dll.tsmmc.msc拷贝到Windows7系统中的C:\WI ...