zoukankan      html  css  js  c++  java
  • Spring MVC文件上传和下载

    今天做了一个在ssm框架中实现文件的上传和下载的案例,以此学习ssm中的文件上传和下载。

    1. 文件上传和下载概述

    1.1 文件上传

    多数文件上传都是通过表单形式提交给后台服务器的,因此,要实现文件上传功能,就需要提供一个文件上传的表单,而该表单必须满足以下3个条件:

    • form表单的method属性设置为post;

    • form表单的enctype属性设置为multipart/form-data;

    • 提供<input type="file" name="filename" />的文件上传输入框。

    文件上传表单示例如下:

    <%--multiple属性是HTML5中新属性,可实现多文件上传--%>
    <form action="uploadUrl" method="post" enctype="multipart/form-data">
        <input type="file" name="filename" multiple="multiple" />
        <input type="submit" value="文件上传" />
    </form>
    

    当form表单的enctype属性为multipart/form-data时,浏览器就会采用二进制流来处理表单数据,服务器端就会对文件上传的请求进行解析处理。Spring MVC通过MultipartResolver实现文件上传功能。MultipartResolver是一个接口对象,需要通过它的实现类CommonsMultipartResolver来完成文件上传工作。
    MultipartResolver配置示例如下

        <bean id="multipartResolver"
              class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <!--设置请求编码格式,必须与JSP中的pageEncoding属性一致,默认为ISO-8859-1-->
            <property name="defaultEncoding" value="UTF-8" />
            <!--设置允许上传文件的最大值(2M),单位为字节-->
            <property name="maxUploadSize" value="2097152" />
            ...
        </bean>
    

    在前面的配置代码中,除配置了CommonsMultipartResolver类外,还通过<property>元素配置了编码格式以及允许上传文件的大小。通过<property>元素可以对文件解析器类CommonsMultipartResolver的如下属性进行配置:

    • maxUploadSize:上传文件最大长度(以字节为单位);

    • maxInMemorySize:缓存中的最大尺寸;

    • defaultEncoding:默认编码格式;

    • resolveLazily:推迟文件解析,以便在Controller中捕获文件大小异常

    注意:因为MultipartResolver接口的实现类CommonsMultipartResolver内部是引用multipartResolver字符串获取该实现类对象并完成文件解析的,所以在配置CommonsMultipartResolver时必须指定该Bean的id为multipartResolver。

    由于CommonsMultipartResolver是Spring MVC内部通过Apache Commons FileUpload技术实现的,所以Spirng MVC的文件上传还需要依赖Apache Commons FileUpload的组件,即需要导入支持文件上传的相关JAR包。

    • commons-fileupload-1.3.2.jar
    • commons-io-2.5.jar
      下载地址

    当完成页面表单和文件上传解析器的配置后,在Controller中编写文件上传的方法即可实现文件上传,其代码如下所示:

    @Controller
    public class FileUploadController {
        @RequestMapping("/fileUpload ")
        public String handleFormUpload(@RequestParam("name") String name,
                                       @RequestParam("filename") MultipartFile file,...) {
            if (!file.isEmpty()) {
    		...
                return "uploadSuccess";
            }
            return "uploadFailure";
        }
    }
    

    在上述代码中,包含一个MultipartFile接口类型的参数file,上传到程序中的文件是被封装在该参数中的。org.springframework.web.multipart.MultipartFile接口中提供了获取上传文件、文件名称等方法,如下表所示:

    1.2 文件下载

    文件下载就是将文件服务器中的文件下载到本机上。在Spring MVC环境中,实现文件下载大致可分为如下两个步骤:
    1.在客户端页面使用一个文件下载的超链接,该链接的href属性要指定后台文件下载的方法以及文件名(需要先在文件下载目录中添加了一个名称为“1.jpg”的文件)。

    <a href="${pageContext.request.contextPath }/download?filename=1.jpg">
        文件下载
    </a>
    

    在后台使用Spring MVC提供的ResponseEntity类型对象完成文件下载,使用它可以很方便的定义返回的HttpHeaders对象和HttpStatus对象,通过对这两个对象的设置,即可完成下载文件时所需的配置信息。

    @RequestMapping("/download")
        public ResponseEntity<byte[]> fileDownload(HttpServletRequest request,
                                                   String filename) throws Exception{
            //指定要下载的文件所在路径
            String path = request.getServletContext().getRealPath("/upload/");
            File file = new File(path+File.separator+filename);
            HttpHeaders headers = new HttpHeaders();
    
            //通知浏览器以下载的方式打开文件
            headers.setContentDispositionFormData("attachment", filename);
            
            //定义以流的形式下载返回文件数据
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            
            //使用Sring MVC框架的ResponseEntity对象封装返回下载数据
            return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.OK);
        }
    

    案例

    开发工具:idea
    Java环境: jdk1.8.0_121
    浏览器:Google

    文件上传

    1.搭建项目环境,如下图:

    2.在web.xml文件中配置前端控制器。

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
        <display-name>chapter14</display-name>
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
        <servlet>
            <servlet-name>DispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-config.xml</param-value>
            </init-param>
    
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    

    3.配置Spring MVC的核心配置文件springmvc-config.xml

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
            <context:component-scan base-package="com.ma.controller"/>
            <mvc:annotation-driven/>
            <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/jsp/"/>
                <property name="suffix" value=".jsp"/>
            </bean>
    
            <!--上传文件解析器-->
            <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
                <!--设置请求编码格式-->
                <property name="defaultEncoding" value="UTF-8"/>
            </bean>
    </beans>
    

    4.编写上传文件的jsp页面fileUpload.jsp,以及上传成功或失败的提示页面。

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>文件上传</title>
        <script>
            function check() {
                var name = document.getElementById("name").value;
                var file = document.getElementById("file").value;
                if (name == "") {
                    alert("填写上传人");
                    return false;
                }
                if (file.length == 0 || file == "") {
                    alert("请选择上传文件!");
                    return false;
                }
                return true;
            }
        </script>
    </head>
    <body>
    <form action="${pageContext.request.contextPath}/fileUpload" method="post" enctype="multipart/form-data" onsubmit="return check()">
        上传人:<input type="text" name="name" id="name"/><br/>
        请选择文件:<input type="file" name="uploadfile" id="file" multiple="multiple"/><br/>
        <input type="submit" value="上传">
    </form>
    </body>
    </html>
    

    5.创建一个用于文件上传的控制器类FileUploadController。

    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * @author mz
     * @version V1.0
     * @Description: 文件上传控制器
     */
    @Controller
    public class FileUploadController {
        /**
         * 执行文件上传
         * @param name 上传人
         * @param uploadfile 上传文件
         * @param request
         * @return
         */
        @RequestMapping("/fileUpload")
        public String handleFormUpload(@RequestParam("name") String name,@RequestParam("uploadfile") List<MultipartFile> uploadfile,
                                       HttpServletRequest request) {
            //判断上传文件是否存在
            if (!uploadfile.isEmpty() && uploadfile.size() > 0) {
                //循环输出上传的文件
                for (MultipartFile file : uploadfile) {
                    //获取上传文件的原始名称
                    String oringinalFilename = file.getOriginalFilename();
                    //获取源文件名后缀
                    //String prefixName = FilenameUtils.getExtension(oringinalFilename);
    
                    //设置上传文件的保存地址目录
                    //String dirPath = request.getSession().getServletContext().getRealPath("/fileupload/");
                    
                    //设置上传文件的保存地址目录
                    String dirPath = request.getServletContext().getRealPath("/upload/");
                    File filePath = new File(dirPath);
                    //如果文件地址不存在 则创建目录
                    if (!filePath.exists()) {
                        filePath.mkdirs();
                    }
                    //使用uuid重新命名上传的文件名称(上传人_uuid_原始文件名称)
                    String newFilename = name + "_" + UUID.randomUUID() + "_" + oringinalFilename;
    
                    try {
                        //使用MultipartFilr接口的方法完成文件上传到指定位置
                        file.transferTo(new File(dirPath + newFilename));
                    } catch (IOException e) {
                        e.printStackTrace();
                        return "error";
                    }
                }
                //跳转到成功页面
                return "success";
            } else {
                return "error";
            }
        }
    }
    

    文件上传测试结果:

    关于文件上传的保存路径,upload文件夹是在项目的发布路径中,而不是创建的项目所有目录。现在运行的是项目所在目录,可以在idea下进行修改。如下图:

    文件下载

    1.在客户端页面使用一个文件下载的超链接,该链接的href属性指定后台文件下载的方法及文件名(先在下载目录里添加一个文件名“1.jpg”),代码如下:

    <a href="${pageContext.request.contextPath}/download?filename=1.jpg">
        文件下载
    </a><br/>
    

    2.在后台Controller类中添加文件下载的方法。

        /**
         * 文件下载
         * @param request
         * @param filename
         * @return
         * @throws IOException
         */
        @RequestMapping("/download")
        public ResponseEntity<byte[]> fileDownload(HttpServletRequest request, String filename) throws IOException {
            //指定要下载文件的路径
            String path = request.getServletContext().getRealPath("/upload");
            //创建文件对象
            File file = new File(path+File.separator+filename);
    
            //设置响应头
            HttpHeaders headers = new HttpHeaders();
            //通过浏览器以下载的方式打开文件
            headers.setContentDispositionFormData("attachment", filename);
            //定义以流的形式下载返回文件数据
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            //使用Spring MVC框架的ResponseEntity对象封装返回下载数据
            return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
        }
    

    测试结果:

    中文名称的文件下载

    当对中文名称的文件进行下载时,因为各个浏览器内部转码机制的不同,就会出现不同的乱码以及解析异常问题。
    将1.jpg修改为 图片.jpg,就会出现下图的问题:

    为了解决浏览器中文件下载时中文名称的乱码问题,可以在前端页面发送请求前先对中文名进行统一编码,然后在后台控制器类中对文件名称进行相应的转码。
    1.在下载页面中对中文文件名编码。可以使用Servlet API中URLEncoder.encoder(String s, String enc)方法将中文转为UTF-8编码。

    2.在控制器类中编写对中文名文件下载时进行转码编码的方法。

    修改Controller类中的文件下载的方法:

    @RequestMapping("/download")
        public ResponseEntity<byte[]> fileDownload(HttpServletRequest request, String filename) throws IOException {
            //指定要下载文件的路径
            String path = request.getServletContext().getRealPath("/upload");
            //创建文件对象
            File file = new File(path+File.separator+filename);
    
            //对文件进行编码,防止中文文件乱码
            filename = this.getFilename(request, filename);
    
            //设置响应头
            HttpHeaders headers = new HttpHeaders();
            //通过浏览器以下载的方式打开文件
            headers.setContentDispositionFormData("attachment", filename);
            //定义以流的形式下载返回文件数据
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            //使用Spring MVC框架的ResponseEntity对象封装返回下载数据
            return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK);
        }
    
        /**
         * 根据浏览器的不同进行编码设置,返回编码后的文件名
         * @param request
         * @param filename
         * @return
         */
        public String getFilename(HttpServletRequest request, String filename) throws UnsupportedEncodingException {
            //IE不同版本User-Agent中出现的关键词
            String[] IEBrowserKeyWords = {"MSIE", "Trident", "Edge"};
            //获取请求头代理信息
            String userAgent = request.getHeader("User-Agent");
            for (String keyWord : IEBrowserKeyWords) {
                if (userAgent.contains(keyWord)) {
                    //IE内核浏览器,统一为UTF-8编码显示
                    return URLEncoder.encode(filename, "UTF-8");
    
                }
            }
            //火狐等其他浏览器统一为ISO-8859-1编码显示
            return new String(filename.getBytes("UTF-8"), "ISO-8859-1");
        }
    

    测试结果:

    小结

    主要是对Spring MVC的文件上传和下载的学习做一个总结。并能够掌握中文名称文件下载时乱码的解决方案。

  • 相关阅读:
    浏览器回退
    几个小东西
    获取用户的IP
    easyui datagrid中 formatter的用法
    vscode安装go语言插件失败解决方法
    c#项目NLOG不显示日志
    C# 抽象类与接口的区别
    用SQL Server事件探查器创建跟踪
    使用MathJax在博客园里添加数学公式
    概率主题模型简介 Introduction to Probabilistic Topic Models
  • 原文地址:https://www.cnblogs.com/black-spike/p/7813229.html
Copyright © 2011-2022 走看看