美文网首页
SprngMVC 学习(六)文件上传

SprngMVC 学习(六)文件上传

作者: 年少懵懂丶流年梦 | 来源:发表于2017-03-21 19:06 被阅读783次

    Spring MVC同样支持文件上传功能,不过该功能默认未开启,因为可能有些开发者可能希望自己处理文件上传过程。

    Spring的文件上传功能在org.springframework.web.multipart包下,有两个MultipartResolver实现用来支持文件上传功能:

    • 一个是基于Commons FileUpload
    • 另一个基于Servlet 3.0 multipart请求解析功能

    这两个MultipartResolver差不多,一个需要添加Commons FileUpload的依赖,另一个需要在Servlet 3.0容器上运行。大家可以根据需要选择。

    如果想要使用Spring的文件上传功能,需要在文件上下文中配置MultipartResolver。

    定义MultipartResolver

    使用Commons FileUpload MultipartResolver

    在配置文件中添加如下一段,我们可以在Bean定义中配置上传文件大小等属性。

    <!-- 文件上传 -->
        <bean id="multipartResolver"
            class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    
            <!-- 设置上传文件的最大尺寸位30M -->
            <property name="maxUploadSize" value="31457280" />
            <property name="defaultEncoding" value="UTF-8" />
            <!-- 是否延迟加载,在需要的时候才进行上传文件的解析 -->
            <property name="resolveLazily" value="true" />
            <!-- 文件上传的临时路径,文件上传完成后,临时目录中的临时文件会被自动清除 -->
            <property name="uploadTempDir" value="upload/temp" />
        </bean>
    

    defaultEncoding必须和JSP的pageEncoding属性一致,以便正确读取表单的内容。

    注意:引入commons-fileupload.jar、commons-io.jar 两个包。


    使用Servlet 3.0 MultipartResolver

    由于使用的是Servlet API提供的文件上传功能,所以文件大小等配置需要在web.xml中进行配置。我们需要在dispathcer-servlet中添加<multipart-config>标签,它有四个子标签来设置文件上传的属性。

    这四个属性如下:

    • location ,临时文件的存放位置,这个路径必须是绝对路径。
    • fileSizeThreshold,文件起始值,大于该值文件才会被临时保存,单位是字节。
    • MaxFileSize,单个文件的最大值,单位是字节,不管上传几个文件,只要有一个文件大小超过该值就会抛出IllegalStateException。
    • maxRequestSize,文件上传请求的最大值,单位是字节,主要作用是当上传多个文件是配置整个请求的大小,当超出该值是抛出IllegalStateException。
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
        <multipart-config>
            <max-file-size>100000</max-file-size>
        </multipart-config>
    </servlet>
    

    然后我们在Spring配置文件中添加Servlet 3.0 MultipartResolver。

    <bean id="multipartResolver"
            class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
    </bean>
    

    上传文件

    配置好了Multipart解析器之后,我们就可以接收文件了。

    首先定义一个页面fileupload.jsp,用于上传文件并显示服务器中的文件。

    注意:在表单中我们必须添加<code>enctype="multipart/form-data"</code>才能正确的上传文件。

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>文件上传</title>
        <meta charset="utf-8">
    
    </head>
    <body>
    <h2>文件上传</h2>
    <form action="<c:url value="/mvc/uploadfile.html"/>"
          method="post" enctype="multipart/form-data">
        <label for="file">文件</label>
        <input type="file" name="file" id="file"/>
        <br>
        <input type="submit" value="提交">${result}
    </form>
    
    </body>
    </html>
    

    然后就可以在控制器中获取文件了。由于MultipartFile和它对应的临时文件会在方法结束之后被Spring清除,所以我们必须在方法中将文件保存到合适的地方。

    在请求方法中,我们可以像普通参数那样获取上传的文件,只不过文件对应的类型是MultipartFile,如果使用的是Servlet 3.0标准的,那么类型还可以是javax.servlet.http.Part。

    下面写了两个处理方法,第一个将MultipartFile转化为File保存在web目录下的upload文件夹中,第二个方法用于获取保存在该文件夹的文件。

        @RequestMapping("/uploadfile.html")
        public String uploadFile(@RequestParam("file") MultipartFile multipartFile) throws IOException {
            
            // 获取到web的根目录
            String path = System.getProperty("tansungWeb.root");
            
            if (!multipartFile.isEmpty()) {
                // 获取到源文件名
                String filename = multipartFile.getOriginalFilename();
                // 获取文件的后缀名
                String suffix = filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
                // 如果后缀为mp3的,一上传文件原名保存,否则以时间戳文文件名进行保存
                if (!suffix.equals("mp3")) {
                    //FileUtils.copyInputStreamToFile(multipartFile.getInputStream(),new File(path + "//upload//", System.currentTimeMillis() + "." + suffix));
                    multipartFile.transferTo(new File(path + "//upload//", System.currentTimeMillis() + "." + suffix));
                } else {
                    FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), new File(path + "//upload//", filename));
                }
            }
            model.addAttribute("result", "上传成功!");
            return "fileupload";
        }
    }
    

    Spring MVC会将上传文件绑定到MultipartFile对象中。MultipartFile提供了获取上传文件内容、文件名等内容,通过其transferTo()方法还可将文件存储到硬件中。

    // 获取文件数据
    byte[] getBytes();
    // 获取文件MIME类型,如image/jprg等
    String getContentType();
    // 获取文件流
    InputStream getInputStream();
    // 获取表单中文件组件的名字
    String getName();
    // 获取上传文件的原名
    String getOriginalFilename();
    // 获取文件的字节大小,单位为byte
    long getSize();
    // 是否有上传的文件
    boolean isEmpty();
    // 可以使用该文件将上传文件保存到一个目标文件中
    void transferTo(File dest);
    

    将上传的文件列出来,实现下载的功能。

        @RequestMapping("/listfile")
        public String listFile(Model model)
                throws IOException, ServletException {
            // 获取上传文件的目录
            String uploadFilePath = System.getProperty("tansungWeb.root") + "upload";
            // 存储要下载的文件名
            Map<String, String> fileNameMap = new HashMap<String, String>();
            // 递归遍历filepath目录下的所有文件和目录,将文件的文件名存储到map集合中
            // File既可以代表一个文件也可以代表一个目录
            listfile(new File(uploadFilePath), fileNameMap);
            // 将Map集合发送到list.jsp页面进行显示
            model.addAttribute("fileNameMap", fileNameMap);
            
            return "list";
        }
    
        /**
         * @Method: listfile
         * @Description: 递归遍历指定目录下的所有文件
         * @param file
         *            即代表一个文件,也代表一个文件目录
         * @param map
         *            存储文件名的Map集合
         */
        public void listfile(File file, Map<String, String> map) {
            // 如果file代表的不是一个文件,而是一个目录
            if (!file.isFile()) {
                // 列出该目录下的所有文件和目录
                File files[] = file.listFiles();
                // 遍历files[]数组
                for (File f : files) {
                    // 递归
                    listfile(f, map);
                }
            } else {
                /*
                 * 处理文件名,上传后的文件是以uuid_文件名的形式去重新命名的,去除文件名的uuid_部分
                 * file.getName().indexOf("_")检索字符串中第一次出现"_"字符的位置,如果文件名类似于:
                 * 9349249849-88343-8344_阿凡达.avi
                 * 那么file.getName().substring(file.getName().indexOf("_")+1)
                 * 处理之后就可以得到阿凡达.avi部分
                 */
                String realName = file.getName().substring(file.getName().indexOf("_") + 1);
                // file.getName()得到的是文件的原始名称,这个名称是唯一的,因此可以作为key,realName是处理过后的名称,有可能会重复
                map.put(file.getName(), realName);
            }
        }
    

    编写list.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>
    <meta charset="UTF-8">
    <title>下载列表显示页面</title>
    </head>
    <body>
        <!-- 遍历Map集合 -->  
        <c:forEach var="files" items="${fileNameMap}"> 
            
            <c:url value="/mvc/download" var="downurl">
                <c:param name="filename" value="${files.key}"></c:param>
            </c:url> 
            ${files.value}<a href="${downurl}">下载</a>  
             <!-- 
            <a href="<c:url value="/mvc/download?filename=${files.value}"/>">${files.value}</a>
             -->
            <br/>  
        </c:forEach>
    
    </body>
    </html>
    

    下载文件

    下载功能的实现

    @RequestMapping("/download")
    public void downloadFile(@RequestParam("filename") String filename, Model model, HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
    
        filename = new String(filename.getBytes("iso8859-1"), "UTF-8");
        //上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
        String fileSaveRootPath = System.getProperty("tansungWeb.root") + "upload";
        // 得到要下载的文件
        File file = new File(fileSaveRootPath + "\\" + filename);
        
        // 如果文件不存在
        if (!file.exists()) {
            model.addAttribute("message", "您要下载的资源已被删除!!");
        }
        // 处理文件名
        String realname = filename.substring(filename.indexOf("_") + 1);
        // 设置响应头,控制浏览器下载该文件
        resp.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
        // 读取要下载的文件,保存到文件输入流
        FileInputStream in = new FileInputStream(fileSaveRootPath + "\\" + filename);
        // 创建输出流
        OutputStream out = resp.getOutputStream();
        // 创建缓冲区
        byte buffer[] = new byte[1024];
        int len = 0;
        // 循环将输入流中的内容读取到缓冲区当中
        while ((len = in.read(buffer)) > 0) {
            // 输出缓冲区的内容到浏览器,实现文件下载
            out.write(buffer, 0, len);
        }
        // 关闭文件输入流
        in.close();
        // 关闭输出流
        out.close();
        
    }
    

    相关文章

      网友评论

          本文标题:SprngMVC 学习(六)文件上传

          本文链接:https://www.haomeiwen.com/subject/gtxigttx.html