杰瑞科技汇

Java 如何获取 request 对象?

在 Java Web 开发中,获取 HttpServletRequest 对象是常见的需求,根据不同的运行环境和框架,获取方式有所不同,下面我将为你详细梳理在各种主流场景下如何获取 request 对象。

Java 如何获取 request 对象?-图1
(图片来源网络,侵删)

核心概念

HttpServletRequest 是 Java Servlet API 中的一个接口,它封装了客户端向服务器发送的 HTTP 请求的所有信息,如请求头、请求参数、Cookie、Session、请求方法、URI 等。


原生 Servlet 环境

这是最基础、最直接的方式,在实现了 HttpServlet 的类中,service() 方法或其 doGet(), doPost() 等方法会直接接收 HttpServletRequestHttpServletResponse 作为参数。

示例代码:

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 1. 直接在方法参数中获取
        String requestURI = request.getRequestURI();
        String userAgent = request.getHeader("User-Agent");
        String name = request.getParameter("name");
        System.out.println("请求URI: " + requestURI);
        System.out.println("User-Agent: " + userAgent);
        System.out.println("参数 name: " + name);
        // 使用 response 返回内容
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().println("<h1>你好,Servlet!</h1>");
        response.getWriter().println("<p>你传入的 name 是: " + name + "</p>");
    }
}

在 Servlet 中,这是最标准、最简单的方式。

Java 如何获取 request 对象?-图2
(图片来源网络,侵删)

Spring Framework (Spring MVC / Spring Boot)

在 Spring 框架中,获取 request 的方式非常灵活,因为它使用了依赖注入和 AOP(面向切面编程)。

方式 1:通过方法参数注入 (推荐)

这是最常用、最推荐的方式,Spring 会自动将当前请求的 HttpServletRequest 对象注入到你的方法参数中。

示例代码 (Controller 中):

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
@Controller
public class MyController {
    @GetMapping("/hello")
    public String sayHello(HttpServletRequest request, @RequestParam("id") String userId) {
        // Spring 自动注入 request 对象
        System.out.println("Request URL: " + request.getRequestURL());
        System.out.println("Request Method: " + request.getMethod());
        // 同时可以获取其他参数
        System.out.println("User ID from @RequestParam: " + userId);
        // 获取所有请求头
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            System.out.println(headerName + " : " + request.getHeader(headerName));
        }
        return "hello"; // 返回视图名
    }
}

方式 2:使用 @Autowired 注入

如果你需要在非请求处理方法(如 Service 层、工具类)中访问 request,可以通过 @Autowired 注入一个代理对象,这个代理对象是 ServletRequestAttributes 的一个实例,它持有当前线程的 request

Java 如何获取 request 对象?-图3
(图片来源网络,侵删)

前提: 必须在 Web 环境下,Spring 能管理到注入的类。

示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Service
public class MyService {
    // 注入 RequestContextHolder 的包装类,而不是直接注入 request
    // 因为 request 是作用域相关的,不能直接作为 bean 注入
    @Autowired
    private HttpServletRequest request; // 注意:这种方式在某些情况下可能不推荐,更推荐使用 RequestContextHolder
    public void doSomething() {
        // 推荐使用这种方式,更灵活且安全
        HttpServletRequest currentRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        System.out.println("在 Service 中获取请求 URI: " + currentRequest.getRequestURI());
        // 如果一定要用 @Autowired,需要确保注入的是一个代理
        // 但通常 RequestContextHolder 是更好的选择
        // System.out.println("Autowired request URI: " + this.request.getRequestURI());
    }
}

更推荐的 Service 层获取方式:

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Service
public class MyService {
    public void doSomething() {
        // 1. 获取当前请求的属性
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        // 2. 从属性中获取 request 对象
        HttpServletRequest request = attributes.getRequest();
        // 3. 使用 request
        System.out.println("在 Service 中获取请求 URI: " + request.getRequestURI());
    }
}

注意: RequestContextHolder 使用 ThreadLocal 来存储请求信息,这意味着它只能在处理请求的线程中工作,在异步或多线程场景下需要特殊处理。

方式 3:实现 ServletRequestAware 接口 (旧版 Spring)

在较老的 Spring 版本中,可以实现 ServletRequestAware 接口来获取 request,这种方式在新版 Spring 中已不常用,因为方式1和方式2更简洁。


其他 Java Web 框架

Jakarta EE (原 Java EE)

在 Jakarta EE 的 EJB 或 CDI Bean 中,可以使用 @Context 注解来注入 HttpServletRequest

示例代码 (CDI Bean 中):

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
@RequestScoped
@Path("/myresource")
public class MyResource {
    // 方式1: 使用 @Context 注解
    @Context
    private HttpServletRequest request;
    // 方式2: 使用依赖注入 (需要启用 CDI)
    @Inject
    private HttpServletRequest injectedRequest;
    @GET
    public String get() {
        System.out.println("Request URI from @Context: " + request.getRequestURI());
        return "Hello from JAX-RS!";
    }
}

JSP/Servlet 中的内置对象

在 JSP 页面中,request 是一个内置对象,可以直接使用,无需任何声明。

示例代码 (JSP 中):

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>获取 Request 示例</title>
</head>
<body>
    <h1>在 JSP 中直接使用 request 内置对象</h1>
    <p>请求方法: <%= request.getMethod() %></p>
    <p>请求协议: <%= request.getProtocol() %></p>
    <p>请求路径: <%= request.getRequestURI() %></p>
    <%-- 获取参数 --%>
    <%
        String name = request.getParameter("name");
        if (name != null) {
    %>
            <p>你好, <%= name %>!</p>
    <%
        }
    %>
</body>
</html>

总结与最佳实践

场景 推荐方式 优点 缺点
原生 Servlet 方法参数 简单直接,符合规范 仅限 Servlet 内部
Spring MVC 方法参数注入 最清晰、最推荐,依赖关系明确 仅限 Controller 方法
Spring Service/Tool RequestContextHolder 灵活,可在任何被 Spring 管理的类中使用 需注意线程安全(异步场景)
JSP 直接使用内置对象 request 非常方便 耦合度高,不符合 MVC 思想
Jakarta EE/CDI @Context 注解 标准化,适合 EJB/CDI 环境 需要特定环境支持

核心建议:

  1. 在 Controller 层:优先使用 方法参数注入,这是最清晰、最符合 Spring 设计思想的方式。
  2. 在 Service 或其他业务层:使用 RequestContextHolder.currentRequestAttributes() 来获取,这是获取当前线程请求的标准方式。
  3. 避免在非 Web 环境中使用:确保你的代码只在 Web 请求处理线程中执行,否则 request 对象会是 null
  4. 谨慎使用 @Autowired 注入 request:虽然可能可行,但它隐藏了依赖关系,不如 RequestContextHolder 灵活和明确,通常不推荐。
分享:
扫描分享到社交APP
上一篇
下一篇