Spring Boot Web上下文工具类详解:获取Request、Response和参数

Spring Boot Web上下文工具类详解:获取Request、Response和参数

工具类概述

这个CommonServletUtil工具类提供了在Spring Boot应用中便捷地获取Web上下文相关对象的方法,包括HttpServletRequest、HttpServletResponse以及从多种来源获取参数值。

功能特点

  1. 多来源参数获取:从请求参数、请求头、Cookie和属性中获取值
  2. Web上下文检测:判断当前是否处于Web环境中
  3. 异常处理:对非Web上下文情况进行友好错误提示
  4. 便捷访问:静态方法直接调用,无需注入

完整代码

java 复制代码
package com.mnsn.framework.boot.utils;

import cn.hutool.core.util.ObjectUtil;
import com.mnsn.framework.commons.exception.CheckedException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Generated;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * Servlet工具类
 * 提供Web上下文相关操作的工具方法
 * 
 * @author mnsn
 * @version 1.0
 * @date 2024-01-15
 */
public class CommonServletUtil {
    @Generated
    private static final Logger log = LoggerFactory.getLogger(CommonServletUtil.class);

    private CommonServletUtil() {
        // 工具类,防止实例化
    }

    /**
     * 从请求中获取参数值
     * 按照以下顺序查找:请求参数 -> 请求头 -> Cookie -> 请求属性
     *
     * @param paramName 参数名
     * @return 参数值,如果未找到返回null
     */
    public static String getParamFromRequest(String paramName) {
        HttpServletRequest request = getRequest();
        String paramValue = request.getParameter(paramName);
        
        // 1. 从请求参数中获取
        if (ObjectUtil.isEmpty(paramValue)) {
            paramValue = request.getHeader(paramName);
        }

        // 2. 从请求头中获取
        if (ObjectUtil.isEmpty(paramValue)) {
            Cookie[] cookies = request.getCookies();
            if (ObjectUtil.isNotEmpty(cookies)) {
                // 3. 从Cookie中获取
                for (Cookie cookie : cookies) {
                    String cookieName = cookie.getName();
                    if (cookieName.equals(paramName)) {
                        return cookie.getValue();
                    }
                }
            }
        }

        // 4. 从请求属性中获取
        if (ObjectUtil.isEmpty(paramValue)) {
            paramValue = String.valueOf(request.getAttribute(paramName));
        }

        return paramValue;
    }

    /**
     * 获取当前请求的HttpServletRequest对象
     *
     * @return HttpServletRequest对象
     * @throws CheckedException 非Web上下文时抛出异常
     */
    public static HttpServletRequest getRequest() {
        ServletRequestAttributes servletRequestAttributes;
        try {
            servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        } catch (Exception var2) {
            log.error(">>> 非Web上下文无法获取Request:", var2);
            throw new CheckedException("非Web上下文无法获取Request");
        }

        if (servletRequestAttributes == null) {
            throw new CheckedException("非Web上下文无法获取Request");
        } else {
            return servletRequestAttributes.getRequest();
        }
    }

    /**
     * 获取当前请求的HttpServletResponse对象
     *
     * @return HttpServletResponse对象
     * @throws CheckedException 非Web上下文时抛出异常
     */
    public static HttpServletResponse getResponse() {
        ServletRequestAttributes servletRequestAttributes;
        try {
            servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        } catch (Exception var2) {
            log.error(">>> 非Web上下文无法获取Response:", var2);
            throw new CheckedException("非Web上下文无法获取Response");
        }

        if (servletRequestAttributes == null) {
            throw new CheckedException("非Web上下文无法获取Response");
        } else {
            return servletRequestAttributes.getResponse();
        }
    }

    /**
     * 判断当前是否处于Web上下文中
     *
     * @return true-在Web上下文中, false-不在Web上下文中
     */
    public static boolean isWeb() {
        return RequestContextHolder.getRequestAttributes() != null;
    }
}

Maven依赖配置

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.0</version>
        <relativePath/>
    </parent>
    
    <groupId>com.mnsn.framework</groupId>
    <artifactId>common-utils</artifactId>
    <version>1.0.0</version>
    
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <hutool.version>5.8.11</hutool.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Hutool工具包 -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

使用示例

1. 在Controller中使用

java 复制代码
@RestController
@RequestMapping("/api/user")
public class UserController {
    
    @GetMapping("/info")
    public ResponseEntity<UserInfo> getUserInfo() {
        // 获取请求参数
        String userId = CommonServletUtil.getParamFromRequest("userId");
        String token = CommonServletUtil.getParamFromRequest("token");
        
        // 获取Request对象
        HttpServletRequest request = CommonServletUtil.getRequest();
        String userAgent = request.getHeader("User-Agent");
        
        UserInfo userInfo = userService.getUserInfo(userId, token);
        return ResponseEntity.ok(userInfo);
    }
    
    @PostMapping("/update")
    public ResponseEntity<String> updateUser(@RequestBody User user) {
        // 获取Response对象设置Cookie
        HttpServletResponse response = CommonServletUtil.getResponse();
        Cookie cookie = new Cookie("lastUpdate", String.valueOf(System.currentTimeMillis()));
        response.addCookie(cookie);
        
        userService.updateUser(user);
        return ResponseEntity.ok("更新成功");
    }
}

2. 在Service中使用

java 复制代码
@Service
public class UserService {
    
    public UserInfo getUserInfo(String userId, String token) {
        // 检查是否在Web上下文中
        if (CommonServletUtil.isWeb()) {
            String clientIp = CommonServletUtil.getRequest().getRemoteAddr();
            log.info("客户端IP: {}", clientIp);
        }
        
        // 业务逻辑...
        return userInfo;
    }
}

3. 在拦截器中使用

java 复制代码
@Component
public class AuthInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 使用工具类获取token
        String token = CommonServletUtil.getParamFromRequest("Authorization");
        
        if (StringUtils.isEmpty(token)) {
            throw new UnauthorizedException("未授权访问");
        }
        
        // 验证token逻辑...
        return true;
    }
}

方法详解

getParamFromRequest(String paramName)

这个方法按照以下优先级从请求中获取参数值:

  1. 请求参数request.getParameter(paramName)
  2. 请求头request.getHeader(paramName)
  3. Cookie:遍历所有Cookie查找匹配的名称
  4. 请求属性request.getAttribute(paramName)

getRequest() 和 getResponse()

这两个方法通过Spring的RequestContextHolder获取当前线程绑定的请求和响应对象,如果不在Web上下文中会抛出CheckedException

isWeb()

用于判断当前是否处于Web环境中,在异步任务或定时任务中特别有用。

注意事项

  1. 线程安全性:工具类中的方法都是静态的且无状态,可以在多线程环境中安全使用
  2. Web上下文:在非Web环境(如单元测试、定时任务)中调用getRequest()/getResponse()会抛出异常
  3. 性能考虑:频繁调用getRequest()可能影响性能,建议在需要时缓存引用
  4. 空值处理:getParamFromRequest()方法在找不到参数时返回null,调用方需要处理空值情况

单元测试

java 复制代码
@SpringBootTest
class CommonServletUtilTest {
    
    @Test
    void testIsWebInWebContext() {
        assertTrue(CommonServletUtil.isWeb());
    }
    
    @Test
    void testGetRequest() {
        HttpServletRequest request = CommonServletUtil.getRequest();
        assertNotNull(request);
    }
    
    @Test
    void testGetParamFromRequest() {
        // 需要通过Mock HttpServletRequest来测试
        // 具体实现略...
    }
}

这个工具类大大简化了在Spring Boot应用中处理Web相关操作的工作,提供了统一的方式来访问请求、响应和参数信息。

相关推荐
IT_陈寒3 小时前
7个Java Stream API的隐藏技巧,让你的代码效率提升50%
前端·人工智能·后端
行思理3 小时前
Lombok 新手教程
java·spring boot·lombok
绝无仅有3 小时前
大厂深度面试相关文章:深入探讨底层原理与高性能优化
后端·面试·架构
一 乐3 小时前
医疗保健|医疗养老|基于Java+vue的医疗保健系统(源码+数据库+文档)
java·前端·数据库·vue.js·毕设
观望过往4 小时前
Spring Boot 集成 InfluxDB 2.x 完整技术指南
java·spring boot·influxdb
绝无仅有4 小时前
大厂真实面试指南:解答核心问题与技术深度探讨
后端·面试·架构
Want5954 小时前
HTML炫酷烟花⑨
前端·html
艾小码4 小时前
90%前端面试必问的12个JS核心,搞懂这些直接起飞!
前端·javascript
JaguarJack4 小时前
PHP 现代特性速查 写出更简洁安全的代码(中篇)
后端·php