JavaEE 使用Servlet上传文件

Servlet3.0提供了javax.servlet.http.Part类,通过它可以很方便的上传文件。

Part类介绍

javax.servlet.http.Part是Servlet3.0中新增加的API之一。每个Part对象表示一个文件上传域,该对象提供了许多方法来获得上传文件的类型、大小、输入流等,还提供了一个write方法将文件写入服务器磁盘。

Part类的常用方法有:
- getHeaderNames:获得用户请求头中的MIME值名称;
- getContentType:获得上传文件的类型;
- getSize:获得上传文件的大小;
- getSubmittedFileName:获得上传文件在客户端的绝对路径;
- write:将上传文件写入服务器磁盘。

使用Servlet上传文件

Servlet

先来看我们的程序,首先是处理文件上传的Servlet类:

// UploadServlet.java

@WebServlet(
        urlPatterns = { "/upload" }, 
        initParams = { 
                @WebInitParam(name = "basepath", value = "F:\\workspace\\javaEE\\WebDemo\\res\\")
        }, 
        asyncSupported = true)
@MultipartConfig
public class UploadServlet extends HttpServlet {
    private String basePath;
    private static final long serialVersionUID = 1L;

    public void init(ServletConfig config) throws ServletException {
        basePath=config.getInitParameter("basepath");
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        AsyncContext ac=request.startAsync(request, response);
        ac.setTimeout(10*60*1000);
        ac.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                AsyncContext ac=event.getAsyncContext();
                ac.getResponse().getWriter().println("文件上传成功!<br>");
                ac.dispatch("/upload");
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                event.getAsyncContext().getResponse().getWriter().println("文件上传出错!<br>");
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                event.getAsyncContext().getResponse().getWriter().println("开始上传文件...<br>");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                event.getAsyncContext().getResponse().getWriter().println("文件上传超时!<br>");
            }
        });
        ac.start(new UploadTask(ac, basePath));
    }

    public static class UploadTask implements Runnable {
        private AsyncContext ac;
        private String basePath;

        public UploadTask(AsyncContext a, String bp) {
            ac=a;
            basePath=bp;
        }

        @Override
        public void run() {
            HttpServletRequest request=(HttpServletRequest) ac.getRequest();
            HttpServletResponse response=(HttpServletResponse) ac.getResponse();

            response.setContentType("text/html;charset=GBK");
            PrintWriter out;
            try {
                out = response.getWriter();
                Part part=request.getPart("file");
                // 文件上传头
                Collection<String> headers=part.getHeaderNames();
                // 文件类型
                String fileType=part.getContentType();
                // 文件大小
                long fileSize=part.getSize();
                // 客户端上传的文件名
                String submitName=part.getSubmittedFileName();
                // 服务器保存的文件名
                String fileName=UUID.randomUUID().toString()+
                        submitName.substring(submitName.lastIndexOf('.'));

                out.println("HEADER: "+"<br>");
                for(String header : headers)
                    out.println(header+"="+part.getHeader(header)+"<br>");
                out.println("文件类型: "+fileType+"<br>");
                out.println("文件大小: "+fileSize+"<br>");
                out.println("客户端文件名: "+submitName+"<br>");
                out.println("服务端文件名: "+fileName+"<br>");

                if(fileType.startsWith("image"))
                    part.write(basePath+"image\\"+fileName);
                else if(fileType.startsWith("audio"))
                    part.write(basePath+"audio\\"+fileName);
                else if(fileType.startsWith("video"))
                    part.write(basePath+"video\\"+fileName);
                else
                    part.write(basePath+"file\\"+fileName);

                ac.complete();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ServletException e) {
                e.printStackTrace();
            }
        }
    }
}

由于上传文件是一个耗时的工作,所以我们使用异步处理来上传文件,关于异步处理的内容可以参考我的另一篇文章:《JavaEE Servlet的异步处理》

在UploadTask中进行实际的文件上传工作。request.getPart方法可以获得文件上传域对象,我们通过调用它的一系列方法输出了文件信息,最后调用write方法将其写入磁盘。

另外还要注意,如果想要上传文件,Servlet需要使用@MultipartConfig注解配置。

jsp页面

下面还需要一个jsp页面来选择要上传的文件:

<!-- upload.jsp -->

<body>
<form method="post" action="upload" enctype="multipart/form-data">
    选择文件: <input type="file" id="file" name="file"><br>
    <input type="submit" value="上传"><br>
</form>
</body>

form表单中有几个需要注意的地方:
1. 多了一个enctype属性,它指定表单数据的编码方式,该属性有如下三个值:
- application/x-www-form-urlencoded:这是默认的方式,此方式只会发送文件域的文本框中的字符串,即用户选择文件的绝对路径;
- multipart/form-data:此方式以二进制流处理表单数据,这种方式会发送文件域指定文件的内容;
- text/plain:此方式当表单的action属性为mailto:URL时比较方便,主要适用于直接通过表单发送邮件的方式。
2. 有一个类型为file的input,它就是文件上传域,它用于选择要上传的文件。

上传文件

现在我们开始上传文件,运行Web应用,选择upload.jsp页面,如下所示:
upload_jsp

然后我们随便选择一个文件,点击上传,结果如下(如果文件较大,可能需要等待较长的时间):
upload_servlet

可以看到,这里上传的文件在客户端和服务端具有不同的名字。这是因为如果有多位用户上传文件,他们上传的文件难免会有相同的文件名,所以我们使用java.util.UUID类来产生新的文件名。

UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算方法,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分组合而成:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,经过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡则以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。

源码

上述源代码已经上传到github:
https://github.com/jzyhywxz/WebDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值