文件上传下载对于一个网站来说,重要性不言而喻。今天来分享一个JavaWeb方式实现的文件上传下载的小例子。


项目依赖

这个小例子是使用JavaWeb的JSP+Servlet实现的。另外使用了一些第三方的jar包。现列举如下:

以上这些依赖,都很容易获得。当然也可以在我的repository中直接获取。地址如下:https://github.com/guoruibiao/File_Upload_Download/blob/master/WebContent/WEB-INF/lib

项目目录

在开始项目之前,给出一个项目目录可以使得我们的思路更加的清晰。

工作流程

对于新手而言。对web.xml的配置可能摸不着头脑,下面给大家画个图吧。

文件上传

在开始编码之前,我们还需要了解一些比较基础的知识。可能你会觉得有点啰嗦了,但是为了照顾到不了解这些的童鞋,我还是多说几句吧:-)

表单处的设置

如果我们要想做一个上传文件功能,毫无疑问需要通过表单进行。因此,我们需要遵守一点规则。

<form
        action="${pageContext.request.contextPath }/servlet/UploadHandleServlet"
        enctype="multipart/form-data" method="post">
        上传用户:<input type="text" name="username"><br> 上传文件1:<input
            type="file" name="file1"><br> 上传文件2:<input type="file"
            name="file2"><br> <input type="submit" value="提交">
    </form>

以这个表单为例,我们不难发现。

enctype="multipart/form-data"

这行代码,其作用就是告诉服务器,我们的这个表单将用于文件上传处理。

服务器端

通过表单来实现上传固然很方便,但是除了文件项之外的表单项怎么处理呢? 这时我们就需要了解一下,关于apache-commons-fileupload的文件处理了。


try {
            // 使用Apache上传组件处理文件上传的步骤
            // 1、创建一个DIskFileItemFactory工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 2、创建一个文件上传解析器
            ServletFileUpload uploadparser = new ServletFileUpload(factory);
            // 3、解决上传文件的中文乱码;判断提交上来的数据是否是上传表单的数据
            uploadparser.setHeaderEncoding("UTF-8");
            if (!ServletFileUpload.isMultipartContent(request)) {
                // 不是表单数据,则按照传统方式获取数据
                return;
            }
            // 4、使用ServletFileUpload解析器解析上传的数据,解析结果返回的是一个List<File>集合,每个Item对应一个表单的输入项
            List<FileItem> files = uploadparser.parseRequest(request);
            for (FileItem fileitem : files) {
                // 如果fileitem中封装的是普通的输入项的数据
                if (fileitem.isFormField()) {
                    String name = fileitem.getFieldName();
                    // 解决普通输入项的数据的中文乱码问题
                    String value = fileitem.getString("UTF-8");
                    System.out.println(name + "  =   " + value);
                } else {// 如果fileitem里面封装的是上传的文件,则是用处理文件的方式处理
                    String filename = fileitem.getName();
                    System.out.println(fileitem);
                    if (filename == null || filename.trim().equals("")) {
                        continue;
                    }
                    // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件是带有其客户端本机路径的,有些则不带。所以我们要对上传文件处理,只得到文件名称即可
                    filename = StringUtils.getFileName(filename);
                    // 获取fileitem的上传文件的输入流
                    InputStream is = fileitem.getInputStream();
                    // 创建一个文件输出流
                    FileOutputStream fos = new FileOutputStream(savePath + "\\" + filename);
                    // 创建一个缓冲区
                    byte[] buffer = new byte[1024];
                    // 判断输入流中的数据是否已经读完的标识
                    int len = 0;
                    while ((len = is.read(buffer)) > 0) {
                        // 将数据写入到服务器的对应的文件中
                        fos.write(buffer, 0, len);
                    }
                    is.close();
                    fos.close();
                    fileitem.delete();
                    message = new String("Upload Success!".getBytes(), "UTF-8");

                }
            }

        } catch (Exception e) {
            message = new String("Upload Failed!".getBytes(), "UTF-8") + e;
            e.printStackTrace();
        }

上传功能的实现

好了,下面开始上传功能的实现。

upload.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>文件上传</title>
</head>
<body>
    <form
        action="${pageContext.request.contextPath }/servlet/UploadHandleServlet"
        enctype="multipart/form-data" method="post">
        上传用户:<input type="text" name="username"><br> 上传文件1:<input
            type="file" name="file1"><br> 上传文件2:<input type="file"
            name="file2"><br> <input type="submit" value="提交">
    </form>

</body>
</html>

message.jsp

在软件使用的过程中,为了给用户一个更加友好的用户体验,我们添加了一个与用户单方面交互(简单的提示作用)的页面。用来传递代码过程的必要信息。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>消息提示</title>
</head>
<body>${message }
</body>
</html>

UploadHandleServlet

package controller;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

import stringutil.StringUtils;

public class UploadHandleServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public UploadHandleServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
        // 得到上传文件的保存目录,将上传的文件存放到外界不能直接访问的WEB-INF目录下
//      String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
        String savePath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload";
        File file = new File(savePath);
        // 判断上传文件的目录是否存在
        if (!file.exists() && !file.isDirectory()) {
            System.out.println(savePath + "  Need to Make Directory named ‘upload’!");
            // 开始创建目录
            file.mkdir();
        }

        // 消息提示
        String message = "";
        try {
            // 使用Apache上传组件处理文件上传的步骤
            // 1、创建一个DIskFileItemFactory工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 2、创建一个文件上传解析器
            ServletFileUpload uploadparser = new ServletFileUpload(factory);
            // 3、解决上传文件的中文乱码;判断提交上来的数据是否是上传表单的数据
            uploadparser.setHeaderEncoding("UTF-8");
            if (!ServletFileUpload.isMultipartContent(request)) {
                // 不是表单数据,则按照传统方式获取数据
                return;
            }
            // 4、使用ServletFileUpload解析器解析上传的数据,解析结果返回的是一个List<File>集合,每个Item对应一个表单的输入项
            List<FileItem> files = uploadparser.parseRequest(request);
            for (FileItem fileitem : files) {
                // 如果fileitem中封装的是普通的输入项的数据
                if (fileitem.isFormField()) {
                    String name = fileitem.getFieldName();
                    // 解决普通输入项的数据的中文乱码问题
                    String value = fileitem.getString("UTF-8");
                    System.out.println(name + "  =   " + value);
                } else {// 如果fileitem里面封装的是上传的文件,则是用处理文件的方式处理
                    String filename = fileitem.getName();
                    System.out.println(fileitem);
                    if (filename == null || filename.trim().equals("")) {
                        continue;
                    }
                    // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件是带有其客户端本机路径的,有些则不带。所以我们要对上传文件处理,只得到文件名称即可
                    filename = StringUtils.getFileName(filename);
                    // 获取fileitem的上传文件的输入流
                    InputStream is = fileitem.getInputStream();
                    // 创建一个文件输出流
                    FileOutputStream fos = new FileOutputStream(savePath + "\\" + filename);
                    // 创建一个缓冲区
                    byte[] buffer = new byte[1024];
                    // 判断输入流中的数据是否已经读完的标识
                    int len = 0;
                    while ((len = is.read(buffer)) > 0) {
                        // 将数据写入到服务器的对应的文件中
                        fos.write(buffer, 0, len);
                    }
                    is.close();
                    fos.close();
                    fileitem.delete();
                    message = new String("Upload Success!".getBytes(), "UTF-8");

                }
            }

        } catch (Exception e) {
            message = new String("Upload Failed!".getBytes(), "UTF-8") + e;
            e.printStackTrace();
        }
        request.setAttribute("message", message);
        request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

web.xml配置

<servlet>
        <servlet-name>UploadHandleServlet</servlet-name>
        <servlet-class>controller.UploadHandleServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>UploadHandleServlet</servlet-name>
        <url-pattern>/servlet/UploadHandleServlet</url-pattern>
    </servlet-mapping>

结果展示

文件浏览

要想实现下载功能,我们需要先给用户一个引导,那就是咱们的网站上有什么。所以我们需要对网站上提供下载的文件夹一个遍历。

思路如下:

ListFileServlet.java

package controller;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import stringutil.StringUtils;

/**
 * Servlet implementation class ListFileServlet
 */
@WebServlet("/ListFileServlet")
public class ListFileServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ListFileServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
        // 获取上传文件的目录
        String uploadPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload";
        // 存储要下载的文件名
        Map<String, String> filenameMap = new HashMap<String, String>();
        // 递归遍历filePath下面的所有的文件和目录,将文件的文件名称存储到Map集合中
        listFile(new File(uploadPath), filenameMap);
        // 将集合存入域找那个,方便页面展示层获取数据
        request.setAttribute("filenameMap", filenameMap);
        request.getRequestDispatcher("/listfiles.jsp").forward(request, response);
    }

    public void listFile(File file, Map<String, String> filenameMap) {
        // 如果file代表的不是一个文件,而是一个目录
        if (!file.isFile()) {
            // 列出该目录下面的所有的文件和目录
            File[] files = file.listFiles();
            // 遍历files[] 数组
            for (File f : files) {
                // 递归
                listFile(f, filenameMap);
            }
        } else {
            // 使用自己的那个strigutil来获取文件的名称,而不是路径名称
            String realName = StringUtils.getFileName(file.getName());
            try {
                filenameMap.put(new String(file.getName().getBytes("iso8859-1"),"UTF-8"), realName);
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

listfiles.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML>
<html>
<head>
<title>下载文件显示页面</title>
</head>

<body>
    <!-- 遍历Map集合 -->
    <c:forEach var="me" items="${filenameMap}">
        <c:url value="/servlet/DownLoadServlet" var="downurl">
            <c:param name="filename" value="${me.key}"></c:param>
        </c:url>
         ${me.value}<a href="${downurl}">Download now?</a>
        <br />
    </c:forEach>
</body>
</html>

web.xml配置

<servlet>
        <servlet-name>ListFileServlet</servlet-name>
        <servlet-class>controller.ListFileServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ListFileServlet</servlet-name>
        <url-pattern>/servlet/ListFileServlet</url-pattern>
    </servlet-mapping>

截图结果

注意

这里有几点容易出错的地方,大家需要注意。

路径问题

由于使用this.getServletContext().getRealPath("/WEB-INF/upload");的过程中出现了一些问题,所以我这里使用了绝对路径,大家可以自己的情况随意选择。

JSTL使用

在使用JSTL标签库的时候,千万不要忘记引入相关的jar包。然后在JSP页面上方填写相应的声明。还有就是URI属性不要写错咯。是<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

模板变量

<c:forEach>标签内部,使用的<c:param name="filename" value="${me.key}"></c:param>参数一定不要写错了。因为等会我们会根据这里面的name="filename"属性来唯一确定我们要下载的文件的信息。

文件下载

文件下载的功能本身并不难,核心就是告诉浏览器header是什么,然后通过一个流操作,将要进行下载的数据发送给客户端浏览器即可。

DownLoadServlet.java

package controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import stringutil.StringUtils;

/**
 * Servlet implementation class DownLoadServlet
 */
@WebServlet("/DownLoadServlet")
public class DownLoadServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public DownLoadServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        // 得到要下载的文件名
        String filename = request.getParameter("filename");
        filename = new String(filename.getBytes("iso8859-1"), "UTF-8");
        // 上传的文件都是保存在刚才的那个upload的文件夹下.

        String fileSaveRootPath = "E://Code/jee/File_upload_download/WebContent/WEB-INF/upload";
        // 通过文件名找出文件所在的目录
        // 由于路径有点问题,这里采用绝对路径来进行处理
        // String filePath =
        // findFileSavePathByFileName(filename,fileSaveRootPath);
        String filePath = fileSaveRootPath;
        // 得到要下载的文件
        File file = new File(filePath + "\\" + filename);
        // 如果文件不存在
        if (!file.exists()) {
            request.setAttribute("message", "The File you want to download doesn't exists!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
            return;
        }
        // 处理文件名
        String realname = StringUtils.getFileName(filename);
        // 设置响应头
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
        // 读取要下载的文件,保存到文件输入流
        FileInputStream fis = new FileInputStream(filePath + "\\" + filename);
        // 创建输入流
        OutputStream os = response.getOutputStream();
        // 创建缓冲区
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = fis.read(buffer)) > 0) {
            os.write(buffer, 0, len);
        }
        fis.close();
        os.close();

    }

    private String findFileSavePathByFileName(String filename, String fileSaveRootPath) {
        int hashcode = filename.hashCode();
        int dir1 = hashcode & 0xf; // 0--15
        int dir2 = (hashcode & 0xf0) >> 4; // 0--15
        String dir = fileSaveRootPath + "\\" + dir1 + "\\" + dir2;
        File file = new File(dir);
        if (!file.exists()) {
            // 创建目录
            file.mkdir();
        }
        return dir;
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

web.xml配置

<servlet>
        <servlet-name>DownLoadServlet</servlet-name>
        <servlet-class>controller.DownLoadServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DownLoadServlet</servlet-name>
        <url-pattern>/servlet/DownLoadServlet</url-pattern>
    </servlet-mapping>

截图展示





总结

最后关于整个项目的总结。使用apache-commons-fileupload组件确实是很方便,它可以方便的将表单中上传的数据封装到一个List<fileItem>中,我们只需要对这个集合进行遍历操作,就可以随意的设置自己需要的内容。

最后,希望大家看完之后都能有所收获。让自己的网站的功能更加的丰富。

完整的项目下载地址如下: https://github.com/guoruibiao/File_Upload_Download/。欢迎拍砖 :-)

JavaWeb 文件 上传 下载的更多相关文章

  1. JavaWeb 文件上传下载

    1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图片或网盘等功能都是利用文件上传下 ...

  2. JavaWeb -- 文件上传下载示例

    1. 上传简单示例 Jsp <%@ page language="java" import="java.util.*" pageEncoding=&quo ...

  3. 转载:JavaWeb 文件上传下载

    转自:https://www.cnblogs.com/aaron911/p/7797877.html 1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端 ...

  4. JavaWeb实现文件上传下载功能实例解析

    转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...

  5. JavaWeb实现文件上传下载功能实例解析 (好用)

    转: JavaWeb实现文件上传下载功能实例解析 转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web ...

  6. .JavaWeb文件上传和FileUpload组件使用

    .JavaWeb文件上传 1.自定义上传 文件上传时的表单设计要符合文件提交的方式: 1.提交方式:post 2.表单中有文件上传的表单项:<input type="file" ...

  7. 阿里云负载均衡SLB的文件上传下载问题解决

    Nfs同步文件夹配置 问题描述 : javaweb应用部署到云服务器上时,当服务器配置了SLB负载均衡的时候,多台服务器就会造成文件上传下载获取不到文件的错误, 解决办法有:1.hdfs  2.搭建f ...

  8. springmvc文件上传下载简单实现案例(ssm框架使用)

    springmvc文件上传下载实现起来非常简单,此springmvc上传下载案例适合已经搭建好的ssm框架(spring+springmvc+mybatis)使用,ssm框架项目的搭建我相信你们已经搭 ...

  9. SpringMVC文件上传下载(单文件、多文件)

    前言 大家好,我是bigsai,今天我们学习Springmvc的文件上传下载. 文件上传和下载是互联网web应用非常重要的组成部分,它是信息交互传输的重要渠道之一.你可能经常在网页上传下载文件,你可能 ...

随机推荐

  1. [SDOI 2016]征途

    Description 题库链接 将一个长度为 \(n\) 的正整数序列分为 \(m\) 段,问你这 \(m\) 段最小的方差 \(v\) 为多少.输出 \(v\times m^2\) . \(1\l ...

  2. [WC 2006]水管局长数据加强版

    Description SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一 ...

  3. [HNOI2008]遥远的行星

    题目描述 直线上N颗行星,X=i处有行星i,行星J受到行星I的作用力,当且仅当i<=AJ.此时J受到作用力的大小为 Fi->j=Mi*Mj/(j-i) 其中A为很小的常量,故直观上说每颗行 ...

  4. bzoj 2339: [HNOI2011]卡农

    Description Solution 比较难想.... 我们先考虑去掉无序的这个条件,改为有序,最后除 \(m!\) 即可 设 \(f[i]\) 表示前\(i\)个合法集合的方案数 明确一点: 如 ...

  5. CTSC&APIO2017

    CTSC Day -1 因为越发感到自己与dalao们之间姿势水平的差距,本来打算再多学些姿势,但被老师叫去做noi,于是花了一两周的时间做完了noi2011~2015,也学到了一些奇怪姿势,还是挺有 ...

  6. bzoj 2229: [Zjoi2011]最小割

    Description 小白在图论课上学到了一个新的概念--最小割,下课后小白在笔记本上写下了如下这段话: "对于一个图,某个对图中结点的划分将图中所有结点分成两个部分,如果结点s,t不在同 ...

  7. Orz

    OR: 说实话,感觉Virtual Judge挺好使的,至少到现在,Uva都没注册成功过QAQ,估计是校园网的问题 不得不说现在课越来越多,而且对于我们这种学校ACM才开展两年的来说,时间真的好有限, ...

  8. Python中模块之queue的功能介绍

    模块之queue的功能介绍 队列的分类: 队列主要要分为两种 1.双向队列 2.单项队列 1. 单项队列 创建单项队列 格式:queue.Queue(obj) 例如:que = queue.Queue ...

  9. python2.7练习小例子(三)

        3):题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?     程序分析:假设该数为 x.1.则:x + 100 = n2, x + 100 + ...

  10. centos7.2中文乱码解决办法

    centos7.2 中文乱码解决办法 1.查看安装中文包: 查看系统是否安装中文语言包 (列出所有可用的公共语言环境的名称,包含有zh_CN) # locale -a |grep "zh_C ...