Servlet 实现文件上传

Servlet 实现文件上传

所谓文件上传就是将本地的文件发送到服务器中保存。例如我们向百度网盘中上传本地的资源或者我们将写好的博客上传到服务器等等就是典型的文件上传。

Servlet 3.0

上次完成文件下载功能使用的是 Servlet 2.5,但是想要完成文件上传,那么继续使用 Servlet 2.5 肯定不是一个好的选择,因此我们使用 Servlet 3.0 来完成文件上传。下面我来简单介绍一下 Servlet 3.0 的新特性:

  1. 新增的注解支持
    该版本新增了若干注解,用于简化 Servlet、过滤器(Filter)和监听器(Listener)的声明,这使得 web.xml 部署描述文件从该版本开始不再是必选的了。
  2. HttpServletRequest 对文件上传的支持
    此前,对于处理上传文件的操作一直是让开发者头疼的问题,因为 Servlet 本身没有对此提供直接的支持,需要使用第三方框架来实现,而且使用起来也不够简单。如今这都成为了历史,Servlet 3.0 已经提供了这个功能,而且使用也非常简单。

Servlet 3.0 的新特性当然肯定不止这些,但是其他的新特性在这里我们暂时还用不到,也就不做过多了解了。

必要条件

想要完成文件上传,肯定不是这么简单,它对浏览器端和服务器端都有许多的要求。

对浏览器的要求:

  1. 一个文件的大小一般肯定不止 1 KB,既然这样,那么要上传一个文件肯定不能使用 get 方式了,所以上传文件时必须采用 post 方式。
  2. 2.表单中必须有一个文件上传项 ,而且必须有 name 属性。
  3. 必须设置表单的 enctype 属性值为 multipart/form-data

对服务器的要求:

  1. 当然,我们肯定得使用 Servlet 3.0。
  2. Servlet 3.0 中接收普通上传组件(除了文件上传组件)通过 request.getParameter(String)接收,而文件上传组件通过 request.getPart(String)接收。
  3. Servlet 3.0 要求服务器必须是 Tomcat7 及其以上。

准备工作

工欲善其事,必先利其器。

  1. 首先,打开 Eclipse,新建一个 Dynamic Web Project
    Servlet 实现文件上传_第1张图片
  2. 键入项目名,选择运行时环境为 Apache Tomcat v7.0,选择 Servlet 版本为 3.0,然后点击 Finished
    Servlet 实现文件上传_第2张图片
  3. 在项目的 WebContent 目录下,新建一个文件夹 upload,用来存放上传过来的文件。
    Servlet 实现文件上传_第3张图片
  4. WebContent 目录下新建一个 index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>


    
        
        上传
    
    
    
        


  1. 使用 Tomcat 将次项目发布,并在浏览器中预览。

    将服务器启动,然后在浏览器中输入:http://localhost:8080/upload
    Servlet 实现文件上传_第4张图片

    好吧!样子有点丑,希望不要介意!如果出现以上界面,那么,准备工作就完成了!

完成案例

首先,新建一个 Servlet,在 Servlet 3.0 我们不必再为配置 web.xml 而烦恼了,只要要在 Servlet 的类名上面一行添加一个注解:

@WebServlet("/UploadServlet")

这个注解就相当与 Servlet 2.5 中的:


    UploadServlet
    club.luckylight.upload.UploadServlet


    UploadServlet
    /UploadServlet

这样比较,使用注解不是简便了很多。

然后,我们还需要添加另一个注解:

@MultipartConfig

该注解主要是为了辅助 Servlet 3.0 中 HttpServletRequest 提供的对上传文件的支持。该注解标注在 Servlet 上面,以表示该 Servlet 希望处理的请求的 MIME类型 是 multipart/form-data

接下来,我们就需要根据上传组件的 name 属性获取它了。这里我们使用 Path request.getPart(String) 方法。

Part part = request.getPart("file");

然后,我们就需要根据 part 获取头信息,然后根据头信息获取文件的路径。

在浏览器抓包,获取头信息为:

Servlet 实现文件上传_第5张图片

据此,我们可以获取文件名或者文件路径。

String header = part.getHeader("content-disposition");
String path = header.substring(header.indexOf("filename=") + 10, header.length() - 1);

由于获取的有可能是文件名,也有可能是文件路径,为此,有必要编写一个工具类,用来获取文件的真实名称。

/**
 * 根据文件的路径获取文件真实名称
 * 
 * @param path
 *            文件的路径
 * @return 文件名称
 */
public static String getRealName(String path) {
    int index = path.lastIndexOf("\\");

    if (index == -1) {
        index = path.lastIndexOf("/");
    }

    return path.substring(index + 1);
}

然后,调用这个方法,获得文件名。

String name = UploadUtils.getRealName(path);

接下来,我们有必要,给每个文件分配一个存放目录,因此我又编写了一个方法,用来生成一个目录。

/**
 * 根据文件名返回一个目录
 * 
 * @param name
 *            文件名称
 * @return 目录
 */
public static String getDir(String name) {
    int i = name.hashCode();
    String hex = Integer.toHexString(i);
    int j = hex.length();

    for (int k = 0; k < 8 - j; k++) {
        hex = "0" + hex;
    }

    return "/" + hex.charAt(0) + "/" + hex.charAt(1);
}

到此,万事俱备,只欠东风。我们只需要将文件拷贝到服务器。

// 获取文件的真实路径
String realPath = this.getServletContext().getRealPath("/upload" + dir);
File file = new File(realPath);

if (!file.exists()) {
    file.mkdirs();
}

// 获取输入流
InputStream inputStream = part.getInputStream();
// 定义输出流
FileOutputStream outputStream = new FileOutputStream(new File(file, name));

// 从输入流中读入数据并写到输出字节流中
int len = -1;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
    outputStream.write(bytes, 0, len);
}

// 关闭资源
outputStream.close();
inputStream.close();

// 删除临时文件
part.delete();

下面来测试一下:

Servlet 实现文件上传_第6张图片

然后,在 Tomcatwebapps -> 项目名 -> upload 中就可以找到上传成功的文件了!

最后,我们打开音乐来试验下是否真的上传成功了?

Servlet 实现文件上传_第7张图片

嗯!薛之谦低沉的声音从耳机中传来,看来确实是上传成功了!

完整代码

UploadServlet.java

package club.luckylight.upload;

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

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

import club.luckylight.util.UploadUtils;

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

    private static final long serialVersionUID = 5661013723204858883L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 获取文件上传组件
        Part part = request.getPart("file");

        // 获取文件的路径
        String header = part.getHeader("content-disposition");
        String path = header.substring(header.indexOf("filename=") + 10, header.length() - 1);

        // 获取文件名
        String name = UploadUtils.getRealName(path);

        // 获取文件的存放目录
        String dir = UploadUtils.getDir(name);

        String realPath = this.getServletContext().getRealPath("/upload" + dir);
        File file = new File(realPath);
        if (!file.exists()) {
            file.mkdirs();
        }

        // 对拷流
        InputStream inputStream = part.getInputStream();
        FileOutputStream outputStream = new FileOutputStream(new File(file, name));
        int len = -1;
        byte[] bytes = new byte[1024];
        while ((len = inputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
        }

        // 关闭资源
        outputStream.close();
        inputStream.close();

        // 删除临时文件
        part.delete();

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().print("文件" + name + "上传成功!");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

UploadUtils.java

package club.luckylight.util;

public class UploadUtils {

    /**
     * 根据文件的路径获取文件真实名称
     * 
     * @param path
     *            文件的路径
     * @return 文件名称
     */
    public static String getRealName(String path) {
        int index = path.lastIndexOf("\\");

        if (index == -1) {
            index = path.lastIndexOf("/");
        }

        return path.substring(index + 1);
    }

    /**
     * 根据文件名返回一个目录
     * 
     * @param name
     *            文件名称
     * @return 目录
     */
    public static String getDir(String name) {
        int i = name.hashCode();
        String hex = Integer.toHexString(i);
        int j = hex.length();

        for (int k = 0; k < 8 - j; k++) {
            hex = "0" + hex;
        }

        return "/" + hex.charAt(0) + "/" + hex.charAt(1);
    }
}

总结

这样,文件上传案例就完成了,希望大家喜欢。

你可能感兴趣的:(Servlet 实现文件上传)