在项目中记录操做日志,是一种很常见的需求。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); } // ... }