Servlet 的输出核心依赖于 HttpServletResponse 对象,这个对象代表了服务器的响应,开发者可以通过它来设置响应头、状态码以及最重要的——响应体。

下面我们从基础到高级,全面地介绍 Servlet 的输出方式。
核心概念:HttpServletResponse 对象
当客户端请求一个 Servlet 时,Servlet 容器(如 Tomcat)会创建一个 HttpServletRequest 对象(包含请求信息)和一个 HttpServletResponse 对象(用于构建响应信息),然后将它们作为参数传递给 service() 方法。
我们所有的输出操作,都是通过这个 response 对象来完成的。
最简单的输出:向浏览器输出文本
这是最基础的用法,通常用于输出纯文本、JSON 或 XML 数据。
关键方法:
response.getWriter(): 返回一个PrintWriter对象,用于输出字符文本。适用于文本、HTML、JSON、XML 等字符数据。response.getOutputStream(): 返回一个ServletOutputStream对象,用于输出二进制数据。适用于图片、PDF、Excel 文件、压缩包等非文本数据。
重要提示:
getWriter()和getOutputStream()不能同时使用,否则会抛出IllegalStateException。
示例代码:输出纯文本
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/textOutput")
public class TextOutputServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 设置响应内容的MIME类型(告诉浏览器这是什么类型的数据)
// text/plain 表示纯文本
response.setContentType("text/plain;charset=UTF-8");
// 2. 获取PrintWriter对象
PrintWriter out = response.getWriter();
// 3. 使用PrintWriter输出内容
out.println("Hello, this is a plain text output from Servlet!");
out.println("当前时间: " + new java.util.Date());
// 4. 关闭流(可选,但推荐,Tomcat会在请求结束时自动关闭)
out.close();
}
}
示例代码:输出 HTML
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/htmlOutput")
public class HtmlOutputServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 设置响应内容的MIME类型和字符编码
// text/html 表示HTML文档
response.setContentType("text/html;charset=UTF-8");
// 2. 获取PrintWriter对象
PrintWriter out = response.getWriter();
// 3. 使用PrintWriter输出HTML内容
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset='UTF-8'>");
out.println("<title>Servlet HTML Output</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>欢迎来到 Servlet 世界!</h1>");
out.println("<p>这是由 Servlet 动态生成的 HTML 页面。</p>");
out.println("</body>");
out.println("</html>");
out.close();
}
}
输出 JSON 数据(现代 Web 开发核心)
在前后端分离的架构中,Servlet 经常作为后端 API,返回 JSON 格式的数据。
关键点:
- MIME 类型:必须设置为
application/json。 - 字符编码:设置为
UTF-8以避免中文乱码。 - 数据格式:手动拼接 JSON 字符串,或使用如 Jackson、Gson 等库。
示例代码:手动拼接 JSON
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/jsonOutput")
public class JsonOutputServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 设置响应内容的MIME类型和字符编码
response.setContentType("application/json;charset=UTF-8");
// 2. 获取PrintWriter对象
PrintWriter out = response.getWriter();
// 3. 手动构建JSON字符串
// 注意:手动拼接JSON容易出错,特别是处理复杂对象和特殊字符时。
// 实际项目中强烈推荐使用Jackson或Gson等库。
String jsonString = "{"
+ "\"id\": 101,"
+ "\"name\": \"张三\","
+ "\"age\": 30,"
+ "\"isStudent\": false,"
+ "\"courses\": [\"Java\", \"Servlet\", \"JSP\"]"
+ "}";
// 4. 输出JSON字符串
out.print(jsonString); // 使用 print() 而不是 println(),因为JSON通常不需要末尾的换行
out.close();
}
}
使用 Jackson 库输出 JSON(推荐)
-
添加依赖(在
pom.xml中):<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version> <!-- 使用最新版本 --> </dependency> -
Java 代码:
import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/jsonOutputWithJackson") public class JsonOutputWithJacksonServlet extends HttpServlet { private static final long serialVersionUID = 1L; private ObjectMapper objectMapper = new ObjectMapper(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 设置响应内容的MIME类型和字符编码 response.setContentType("application/json;charset=UTF-8"); // 2. 创建一个Java对象 User user = new User(); user.setId(102); user.setName("李四"); user.setAge(25); user.setStudent(true); user.setCourses(new String[]{"Python", "Spring Boot"}); // 3. 使用Jackson将Java对象转换为JSON字符串并输出 // objectMapper.writeValue() 可以直接写入 response 的输出流 objectMapper.writeValue(response.getOutputStream(), user); } } // 一个简单的POJO类 class User { private int id; private String name; private int age; private boolean isStudent; private String[] courses; // Getters and Setters (省略,实际开发中需要) public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public boolean isStudent() { return isStudent; } public void setStudent(boolean student) { isStudent = student; } public String[] getCourses() { return courses; } public void setCourses(String[] courses) { this.courses = courses; } }
输出文件下载
当需要让用户下载文件时,需要设置特定的响应头。
关键响应头:
Content-Type: 设置为application/octet-stream(表示二进制流,浏览器会提示下载)。Content-Disposition: 最重要。attachment; filename="..."表示作为附件下载,并指定下载时的文件名。Content-Length: 可选,但推荐,设置文件的大小,方便浏览器显示下载进度。
示例代码:提供一个文本文件下载
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/downloadFile")
public class FileDownloadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 要下载的文件路径(这里假设在webapp的files目录下)
String filePath = getServletContext().getRealPath("/files/sample.txt");
File downloadFile = new File(filePath);
FileInputStream inStream = new FileInputStream(downloadFile);
// 2. 设置响应头
response.setContentType("application/octet-stream");
response.setContentLength((int) downloadFile.length());
// 设置下载的文件名,如果文件名是中文,需要进行URL编码
String fileName = "下载示例文件.txt";
response.setHeader("Content-Disposition", "attachment; filename=\"" + java.net.URLEncoder.encode(fileName, "UTF-8") + "\"");
// 3. 获取输出流并写入文件内容
OutputStream outStream = response.getOutputStream();
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, bytesRead);
}
// 4. 关闭流
inStream.close();
outStream.close();
}
}
使用响应码(setStatus)
除了成功(200 OK),Servlet 还可以返回其他状态码,
404 Not Found: 请求的资源不存在。500 Internal Server Error: 服务器内部错误。302 Found / 301 Moved Permanently: 重定向。
示例代码:返回 404 错误
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/notFound")
public class NotFoundServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 显式设置状态码为404
response.sendError(HttpServletResponse.SC_NOT_FOUND, "您请求的资源不存在哦!");
}
}
示例代码:重定向(sendRedirect)
重定向会让客户端的浏览器向新的 URL 发送一个新的请求。
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 重定向到另一个URL(可以是本应用内的,也可以是外部的)
// 这会发送一个302状态码和Location响应头
response.sendRedirect("https://www.google.com");
// 也可以重定向到本应用的另一个Servlet
// response.sendRedirect(request.getContextPath() + "/textOutput");
}
}
总结与最佳实践
| 输出类型 | MIME 类型 | 关键方法 | 示例 |
|---|---|---|---|
| 纯文本 | text/plain |
response.getWriter().print() |
输出日志信息 |
| HTML | text/html |
response.getWriter().println() |
动态生成网页 |
| JSON | application/json |
response.getWriter().print() 或 Jackson.writeValue() |
前后端分离 API |
| XML | application/xml |
response.getWriter().print() |
WebService 接口 |
| 文件下载 | application/octet-stream |
response.getOutputStream().write() |
提供下载链接 |
| 重定向 | (无特定类型) | response.sendRedirect() |
页面跳转 |
最佳实践:
- 始终设置字符编码:在调用
getWriter()或getOutputStream()之前,设置response.setContentType("...;charset=UTF-8"),可以有效防止中文乱码。 - 优先使用库:处理 JSON、XML 等复杂格式时,优先使用 Jackson、Gson、JAXB 等成熟库,而不是手动拼接字符串。
- 选择正确的输出流:文本数据用
PrintWriter,二进制文件用ServletOutputStream。 - 善用状态码和重定向:根据业务逻辑正确使用
sendError()和sendRedirect(),让客户端和搜索引擎更好地理解你的应用行为。
