笔记:工具类ServletUtils一、RequestContextHolder 概述RequestContextHolder是 Spring 框架提供的一个线程级请求上下文管理器用于在任意层如 Controller、Service、AOP、Filter 等中获取当前的HttpServletRequestHttpServletResponseHttpSession它属于org.springframework.web.context.request包底层依赖ThreadLocal保存请求上下文。机制当 HTTP 请求到达时Spring MVC 会为当前线程创建一个ServletRequestAttributes对象并通过RequestContextHolder.setRequestAttributes()将其绑定到当前线程的 ThreadLocal 中。因此在同一个请求线程内的任何代码中都可以通过ServletRequestAttributesattrs(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();HttpServletRequestrequestattrs.getRequest();HttpServletResponseresponseattrs.getResponse();直接获取当前请求对象。二、设计理念ServletUtils工具类的核心目标是在任意位置安全、方便地访问当前请求上下文。它通过整合Spring 的RequestContextHolder线程上下文Hutool 的JakartaServletUtilHTTP 辅助工具三、核心思想利用 RequestContextHolder 实现“随处可取 Request”在传统 Web 开发中HttpServletRequest只能通过 Controller 参数显式传入GetMapping(/hello)publicStringhello(HttpServletRequestrequest){returnrequest.getHeader(User-Agent);}但在 Service 或工具层这种方式会导致层间耦合。ServletUtils的巧妙之处在于它可以在任意层这样调用StringtokenServletUtils.getRequest().getHeader(Authorization);其内部核心实现如下publicstaticHttpServletRequestgetRequest(){try{returngetRequestAttributes().getRequest();}catch(Exceptione){returnnull;}}publicstaticServletRequestAttributesgetRequestAttributes(){RequestAttributesattributesRequestContextHolder.getRequestAttributes();return(ServletRequestAttributes)attributes;}关键逻辑Spring MVC 绑定阶段每次请求进入 DispatcherServlet 时Spring 自动绑定ServletRequestAttributes到当前线程。全局访问只要在同一线程内执行任何地方都能通过RequestContextHolder获取当前请求。安全封装在非 Web 环境下如定时任务或异步线程该方法返回null而不是抛出异常保证健壮性。四、工具类价值总结ServletUtils不仅仅是一个 Request 封装器而是围绕“Web 上下文访问”这一核心场景提供了全方位的能力支持分类功能示例参数获取获取请求参数并自动转换类型getParameterToInt(page, 1)头部操作获取指定请求头或全部头部getHeader(request, User-Agent)Session 管理获取或创建会话对象getSession()响应渲染输出 JSON 响应renderString(response, jsonStr)客户端信息获取真实 IPgetClientIP()请求类型判断判断是否为 Ajax 请求isAjaxRequest(request)URL 编解码统一 UTF-8 编解码urlEncode(value)/urlDecode(value)代码如下,方便抄packageorg.dromara.common.core.utils;importcn.hutool.core.convert.Convert;importcn.hutool.extra.servlet.JakartaServletUtil;importcn.hutool.http.HttpStatus;importjakarta.servlet.ServletRequest;importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importjakarta.servlet.http.HttpSession;importlombok.AccessLevel;importlombok.NoArgsConstructor;importorg.springframework.http.MediaType;importorg.springframework.util.LinkedCaseInsensitiveMap;importorg.springframework.web.context.request.RequestAttributes;importorg.springframework.web.context.request.RequestContextHolder;importorg.springframework.web.context.request.ServletRequestAttributes;importjava.io.IOException;importjava.net.URLDecoder;importjava.net.URLEncoder;importjava.nio.charset.StandardCharsets;importjava.util.Collections;importjava.util.Enumeration;importjava.util.HashMap;importjava.util.Map;/** * 客户端工具类提供获取请求参数、响应处理、头部信息等常用操作 * * author ruoyi */NoArgsConstructor(accessAccessLevel.PRIVATE)publicclassServletUtilsextendsJakartaServletUtil{/** * 获取指定名称的 String 类型的请求参数 * * param name 参数名 * return 参数值 */publicstaticStringgetParameter(Stringname){returngetRequest().getParameter(name);}/** * 获取指定名称的 String 类型的请求参数若参数不存在则返回默认值 * * param name 参数名 * param defaultValue 默认值 * return 参数值或默认值 */publicstaticStringgetParameter(Stringname,StringdefaultValue){returnConvert.toStr(getRequest().getParameter(name),defaultValue);}/** * 获取指定名称的 Integer 类型的请求参数 * * param name 参数名 * return 参数值 */publicstaticIntegergetParameterToInt(Stringname){returnConvert.toInt(getRequest().getParameter(name));}/** * 获取指定名称的 Integer 类型的请求参数若参数不存在则返回默认值 * * param name 参数名 * param defaultValue 默认值 * return 参数值或默认值 */publicstaticIntegergetParameterToInt(Stringname,IntegerdefaultValue){returnConvert.toInt(getRequest().getParameter(name),defaultValue);}/** * 获取指定名称的 Boolean 类型的请求参数 * * param name 参数名 * return 参数值 */publicstaticBooleangetParameterToBool(Stringname){returnConvert.toBool(getRequest().getParameter(name));}/** * 获取指定名称的 Boolean 类型的请求参数若参数不存在则返回默认值 * * param name 参数名 * param defaultValue 默认值 * return 参数值或默认值 */publicstaticBooleangetParameterToBool(Stringname,BooleandefaultValue){returnConvert.toBool(getRequest().getParameter(name),defaultValue);}/** * 获取所有请求参数以 Map 的形式返回 * * param request 请求对象{link ServletRequest} * return 请求参数的 Map键为参数名值为参数值数组 */publicstaticMapString,String[]getParams(ServletRequestrequest){finalMapString,String[]maprequest.getParameterMap();returnCollections.unmodifiableMap(map);}/** * 获取所有请求参数以 Map 的形式返回值为字符串形式的拼接 * * param request 请求对象{link ServletRequest} * return 请求参数的 Map键为参数名值为拼接后的字符串 */publicstaticMapString,StringgetParamMap(ServletRequestrequest){MapString,StringparamsnewHashMap();for(Map.EntryString,String[]entry:getParams(request).entrySet()){params.put(entry.getKey(),StringUtils.joinComma(entry.getValue()));}returnparams;}/** * 获取当前 HTTP 请求对象 * * return 当前 HTTP 请求对象 */publicstaticHttpServletRequestgetRequest(){try{returngetRequestAttributes().getRequest();}catch(Exceptione){returnnull;}}/** * 获取当前 HTTP 响应对象 * * return 当前 HTTP 响应对象 */publicstaticHttpServletResponsegetResponse(){try{returngetRequestAttributes().getResponse();}catch(Exceptione){returnnull;}}/** * 获取当前请求的 HttpSession 对象 * p * 如果当前请求已经关联了一个会话即已经存在有效的 session ID * 则返回该会话对象如果没有关联会话则会创建一个新的会话对象并返回。 * p * HttpSession 用于存储会话级别的数据如用户登录信息、购物车内容等 * 可以在多个请求之间共享会话数据 * * return 当前请求的 HttpSession 对象 */publicstaticHttpSessiongetSession(){returngetRequest().getSession();}/** * 获取当前请求的请求属性 * * return {link ServletRequestAttributes} 请求属性对象 */publicstaticServletRequestAttributesgetRequestAttributes(){try{RequestAttributesattributesRequestContextHolder.getRequestAttributes();return(ServletRequestAttributes)attributes;}catch(Exceptione){returnnull;}}/** * 获取指定请求头的值如果头部为空则返回空字符串 * * param request 请求对象 * param name 头部名称 * return 头部值 */publicstaticStringgetHeader(HttpServletRequestrequest,Stringname){Stringvaluerequest.getHeader(name);if(StringUtils.isEmpty(value)){returnStringUtils.EMPTY;}returnurlDecode(value);}/** * 获取所有请求头的 Map键为头部名称值为头部值 * * param request 请求对象 * return 请求头的 Map */publicstaticMapString,StringgetHeaders(HttpServletRequestrequest){MapString,StringmapnewLinkedCaseInsensitiveMap();EnumerationStringenumerationrequest.getHeaderNames();if(enumeration!null){while(enumeration.hasMoreElements()){Stringkeyenumeration.nextElement();Stringvaluerequest.getHeader(key);map.put(key,value);}}returnmap;}/** * 将字符串渲染到客户端以 JSON 格式返回 * * param response 渲染对象 * param string 待渲染的字符串 */publicstaticvoidrenderString(HttpServletResponseresponse,Stringstring){try{response.setStatus(HttpStatus.HTTP_OK);response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.setCharacterEncoding(StandardCharsets.UTF_8.toString());response.getWriter().print(string);}catch(IOExceptione){e.printStackTrace();}}/** * 判断当前请求是否为 Ajax 异步请求 * * param request 请求对象 * return 是否为 Ajax 请求 */publicstaticbooleanisAjaxRequest(HttpServletRequestrequest){// 判断 Accept 头部是否包含 application/jsonStringacceptrequest.getHeader(accept);if(accept!nullaccept.contains(MediaType.APPLICATION_JSON_VALUE)){returntrue;}// 判断 X-Requested-With 头部是否包含 XMLHttpRequestStringxRequestedWithrequest.getHeader(X-Requested-With);if(xRequestedWith!nullxRequestedWith.contains(XMLHttpRequest)){returntrue;}// 判断 URI 后缀是否为 .json 或 .xmlStringurirequest.getRequestURI();if(StringUtils.equalsAnyIgnoreCase(uri,.json,.xml)){returntrue;}// 判断请求参数 __ajax 是否为 json 或 xmlStringajaxrequest.getParameter(__ajax);returnStringUtils.equalsAnyIgnoreCase(ajax,json,xml);}/** * 获取客户端 IP 地址 * * return 客户端 IP 地址 */publicstaticStringgetClientIP(){returngetClientIP(getRequest());}/** * 对内容进行 URL 编码 * * param str 内容 * return 编码后的内容 */publicstaticStringurlEncode(Stringstr){returnURLEncoder.encode(str,StandardCharsets.UTF_8);}/** * 对内容进行 URL 解码 * * param str 内容 * return 解码后的内容 */publicstaticStringurlDecode(Stringstr){returnURLDecoder.decode(str,StandardCharsets.UTF_8);}}