问题
I'm using a default JSF servlet and RestEasy servlet to serve URI requests (Wildfly 8.1). I want every single URI request to be logged with a @SessionScoped backing bean. Either CDI bean (@Named) or ManagedBean (@ManagedBean) so that I can log the http requests from this visitor.
My requirements:
- I don't want to invoke the logging of the access from each JSF page, nor from each REST Resource Java file.
- Every request must be linkable to @SessionScoped annotated backing bean
Visit. TheVisitobject stores:- a user (if identified)
- start of visit
- an IP Address
- n URI requests in a list: JSF resource requests and rest resource requests
My questions:
- How do I register a filter in web.xml that logs both requests - be it JSF or REST - to the @SessionScoped annotated backing bean
Visit? - If I could access this backing bean, how do I ensure that it is the session fo the same user? This session management of the web container is unclear to me. How does the web container map the request to a known session instance? By a default cookie?
Of course there is already a servlet-mapping on the url-pattern /* and one on /restresources/* One could not register 2 filters for the same path, could you? :
<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>
回答1:
Okay. For others that want to log every page and REST resource access, too.
Create the filter in the web.xml file.
<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>
Also, create the filter class.
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
}
}
In this code I removed the logging of repetitive requests. Only jsf page requests and REST resource requests are logged. Thus, no images, css or js requests. Adapt the RegEx according to your own needs. The EJB function saveUriRequest I have annotated with @Asynchronous, to avoid laggy delays of the response.
Answering my own questions:
- The filter will pick up every single http request - be it a JSF page or REST resource call. Annotate the
Filteras a CDI bean with @Named and @SessionScoped. Now you have a filter for every single visitor. A WORD OF CAUTION - DON'T DO THIS IF YOU HAVE HIGH NUMBER OF DIFFERENT USERS. THIS WILL RAPIDLY BRING DOWN YOUR AVAILABLE MEMORY. Alternatively you could mark it as @ApplicationScoped and get a visitor id from theServletRequest requestheader instance and assign the request to a visitor. Also, this is prone to Denials-Of-Service attacks. (I'm using this only for internal purpose.) - Yes, the web container distriguishes between sessions by a jsessionid also from the
ServletRequest request.
Hope this helps someone, too.
来源:https://stackoverflow.com/questions/26401368/how-to-log-every-uri-access-with-the-jsf-servlet-and-the-rest-servlet