杰瑞科技汇

Java Servlet 如何实现输出?

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

Java Servlet 如何实现输出?-图1
(图片来源网络,侵删)

下面我们从基础到高级,全面地介绍 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 格式的数据。

关键点:

  1. MIME 类型:必须设置为 application/json
  2. 字符编码:设置为 UTF-8 以避免中文乱码。
  3. 数据格式:手动拼接 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(推荐)

  1. 添加依赖(在 pom.xml 中):

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version> <!-- 使用最新版本 -->
    </dependency>
  2. 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() 页面跳转

最佳实践:

  1. 始终设置字符编码:在调用 getWriter()getOutputStream() 之前,设置 response.setContentType("...;charset=UTF-8"),可以有效防止中文乱码。
  2. 优先使用库:处理 JSON、XML 等复杂格式时,优先使用 Jackson、Gson、JAXB 等成熟库,而不是手动拼接字符串。
  3. 选择正确的输出流:文本数据用 PrintWriter,二进制文件用 ServletOutputStream
  4. 善用状态码和重定向:根据业务逻辑正确使用 sendError()sendRedirect(),让客户端和搜索引擎更好地理解你的应用行为。
分享:
扫描分享到社交APP
上一篇
下一篇