1.文件上传
1.1实现原理:
springMVC提供了一个接口MultipartFile来实现文件上传。MultipartFile底层是基于commons-fileupload组件的文件上传。MultipartFile对commons-fileupload上传组件进行了封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。
在springMVC中上传使用的是MultipartFile的实现类,实现类底层调用commons-fileupload组件。
1.2 开发思路
(1)使用MultipartFile的实现类完成上传的工作。需要配置。
(2)底层调用commons-fileupload组件。需要它的jar包。
SpringMVC文件上传的过程分析:
1.3 准备工作
导入commons-fileupload组件的jar包。
1.4 上传开发分析
(1)spring使用MultipartFile来实现文件上传。
(2)MultipartFile的底层使用的fileupload组件来完成文件上传。
(3)Jsp需要开发文件表单组件。
(4)在javaweb开发中,文件上传都是使用表单提交/基于表单提交。
(5)controller中需要获取文件基本信息。需要将文件基本信息入库。
(6)Controller需要对文件进行存储。在实际的项目应用开发过程中,一般会使用文件服务器来存储文件。在本机测试的时候由于没有文件服务器,可以将文件存储到项目WEB-INF目录下,或者在本地创建一个本地磁盘仓库映射,本文采用第2种方式。
(7)Controller中返回操作信息给前端。
1.5 开发步骤
1.在springMVC配置文件中配置spring MultiPartFile bean类。
2.jsp开发
(1)文件表单组件的开发
(2)请求发起的方式为表单提交
(3)设置表单的enctype和method
3.controller开发
(1)获取文件信息
(2)文件基本信息入库
(3)文件存储
4.controller返回信息。
1.5.1 MultipartFile接口
两个实现类:
CommonsMultipartFile的方法:
1.5.2 springMVC配置multipartResolver
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传文件的最大大小,单位为字节 -->
<property name="maxUploadSize" value="17367648787"></property>
<!-- 上传文件的编码 -->
<property name="defaultEncoding" value="UTF-8"></property>
</bean>
1.5.3 Jsp开发
<body>
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"><br><br>
<input type="submit" value="上传">
</form>
</body>
1.5.4 Controller开发
1.5.4.1 基本思路
在controller方法中使用方法形参MultipartFile multipartFile接收文件信息,调用multipartFile方法解析上传文件信息。
1.5.4.2 方法形参
public String uploadFile(MultipartFile multipartFile,HttpServletRequest request) throws Exception
1.5.4.3 文件名称处理
/*
* 文件存储的时候不会使用原始名称:
* 1.名称中有中文或者特殊字符。
* 2.有可能会重复。
*
* 需要从原始文件名称中解析后缀。
* 新的名称:
* (1)offerid.
* (2)UUID.randomUUID() 生成文件名称。
*
* xxxx.jpg
* */
String filename = multipartFile.getOriginalFilename();
//文件名称重命名:商品的id作为文件名称。存储的使用的文件名
int suffixIndex=filename.indexOf(".");
String suffix=filename.substring(suffixIndex);
String fileRealName=offerVo.getOffer().getId()+suffix;
1.5.4.4 文件存储磁盘
(1)创建本地路径的服务器映射
该映射表示的含义是:
服务器http://localhost:8080/files 路径和本地路径:E:\ssm是一个含义。
实际上就创建了一本地路径和服务器路径的映射关系。
文件存储到本地路径:E:\ssm
访问的文件的路径:http://localhost:8080/files
(2)文件存储
(1)在指定的本地磁盘路径创建了一个空的文件,名称为上面生成的文件名称。
file = new File(localPath,fileRealName);
(2)将内存中的文件信息写入到创建的文件中。
multipartFile.transferTo(file);
1.5.4.5 文件入库
1.表设计:在offer扩展信息表中存储图片的路径
2.OfferExtend 中增加属性imagePath
3.controller方法中给OfferVo.offerExtend.imagePath属性赋值
offerVo.getOfferExtend().setImagePath(path);
4.mybatis映射文件中添加插入imagePath
<insert id="saveOfferDetail" parameterType="offerVO">
insert into offer_detail values(#{offer.id},#{offerExtend.companyName},
#{offerExtend.country},#{offerExtend.pinpai},#{offerExtend.xinghao},#{offerExtend.expireDate},#{offerExtend.imagePath});
</insert>
1.5.4.5 参考示例
RequestMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file, HttpServletRequest req)
throws IllegalStateException, IOException {
//解析文件基本信息
//获取文件的原始名称
/*
* 文件存储的时候不会使用原始名称:
* 1.名称中有中文或者特殊字符。
* 2.有可能会重复。
*
* 需要从原始文件名称中解析后缀。
* 新的名称:
* (1)offerid.
* (2)UUID.randomUUID() 生成文件名称。
*
* xxxx.jpg
* */
String filename = multipartFile.getOriginalFilename();
//文件名称重命名:商品的id作为文件名称。存储的使用的文件名
int suffixIndex=filename.indexOf(".");
String suffix=filename.substring(suffixIndex);
String fileRealName=offerVo.getOffer().getId()+suffix;
/*文件存储路径
*1:存储的地方
*(1)无法识别"WEB-INF/file/"
*String path="WEB-INF/file/"+fileRealName;
*(2)项目在服务器上部署后的WEB-INF/file路径。
*request.getServletContext().getRealPath("/WEB-INF/file")
*D:workspace....
*2.存储的地方有什么讲究
*需要能够访问到。
*(1)将文件放到路径文件服务器
*(2)创建一个本地路径与应用服务器映射。
*E:\ssm
*http://localhost:8080/files/xxx.jpg
*/
String path=filePath+"/"+fileRealName;
//存储文件。
//文件存储到本地
//在本地磁盘路径,创建了一个文件。这个名称是fileRealName,
file = new File(localPath,fileRealName);
//transferTo方法用于存储文件。参数是一个File.
//将内存中的文件信息写入到创建的file中。文件在内存中是保存在multipartFile
multipartFile.transferTo(file);
return "success";
}
2.多文件上传
2.1 多文件上传的过程分析
说明:
(1)JSP中多个文件的name相同。并且和pojo中定义的属性名称相同。
(2)springMVC框架文件上传自动把文件绑定为MultipartFile。
(3)将名称相同的file绑定到pojo中定义的List集合中。
(4)Controller方法形参中,使用pojo对象来接收上传的file。遍历pojo对象中的List,从MultipartFile中分别解析出上传的各个文件进行存储磁盘和入库。
注意:使用MultipartFile进行文件上传,实际上是将文件一次写入内存,如果文件非常大,或者说频繁并发上传较大的文件,可能会导致内存溢出,并且这种方式无法实现文件的切割存储。对于大文件的上传或者需要文件切割的情况,建议使用文件流完成。
2.2 JSP开发
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="multipartFileList" enctype="multipart/form-data" method="post">
文件1:<input type="file" name="file"><br/>
文件2:<input type="file" name="file"><br/>
文件3:<input type="file" name="file"><br/>
文件4:<input type="file" name="file"><br/>
<input type="submit" value="提交">
</form>
</body>
</html>
2.3 多文件接收包装类Pojo开发
import java.util.List;
import org.springframework.web.multipart.MultipartFile;
public class MultipartFilePojo {
//定义一个list
private List<MultipartFile> file;
public List<MultipartFile> getFile() {
return file;
}
public void setFile(List<MultipartFile> file) {
this.file = file;
}
}
2.4 Controller开发
//多文件上传
@RequestMapping("/multipartFileList")
public String multipartFileList(MultipartFilePojo multipartFile,HttpServletRequest request) throws IllegalStateException, IOException {
//multipartFile获取list
List<MultipartFile> fileList = multipartFile.getFile();
String realFileName="";
//在循环语句中,不要new对象。
File file=null;
for (MultipartFile multiFile : fileList) {
//获取原始的文件名称
String originalFilename = multiFile.getOriginalFilename();
//xxx.jpg
int splitIndex=originalFilename.indexOf(".");
//获取文件后缀
String suffix = originalFilename.substring(splitIndex);
//新的文件名称
realFileName=UUID.randomUUID()+suffix;
//创建一个本地空文件
file= new File(localPath,realFileName);
//写入文件内容
multiFile.transferTo(file);
//入库
}
return "success";
}
3.文件下载
SpringMVC文件下载的支持类ResponseEntity。SpringMVC会将文件封装为ResponseEntity返回给浏览器。
HttpHeaders类中需要设置标识该返回信息是文件,让浏览器作为文件进行解析。
“Content-Disposition”, “attchement;filename=” + filename
Filename:标识下载的时候附件的名称。
3.1 查询文件列表
3.1.1 过程分析
(1)浏览器发起请求给controller方法。
(2)Controller方法去查询磁盘种的文件信息。
(3)SprinMVC将查询到的文件信息装配到JSP中
(4)Controller返回渲染后的JSP给浏览器
3.1.2 查询文件列表开发步骤
1.Jsp开发
2.Controller端读取本地文件,返回文件信息给JSP。
*读取本地文件-》java API
*返回的信息-》文件名称
3.1.3 参考示例
JSP开发:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!doctype html>
<html>
<head>
<base href="<%=basePath%>">
<title>图片列表</title>
</head>
<body>
<form name="fileDown" method="get">
<table>
<tr>
<td>被下载的文件名</td>
</tr>
<!-- 遍历model中的files -->
<c:forEach items="${files}" var="filename">
<tr>
<td><a href="${pageContext.request.contextPath }/offer/down?filename=${filename}">${filename}</a></td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
Controller开发:
public String queryImageList(Model model) {
File dic = new File(localPath);
String[] files = dic.list();
model.addAttribute("files", files);
return "offerManager/imageList";
}
3.2 文件下载JSP开发
<table>
<tr>
<td>被下载的文件名</td>
</tr>
<!-- 遍历model中的files -->
<c:forEach items="${files}" var="filename">
<tr>
<td><a href="${pageContext.request.contextPath }/offer/down?filename=${filename}">${filename}</a></td>
</tr>
</c:forEach>
</table>
3.3文件下载Contoller开发
过程分析:
(1)读取本地文件
(2)将读取到本地文件写入到字节数组
(3)将字节数组中的数据写入到ResponseEntity中,并且指定返回的头部信息和请求状态。
(4)返回头部信息是通过HttpReaders指定,请求状态HttpStatus指定。
(5)将ResponseEntity返回给浏览器。
注意:
文件下载的过程,实际上是将磁盘文件最终放到服务端内存中,使用ResponseEntity保存,并且返回给浏览器。如果文件很大的话,可能会导致内存溢出。当文件很大的时候,使用IO流。
开发实例:
@RequestMapping("/downFile")
public ResponseEntity downFile(String filename) throws Exception {
//读取文件。
File file = new File(localPath+"/"+filename);
//需要将文件转换为字节数组-将文件读取到字节数组
//初始化文件读取流
FileInputStream fis = new FileInputStream(file);
//定义一个字节数组的长度与文件输入流读取的数据长度相同
byte[] body=new byte[fis.available()];
fis.read(body);
//设置头信息
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attchement;filename=" + filename);
//封装到ResponseEntity
ResponseEntity entity = new ResponseEntity(body,headers,HttpStatus.OK);
return entity;
}