如何在不使用 HTML 表单的情况下将文件上传到 Java Servlet

使用由 HTML 代码制作的 Web 表单将文件从 Web 浏览器上传到服务器是很简单的。这通常称为基于表单的文件上传,通常适用于基于 Web 的应用程序。独立或基于命令行的应用程序——有时需要将文件上传到 Web 服务器,但不能使用 HTML 格式的上传表单?那么,本文将通过实现以下解决方案来回答这个问题:

  • 服务器:使用 Java servlet 接收从客户端上传的文件,并将其保存到服务器磁盘上的文件中。
  • 客户端:是一个基于命令行的程序,它将HTTP POST 请求连同文件的二进制数据一起发送到 servlet。

我们可以将此方法称为基于非表单的文件上传。请记住,这不是 FTP 上传,因为它仍然使用 HTTP 协议来传输文件。

让我们来看看每个部分是如何实现的。

 

编码文件上传 Servlet

编写一个 Java servlet,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package net.codejava.servlet;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * This servlet demonstrates how to receive file uploaded from the client
 * without using third-party upload library such as Commons File Upload.
 * @author www.codejava.net
 */
public class ReceiveFileServlet extends HttpServlet {
    static final String SAVE_DIR = "E:/Test/Upload/";
    static final int BUFFER_SIZE = 4096;
     
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
         
        // Gets file name for HTTP header
        String fileName = request.getHeader("fileName");
        File saveFile = new File(SAVE_DIR + fileName);
         
        // prints out all header values
        System.out.println("===== Begin headers =====");
        Enumeration<String> names = request.getHeaderNames();
        while (names.hasMoreElements()) {
            String headerName = names.nextElement();
            System.out.println(headerName + " = " + request.getHeader(headerName));        
        }
        System.out.println("===== End headers =====\n");
         
        // opens input stream of the request for reading data
        InputStream inputStream = request.getInputStream();
         
        // opens an output stream for writing file
        FileOutputStream outputStream = new FileOutputStream(saveFile);
         
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead = -1;
        System.out.println("Receiving data...");
         
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
         
        System.out.println("Data received.");
        outputStream.close();
        inputStream.close();
         
        System.out.println("File written to: " + saveFile.getAbsolutePath());
         
        // sends response to client
        response.getWriter().print("UPLOAD DONE");
    }
}

此 servlet 在其doPost()中处理 HTTP POST 请求方法。这段代码中有一些重要的点:

  • 上传文件的名称是从名为“ fileName ”的 HTTP 标头中检索的——该标头由客户端设置。
  • 我们创建了一个saveFile对象,以便将上传文件保存到磁盘中。它的路径由SAVE_DIR常量和fileName头构成。FileOutputStream对象包装此saveFile以将字节数组写入文件。
  • 最重要的一点是从HttpServletRequest打开InputStream以读取从客户端传输的字节。
  • 我们使用 while 循环从请求的输入流中重复读取字节数组并将它们写入saveFile的输出流。这是微不足道的。
  • 最后,始终关闭打开的输入流和输出流,然后向客户端发送响应(在这种情况下,是一条简单的文本消息“UPLOAD DONE”)。

现在让我们看看客户端是如何实现的。

 

编写文件上传客户端程序

以下是客户端程序的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
 
/**
 * This program demonstrates how to upload files to a web server
 * using HTTP POST request without any HTML form.
 * @author www.codejava.net
 *
 */
public class NonFormFileUploader {
    static final String UPLOAD_URL = "http://localhost:8080/CodeWeb/ReceiveFileServlet";
    static final int BUFFER_SIZE = 4096;
 
    public static void main(String[] args) throws IOException {
        // takes file path from first program's argument
        String filePath = args[0];
        File uploadFile = new File(filePath);
 
        System.out.println("File to upload: " + filePath);
 
        // creates a HTTP connection
        URL url = new URL(UPLOAD_URL);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setUseCaches(false);
        httpConn.setDoOutput(true);
        httpConn.setRequestMethod("POST");
        // sets file name as a HTTP header
        httpConn.setRequestProperty("fileName", uploadFile.getName());
 
        // opens output stream of the HTTP connection for writing data
        OutputStream outputStream = httpConn.getOutputStream();
 
        // Opens input stream of the file for reading data
        FileInputStream inputStream = new FileInputStream(uploadFile);
 
        byte[] buffer = new byte[BUFFER_SIZE];
        int bytesRead = -1;
 
        System.out.println("Start writing data...");
 
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
 
        System.out.println("Data was written.");
        outputStream.close();
        inputStream.close();
 
        // always check HTTP response code from server
        int responseCode = httpConn.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            // reads server's response
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    httpConn.getInputStream()));
            String response = reader.readLine();
            System.out.println("Server's response: " + response);
        else {
            System.out.println("Server returned non-OK code: " + responseCode);
        }
    }
}

这里的重点是我们使用HttpURLConnection对象在 servlet 的 URL(由常量UPLOAD_URL标识)处向服务器发送 HTTP POST 请求,并打开此连接的OutputStream以写入上传文件的字节数组。该文件的路径作为程序的第一个参数传递。


 

与 servlet 类似,我们使用 while 循环从文件的输入流/请求的输出流读取/写入字节数组。

最后,我们在使用请求的输入流关闭两个输入/输出流后从服务器读取响应。

 

测试文件上传应用程序

在 Tomcat 等 servlet 容器上部署ReceiveFileServlet并启动服务器。然后通过执行以下命令运行客户端程序:

java NonFormFileUploader e:\Test\RecordAudio.wav

这里我们传递一个要上传的 WAV 音频文件。服务器将产生一些输出,如下图所示:

从这个日志中,我们可以检查从客户端发送的所有 HTTP 标头的值。几乎所有的值都是由 Java 自动设置的,除了文件名是从客户端手动设置的。

这是客户端程序的输出:

笔记:

  • 服务器和客户端都没有处理多部分请求(这是基于表单的上传的标准)。请注意,请求的内容类型设置为 application/x-www-form-urlencoded 而不是 multipart/form-data
  • 因此客户端程序不能应用于接受多部分请求的服务器。服务器端必须像 ReceiveFileServlet那样实现。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值