Java 我可以从<;中排除一些具体的URL吗;url模式>;内部<;过滤器映射>;?

Java 我可以从<;中排除一些具体的URL吗;url模式>;内部<;过滤器映射>;?,java,servlets,servlet-filters,Java,Servlets,Servlet Filters,我希望对除一个具体URL之外的所有URL应用一些具体筛选器(即,除/specialpath之外的/*) 有可能这样做吗 示例代码: 某些过滤器 org.somproject.AFilter 某些过滤器 /* 要求 向前地 标准Servlet API不支持此功能。您可能希望对此类文件使用重写URL筛选器(与Apache HTTPD的mod_rewrite非常类似),或者在侦听/*的筛选器的doFilter()方法中添加检查 String path = ((HttpServletReque

我希望对除一个具体URL之外的所有URL应用一些具体筛选器(即,除
/specialpath
之外的
/*

有可能这样做吗


示例代码:


某些过滤器
org.somproject.AFilter
某些过滤器
/*   
要求
向前地

标准Servlet API不支持此功能。您可能希望对此类文件使用重写URL筛选器(与Apache HTTPD的
mod_rewrite
非常类似),或者在侦听
/*
的筛选器的
doFilter()
方法中添加检查

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    // Do your business stuff here for all paths other than /specialpath.
}
如有必要,您可以将要忽略的路径指定为筛选器的
init param
,以便您可以在
web.xml
中对其进行控制。您可以在过滤器中获得它,如下所示:

private String pathToBeIgnored;

public void init(FilterConfig config) {
    pathToBeIgnored = config.getInitParameter("pathToBeIgnored");
}
如果筛选器是第三方API的一部分,因此您无法修改它,则将其映射到更具体的
url模式
,例如
/otherfilterpath/*
,并在
/*
上创建一个新筛选器,该筛选器将转发到与第三方筛选器匹配的路径

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    request.getRequestDispatcher("/otherfilterpath" + path).forward(request, response);
}
为避免此筛选器在无限循环中调用自身,您需要让它仅在
请求上侦听(分派),而第三方筛选器仅在
转发上侦听(分派)

另见:

我不认为您可以,唯一的其他配置替代方案是枚举要筛选的路径,因此,您可以为
/this/*
/this/*
等添加一些,而不是
/*
,但当您有很多路径时,这并不能提供足够的解决方案

您可以向过滤器添加一个参数,提供一个表达式(如正则表达式),用于跳过匹配路径的过滤器功能。 servlet容器仍然会为这些url调用您的过滤器,但您可以更好地控制配置

编辑

既然您提到您对过滤器没有控制权,那么您可以做的就是继承该过滤器,在其方法中调用
super
方法,除非您要跳过的url路径存在,并遵循@BalusC建议的过滤器链,或者构建一个过滤器,在相同的情况下实例化过滤器和委托。在这两种情况下,过滤器参数都将包括您添加的表达式参数和您从中继承或委托到的过滤器参数

构建委托过滤器(包装器)的优点是,您可以将包装过滤器的过滤器类添加为参数,并在其他类似情况下重用它。

我使用了一种方法:我创建了一个特殊的servlet,它总是使用403代码进行响应,并将其映射放在常规的之前

映射片段:


通用服务
project.servlet.GeneralServlet
特殊小酒店
project.servlet.SpecialServlet
特殊小酒店
/资源/限制/*
通用服务
/资源/*
和servlet类:

public class SpecialServlet extends HttpServlet {
    public SpecialServlet() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
}

当您想要阻止某个筛选器和以下所有筛选器时,此方法会起作用。如果您希望在servlet容器中作为静态资源提供某些内容,而不是让您的应用程序逻辑(通过类似GuiceFilter的过滤器)运行,那么它应该工作得很好:

将包含静态资源文件的文件夹映射到默认servlet。创建一个servlet过滤器,并将其放在web.xml中的GuiceFilter之前。在创建的筛选器中,可以将一些请求转发给GuiceFilter,而将其他请求直接转发给dispatcher。下面是一个例子

web.xml


违约
/静止的/*
静态资源过滤器
com.project.filter.StaticResourceFilter
静态资源过滤器
/静止的/*
guiceFilter
com.google.inject.servlet.GuiceFilter
guiceFilter
/*
StaticResourceFilter.class

public class StaticResourceFilter implements Filter {

    private final static Logger LOGGER = LoggerFactory.getLogger(StaticResourceFilter.class);

    private static final String RESOURCE_PATH = "/static/";
    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        LOGGER.info("StaticResourceFilter initialized");
    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
                         final FilterChain chain) throws IOException, ServletException {

        String path = ((HttpServletRequest) request).getServletPath();
        if (path.toLowerCase().startsWith(RESOURCE_PATH)) {
            request.getRequestDispatcher(path).forward(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        LOGGER.info("StaticResourceFilter destroyed");
    }
}

不幸的是,如果您只想跳过筛选链中的一个步骤,而保留后面的步骤,这将不起作用。

我还必须根据java代码中的URL模式(/{servicename}/api/stats/)进行筛选

if (path.startsWith("/{servicename}/api/statistics/")) {
validatingAuthToken(((HttpServletRequest) request).getHeader("auth_token"));
filterChain.doFilter(request, response);            
}

但奇怪的是,servlet不支持除(/*)以外的url模式,这对于servlet API来说应该是非常常见的情况

我也遇到过同样的问题,但我发现下面有一个例子

web.xml

 <!-- set this param value for the filter-->
    <init-param>
            <param-name>freePages</param-name>
            <param-value>
            MainFrame.jsp;
            </param-value>
    </init-param>

通过这种方式,您不必骚扰具体的筛选器类。

如果出于任何原因您无法更改原始筛选器映射(在我的情况下为“/*”),并且您要将其分派到一个不可更改的第三方筛选器,您可以发现以下有用信息:

  • 拦截要绕过的路径
  • 跳到并执行过滤器链的最后一环(servlet本身)
  • 跳过是通过反射完成的,在调试模式下检查容器实例
Weblogic 12.1.3中的以下工作:


在Spring2中,我能够如下处理这个问题

 private boolean isInPath(ServletRequest request) {
   String PATH_TO_VALIDATE = "/path/";
   String path = ((HttpServletRequest) request).getRequestURI();
   return path != null && path.toLowerCase().contains(PATH_TO_VALIDATE);
}

我的问题是过滤器不是我的,它来自组件库。Ypu应该使用组件库过滤器并对其进行扩展,以便添加要用于执行排除的代码。@BalusC如果“/specialpath”只提供js、css等静态资源,chain.doFilter()是否会使响应变慢?有没有一种方法可以在不链接过滤器的情况下直接为资源提供服务?@BenhurCD:我真的不知道你如何解决这个性能问题。我试图采用你的解决方案,但对于我应用过滤器并打破链接的文件,我得到了以下错误信息;筛选器静态资源筛选器引发的未捕获异常:java.io.FileNotFoundException。知道为什么吗?在多上下文设置中,使用
.getRequestURI()
将中断(很可能导致404),因为
.getRequestDispatcher
相对于上下文解析
      import org.apache.commons.lang3.reflect.FieldUtils;
      import javax.servlet.Filter;

      [...]

      @Override   
      public void doFilter(ServletRequest request, ServletRespons response, FilterChain chain) throws IOException, ServletException { 
          String path = ((HttpServletRequest) request).getRequestURI();

          if(!bypassSWA(path)){
              swpFilterHandler.doFilter(request, response, chain);

          } else {
              try {
                  ((Filter) (FieldUtils.readField(
                                (FieldUtils.readField(
                                        (FieldUtils.readField(chain, "filters", true)), "last", true)), "item", true)))
                  .doFilter(request, response, chain);
              } catch (IllegalAccessException e) {
                  e.printStackTrace();
              }           
          }   
      }
 private boolean isInPath(ServletRequest request) {
   String PATH_TO_VALIDATE = "/path/";
   String path = ((HttpServletRequest) request).getRequestURI();
   return path != null && path.toLowerCase().contains(PATH_TO_VALIDATE);
}