SpringMVC的文件上传,下载,静态资源处理
一,静态资源处理
SpringMVC在DispatcherServlet使用/
会导致拦截静态资源(HTML,CSS,JS...)也就导致找不到静态文件
所以建议处理方式有一下两种:
1.在SpringMVC配置文件中使用默认处理方式
<mvc:default-servlet-handler/>
2.修改Spring的全局拦截设置为*.xxx的拦截(在web.xml)
<servlet>
2 <servlet-name>SpringMVC</servlet-name>
3 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
4 <init-param>
5 <param-name>contextConfigLocation</param-name>
6 <param-value>classpath:spring-mvc.xml</param-value>
7 </init-param>
8 <load-on-startup>1</load-on-startup>
9 <async-supported>true</async-supported>
10 </servlet>
11 <servlet-mapping>
12 <servlet-name>SpringMVC</servlet-name>
13 <url-pattern>*.xxx</url-pattern>
14 </servlet-mapping>
SpringMVC只会拦截.xxx
结尾的请求
二,文件上传
1.环境配置
需要Jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2.配置文件
引入CommonsMultipartResolver用于处理文件上传
MultipartFile 封装了请求数据中的文件,此时这个文件存储在内存中或临时的磁盘文件中,需要将其转存到一个合适的位置,因为请求结束后临时存储将被清空。在 MultipartFile 接口中有如下方法:
- String getName(); // 获取参数的名称
- String getOriginalFilename(); // 获取文件的原名称
- String getContentType(); // 文件内容的类型
- boolean isEmpty(); // 文件是否为空
- long getSize(); // 文件大小
- byte[] getBytes(); // 将文件内容以字节数组的形式返回
- InputStream getInputStream(); // 将文件内容以输入流的形式返回
- void transferTo(File dest); // 将文件内容传输到指定文件中
注意:Beanid必须为multipartResolver
还可以设置上传文件的大小限制
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2097152"/>
</bean>
3.编写上传表单
其中注意的是:
enctype="multipart/form-data"指定为上传文件
input 类型为file 名字为传递到conetroller的名字,应该和controller形参对应起来
<body>
<form action="#对应Controller" method="post" enctype="multipart/form-data">
上传:<input name="FileLoad" type="file"><br>
<input type="submit" value="确认">
</form>
</body>
4.编写Controller
注意点:
- 传入 request是为了获取路径
- MultipartFile的transferTo是保存文件操作参数为File类型
@Controller
@RequestMapping(value = "uploadController")
public class UploadController {
@RequestMapping(value = "FileLoad")
public String fileLoad(MultipartFile FileLoad, HttpServletRequest request) throws IOException {
/*
**只是为了测试上传的信息
System.out.println("filename = " + FileLoad.getOriginalFilename());
System.out.println("fileSize = " + FileLoad.getSize());
System.out.println("fileType = " + FileLoad.getContentType());
*/
//1.获取存储目的路径
String realPath = request.getSession().getServletContext().getRealPath("/UplodaResourse");
//2.修改文件名的操作 使用UUID避免文件重名
String FName= FilenameUtils.getExtension(FileLoad.getOriginalFilename());
String FileName=UUID.randomUUID().toString()+"."+FName;
//3.保存文件
FileLoad.transferTo(new File(realPath,FileName));
return "UpLoadPage/Upload";
}
}
小坑:使用idea时如果在服务器根目录下创建文件夹存放上传的文件,如果文件夹为空则idea不会部署空文件夹到服务器,可以随便放点东西进去
三,文件下载
我觉得下载有点困难,涉及的东西比较多,比如读,找,写,传输,缓冲
开发步骤:
- 确定哪些文件提供给用户下载
- 把确定的文件放入服务器下载目录
- 开发一个视图提供下载链接
- 开发下载的控制器(难)
1.开发视图
提供一个url带上值Filename给控制器,让控制器知道确定的下载文件
<body>
<a href="${pageContext.request.contextPath}/download/Resourse?Filename=LoadTXT.txt">下载LoadTXT.txt</a>
</body>
</html>
2.开发控制器
核心:
- 获取文件名字,从url传值方式获得
- 获取存放文件的文件夹位置
- 由文件名字和位置读取文件输入流
- 设置响应相关参数
- 通过response对象获取OutputStream流
- 设置缓冲区
- 将FileInputStream流写入到buffer缓冲区
- 使用OutputStream将缓冲区的数据输出到客户端浏览器
- 关闭流
获取文件名字,从url传值方式获得
在形参列表设置和url的key对应即可
//片段一:
public String DownLoadResourse(String Filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
//用于测试
//System.out.println("Filename = " + Filename);
}
获取存放文件的文件夹位置
依然使用request作用域获取相对位置
//片段二:
String realpath=request.getSession().getServletContext().getRealPath("/DownLoadReourse");
//用于测试
//System.out.println("realpath = " + realpath);
由文件名字和位置读取文件的输入流
FileInputStream fileInputStream=new FileInputStream((new File(realpath,Filename)));
设置响应相关参数(也是常用的参数)
**Response.setContentType ** (表示后面的文档属于什么MIME类型,Servlet默认为text/plain)
设置发送到客户端的响应的内容类型,决定浏览器将以什么形式、什么编码读取这个文件。
作用是使得客户端的浏览器区分不同种类的数据,并根据不同的MIME调用浏览器内不同的程序嵌入模块来处理相应的数据。
因为流只是读入数据,那么数据还得有对应的程序来处理,比如这里MIME设置为text/plain,那么浏览器就会按照TXT后缀文件处理
Tomcat的安装目录\conf\web.xml 中就定义了大量MIME类型可以查看对应的K-V来确定响应类型
response.setHeader (设置HTTP协议中的头)
当Content-Type 的类型为要下载的类型时 , 这个信息头会告诉浏览器这个文件的名字和类型。
value:attachment意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,将 Filename
的值预填为下载后的文件名,假如它存在的话
value:inline 浏览器会在浏览器内打开文件,如果无法打开则会附件下载这个文件
//片段三
//设置文件的类型和编码 免得文件中文乱码
response.setContentType("text/plain;UTF-8");
//设置响应头控制浏览器的行为
response.setHeader("Content-disposition","attachment;"+Filename);
通过response对象获取OutputStream流
ServletOutputStream outputStream = response.getOutputStream();
设置缓冲区
将FileInputStream流写入到buffer缓冲区
使用OutputStream将缓冲区的数据输出到客户端浏览器
read( byte [ ] ):作用是返回读入缓冲区的字节总数,当返回为-1表示读取到文件末尾
outputStream.write:利用字节流作为底层输出流然后构建字符输出流,字符输出流输出字符到流中
例如:
文件大小为1028
read一次之后is
流还剩4,4不等于-1,所以继续
len为1024
write(arry,0,len)os
流读取字节数组之后又把数组设为0了
第二次读取
os
流把剩下的4读完了,所有数据到outputStream准备就绪
第三次程序结束
//片段四
int len;
byte[] arry=new byte[1024];
while (true){
len=fileInputStream.read(arry);
if (len==-1)break;
//将缓冲区数据输出到浏览器
outputStream.write(arry,0,len);
}
关闭流
流是重量资源,关闭它
//片段5
fileInputStream.close();
outputStream.close();
完整代码
@Controller
@RequestMapping(value = "download")
public class MyDwonLoadController {
@RequestMapping(value = "Resourse")
public String DownLoadResourse(String Filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("Filename = " + Filename);
String realpath=request.getSession().getServletContext().getRealPath("/DownLoadReourse");
System.out.println("realpath = " + realpath);
FileInputStream fileInputStream=new FileInputStream((new File(realpath,Filename)));
response.setContentType("text/plain");
response.setCharacterEncoding("UTF-8");
//设置响应头控制浏览器的行为
response.setHeader("Content-disposition","attachment;"+Filename);
ServletOutputStream outputStream = response.getOutputStream();
int len;
byte[] arry=new byte[1024];
while (true){
len=fileInputStream.read(arry);
if (len==-1)break;
//将缓冲区数据输出到浏览器
outputStream.write(arry,0,len);
}
fileInputStream.close();
outputStream.close();
return "DownLoadPage/Download";
}
}
3.开发补充
1.下载选项
一般除了直接下载,通常我们还会设置在线打开或者下载的选项
所以我们在控制器里这样设置
同时记得在url传值的时候随意给OpenStyle设置一个值即可
public String DownLoadResourse(String Filename,String OpenStyle){
OpenStyle=OpenStyle==null?"inline":"attachment";
response.setHeader("Content-disposition","OpenStyle;"+Filename);
}
就可以便捷的设置打开方式
2.IOUtils
操作Io使用IOUtils.copy(is,os)就可以代替上面的片段四
同时操作文件还有FileUtils可以使用
3.传送中文文件名乱码
response.setHeader("Content-disposition","OpenStyle;"+URLencoder.encoder(filename,"UTF-8"));
当然了为了所有地方统一,可以专门设置一个变量处理传值来的中文乱码问题