могу ли я исключить некоторые конкретные url-адреса из <url-pattern> внутри <filter-mapping>?

<p>я хочу, чтобы какой-то конкретный фильтр применялся ко всем url-адресам, кроме одного конкретного (т.е. для <code>/*</code>, кроме <code>/specialpath</code>).</p><p>есть ли возможность сделать это?</p><hr><p>образец кода:</p><pre class="lang-xml prettyprint-override"><code><filter> <filter-name>somefilter</filter-name> <filter-class>org.somproject.afilter</filter-class> </filter> <filter-mapping> <filter-name>somefilter</filter-name> <url-pattern>/*</url-pattern> <!-- the question is: how to modify this line? --> <dispatcher>request</dispatcher> <dispatcher>forward</dispatcher> </filter-mapping> </code></pre>

<p>стандартный servlet api не поддерживает эту возможность. вы можете захотеть использовать фильтр перезаписи url для этого типа <a href="http://tuckey.org/urlrewrite/">tuckey's</a> (который очень похож на apache httpd <code>mod\_rewrite</code>), или добавить проверку в методе <code>dofilter()</code> фильтра, прослушивающего <code>/*</code>.</p><pre><code>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. } </code></pre><p>при необходимости вы можете указать игнорируемые пути в качестве <code>init-param</code> фильтра, чтобы вы могли в любом случае управлять им в <code>web.xml</code>. вы можете получить его в фильтре следующим образом:</p><pre><code>private string pathtobeignored; public void init(filterconfig config) { pathtobeignored = config.getinitparameter("pathtobeignored"); } </code></pre><p>если фильтр является частью стороннего api и, следовательно, вы не можете его изменить, сопоставьте его с более конкретным <code>url-pattern</code>, например, <code>/otherfilterpath/*</code> и создайте новый фильтр для <code>/*</code>, который перенаправляет на путь, соответствующий стороннему фильтру.</p><pre><code>string path = ((httpservletrequest) request).getrequesturi(); if (path.startswith("/specialpath/")) { chain.dofilter(request, response); // just continue chain. } else { request.getrequestdispatcher("/otherfilterpath" + path).forward(request, response); } </code></pre><p>чтобы избежать вызова этого фильтра в бесконечном цикле, необходимо разрешить ему прослушивать (отправлять) только <code>request</code> и сторонний фильтр только <code>forward</code>.</p><h3>смотрите также:</h3><ul> <li> <a href="https://stackoverflow.com/questions/13521946/how-to-prevent-static-resources-from-being-handled-by-front-controller-servlet-w">как предотвратить обработку статических ресурсов сервлетом фронт-контроллера, который отображается на/*</a> </li> <li> <a href="https://stackoverflow.com/questions/1483063/spring-mvc-3-and-handling-static-content-am-i-missing-something">как обрабатывать статический контент в spring mvc?</a> </li> </ul>

<p>я использовал подход <a href="http://blog.ericdaugherty.com/2010/02/excluding-content-from-url-pattern-in.html">описанный эриком даугерти</a> : я создал специальный сервлет, который всегда отвечает кодом 403 и ставит его отображение перед общим.</p><p>фрагмент карты:</p><pre class="lang-xml prettyprint-override"><code> <servlet> <servlet-name>generalservlet</servlet-name> <servlet-class>project.servlet.generalservlet</servlet-class> </servlet> <servlet> <servlet-name>specialservlet</servlet-name> <servlet-class>project.servlet.specialservlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>specialservlet</servlet-name> <url-pattern>/resources/restricted/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>generalservlet</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> </code></pre><p>и класс сервлетов:</p><pre><code>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); } } </code></pre>

<p>этот подход работает, когда вы хотите предотвратить определенный фильтр и все последующие. это должно работать хорошо, если вы, например. хотите использовать некоторый контент в качестве статических ресурсов в контейнере сервлета, вместо того, чтобы пропустить логику вашего приложения (через фильтр, такой как guicefilter):</p><p>сопоставьте папку со своими статическими файлами ресурсов с сервлетом по умолчанию. создайте фильтр сервлетов и поместите его <em>перед</em> guicefilter в вашем файле web.xml. в созданном вами фильтре вы можете разделить некоторые запросы к guicefilter, а другие - непосредственно диспетчеру. пример следует ...</p><p><strong> web.xml </strong></p><pre class="lang-xml prettyprint-override"><code><servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/static/*</url-pattern> </servlet-mapping> <filter> <filter-name>staticresourcefilter</filter-name> <filter-class>com.project.filter.staticresourcefilter</filter-class> </filter> <filter-mapping> <filter-name>staticresourcefilter</filter-name> <url-pattern>/static/*</url-pattern> </filter-mapping> <filter> <filter-name>guicefilter</filter-name> <filter-class>com.google.inject.servlet.guicefilter</filter-class> </filter> <filter-mapping> <filter-name>guicefilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </code></pre><p><strong> staticresourcefilter.class </strong></p><pre><code>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"); } } </code></pre><p>к сожалению, если вы просто хотите пропустить один шаг в цепочке фильтров, оставив при этом следующие, это не сработает.</p>

<p>я не думаю, что вы можете, единственная альтернатива конфигурации - перечислить пути, которые вы хотите отфильтровать, поэтому вместо <code>/*</code> вы можете добавить некоторые для <code>/this/*</code> и <code>/that/*</code> и т.д., но это не приведет к достаточному решению, когда у вас много таких путей.</p><p>что вы можете сделать, это добавить параметр в фильтр, обеспечивающий выражение (например, регулярное выражение), которое используется для пропуска функциональности фильтра для совпавших путей .. контейнер сервлета по-прежнему будет вызывать ваш фильтр для этих url-адресов, но вы будете лучше контролировать конфигурацию.</p><p><strong> правка </strong></p><p>теперь, когда вы упомянули, что не имеете никакого контроля над фильтром, вы можете либо наследовать от этого фильтра, вызывая методы <code>super</code> в его методах, кроме случаев, когда присутствует url-путь, который вы хотите пропустить, и следовать цепочке фильтров, как предложено @balusc, или создайте фильтр, который создает экземпляр вашего фильтра и делегатов при тех же обстоятельствах. в обоих случаях параметры фильтра будут включать как параметр выражения, который вы добавляете, так и параметр фильтра, от которого вы наследуете или делегируете.</p><p>преимущество создания делегирующего фильтра (оболочки) заключается в том, что вы можете добавить класс фильтра упакованного фильтра в качестве параметра и использовать его в других ситуациях, подобных этой.</p>

<p>мне также пришлось фильтровать по шаблону url (/ {servicename}/api/stats /) в коде java.</p><pre><code>if (path.startswith("/{servicename}/api/statistics/")) { validatingauthtoken(((httpservletrequest) request).getheader("auth\_token")); filterchain.dofilter(request, response); } </code></pre><p>но странно, что сервлет не поддерживает шаблон url, кроме (/ *), это должно быть очень распространенным случаем для api сервлетов! </p>

<p>я столкнулся с той же проблемой, но я нашел ответ, показанный ниже.</p><p>web.xml</p><pre><code> <!-- set this param value for the filter--> <init-param> <param-name>freepages</param-name> <param-value> mainframe.jsp; </param-value> </init-param> </code></pre><p>filter.java</p><pre><code>strfreepages = config.getinitparameter("freepages"); //get the exclue pattern from config file isfreepage(strrequestpage) //decide the exclude path </code></pre><p>таким образом, вам не нужно беспокоить конкретный класс filter.</p>

<p>если по какой-либо причине вы не можете изменить исходное сопоставление фильтра (в моем случае "/ *") и отправляете на неизменяемый сторонний фильтр, вы можете найти следующее:</p><ul> <li>перехватить путь, который нужно обойти</li> <li>пропустить и выполнить последнее кольцо цепочки фильтров (сам сервлет)</li> <li>пропуск выполняется через отражение, осматривая экземпляры контейнера в режиме отладки. </li> </ul><p>следующие работы в weblogic 12.1.3:</p><blockquote> <pre><code> 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(); } } } </code></pre> </blockquote>