1. Overview
1.概述
A common feature of web applications is the ability to download files.
网络应用的一个共同特点是能够下载文件。
In this tutorial, we’ll cover a simple example of creating a downloadable file and serving it from a Java Servlet application.
在本教程中,我们将介绍一个创建可下载文件并从Java Servlet应用程序中提供服务的简单例子。
The file we are using will be from the webapp resources.
我们所使用的文件将来自webapp资源。
2. Maven Dependencies
2.Maven的依赖性
If using Jakarta EE, then we wouldn’t need to add any dependencies. However, if we’re using Java SE, we’ll need the javax.servlet-api dependency:
如果使用Jakarta EE,那么我们就不需要添加任何依赖项。然而,如果我们使用Java SE,我们将需要javax.servlet-api依赖项。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
The latest version of the dependency can be found here.
最新版本的依赖关系可以在这里找到。
3. Servlet
3.Servlet
Let’s have a look at the code first and then find out what’s going on:
让我们先看一下代码,然后看看发生了什么事。
@WebServlet("/download")
public class DownloadServlet extends HttpServlet {
private final int ARBITARY_SIZE = 1048;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/plain");
resp.setHeader("Content-disposition", "attachment; filename=sample.txt");
try(InputStream in = req.getServletContext().getResourceAsStream("/WEB-INF/sample.txt");
OutputStream out = resp.getOutputStream()) {
byte[] buffer = new byte[ARBITARY_SIZE];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
}
}
}
3.1. Request End Point
3.1 请求端点
@WebServlet(“/download”) annotation marks the DownloadServlet class to serve requests directed at the “/download” end-point.
@WebServlet(“/download”)注解标志着DownloadServlet类将为指向“/download”端点的请求提供服务。
Alternatively, we can do this by describing the mapping in the web.xml file.
另外,我们也可以通过在web.xml文件中描述映射来做到这一点。
3.2. Response Content-Type
3.2.响应Content-Type
The HttpServletResponse object has a method called as setContentType which we can use to set the Content-Type header of the HTTP response.
HttpServletResponse对象有一个名为setContentType的方法,我们可以用它来设置HTTP响应的Content-Type标头。
Content-Type is the historical name of the header property. Another name was the MIME type (Multipurpose Internet Mail Extensions). We now simply refer to the value as the Media Type.
Content-Type是该头文件属性的历史名称。另一个名称是MIME类型(Multipurpose Internet Mail Extensions)。现在我们简单地把这个值称为媒体类型。
This value could be “application/pdf”, “text/plain”, “text/html”, “image/jpg”, etc., the official list is maintained by the Internet Assigned Numbers Authority (IANA) and can be found here.
这个值可以是 “application/pdf”、”text/plain”、”text/html”、”image/jpg “等等。,官方列表由互联网号码分配机构(IANA)维护,可以在这里找到。
For our example, we are using a simple text file. The Content-Type for a text file is “text/plain”.
对于我们的例子,我们使用的是一个简单的文本文件。文本文件的Content-Type是 “text/plain”。
3.3. Response Content-Disposition
3.3.响应Content-Disposition
Setting the Content-Disposition header in the response object tells the browser how to handle the file it is accessing.
在响应对象中设置Content-Disposition header,告诉浏览器如何处理它所访问的文件。
Browsers understand the use of Content-Disposition as a convention but it’s not actually a part of the HTTP standard. W3 has a memo on the use of Content-Disposition available to read here.
浏览器理解使用Content-Disposition是一种惯例,但它实际上不是HTTP标准的一部分。W3有一份关于使用Content-Disposition的备忘录,可以阅读这里。
The Content-Disposition values for the main body of a response will be either “inline” (for webpage content to be rendered) or “attachment” (for a downloadable file).
响应主体的Content-Disposition值将是 “inline”(用于渲染网页内容)或 “附件”(用于可下载的文件)。
If not specified, the default Content-Disposition is “inline”.
如果没有指定,默认Content-Disposition是 “inline”。
Using an optional header parameter, we can specify the filename “sample.txt”.
使用一个可选的标题参数,我们可以指定文件名 “sample.txt”。
Some browsers will immediately download the file using the given filename and others will show a download dialog containing our predefined value.
有些浏览器会立即使用给定的文件名下载文件,有些浏览器会显示一个包含我们预定义值的下载对话框。
The exact action taken will depend on the browser.
采取的具体行动将取决于浏览器。
3.4. Reading From File and Writing to Output Stream
3.4.从文件中读取并写入输出流
In the remaining lines of code, we take the ServletContext from the request, and use it to obtain the file at “/WEB-INF/sample.txt”.
在剩下的几行代码中,我们从请求中获取ServletContext,并使用它来获取”/WEB-INF/sample.txt “中的文件。
Using HttpServletResponse#getOutputStream(), we then read from the input stream of the resource and write to the response’s OutputStream.
使用HttpServletResponse#getOutputStream(),然后我们从资源的输入流中读取,并写入响应的OutputStream。
The size of the byte array we use is arbitrary. We can decide the size based on the amount of memory is reasonable to allocate for passing the data from the InputStream to the OutputStream; the smaller the nuber, the more loops; the bigger the number, the higher memory usage.
我们使用的字节数组的大小是任意的。我们可以根据分配给从InputStream到OutputStream的数据的合理内存量来决定大小;数值越小,循环越多;数值越大,内存用量越大。
This cycle continues until numByteRead is 0 as that indicates the end of the file.
这个循环一直持续到numByteRead为0,因为这表示文件的结束。
3.5. Close and Flush
3.5.关闭和平移
Stream instances must be closed after use to release any resources it is currently holding. Writer instances must also be flushed to write any remaining buffered bytes to it’s destination.
Stream实例在使用后必须被关闭,以释放它当前持有的任何资源。Writer实例也必须被刷新,以便将任何剩余的缓冲字节写到它的目的地。
Using a try-with-resources statement, the application will automatically close any AutoCloseable instance defined as part of the try statement. Read more about try-with-resources here.
使用try-with-resources语句,应用程序将自动关闭作为try语句一部分定义的任何AutoCloseable实例。阅读有关 try-with-resources 的更多信息这里。
We use these two methods to release memory, ensuring that the data we have prepared is sent out from our application.
我们使用这两种方法来释放内存,确保我们准备的数据从我们的应用程序中发送出去。。
3.6. Downloading the File
3.6.下载文件
With everything in place, we are now ready to run our Servlet.
一切准备就绪后,我们现在就可以运行我们的Servlet了。
Now when we visit the relative end-point “/download”, our browser will attempt to download the file as “simple.txt”.
现在,当我们访问相对端点“/download”时,我们的浏览器将尝试下载文件为 “simple.txt”。
4. Conclusion
4.总结
Downloading a file from a Servlet becomes a simple process. Using streams allow us to pass out the data as bytes and the Media Types inform the client browser what type of data to expect.
从Servlet中下载一个文件成为一个简单的过程。使用流允许我们将数据以字节的形式传递出去,而媒体类型则告知客户端浏览器应该期待什么类型的数据。
It is down to the browser to determine how to handle the response, however, we can give some guidelines with the Content-Disposition header.
如何处理响应是由浏览器决定的,但是,我们可以通过Content-Disposition头给出一些指南。
All code in this article can be found over over on GitHub.
本文的所有代码都可以在GitHub上找到。