Spring MVC使用篇(十四)—— 文件上传与下载

1、上传单个文件

1.1 导入文件上传依赖jar包

  Spring MVC实现文件上传,需要再添加两个jar包。一个是文件上传的jar包,一个是其所依赖的IO包。这两个jar包,均在Spring支持的org.apache.commons中。具体jar包如下:
在这里插入图片描述

1.2 创建上传页面

  在WEB-INF/jsp下创建名为“upload”的文件夹用来存放文件上传页面,在该文件夹下创建名为“upload.jsp”的具有文件上传功能的JSP页面。其表单的设置需要注意,method属性为POST,enctype属性为multipart/form-data。另外,需要注意file表单元素的参数名称,Controller中需要使用,具体代码如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
    <h1>单文件上传演示案例</h1>
    <form action="doUploadSingle.action" method="post" enctype="multipart/form-data">
        请选择上传的图片:<input type="file" name="photo" /><br/>
        <input type="submit" value="上传单个文件" />
    </form>
</body>
</html>

1.3 定义处理器(Controller)

  提前在“out/artifacts/SSMLearn_war_exploded/”路径下创建名为“images”的文件夹用来保存上传到服务器上的图片。路径如下图所示:
在这里插入图片描述
  然后,在“com.ccff.controller”下创建名为“UploadController”的控制器。具体代码如下所示:

package com.ccff.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Controller
@RequestMapping("/UploadTest")
public class UploadController {
    @RequestMapping("/upload")
    public String upload(){
        return "upload/upload";
    }

    @RequestMapping("/doUploadSingle")
    public String doUploadSingle(MultipartFile photo, HttpServletRequest request, Model model) throws IOException {
        if (!photo.isEmpty()){
            //服务端的images目录需要手动先创建好
            String path = request.getServletContext().getRealPath("/images");
            //获取原始文件名
            String fileName = photo.getOriginalFilename();
            //新的图片名称(UUID的随机名称)
            String newFileName = UUID.randomUUID() + "-" + fileName;
            //限制文件上传类型
            if (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith("gif")){
                File file = new File(path,newFileName);
                //完成上传
                photo.transferTo(file);
                //图片回显
                model.addAttribute("fileName",newFileName);
            }else {
                return "upload/fail";
            }
        }
        return "upload/success";
    }
}

  用于接收表单元素所提交参数的处理器方法的形参类型不是File,而是MultipartFile。MultipartFile为一个接口,专门用于处理文件上传问题。该类型参数的名称为映射前端上传页面的图片资源input标签的name属性。在Spring MVC中,MultipartFile类主要用来接收并转换request请求中multipart类型的文件数据。执行Controller获得MultipartFile类型的参数后,就可以使用该参数进行文件处理了。

  MultipartFile类常用的方法如下表所示:

方法名返回值释义
getContentType()String获取文件MIME类型
getInputStream()InputStream获取文件流
getName()String获取form表单中文件组件的名字
getOriginalFilename()String获取上传文件的原名
getSize()long获取文件的大小,单位为byte
isEmpty()boolean是否为空
transferTo(File dest)void将数据保存到一个目标文件中

1.4 注册文件上传处理器

  使用Spring MVC上传文件,需要在类加载配置文件springmvc.xml中配置multipart类型解析器(即MultipartFile接口的实现类CommonsMultipartResolver)。要求该bean的id必须为multipartResolver。 具体配置信息如下:

	<!--注册multipart解析器,这个id名字固定,是由DispatcherServlet直接调用的-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8" />
        <property name="maxUploadSize" value="1048576" />
    </bean>

  该Bean是由中央调度器(DispatcherServlet)执行处理器映射器RequestMapping之前加载调用进行判断的。如果容器中定义了名为multipartResolver的Bean,且请求也为multipart类型(即enctype属性值为multipart/form-data),则返回MultipartHttpServletRequest请求类型,完成文件上传功能。否则,返回普通的HttpServletRequest请求类型。

  对于文件名为中文的文件,默认情况下上传完成后,文件名为乱码,因为默认情况下文件上传处理器使用的字符集为ISO-8859-1。可以他通过设置属性defaultEncoding来指定文件上传所使用的字符集。

  MultipartFile接口的实现类CommonsMultipartResolver继承自CommonsFileUploadSupport类,而该类有一个属性maxUploadSize可以用来限制上传文件的大小,单位字节B。如果不对属性进行设置,或指定其值为-1,则表示不对文件上传大小做限制。这里需要注意的是,该大小为上传文件的总大小。即,多个上传文件大小之和不能大于该设定值。

  当然,也可通过设置属性maxUploadSizePerFile,再添加对每个上传文件的大小设置。即每个文件的大小不能超过maxUploadSizePerFile指定值,而文件大小综合也不能超过maxUploadSize指定值。

1.5 创建结果页面

  在“WEB-INF/jsp/upload”下创建名为“success.jsp”的JSP页面用来提示文件上传成功,并且回显上传的图片。创建名为“fail.jsp”的JSP页面用来提示文件上传失败。

  success.jsp具体代码如下所示:

<%@ page import="java.net.URLEncoder" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
    <title>上传成功</title>
</head>
<body>
    <h1>上传成功!</h1>
    <c:if test="${fileName != null}">
        ${fileName}:<br/><img src="/demo/images/${fileName}">
    </c:if>
</body>
</html>

  fali.jsp具体代码如下所示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>上传失败</title>
</head>
<body>
    <h1>上传失败!</h1>
</body>
</html>

1.6 测试结果

  将项目部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/UploadTest/upload.action 后显示文件上传页面(upload.jsp)如下所示:
在这里插入图片描述
  选择一张图片进行上传,如下所示:
在这里插入图片描述
  点击上传按钮提交表单后,将该表单提交给Controller中的doUploadSingle方法处理,上传文件并显示结果如下:
在这里插入图片描述
在这里插入图片描述

1.7 解决中文图片名回显问题

  仔细回顾我们会发现,第一次我们测试的时候上传的图片的图片名称为英文,接下来我们上传一张图片名称含有中文的图片再次测试,当上传如下图片时:
在这里插入图片描述
  点击上传按钮提交表单后我们会发现,文件上传虽然成功,但是上传后的图片无法回显在页面中,结果如下:
在这里插入图片描述
在这里插入图片描述
  此时当我们查看网页源代码的时候也发现,路径应该也是没有问题的,具体显示如下:
在这里插入图片描述
  该问题就出现在源文件中img标签中的src属性中的图片的名字中存在中文。导致该问题的原因是当加载该网页的时候浏览器还会再发送一次get请求到Tomcat服务器来加载img标签中的图片,而一般浏览器默认用的发送编码为UTF-8,Tomcat服务器的http Connector所用的URI解码默认用的是 ISO-8859-1,由于两个编码方式不一样,这里就出现了问题。

  经过多方位了查找资料,最靠谱的方式就是修改Tomcat服务器的配置文件server.xml,找到如下代码段:

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

  将其修改为如下所示,其中URIEncoding=“UTF-8” 这项,其含义是指定URI的编码为:UTF-8。在后面加上这一项,重启Tomcat服务器后问题就可以解决了。

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="utf-8" />

  再次上传含有中文的图片,此时显示成功。
在这里插入图片描述

2、上传多个文件

2.1 修改文件上传页面(upload.jsp)

  在之前上传单个文件的基础上,修改upload.jsp页面,使得其能够显示上传多个文件的表单,具体代码如下所示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>
    <h1>单文件上传演示案例</h1>
    <form action="doUploadSingle.action" method="post" enctype="multipart/form-data">
        请选择上传的图片:<input type="file" name="photo" /><br/><br/>
        <input type="submit" value="上传单个文件" />
    </form>
    <br/>
    <hr>
    <br/>
    <h1>多文件上传演示案例</h1>
    <form action="doUploadMore.action" method="post" enctype="multipart/form-data">
        请选择需要上传的图片1:<input type="file" name="images" /><br/>
        请选择需要上传的图片2:<input type="file" name="images" /><br/>
        请选择需要上传的图片3:<input type="file" name="images" /><br/><br/>
        <input type="submit" value="上传多个文件" />
    </form>
</body>
</html>

2.2 修改控制器(Controller)

  在原有的控制器(Controller)的基础上增加doUploadMore方法,用来处理多文件上传。这里需要注意的是,处理多文件的上传与处理单文件的上传的不同之处在于MultipartFile类型参数。单文件为一个MultipartFile类型参数,而多文件为一个MultipartFile类型的数组。由于Controller并不能直接自动转成MultipartFile类型的数组,因此需要利用@RequestParam注解对其进行参数校正,该注解不能省略。 添加的doUploadMore方法具体代码如下所示:

	/**
     * 实现过个文件上传
     * @param images
     * @param request
     * @param model
     * @return
     * @throws IOException
     */
    @RequestMapping("/doUploadMore")
    public String doUploadMore(@RequestParam MultipartFile[] images, HttpServletRequest request, Model model) throws IOException {
        //服务端的images目录需要手动先创建好
        String path = request.getServletContext().getRealPath("/images");
        List<String> fileNames = new ArrayList<>();
        for (MultipartFile photo : images){
            if (!photo.isEmpty()){
                //获取原始文件名
                String fileName = photo.getOriginalFilename();
                //新的图片名称(UUID的随机名称)
                String newFileName = UUID.randomUUID() + "-" + fileName;
                //限制文件上传类型
                if (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith("gif")){
                    File file = new File(path,newFileName);
                    //完成上传
                    photo.transferTo(file);
                    fileNames.add(newFileName);
                }else {
                    return "upload/fail";
                }
            }
        }
        if (fileNames.size() > 0){
            model.addAttribute("fileNames",fileNames);
        }
        return "upload/success";
    }

2.3 修改上传成功页面(success.jsp)

  修改原有的success.jsp,使其能够显示多文件上传成功后的提示信息并回显上传的图片,具体修改如下:

<%@ page import="java.net.URLEncoder" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
    <title>上传成功</title>
</head>
<body>
    <c:if test="${fileName != null}">
        <h1>单个文件上传成功!</h1>
        ${fileName}:<br/><img src="/demo/images/${fileName}">
    </c:if>
    <c:if test="${fileName != null} && ${fileNames != null}">
        <br/>
        <hr/>
        <br/>
    </c:if>
    <c:if test="${fileNames != null}">
        <h1>多个文件上传成功!</h1>
        <c:forEach items="${fileNames}" var="fileName">
            ${fileName}:<br/><img src="/demo/images/${fileName}"><br/>
        </c:forEach>
    </c:if>
</body>
</html>

2.4 测试结果

  将项目重新部署到Tomcat上后,在浏览器内输入如下请求URL:http://localhost:8080/demo/UploadTest/upload.action 后显示如下界面:
在这里插入图片描述
  直接在多文件上传演示案例处选择三张图片进行上传,如下所示:
在这里插入图片描述
  当点击上传按钮后将表单提交给Controller中的doUploadMore方法进行多文件上传的处理,当文件上传成功后会显示提示信息,并回显上传成功的图片,结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、文件下载

  文件下载比较简单,直接在页面中给出一个超链接,该链接href的属性等于要下载文件的文件名,就可以实现文件下载了。但是如果该文件的文件名为中文文件名,在某些早期的浏览器上就会导致下载失败;如果使用最新的Firefox、Opera、Chrome、Safari则都可以正常下载文件名为中文的文件了。

  Spring MVC提供了一个ResponseEntity类型,使用它可以很方便地定义返回的HttpHeaders和HttpStatus。

  首先,在“WEB-INF/jsp/upload”下创建名为“download.jsp”的JSP页面用于展示下载页。具体代码如下所示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>下载</title>
</head>
<body>
    <h1>文件下载</h1>
    <br/>
    <a href="doDownLoad/40044eab-62a8-4363-8716-a29fc1b508c6-timg (2).jpg">反正是一张图片,你就不想下载下来看一眼吗?</a>
</body>
</html>

  然后,在UploadController控制器类中添加download方法和doDownLoad方法。其中,download方法用于展示下载页面,doDownLoad方法用于处理下载逻辑。具体代码如下所示:

	/**
     * 显示文件下载页面
     * @return
     */
    @RequestMapping("/download")
    public String download(){
        return "upload/download";
    }

    /**
     * 实现文件下载
     * @param request
     * @param filename
     * @return
     * @throws IOException
     */
    @RequestMapping(value = "/doDownLoad/{filename}", method = {RequestMethod.GET})
    public ResponseEntity<byte[]> doDownLoad(HttpServletRequest request, @PathVariable("filename") String filename) throws IOException {
        //下载文件路径
        String path = request.getServletContext().getRealPath("/images/");
        System.out.println(path+"\\"+filename+".jpg");
        File file = new File(path+"\\"+filename+".jpg");
        HttpHeaders headers = new HttpHeaders();
        //下载显示的文件名,解决中文名称乱码问题
        String downliadFileName = new String(filename.getBytes("UTF-8"),"iso-8859-1");
        //通知浏览器以attachment(下载方式)打开图片
        headers.setContentDispositionFormData("attachment",downliadFileName);
        //application/octet-stream:二进制流数据(最常见的文件下载)
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        //201 HttpStatus.CREATED
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);
    }

  doDownLoad方法接收到页面传递的文件名filename后,使用Apache Commons FileUpload组件的FileUtils读取项目的images文件夹下的该文件,并将其构建成ResponseEntity对象返回客户端下载。

  使用ResponseEntity对象,可以很方便地定义返回的HttpHeaders和HttpStatus。上面代码中的MediaType,代表的是Internet Media Type,即互联网媒体类型,也叫做MIME类型。在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。HttpStatus类型代表的是Http协议中的状态。有关MediaType和HttpStatus类的详细信息请参考Spring MVC的API文档。

  最后,将项目重新部署到Tomcat上后,在浏览器内输入请求URL:http://localhost:8080/demo/UploadTest/download 后即可显示下载页面,如下所示:
在这里插入图片描述
  当点击超链接后,跳出下载提示界面,选择下载地址,保存,完成下载即可。
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值