杰瑞科技汇

java response输出

HttpServletResponse

无论你使用哪种框架,底层的核心都是 javax.servlet.http.HttpServletResponse 对象,它代表了服务器对客户端的响应,所有的输出操作,最终都是通过这个对象或其包装对象来完成的。


在原生 Java Servlet 中输出

这是最基础的方式,理解它有助于理解更高级框架的原理。

输出文本(HTML, JSON, XML 等)

使用 PrintWriterOutputStream

示例:输出 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("/textOutput")
public class TextOutputServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 1. 设置响应内容类型和字符编码
        // 告诉浏览器我们返回的是 JSON,并使用 UTF-8 编码,防止中文乱码
        response.setContentType("application/json;charset=UTF-8");
        // 2. 获取 PrintWriter 对象
        PrintWriter out = response.getWriter();
        // 3. 写入响应内容
        String jsonResponse = "{\"name\":\"张三\", \"age\":30, \"city\":\"北京\"}";
        out.print(jsonResponse);
        // 4. 关闭流(虽然 Tomcat 等容器会自动关闭,但显式关闭是好习惯)
        out.close();
    }
}

输出二进制文件(图片、PDF、Excel 等)

使用 OutputStream

示例:下载一个文本文件

import java.io.File;
import java.io.FileInputStream;
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("/fileDownload")
public class FileDownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        // 1. 设置响应头,告诉浏览器这是一个要下载的文件
        response.setContentType("application/octet-stream");
        // 设置下载文件的默认名称
        String headerKey = "Content-Disposition";
        String headerValue = "attachment; filename=\"example.txt\"";
        response.setHeader(headerKey, headerValue);
        // 2. 获取文件的输入流
        File file = new File(getServletContext().getRealPath("/files") + File.separator + "example.txt");
        FileInputStream inStream = new FileInputStream(file);
        // 3. 获取响应的输出流
        ServletOutputStream outStream = response.getOutputStream();
        // 4. 使用缓冲区进行读写
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, bytesRead);
        }
        // 5. 关闭流
        inStream.close();
        outStream.close();
    }
}

在 Spring Boot 中输出

Spring Boot 极大地简化了 Response 的输出,主要通过 @ResponseBody 注解和 ResponseEntity

使用 @ResponseBody(最简单)

直接在 Controller 方法上使用 @ResponseBody,返回的对象会被 Spring 的 HttpMessageConverter 自动序列化为 JSON(默认情况下)。

示例:返回一个对象自动转为 JSON

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // @RestController = @Controller + @ResponseBody
public class MyRestController {
    @GetMapping("/user")
    public User getUser() {
        User user = new User();
        user.setName("李四");
        user.setAge(25);
        return user; // Spring Boot 会自动将这个 User 对象转为 JSON 并写入响应体
    }
}
// 假设的 User 类
class User {
    private String name;
    private int age;
    // getters and setters
}

访问 http://localhost:8080/user,你会得到类似 {"name":"李四","age":25} 的响应。

使用 ResponseEntity(最灵活)

ResponseEntity 允许你完全控制 HTTP 响应的状态码、响应头和响应体

示例:自定义状态码和响应头

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
@RestController
public class ResponseEntityController {
    @GetMapping("/customResponse")
    public ResponseEntity<String> getCustomResponse() {
        // 1. 创建自定义响应头
        HttpHeaders headers = new HttpHeaders();
        headers.add("Custom-Header", "MyValue");
        headers.add("Content-Type", "application/json;charset=UTF-8");
        // 2. 创建响应体
        String body = "{\"message\":\"这是一个自定义的响应\"}";
        // 3. 返回 ResponseEntity,指定状态码、响应头和响应体
        return new ResponseEntity<>(body, headers, HttpStatus.OK);
    }
    @GetMapping("/notFound")
    public ResponseEntity<String> getNotFoundResponse() {
        return new ResponseEntity<>("资源未找到", HttpStatus.NOT_FOUND);
    }
}

直接写入 HttpServletResponse(不常用,但有时需要)

当你需要使用 OutputStream 写二进制文件时,可以直接注入 HttpServletResponse

示例:下载文件

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@Controller
public class FileDownloadController {
    @GetMapping("/download")
    public void downloadFile(HttpServletResponse response) throws IOException {
        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=\"report.pdf\"");
        // 获取文件输入流
        File file = new File("path/to/your/report.pdf");
        InputStream inStream = new FileInputStream(file);
        // 获取响应输出流并写入
        org.apache.commons.io.IOUtils.copy(inStream, response.getOutputStream());
        inStream.close();
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }
}

注意:这种方式下,Controller 方法的返回类型通常是 voidString(如 "forward:viewName"),因为你要手动操作 response 对象。


总结与对比

场景/框架 核心对象/注解 优点 缺点 适用场景
原生 Servlet HttpServletResponse 底层清晰,不依赖框架 代码繁琐,需要手动处理流、编码等 学习 Servlet 原理,旧项目维护
Spring Boot (@ResponseBody) @ResponseBody / @RestController 极其简洁,自动序列化 对响应的控制力较弱(主要是状态码和体) RESTful API 开发,返回 JSON/XML 等文本数据
Spring Boot (ResponseEntity) ResponseEntity 最灵活,可全面控制响应 代码比 @ResponseBody 稍多 需要自定义状态码、响应头的复杂 API 响应
Spring Boot (直接注入) HttpServletResponse 功能强大,可处理二进制流 违背了 Spring 的 MVC 设计理念,代码耦合 下载文件、流式响应等必须操作原始 response 的场景

最佳实践建议

  1. 对于 RESTful API:优先使用 @RestController + @ResponseBody,如果需要更精细的控制(如设置特定状态码、添加自定义头),升级到 ResponseEntity,这是现代 Java Web 开发的主流方式。
  2. 对于文件下载:在 Spring Boot 中,推荐使用 ResponseEntity<byte[]> 的方式,这样更符合 Spring 的设计模式,但如果文件特别大,直接注入 HttpServletResponse 并使用流式传输可能更节省内存。
  3. 始终注意字符编码:在输出文本(尤其是中文)时,务必设置正确的 Content-Type,包含 charset=UTF-8,以防止乱码,在 Spring Boot 中,通常在 application.properties 中配置 spring.http.encoding.charset=UTF-8 即可全局解决。
分享:
扫描分享到社交APP
上一篇
下一篇