第十章 文件上传与下载

target

了解使用 JavaWeb方式的文件上传
掌握文件上传的表单设置
掌握使用 SpringMVC 进行文件上传
理解使用SpringMVC进行文件下载

文件上传你是任何一个项目都必不缺少的,抖音里面头像的上传,QQ里面视频的上传,拼多多里面商品详情介绍等,文件上传随处可见。下面介绍JavaWeb方式的原始上传和SpringMVC方式的上传。

1. 文件上传-JavaWeb方式

对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

新建动态Web项目:FileUpload-1

在WebContent目录下新建上传表单:upload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>

    <form method="post" action="${pageContext.servletContext.contextPath }/upload"
        enctype="multipart/form-data">
        上传用户:<input type="text" name="username"><br> 
        上传文件:<input type="file" name="myfile" multiple="multiple"><br> 
        <input type="submit" value="上传">
    </form>

</body>
</html>

新建 UploadServlet类处理文件上传:

package com.lee.servlet;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private static final int FILE_SIZE = 10;// 单个文件最大值
    private static final String EXT_NAME = "gif,pdf,dmg,jpg,jpeg,png,bmp,swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2";// 定义允许上传的文件名
    private static final String savePath = "WEB-INF/upload";
    private static final String temPath = "WEB-INF/tem";
    
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 得到上传文件的保存目录,将上传文件存放在WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
        String saveRealPath = this.getServletContext().getRealPath(savePath);
        createDir(saveRealPath);// 创建WEB-INF/upload目录

        // 上传时生成临时文件保存目录
        String saveTemPath = this.getServletContext().getRealPath(temPath);
        File temDir = createDir(saveTemPath);// 创建WEB-INF/tem文件夹

        String message = "";// 消息提醒

        String fileName = "";// 上传的文件名

        // 使用Apache文件上传组件处理文件上传步骤
        try {
            /**
             * 1.创建DiskFileItemFactory对象
             */
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 设置工厂的缓冲区大小,当上传的文件大小超过缓冲区大小时,就会生成一个临时文件存放在指定的临时目录之中
            // 设置缓冲区大小为100kb,如果不设置,默认缓冲区大小是10kb
            factory.setSizeThreshold(1024 * 100);
            // 设置上传时生成的临时文件的保存目录
            factory.setRepository(temDir);

            /**
             * 2.创建文件上传解析器
             */
            ServletFileUpload upload = new ServletFileUpload(factory);

            // 解决上传文件名的中文乱码问题
            upload.setHeaderEncoding("UTF-8");

            // 判断提交上来的数据是否是文件表单
            if (!ServletFileUpload.isMultipartContent(req)) {
                // 终止文件上传处理
                return;
            }
            // 获取文件表单中的所有文件
            List<FileItem> items = upload.parseRequest(req);
            for (FileItem item : items) {
                if (item.isFormField()) {// formfield中封装的是普通的输入项数据
                    String name = item.getFieldName();
                    // 解决输入项数据中文乱码问题
                    String value = item.getString("UTF-8");
                    // value = new String(value.getBytes("iso8859-1"),"UTF-8");
                    System.out.println(name + "=" + value);
                } else {// formfield中封装的是上传文件
                    fileName = item.getName();// 得到文件上传名
                    System.out.println("文件名:" + fileName);
                    if (fileName == null || fileName.trim().length() == 0) {
                        continue;
                    }

                    /**
                     * 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的 如: C:\Users\H__D\Desktop\1.txt
                     * 而有些则是: 1.txt
                     */

                    // 处理获取到的上传文件的文件名的路径部分,只保留文件名部分
                    fileName = fileName.substring(fileName.lastIndexOf(File.separator) + 1);
                    // 得到上传文件的扩展名
                    String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

                    // 通过扩展名判断上传文件是否合法
                    System.out.println("上传文件的扩展名是:" + fileExt);
                    if (!EXT_NAME.contains(fileExt)) {
                        System.out.println("不允许上传" + fileExt + "格式的文件!");
                        message += "文件:" + fileName + ",上传文件扩展名不允许是" + fileExt + "<br>";
                        continue;
                    }

                    // 检查文件大小
                    if (item.getSize() == 0 || item.getSize() > FILE_SIZE * 1024 * 1024) {
                        message += "文件大小为:" + item.getSize() / 1024 / 1024 + "M,规定大小不超过" + FILE_SIZE + "M<br>";
                        continue;
                    }

                    // 得到存储的文件名
                    String saveFileName = makeFileName(fileName);
                    // 获取item中上传文件的输入流
                    InputStream is = item.getInputStream();
                    // 创建文件输出流
                    FileOutputStream out = new FileOutputStream(saveRealPath + File.separator + saveFileName);
                    // 创建一个缓冲区
                    byte[] b = new byte[1024];
                    int len = 0;
                    while ((len = is.read(b)) > 0) {
                        out.write(b, 0, len);
                    }
                    // 关闭流
                    out.close();
                    is.close();
                    // 删除临时文件
                    item.delete();
                    message += "文件:" + fileName + "上传成功!<br>";
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            message += fileName + "上传失败!";
        }

        req.setAttribute("message", message);
        req.getRequestDispatcher("WEB-INF/views/message.jsp").forward(req, resp);
    }

    /**
     * 为防止文件覆盖现象,为上传文件产生一个唯一的文件名
     * 
     * @param fileName
     * @return
     */
    private String makeFileName(String fileName) {
        return UUID.randomUUID().toString().replaceAll("-", "") + "_" + fileName;
    }

    /**
     * 创建目录
     * 
     * @param path
     */
    private File createDir(String path) {
        File pathDir = new File(path);
        if (!pathDir.exists()) {
            // 创建WEB-INF/upload目录
            pathDir.mkdirs();
        }
        return pathDir;
    }
}

在WEB-INF/views目录下新建消息页面:message.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>提示</title>
</head>
<body>
${message }
</body>
</html>

访问地址:http://localhost:8080/File/upload.jsp

此种方式可以上传一个或多个文件。

文件上传到服务器的位置"upload",该位置是指:workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps

几个细节:

①为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
②为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
③要限制上传文件的最大值。
④要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
⑤表单的enctype="multipart/form-data" method="post"

2. 文件上传-SpringMVC方式

Spring MVC 框架的文件上传是基于 commons-fileupload 组件的文件上传,只不过 Spring MVC 框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现,取消了不同上传组件上的编程差异。

commons-fileupload 组件依赖于 Apache 的另外一个项目(commons-io),因此需要导入commons-io的jar包。

Commons 是 Apache 开放源代码组织中的一个 Java子项目,该项目包括文件上传、命令行处理、数据库连接池、XML 配置文件处理等模块。fileupload 就是其中用来处理基于表单的文件上传的子项目,commons-fileupload 组件性能优良,并支持任意大小文件的上传。

2.1 表单属性

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

  • form表单的method属性设置为post;
  • form表单的enctype属性设置为multipart/form-data
  • 提供<input type="file" name="fileName" />的文件上传输入框。

表单的 enctype 属性指定的是表单数据的编码方式,该属性有以下 3 个值:

  • application/x-www-form-urlencoded:这是默认的编码方式,它只处理表单域里的 value 属性值。
  • multipart/form-data:该编码方式以二进制流的方式来处理表单数据,并将文件域指定文件的内容封装到请求参数里。
  • text/plain:该编码方式只有当表单的 action 属性为“mailto:”URL 的形式时才使用,主要适用于直接通过表单发送邮件的方式。

在HTML5之前,如果想要上传多个文件,必须使用多个<input>元素。但是在HTML5中,在<input>元素配置multiple属性即可进行多个文件的上传:

<input type="file" name="fileName" multiple />

2.3 MultipartFile接口

在 Spring MVC 框架中上传文件时将文件相关信息及操作封装到 MultipartFile 对象中,因此开发者只需要使用 MultipartFile 类型声明模型类的一个属性即可对被上传文件进行操作。该接口具有如下方法:

名称 作用
byte[] getBytes() 以字节数组的形式返回文件的内容
String getContentType() 返回文件的内容类型
InputStream getInputStream() 返回一个InputStream,从中读取文件的内容
String getName() 返回请求参数的名称
String getOriginalFillename() 返回客户端提交的原始文件名称
long getSize() 返回文件的大小,单位为字节
boolean isEmpty() 判断被上传文件是否为空
void transferTo(File destination) 将上传文件保存到目标目录下

在上传文件时需要在配置文件中使用 Spring 的 org.springframework.web.multipart.commons.CommonsMultipartResolver 类配置 MultipartResolver 用于文件上传。

2.3 springmvc配置文件

当客户端form表单的enctype属性为multipart/form-data时,浏览器就会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP请求。Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。

在Sring MVC中使用MultipartResolver也非常简单,只需要在Spring MVC配置文件springmvc.xml中定义MultipartResolver接口实现类即可,示例如下:

<!-- 配置文件解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  <!-- 设置最大允许上传的文件的大小,单位是B -->
  <property name="maxUploadSize" value="50000000"></property>
  <!-- 设置最大允许上传的单个文件的大小,单位是B -->
  <property name="maxUploadSizePerFile" value="10000000"></property>
  <property name="defaultEncoding" value="UTF-8"></property>
</bean>

注意:

由于MultipartResolver实现类CommonsMultipartResolver内部是引用multipartResolver字符串获取该实现类对象并完成文件上传操作的,所以在配置CommonsMultipartResolver时必须指定该bean的id为multipartResolver。

由于MultipartResolver实现类CommonsMultipartResolver是Spring MVC内部通过Apache Commons FileUpload技术实现的。因此Spirng MVC的文件上传还需要依赖Apache Commons FileUpload的组件,即需要导入支持文件上传和下载的JAR包,具体如下:

  • commons-fileupload.jar
  • commons-io.jar

2.4 代码实现

新建动态Web项目:FileUpload-2

① 引入 jar

将一下jar 复制到lib文件夹下:

commons-fileupload-1.4.jar
commons-io-2.6.jar
commons-logging-1.2.jar
spring-aop-4.3.9.RELEASE.jar
spring-beans-4.3.9.RELEASE.jar
spring-context-4.3.9.RELEASE.jar
spring-core-4.3.9.RELEASE.jar
spring-expression-4.3.9.RELEASE.jar
spring-web-4.3.9.RELEASE.jar
spring-webmvc-4.3.9.RELEASE.jar

② 创建 web.xml 文件

在 WEB-INF 目录下创建 web.xml 文件。为防止中文乱码,需要在 web.xml 文件中添加字符编码过滤器。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>FileUpload-2</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  
  <!-- The front controller of this Spring Web application, responsible for 
        handling all application requests -->
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map all requests to the DispatcherServlet for handling -->
    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

③ 创建 springmvc配置文件

在 src 下配置 springmvc.xml ,配置包扫描、视图解析器以及文件上传相关设置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

    <!-- 使用扫描机制扫描控制器类 -->
    <context:component-scan
        base-package="com.lee.controller" />

    <!-- 配置视图解析器 -->
    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- 配置文件解析器 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置最大允许上传的文件的大小,单位是B -->
        <property name="maxUploadSize" value="1000000000"></property>
        <!-- 设置最大允许上传的单个文件的大小,单位是B -->
        <property name="maxUploadSizePerFile" value="100000000"></property>
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>
</beans>

开发经验:一定要加上id="multipartResolver",否则会报错400。
④ 文件上传页面

在 WebContent 目录下创建 JSP页面 upload.jsp,在该页面中使用表单上传文件(可以一个或多个文件呢),具体代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SpringMVC方式上传</title>
</head>
<body>

    <form action="${pageContext.servletContext.contextPath }/upload" method="post" enctype="multipart/form-data">
        上传文件:<input type="file" name="files" multiple />
         <input type="submit" value="上传">
    </form>
</body>
</html>

⑤ 创建控制器类

package com.lee.controller;

@Controller
public class UploadController {
    private static final String EXT_NAME = "gif,pdf,dmg,jpg,jpeg,png,bmp,swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb,doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2";// 定义允许上传的文件名
    private static final String SAVE_PATH = "WEB-INF/upload";

    @RequestMapping("/upload")
    public String fileUpload(@RequestParam("files") List<MultipartFile> files, HttpServletRequest req,
            Map<String, Object> map) {

        String message = "";
        // 对上传的文件进行解析
        if (files != null && files.size() > 0) {
            for (MultipartFile file : files) {
                // 获取文件的原始名字
                String filename = file.getOriginalFilename();
                // 设置文件保存目录
                String saveRealPath = req.getServletContext().getRealPath(SAVE_PATH);
                File saveDir = new File(saveRealPath);
                if (!saveDir.exists()) {
                    saveDir.mkdirs();
                }

                // 判断文件格式是否符合
                String extFileName = filename.substring(filename.lastIndexOf(".") + 1);
                if (!EXT_NAME.contains(extFileName)) {
                    message += filename + "格式不符合!<br>";
                    map.put("message", message);
                    continue;
                }
                // 设置保存文件的名字:UUID或者时间进行重新命名
                String newFileName = UUID.randomUUID().toString().replaceAll("-", "") + "_" + filename;

                // 使用multipartFile接口上传
                try {
                    File saveFile = new File(saveRealPath + File.separator + newFileName);
                    file.transferTo(saveFile);
                    message += filename + "上传成功!<br>";
                } catch (Exception e) {
                    e.printStackTrace();
                    message += filename + "上传失败!<br>";
                }
                map.put("message", message);
            }
        }
        return "success";
    }
}

⑥ 创建成功显示页面

在 WEB-INF/views 目录下创建页面 success.jsp。具体代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>提示</title>
  </head>
  <body>
    ${message }
  </body>
</html>

部署项目,进行测试,可以选择一个或多个文件测试。

3. 文件下载

3.1 实现方法

实现文件下载有以下两种方法:

  • 通过超链接实现下载。
  • 利用程序编码实现下载。

通过超链接实现下载固然简单,但暴露了下载文件的真实位置,并且只能下载存放在 Web 应用程序所在的目录下的文件。

利用程序编码实现下载可以增加安全访问控制,还可以从任意位置提供下载的数据,可以将文件存放到 Web 应用程序以外的目录中,也可以将文件保存到数据库中。

利用程序实现下载需要设置两个报头:

① Web 服务器需要告诉浏览器其所输出内容的类型不是普通文本文件或 HTML 文件,而是一个要保存到本地的下载文件,这需要设置 Content-Type 的值为 application/x-msdownload。

② Web 服务器希望浏览器不直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中,这需要设置 Content-Disposition 报头。

该报头指定了接收程序处理数据内容的方式,在 HTTP 应用中只有 attachment 是标准方式,attachment 表示要求用户干预。在 attachment 后面还可以指定 filename 参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。

设置报头的示例如下:

response.setHeader("Content-Type", "application/x-msdownload");
response.setHeader("Content-Disposition", "attachment;filename="+filename);

3.2 代码实现

下面继续通过 FileUpload-2 应用讲述利用程序实现下载的过程,要求从(workspace.metadata.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\WEB-INF\uploadf)中下载文件,具体开发步骤如下:

① 编写控制器类

首先编写控制器类 FileDownController,在该类中有 3 个方法,即 show、down 和 toUTF8String。其中,show 方法获取被下载的文件名称;down 方法执行下载功能;toUTF8String 方法是下载保存时中文文件名的字符编码转换方法。

package com.lee.controller;

@Controller
public class FileDownController {

     /**
     * 显示要下载的文件
     */
    @RequestMapping("showDownFiles")
    public String show(HttpServletRequest request, Model model) {
        // 从 workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\下载
        String realpath = request.getServletContext()
                .getRealPath("WEB-INF/upload");
        File dir = new File(realpath);
        File files[] = dir.listFiles();
        // 获取该目录下的所有文件名
        ArrayList<String> fileName = new ArrayList<String>();
        for (int i = 0; i < files.length; i++) {
            fileName.add(files[i].getName());
        }
        model.addAttribute("files", fileName);
        return "showDownFiles";
    }
    /**
     * 执行下载
     */
    @RequestMapping("down")
    public String down(@RequestParam String filename,
            HttpServletRequest request, HttpServletResponse response) {
        String aFilePath = null; // 要下载的文件路径
        FileInputStream in = null; // 输入流
        ServletOutputStream out = null; // 输出流
        try {
            // 从workspace\.metadata\.plugins\org.eclipse.wst.server.core\
            // tmp0\wtpwebapps下载
            aFilePath = request.getServletContext().getRealPath("WEB-INF/upload");
            // 设置下载文件使用的报头
            response.setHeader("Content-Type", "application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment; filename="
                    + toUTF8String(filename));
            // 读入文件
            in = new FileInputStream(aFilePath + File.separator+ filename);
            // 得到响应对象的输出流,用于向客户端输出二进制数据
            out = response.getOutputStream();
            out.flush();
            int aRead = 0;
            byte b[] = new byte[1024];
            while ((aRead = in.read(b)) != -1 & in != null) {
                out.write(b, 0, aRead);
            }
            out.flush();
            in.close();
            out.close();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 下载保存时中文文件名的字符编码转换方法
     */
    public String toUTF8String(String str) {
        StringBuffer sb = new StringBuffer();
        int len = str.length();
        for (int i = 0; i < len; i++) {
            // 取出字符中的每个字符
            char c = str.charAt(i);
            // Unicode码值为0~255时,不做处理
            if (c >= 0 && c <= 255) {
                sb.append(c);
            } else { // 转换 UTF-8 编码
                byte b[];
                try {
                    b = Character.toString(c).getBytes("UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    b = null;
                }
                // 转换为%HH的字符串形式
                for (int j = 0; j < b.length; j++) {
                    int k = b[j];
                    if (k < 0) {
                        k &= 255;
                    }
                    sb.append("%" + Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return sb.toString();
    }
}

② 创建文件列表页面

下载文件示例需要一个显示被下载文件的 JSP 页面 showDownFiles.jsp,在WEB-INF/views目录下编写,代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Insert title here</title>
</head>
<body>
  <table>
    <tr>
      <td>被下载的文件名</td>
    </tr>
    <!--遍历 model中的 files-->
    <c:forEach items="${files}" var="filename">
      <tr>
        <td>
          <a href="${pageContext.request.contextPath }/down?filename=${filename}">${filename}</a>
        </td>
      </tr>
    </c:forEach>
  </table>
</body>
</html>

③ 测试下载功能

将应用部署到到 Tomcat 服务器并启动 Tomcat 服务器,然后通过地址"http://localhost:8080/FileUpload-2/showDownFiles"测试下载示例。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 175,490评论 5 419
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 74,060评论 2 335
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 124,407评论 0 291
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 47,741评论 0 248
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 56,543评论 3 329
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 43,040评论 1 246
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 34,107评论 3 358
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 32,646评论 0 229
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 36,694评论 1 271
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 32,398评论 2 279
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 33,987评论 1 288
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 30,097评论 3 285
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 35,298评论 3 282
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 27,278评论 0 14
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 28,413评论 1 232
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 38,397评论 2 309
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 38,099评论 2 314

推荐阅读更多精彩内容