關(guān)于ThreadLocal對(duì)request和response的用法說(shuō)明
記得在一篇博文中看到描述threadLocal的一句話:
ThreadLocal除了適用于多線程保證每條線程都有自己的變量副本外,還適用于在線程上下文中共享某些變量值。
這兩種說(shuō)法是有區(qū)別的。前者強(qiáng)調(diào)的是,使用ThreadLocal對(duì)副本做保護(hù),避免同步、加鎖,降低效率;后者強(qiáng)調(diào)的是,某個(gè)變量線程上下文中,A處用到、B處用到、C處用到,先在入口處set一個(gè)值,后使用ThreadLocal的get方法直接在需要用到的地方拿這個(gè)值。
項(xiàng)目中,最近理由cookie存值,使用到了threadLocal這個(gè)字段,自己就想去研究下,原理這里跟后者強(qiáng)調(diào)的一樣,上代碼:
1.web.xml里邊配置過(guò)濾器,攔截請(qǐng)求,做處理
<filter> <filter-name>InterceptorFilter</filter-name> <filter-class>com.fx.anniversary.core.filter.InterceptorFilter</filter-class> </filter> <filter-mapping> <filter-name>InterceptorFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.賦值
public class InterceptorFilter implements Filter{ publicvoiddestroy(){ } publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{ HttpServletRequesthttpRequest=(HttpServletRequest)request; HttpServletResponsehttpResponse=(HttpServletResponse)response; InterceptorContext.setRequest(httpRequest); InterceptorContext.setResponse(httpResponse); try{ chain.doFilter(request, response); }finally{ //不管有木有出現(xiàn)異常,finally塊中代碼都會(huì)執(zhí)行;在這里,相當(dāng)于只服務(wù)于當(dāng)前請(qǐng)求。 InterceptorContext.removeRequest(); InterceptorContext.removeResponse(); } } public void init(FilterConfigfilterConfig)throwsServletException{ } }
3.InterceptorContext實(shí)體
public class InterceptorContext{ private static ThreadLocal<httpservletrequest> _request = newThreadLocal<httpservletrequest>(); private static ThreadLocal<httpservletresponse> _response = newThreadLocal<httpservletresponse>(); publicstaticvoidsetRequest(HttpServletRequestrequest){ _request.set(request); } public static HttpServletRequestgetRequest(){ HttpServletRequestrequest=_request.get();returnrequest; } public static void removeRequest(){ _request.remove(); } public static void setResponse(HttpServletResponseresponse){ _response.set(response); } public static HttpServletResponsegetResponse(){ HttpServletResponseresponse=_response.get(); return response; } public static void removeResponse(){ _response.remove(); } }
4.項(xiàng)目中的開(kāi)始調(diào)用。(因?yàn)檫@兩個(gè)方法調(diào)用的地方太多,每次都帶一個(gè)參數(shù)也比較繁瑣,所以采用這種方式,文章開(kāi)頭總結(jié)過(guò))
public String getAttribute(Stringkey){ HttpServletRequestrequest = InterceptorContext.getRequest(); Cookie[]cookies=request.getCookies(); if(cookies!=null){ for(Cookie cookie: cookies){ if(cookie.getName().equals(key)){ return cookie.getValue(); } } } return""; } @Override public void setAttribute(String key,String value){ HttpServletResponse response=InterceptorContext.getResponse(); Cookiecookie=newCookie(key,value); response.addCookie(cookie); }
補(bǔ)充知識(shí):利用ThreadLocal管理request和session以及用戶信息,實(shí)現(xiàn) Use anywhere
1.我們有時(shí)需要獲取request或session中的數(shù)據(jù)的時(shí)候,首先需要獲取request和session對(duì)象,這個(gè)通常是在Controller的時(shí)候當(dāng)做入?yún)@取,這樣方法的入?yún)?huì)顯得很長(zhǎng)很臃腫的感覺(jué)。這就是的出發(fā)點(diǎn),接下來(lái)就展示一下是如何實(shí)現(xiàn)的。
2.首先我們寫(xiě)個(gè)一個(gè)攔截器:WebContextFilter
package com.office.common.filter; import java.io.IOException; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.filter.OncePerRequestFilter; import com.office.common.context.WebContextHolder; /** * webcontent信息加載到TheadLocal中 * @author Neo * @date 2017年10月20日11:38:45 */ public class WebContextFilter extends OncePerRequestFilter { public WebContextFilter() { } protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request == null || response == null) { return; } else { WebContextHolder.setRequest(request); WebContextHolder.setResponse(response); filterChain.doFilter(request, response); return; } } }
3.然后我們將寫(xiě)好的攔截器配置到web.xml中:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </context-param> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- ******************************************************************* --> <!-- *************** webcontent信息加載到TheadLocal中 ******************** --> <!-- ******************************************************************* --> <filter> <filter-name>webContentFilter</filter-name> <filter-class>com.office.common.filter.WebContextFilter</filter-class> </filter> <filter-mapping> <filter-name>webContentFilter</filter-name> <url-pattern>/*</url-pattern><!-- /* --> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
4.編寫(xiě)一個(gè)同一個(gè)管理操作工具類:WebContextHolder
package com.office.common.context; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.office.common.dto.UserDTO; /** * 上下文 * @author Neo * @date 2017年10月20日11:42:57 */ @SuppressWarnings({ "rawtypes", "unchecked" }) public class WebContextHolder { public WebContextHolder() { } public static String getRequestIp() { if (getRequest() == null) return null; HttpServletRequest request = getRequest(); String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getHeader("Proxy-Client-IP"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getHeader("WL-Proxy-Client-IP"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getHeader("HTTP_CLIENT_IP"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getHeader("HTTP_X_FORWARDED_FOR"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) ip = request.getRemoteAddr(); } else if (ip.length() > 15) { String ips[] = ip.split(","); int index = 0; do { if (index >= ips.length) break; String strIp = ips[index]; if (!"unknown".equalsIgnoreCase(strIp)) { ip = strIp; break; } index++; } while (true); } return ip; } public static HttpServletRequest getRequest() { if (requestLocal == null) return null; else return (HttpServletRequest) requestLocal.get(); } public static String getContextPath() { if (getRequest() == null) return null; else return (new StringBuilder()).append(getRequest().getContextPath()).append("/").toString(); } public static String getCurrRequestURI() { if (getRequest() == null) return null; else return (new StringBuilder()).append(getRequest().getRequestURI().replace(getRequest().getContextPath(), "")) .append("/").toString(); } public static HttpServletResponse getResponse() { if (responseLocal == null) return null; else return (HttpServletResponse) responseLocal.get(); } public static HttpSession getSession() { if (requestLocal == null) return null; if (requestLocal.get() == null) return null; else return ((HttpServletRequest) requestLocal.get()).getSession(); } public static UserDTO getLoginUserSession(Class loginUserClass) { if (getSession() == null) return null; Object obj = getSession().getAttribute(CURRENT_USER); if (obj == null) return null; else return (UserDTO) obj; } public static UserDTO getLoginUserSession() { return getLoginUserSession(UserDTO.class); } public static void createLoginUserSession(UserDTO loginUser) { if (loginUser != null) getSession().setAttribute(CURRENT_USER, loginUser); } public static void destroyLoginUserSession() { if (getLoginUserSession() != null) { getSession().removeAttribute(CURRENT_USER); getSession().invalidate(); } } public static void setRequest(HttpServletRequest request) { if (requestLocal == null) requestLocal = new ThreadLocal(); requestLocal.set(request); } public static void setResponse(HttpServletResponse response) { if (responseLocal == null) responseLocal = new ThreadLocal(); responseLocal.set(response); } /** * 獲取項(xiàng)目請(qǐng)求的根目錄 * * @return eg:http://localhost:8080/projectName */ public static String getProjectRequestRootPath() { HttpServletRequest request = WebContextHolder.getRequest(); StringBuffer sb = new StringBuffer(); sb.append(request.getScheme()). append("://"). append(request.getServerName()). append(":"). append(request.getServerPort()). append(request.getContextPath()). append("/"); return sb.toString(); } private static ThreadLocal requestLocal; private static ThreadLocal responseLocal; public static String CURRENT_USER = "CURRENT_USER"; }
5.使用展示:
//我們可以在任何地方使用這種方法取值
WebContextHolder.getRequest().getParameter("id");
以上這篇關(guān)于ThreadLocal對(duì)request和response的用法說(shuō)明就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Springboot整合Socket實(shí)現(xiàn)單點(diǎn)發(fā)送,廣播群發(fā),1對(duì)1,1對(duì)多實(shí)戰(zhàn)
本文主要介紹了Springboot整合Socket實(shí)現(xiàn)單點(diǎn)發(fā)送,廣播群發(fā),1對(duì)1,1對(duì)多實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08詳解如何為SpringBoot Web應(yīng)用的日志方便追蹤
在Web應(yīng)用程序領(lǐng)域,有效的請(qǐng)求監(jiān)控和可追溯性對(duì)于維護(hù)系統(tǒng)完整性和診斷問(wèn)題至關(guān)重要,SpringBoot是一種用于構(gòu)建Java應(yīng)用程序的流行框架,在本文中,我們探討了在SpringBoot中向日志添加唯一ID的重要性,需要的朋友可以參考下2023-11-11Java通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)一個(gè)簡(jiǎn)單的攔截器操作
這篇文章主要介紹了Java通過(guò)動(dòng)態(tài)代理實(shí)現(xiàn)一個(gè)簡(jiǎn)單的攔截器操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Spring Security無(wú)法調(diào)用接口錯(cuò)誤的問(wèn)題解決
記錄一下之前在寫(xiě)程序的時(shí)候遇到的問(wèn)題,Spring Security無(wú)法調(diào)用接口錯(cuò)誤的問(wèn)題,本文就來(lái)介紹一下解決方法,感興趣的可以了解一下2023-08-08spring boot創(chuàng)建和數(shù)據(jù)庫(kù)關(guān)聯(lián)模塊詳解
這篇文章主要給大家介紹了關(guān)于spring boot創(chuàng)建和數(shù)據(jù)庫(kù)關(guān)聯(lián)模塊的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Java實(shí)戰(zhàn)之校園外賣(mài)點(diǎn)餐系統(tǒng)的實(shí)現(xiàn)
這篇文章主要介紹了如何利用Java實(shí)現(xiàn)簡(jiǎn)易的校園外賣(mài)點(diǎn)餐系統(tǒng),文中采用的技術(shù)有:JSP、Spring、SpringMVC、MyBatis 等,感興趣的可以了解一下2022-03-03IntelliJ?idea報(bào)junit?no?tasks?available問(wèn)題的解決辦法
這篇文章主要給大家介紹了關(guān)于IntelliJ?idea報(bào)junit?no?tasks?available問(wèn)題的解決辦法,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11