如何使用嵌入式码头添加 servlet 过滤器
Posted
技术标签:
【中文标题】如何使用嵌入式码头添加 servlet 过滤器【英文标题】:How to add servlet Filter with embedded jetty 【发布时间】:2013-01-01 16:05:51 【问题描述】:我正在将 jetty 嵌入到我的应用程序中,并试图弄清楚如何添加 servlet 过滤器(用于 cookie 处理)。 wiki 和 javadoc 并没有说得很清楚,我错过了什么:
Server server = new Server(port);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
FilterHolder f = new FilterHolder(new AuthorisationFilter());
context.addFilter(... f ...); // ?????
context.addServlet(new ServletHolder(new TestServlet()), "/");
我在这方面找到的唯一信息是forum post suggesting the documentation,这需要改进。
【问题讨论】:
是否有您无法在 web.xml 文件中定义它的原因。我意识到这是嵌入的,但只要你在 WEB-INF/web.xml 下的类路径中有文件,你应该没问题。 好久没用web.xml了,一般只用servlet 3.0 spec注解。我只是不喜欢处理 XML 文件。 【参考方案1】:更新:对于 Jetty 版本 9.2.2:
Server server = new Server();
// Note: if you don't want control over type of connector, etc. you can simply
// call new Server(<port>);
ServerConnector connector = new ServerConnector(server);
connector.setHost("0.0.0.0");
connector.setPort(8085);
// Setting the name allows you to serve different app contexts from different connectors.
connector.setName("main");
server.addConnector(connector);
WebAppContext context = new WebAppContext();
context.setContextPath("/");
// For development within an IDE like Eclipse, you can directly point to the web.xml
context.setWar("src/main/webapp");
context.addFilter(MyFilter.class, "/", 1);
HandlerCollection collection = new HandlerCollection();
RequestLogHandler rlh = new RequestLogHandler();
// Slf4j - who uses anything else?
Slf4jRequestLog requestLog = new Slf4jRequestLog();
requestLog.setExtended(false);
rlh.setRequestLog(requestLog);
collection.setHandlers(new Handler[] context, rlh );
server.setHandler(collection);
try
server.start();
server.join();
catch (Exception e)
// Google guava way
throw Throwables.propagate(e);
原始答案 ===
如果你不想使用 web.xml,那么使用这个:
SocketConnector socketConnector = new SocketConnector();
socketConnector.setPort(7000); // Change to port you want
Server server.setConnectors(new Connector[] socketConnector );
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/"); // For root
webapp.setWar("/"); // Appropriate file system path.
// Now you can use the various webapp.addFilter() methods
webapp.addFilter(MyFilter.class, "/test", 1); // Will serve request to /test.
// There are 3 different addFilter() variants.
// Bonus ... request logs.
RequestLogHandler logHandler = new RequestLogHandler();
NCSARequestLog requestLog = new NCSARequestLog("/tmp/jetty-yyyy_mm_dd.request.log");
requestLog.setRetainDays(90);
requestLog.setAppend(true);
requestLog.setExtended(false);
requestLog.setLogTimeZone("GMT");
logHandler.setRequestLog(requestLog);
logHandler.setHandler(webapp);
HandlerList handlerList = new HandlerList();
handlerList.addHandler(logHandler);
server.setHandler(handlerList);
server.start();
如果您确实想使用 web.xml,而不是 addFilter() 方法,只需确保您的 webapp 根路径中有一个 WEB-INF/web.xml,并带有以下 xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<filter>
<filter-name>filterName</filter-name>
<filter-class>com.x.y.z.FilterClass</filter-class>
</filter>
<filter-mapping>
<url-pattern>/test</url-pattern>
<filter-name>filterName</filter-name>
</filter-mapping>
</web-app>
【讨论】:
谢谢。webapp.addFilter(MyFilter.class, "/test", 1)
中的 1 是什么意思。在我的代码中,我只是忽略了它并传入了 NULL,这似乎也有效。
值为1的参数是启动时要启动的实例数。
据我了解 jetty 9.1.3,最后一个参数是 EnumSet我遇到了同样的问题,但我认为 Καrτhικ 的答案太复杂了。我找到了这个简单的方法:
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/");
context.addFilter(AppFilter.class, "/*", EnumSet.of(DispatcherType.INCLUDE,DispatcherType.REQUEST));
server.setHandler(context);
server.start();
server.join();
我的码头版本是8.1.14.v20131031
。
【讨论】:
是的,另一个答案有很多与实际问题无关的东西。【参考方案3】:ServletContextHandler.addFilter(...)
方法只是 ServletHandler.addFilter(...)
方法的便捷包装。如果您只需要一个<url-pattern>
,他们非常非常方便。但是,如果您需要多个模式或选择使用<servlet-name>
,您将需要更多类似的东西:
ServletContextHandler context = new ServletContextHandler(
ServletContextHandler.SESSIONS);
FilterMapping mapping = new FilterMapping();
mapping.setFilterName( "Foobar Filter" );
mapping.setPathSpecs( new String[] "/foo/*", "/bar/*" );
mapping.setServletNames( new String[] "foobar" );
mapping.setDispatcherTypes(
EnumSet.of( DispatcherType.INCLUDE,DispatcherType.REQUEST ) ) );
FilterHolder holder = new FilterHolder( FoobarFilter.class );
holder.setName( "Foobar Filter" );
context .getServletHandler().addFilter( holder, mapping );
【讨论】:
【参考方案4】:为 java 11 而不是 javax 更新。使用雅加达。和 11.0.3 用于码头
ServletHolder servletHolder = new ServletHolder(DefaultServlet.class);
servletHolder.setInitParameter("resourceBase","./resource");
servletHolder.setInitParameter("dirAllowed", "false");
servletHolder.setInitParameter("pathInfoOnly", "true");
servletHandler.addServlet(servletHolder, "/api/source/*");
FilterHolder f = new FilterHolder(new MyFilter());
servletHandler.addFilter(MediaFilter.class, "/api/source/*",
EnumSet.allOf(DispatcherType.class));
【讨论】:
以上是关于如何使用嵌入式码头添加 servlet 过滤器的主要内容,如果未能解决你的问题,请参考以下文章
在 servlet 中以编程方式调用过滤器(使用码头/火花创建)?