spring-mvc 非 controller 層獲取HttpServletRequest

在項目中記錄操做日誌,是一種很常見的需求。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);
    }
// ...
}
相關文章
相關標籤/搜索