關(guān)于ThreadLocal對request和response的用法說明
記得在一篇博文中看到描述threadLocal的一句話:
ThreadLocal除了適用于多線程保證每條線程都有自己的變量副本外,還適用于在線程上下文中共享某些變量值。
這兩種說法是有區(qū)別的。前者強調(diào)的是,使用ThreadLocal對副本做保護,避免同步、加鎖,降低效率;后者強調(diào)的是,某個變量線程上下文中,A處用到、B處用到、C處用到,先在入口處set一個值,后使用ThreadLocal的get方法直接在需要用到的地方拿這個值。
項目中,最近理由cookie存值,使用到了threadLocal這個字段,自己就想去研究下,原理這里跟后者強調(diào)的一樣,上代碼:
1.web.xml里邊配置過濾器,攔截請求,做處理
<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塊中代碼都會執(zhí)行;在這里,相當(dāng)于只服務(wù)于當(dāng)前請求。
InterceptorContext.removeRequest();
InterceptorContext.removeResponse();
}
}
public void init(FilterConfigfilterConfig)throwsServletException{
}
}
3.InterceptorContext實體
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.項目中的開始調(diào)用。(因為這兩個方法調(diào)用的地方太多,每次都帶一個參數(shù)也比較繁瑣,所以采用這種方式,文章開頭總結(jié)過)
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);
}
補充知識:利用ThreadLocal管理request和session以及用戶信息,實現(xiàn) Use anywhere
1.我們有時需要獲取request或session中的數(shù)據(jù)的時候,首先需要獲取request和session對象,這個通常是在Controller的時候當(dāng)做入?yún)@取,這樣方法的入?yún)@得很長很臃腫的感覺。這就是的出發(fā)點,接下來就展示一下是如何實現(xiàn)的。
2.首先我們寫個一個攔截器: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.然后我們將寫好的攔截器配置到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.編寫一個同一個管理操作工具類: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);
}
/**
* 獲取項目請求的根目錄
*
* @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對request和response的用法說明就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot集成Redis及SpringCache緩存管理示例詳解
本文介紹了如何在SpringBoot中集成Redis并使用SpringCache進行緩存管理,詳解了Redis的配置、使用以及SpringCache的注解,還闡述了SpringCache的工作原理,包括其AOP實現(xiàn)和與各種緩存框架的集成,使得開發(fā)者可以輕松實現(xiàn)緩存功能,以提高應(yīng)用性能2024-09-09
在Spring Boot中集成RabbitMQ詳細步驟(最新推薦)
本文將介紹如何在Spring Boot項目中集成RabbitMQ,實現(xiàn)生產(chǎn)者和消費者的基本配置,本文分步驟給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-12-12
Java設(shè)計模式之責(zé)任鏈模式(Chain of Responsibility模式)介紹
這篇文章主要介紹了Java設(shè)計模式之責(zé)任鏈模式(Chain of Responsibility模式)介紹,本文講解了如何使用責(zé)任鏈模式,并給出了4種使用實例,需要的朋友可以參考下2015-03-03
關(guān)于BigDecimal類型數(shù)據(jù)的絕對值和相除求百分比
這篇文章主要介紹了關(guān)于BigDecimal類型數(shù)據(jù)的絕對值和相除求百分比,Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數(shù)進行精確的運算,需要的朋友可以參考下2023-07-07
Java基礎(chǔ)之刪除文本文件中特定行的內(nèi)容
這篇文章主要介紹了Java基礎(chǔ)之刪除文本文件中特定行的內(nèi)容,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04

