J2EE开发技术点3:文件上传下载

前言

文件上传下载在类似注册表单中经常会使用到,这里也单独抽取出来,以便日后直接使用。文件上传是以流的方式提交到服务器的,这点与普通的表单提交不同,所以需要对有文件上传域的表单特别声明,这样提交到后台的时候就可以以流的方式进行存取了。实现这个功能我们需要借助Apache的两个jar包:commons-fileupload-1.2.2.jar
commons-io-2.0.1.jar。这两个jar可以在网上直接下载。

文件上传

1、创建一个web工程,并导入上面两个jar包,如下图:
J2EE开发技术点3:文件上传下载
2、创建文件上传表单

  <body>
    <form action="uploadServlet" enctype="multipart/form-data" method="post">
        <h3>文件上传</h3><br>
        上传文件1:<input type="file" name="pic1"><br>
        上传文件2:<input type="file" name="pic2">
    </form>
  </body>

3、建立uploadServlet.java文件

package com.rhwayfun.servlet;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
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.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadServlet extends HttpServlet {

    @SuppressWarnings("unchecked")
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        //1、创建DiskFileItemFactory工厂
        FileItemFactory factory = new DiskFileItemFactory();
        //2、创建一个文件上传解析器
        ServletFileUpload su = new ServletFileUpload(factory);
        //解决上传文件名乱码
        su.setHeaderEncoding("UTF-8"); 
        List<FileItem> list = null;
        //获取输出流对象
        PrintWriter out = response.getWriter();
        try {
            //3、解析Request对象,以便对文件上传域对象进行处理
            list= su.parseRequest(request);
            for (FileItem fileItem : list) {
                if(fileItem.isFormField()){//普通表单域
                    if(fileItem.getFieldName().equals("username")){
                        //处理表单提交字段,解决普通输入域中文乱码问题
                        String username = fileItem.getString("utf-8");
                        out.print(username + ",");
                    }
                }else{//文件上传域
                    //得到上传文件的保存目录,将上传的文件保存到WebRoot下的upload文件夹中
                    String path = this.getServletContext().getRealPath("/WEB-INF/upload");
                    //浏览器请求路径,这是一个相对路径
                    String url = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/upload/";
                    //获取上传文件的文件名
                    String fileName = fileItem.getName();
                    //得到上传文件的扩展名
                    String extName = fileName.substring(fileName.lastIndexOf(".")+1);
                    //服务器只支持jpg和gif两种格式的文件
                    if(extName.equals("jpg") || extName.equals("gif")){
                        File uFile = new File(path);
                        //如果保存的目录不存在就创建一个目录
                        if(!uFile.exists()){
                            uFile.mkdirs();
                        }
                        File file = new File(path,fileName);
                        //写入文件到保存的目录中
                        fileItem.write(file);
                    }else{
                        System.out.println("文件格式不支持");
                    }

                }
            }
            out.print("上传成功");
        } catch (Exception e) {
            out.print("对不起,上传失败");
            e.printStackTrace();
        }
    }
}

4、配置web.xml文件

<servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.rhwayfun.servlet.UploadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/uploadServlet</url-pattern>
  </servlet-mapping>

5、验证是否上传成功
J2EE开发技术点3:文件上传下载
J2EE开发技术点3:文件上传下载

文件下载
实现文件下载需要得到服务器上指定目录下的所有资源,所以第一步是创建一个Servlet用于得到所有的下载资源列表,该Servlet在获取所有资源之后,返回到下载列表的页面,用户可以对其中下载列表进行下载。

首先创建ListFileServlet,用于获取下载资源列表:

package com.rhwayfun.servlet;

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

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

public class ListFileServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //上传文件的时候保存的路径
        String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
//      System.out.println(uploadPath);
        //创建一个Map用于保存该目录下的所有文件
        Map<String,String> files = new HashMap<String,String>();
        //遍历该目录,并保存到该map中
        listFileAndSave(new File(uploadPath),files);
        //返回给浏览器端
        request.setAttribute("files", files);
        request.getRequestDispatcher("listFile.jsp").forward(request, response);
    }

    private void listFileAndSave(File file, Map<String, String> files) {
        //首先判断是否是一个目录
        if(!file.isFile()){//表示这是一个目录
            //得到该目录下的所有文件
            File[] fs = file.listFiles();
            //遍历列出的所有文件,直到全部都是文件而不是目录为止
            for (File file2 : fs) {
                listFileAndSave(file2, files);
            }
        }else{//表示这是一个文件
            //需要得到这个文件真实的文件名,比如一个文件为
            //D:\apache-tomcat-7.0.42\webapps\\uploadAndDownload\WEB-INF\\upload\c.jpg
            //那么其真实的文件名应该是c.jpg才对,所以需要对该文件进行字符串的截取
//          System.out.println(file.getPath());
            String fileName = file.getPath().substring(file.getPath().lastIndexOf("\\")+1);
            files.put(file.getPath(), fileName);
        }
    }
}

然后配置web.xml文件:

<servlet>
    <servlet-name>ListFileServlet</servlet-name>
    <servlet-class>com.rhwayfun.servlet.ListFileServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>ListFileServlet</servlet-name>
    <url-pattern>/listFileServlet</url-pattern>
  </servlet-mapping>

接着编写listFile.jsp页面:

<%@ page language="java" import="java.util.*" 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 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    <title>下载列表</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
  </head>

  <body>
  <form action="">
    <c:forEach items="${files }" var="file">
        <c:url value="downLoadServlet" var="downurl">
             <c:param name="filepath" value="${file.key}"></c:param>
        </c:url>
       ${file.value}<a href="${downurl}">下载</a>
       <br>
    </c:forEach>
    </form>
  </body>
</html>

为了防止出错,我们先测试以上代码是否有错:
J2EE开发技术点3:文件上传下载

ok,经过测试,我们的代码是正确的。接下来就要实现下载功能了,首先需要编写DownLoadServlet类,对下载的资源进行处理,请看代码:

package com.rhwayfun.servlet;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

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

public class DownLoadServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        //获取要下载文件的服务器路径
        String filepath = request.getParameter("filepath");
        //获取文件名
        String filename = filepath.substring(filepath.lastIndexOf("\\")+1);
        //设置响应头,控制浏览器下载该文件
        response.setContentType("application/x-msdownload");
        response.setHeader("Content-disposition", "attachment;filename="+ new String(filename.getBytes("utf-8"), "ISO-8859-1"));
        //创建输入流
        FileInputStream fis = new FileInputStream(filepath);
        //读取文件至缓冲区中
        byte[] data = new byte[fis.available()];
        fis.read(data);
        //关闭流
        fis.close();
        //创建输出流
        OutputStream os = response.getOutputStream();
        //写入到文件中
        os.write(data);
        os.close();
    }
}

再配置web.xml文件:

<servlet>
    <servlet-name>DownLoadServlet</servlet-name>
    <servlet-class>com.rhwayfun.servlet.DownLoadServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>DownLoadServlet</servlet-name>
    <url-pattern>/downLoadServlet</url-pattern>
  </servlet-mapping>

最后,我们来测试我们的下载功能是否正常:
J2EE开发技术点3:文件上传下载

小结
至此,我们就把文件上传域下载两个功能做完了,实现思路不复杂,主要有一些细节的处理,比如文件名中文乱码问题等。文件上传下载是特别实用的功能,需要介绍的内容也就这么多了。在以后的开发中,直接复用这些代码就很方便了。

上一篇:数据结构基础


下一篇:剑指offer系列之四:重建二叉树