SpringMVC-文件上传和下载

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;
	}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值