4.SpringMVC的文件上传,下载,静态资源处理

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>

参考:SpringMVC工作原理

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. 确定哪些文件提供给用户下载
  2. 把确定的文件放入服务器下载目录
  3. 开发一个视图提供下载链接
  4. 开发下载的控制器(难)

1.开发视图

提供一个url带上值Filename给控制器,让控制器知道确定的下载文件

<body>
<a href="${pageContext.request.contextPath}/download/Resourse?Filename=LoadTXT.txt">下载LoadTXT.txt</a>
</body>
</html>

2.开发控制器

核心:

  1. 获取文件名字,从url传值方式获得
  2. 获取存放文件的文件夹位置
  3. 由文件名字和位置读取文件输入流
  4. 设置响应相关参数
  5. 通过response对象获取OutputStream流
  6. 设置缓冲区
    • 将FileInputStream流写入到buffer缓冲区
    • 使用OutputStream将缓冲区的数据输出到客户端浏览器
  7. 关闭流

获取文件名字,从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"));

当然了为了所有地方统一,可以专门设置一个变量处理传值来的中文乱码问题

posted on 2021-08-14 16:51  NathenJames  阅读(224)  评论(0编辑  收藏  举报