【问题标题】:How to log every URI access with the JSF servlet and the rest servlet如何使用 JSF servlet 和其余 servlet 记录每个 URI 访问
【发布时间】:2014-12-11 15:23:05
【问题描述】:

我正在使用默认的 JSF servlet 和 RestEasy servlet 来处理 URI 请求(Wildfly 8.1)。我希望使用@SessionScoped 支持bean 记录每个URI 请求。 CDI bean (@Named) 或 ManagedBean (@ManagedBean) 以便我可以记录来自该访问者的 http 请求。

我的要求:

  • 我不想从每个 JSF 页面调用访问记录, 也不是来自每个 REST 资源 Java 文件。
  • 每个请求都必须可链接到 @SessionScoped 注释的支持 bean VisitVisit 对象存储:
    • 用户(如果已识别)
    • 开始访问
    • IP 地址
    • 列表中的n个URI请求:JSF资源请求和剩余资源请求

我的问题:

  1. 如何在 web.xml 中注册一个过滤器,将两个请求(无论是 JSF 还是 REST)记录到 @SessionScoped 带注释的支持 bean Visit
  2. 如果我可以访问这个支持 bean,我如何确保它是同一用户的会话?我不清楚 Web 容器的会话管理。 Web 容器如何将请求映射到已知会话实例?通过默认 cookie?

当然,在 url-pattern /*/restresources/* 上已经有一个 servlet 映射,不能为同一路径注册 2 个过滤器,可以吗? :

<filter>
    <filter-name>UriLogger</filter-name>
    <filter-class>com.doe.filters.UriAccessLogger</filter-class>
</filter>
<filter-mapping>
    <filter-name>UriLogger</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

【问题讨论】:

  • 我想把这些记录放到数据库中。我可能也可以使用 log4j 来做到这一点,并将输出发送到数据库而不是滚动日志文件。真的。但是,我认为过滤器应该这样做。如果效果很好,我会写一个并回答我自己的问题。无论如何,谢谢!

标签: rest servlets jsf-2


【解决方案1】:

好的。对于其他想要记录每个页面和 REST 资源访问的人也是如此。

在 web.xml 文件中创建过滤器。

<filter>
    <filter-name>UriLogger</filter-name>
    <filter-class>com.doe.filters.UriLoggingFilter </filter-class>
</filter>
<filter-mapping>
    <filter-name>UriLogger</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

另外,创建过滤器类。

package com.doe.webapp.controller.general.filters;

import java.io.IOException;
import java.io.Serializable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import com.doe.webapp.controller.general.VisitController;

@Named
@SessionScoped
public class UriLoggingFilter implements Serializable, Filter {

    private static final long serialVersionUID = 1472782644963167647L;
    private static Logger LOGGER = Logger.getLogger(UriLoggingFilter.class);
    private String lastLoggedUri = "";

    FilterConfig filterConfig = null;
    @Inject
    VisitController visitController;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    /**
     * Log requests of interest with the VisitController.
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,
            ServletException {

        // Run the other filters.
        filterChain.doFilter(request, response);

        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            String uri = httpServletRequest.getRequestURI();

            String regex = "((/{1}\\w+$)|(/{1}\\w+\\.jsf$))";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(uri);
            while (m.find()) {
                LOGGER.info("match " + m.group());

                if (!lastLoggedUri.equals(uri)) {
                    visitController.saveUriRequest(httpServletRequest);
                    lastLoggedUri = uri;
                } else {
                    LOGGER.warn("Multiple URI access to the same resource of the same user: " + uri);
                }
                break;
            }
        }

    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
}

在这段代码中,我删除了重复请求的记录。仅记录 jsf 页面请求和 REST 资源请求。因此,没有图像、css 或 js 请求。根据您自己的需要调整 RegEx。 EJB 函数saveUriRequest 我已经用@Asynchronous 注释,以避免响应延迟。

回答我自己的问题:

  1. 过滤器将获取每个单独的 http 请求 - 无论是 JSF 页面还是 REST 资源调用。使用@Named 和@SessionScopedFilter 注释为CDI bean。现在,您为每个访问者设置了一个过滤器。注意事项 - 如果您有大量不同的用户,请不要这样做。这将迅速减少您的可用内存。或者,您可以将其标记为 @ApplicationScoped 并从 ServletRequest request 标头实例中获取访问者 ID,并将请求分配给访问者。此外,这很容易受到拒绝服务攻击。 (我仅将其用于内部目的。)
  2. 是的,Web 容器通过同样来自 ServletRequest request 的 jsessionid 在会话之间进行分配。

希望这也对某人有所帮助。

【讨论】:

    猜你喜欢
    • 2023-03-20
    • 2011-04-04
    • 2012-08-12
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 2014-07-16
    • 2016-12-08
    • 2017-08-18
    相关资源
    最近更新 更多