在項目中記錄操做日誌,是一種很常見的需求。html
有時咱們在service或者dao層記錄日誌,須要同時保存訪問ip、登陸用戶名等。若是從controller層把HttpServletRequest 對象傳過去會顯得很麻煩。HttpSession能夠經過HttpServletRequest 間接獲取。java
須要注意的是RequestContextListener實現了javax.servlet.ServletRequestListener,這是servlet2.4以後纔有的,一些比較老的容器使用這一功能會報空指針異常。web
/* * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the "License"). You may not use this file except * in compliance with the License. * * You can obtain a copy of the license at * glassfish/bootstrap/legal/CDDLv1.0.txt or * https://glassfish.dev.java.net/public/CDDLv1.0.html. * See the License for the specific language governing * permissions and limitations under the License. * * When distributing Covered Code, include this CDDL * HEADER in each file and include the License file at * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable, * add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your * own identifying information: Portions Copyright [yyyy] * [name of copyright owner] * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * Portions Copyright Apache Software Foundation. */ package javax.servlet; import java.util.EventListener; /** * A ServletRequestListener can be implemented by the developer * interested in being notified of requests coming in and out of * scope in a web component. A request is defined as coming into * scope when it is about to enter the first servlet or filter * in each web application, as going out of scope when it exits * the last servlet or the first filter in the chain. * * @since Servlet 2.4 */ public interface ServletRequestListener extends EventListener { /** The request is about to go out of scope of the web application. */ public void requestDestroyed ( ServletRequestEvent sre ); /** The request is about to come into scope of the web application. */ public void requestInitialized ( ServletRequestEvent sre ); }
在web.xml配置spring
<listener> <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> </listener>
在service或者dao中獲取HttpServletRequest 的代碼以下bootstrap
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest();
爲了方便,能夠如上代碼提取到一個工具方法中,避免重複。
app
他的原理就是使用ThreadLocal,RequestContextListener監聽器將HttpServletRequest綁定到當前線程。如下是部分源碼ide
public class RequestContextListener implements ServletRequestListener { private static final String REQUEST_ATTRIBUTES_ATTRIBUTE = RequestContextListener.class.getName() + ".REQUEST_ATTRIBUTES"; public void requestInitialized(ServletRequestEvent requestEvent) { if (!(requestEvent.getServletRequest() instanceof HttpServletRequest)) { throw new IllegalArgumentException( "Request is not an HttpServletRequest: " + requestEvent.getServletRequest()); } HttpServletRequest request = (HttpServletRequest) requestEvent.getServletRequest(); ServletRequestAttributes attributes = new ServletRequestAttributes(request); request.setAttribute(REQUEST_ATTRIBUTES_ATTRIBUTE, attributes); LocaleContextHolder.setLocale(request.getLocale()); RequestContextHolder.setRequestAttributes(attributes); } // ... }