Java for Web学习笔记(九):Servlet(7)上传文件

时间:2023-02-24 19:12:37

上传文件

Servlet的参数设置

采用annotation方式如下:

@WebServlet(
name = "TicketServlet",
urlPatterns = {"/tickets"},
loadOnStartup = 1
)
/* MultipartConfig配置了本Servlet的文件上传参数,
* location:这里没有列出的是location参数,表示存放临时文件的位置,一般无需配置,选择缺省的临时文件夹
* fileSizeThreshold:表示收到文件到达这么大后,不在放入缓存,而是写入临时文件。本例中,如果文件小于5M,则存放在缓存,然后被垃圾回收;同样的,如果采用临时文件方式,临时文件也会被删除。
* maxFileSize:限制文件的最大值,本例文件不超过20M
* maxRequestSize:由于可能同时上传多个文件,servlet可能会被同时请求,此限制总量。
*/
@MultipartConfig(
fileSizeThreshold = 5_242_880, // 5M
maxFileSize = 20_971_520L, //20M
maxRequestSize = 41_943_040L //40M
)

采用web.xml的方式如下:

<servlet>
<multipart-config>
<location>......</location>
<file-size-threshold>......</file-size-threshold>
<max-file-size>......</<max-file-size>
<max-request-size>......</max-request-size>
</multipart-config>
</servlet>

Multipart上传文件

下面是Create Ticket的HTML,文件上传有关的是<form… enctype="multipart/form-data"/><input type="file" name="file1"/>

<!DOCTYPE html>
<html>
<head>
<title>Customer Support</title>
</head>
<body>
<h2>Create a Ticket</h2>
<form method="POST" action="tickets" enctype="multipart/form-data">
<input type="hidden" name="action" value="create"/>
Your Name<br/>
<input type="text" name="customerName"/><br/><br/>
Subject<br/>
<input type="text" name="subject"/><br/><br/>
Body<br/>
<textarea name="body" rows="5" cols="30"></textarea><br/><br/>
<b>Attachments</b><br/>
<input type="file" name="file1"/><br/><br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>

点击submite,将触发一个action=create的POST请求,抓包如下:

POST /customer-support/tickets HTTP/1.1
Host: 191.8.1.103:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://191.8.1.103:8080/customer-support/tickets?action=create
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------168557226814076645131805352216
Content-Length: 729

-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="action"

create
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="customerName"

Wei
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="subject"

moon
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="body"

Hello,world
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="file1"; filename="moon.txt"
Content-Type: text/plain

Hello, Moon!
Hello, my friend!

-----------------------------168557226814076645131805352216--

先对比普通的form-data的HTTP POST消息体的例子如下。和GET的参数传递部分是一样的。

action=create&customerName=j&subject=jj&body=jjjj

现在,我们在HTML中指明enctype="multipart/form-data",因此在HTTP POST的封装中采用了multipart/form-data的方式。这在RFC1867 Form-based File Uploadin HTML中有详细的规定,包括file类型。对于普通的form-data的内容读取有下面两个方式:

(1)通过javax.servlet.http.part类来读取

Part part1 = request.getPart("customerName");
System.out.println(part1.getHeader("Content-Disposition"));
InputStream is = part1.getInputStream();
int len = is.available();
byte[] buff = new byte[len];
is.read(buff);
System.out.println(new String(buff));

(2)提供了更直接的方式

System.<em>out</em>.println(<strong>request.getParameter("customerName"));</strong>

毫无疑问,我们会采用第二种方式,但是第一种方式提供了通用的读取multipart的方法。我们将使用该方式读取上传文件部分,小例子的代码如下:

private void createTicket(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
//获取普通的form-data信息
String customerName = request.getParameter("customerName");
String subject = request.getParameter("subject");
String body = request.getParameter("body");

//读取上传文件部分:获取相应的multipart
Part filePart = request.getPart("file1");
//读取上传文件部分:getSize()是multipart中信息的大小,而非整个multipart的大小,对应即为上传文件的大小
if(filePart != null && filePart.getSize() > 0){
// 获取文件名称,即Content-Disposition: form-data; name="file1"; filename="moon.txt"中的filename,我们可以通过filePart.getHeader("Content-Disposition")分析获取。javax.servlet.http.Part直接提供了方法
String fileName = filePart.getSubmittedFileName();
// 获取文件上传内容放。
InputStream inputStream = filePart.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int read;
final byte[] bytes = new byte[1024];
while((read = inputStream.read(bytes)) != -1){
outputStream.write(bytes, 0, read);
}
/* 如果是二进制,通过outputStream.toByteArray()获得byte[]。任何格式均适合二进制;如果是文本文件,可以先通过filePart.getHeader("Content-Type")来确认,直接outputStream.toString() */
… …
}
......
}


相关链接: 我的Professional Java for Web Applications相关文章