如何在嵌入式Jetty中添加Servlet Filter

26

我正在将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()), "/");

我找到的唯一关于这个问题的信息是一个论坛帖子建议改进文档


你不能在web.xml文件中定义它吗?我知道这是嵌入式的,但只要你在WEB-INF/web.xml下有文件的类路径,就应该没问题。 - Καrτhικ
7
我已经很久没有使用web.xml了,通常我只使用servlet 3.0规范的注解。我只是不喜欢在XML文件中到处搞。 - Jay
4个回答

28

我遇到了同样的问题,但我认为Κα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();

我的jetty版本是8.1.14.v20131031


4
没错,另一个答案对于实际问题有很多无关的内容。 - Renato

27
更新:对于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()方法,请确保在Web应用程序的根路径下有一个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,似乎也可以工作。 - Jay
参数值为1的参数是启动时要启动的实例数量。 - Καrτhικ
据我理解Jetty 9.1.3,最后一个参数是EnumSet<DispatcherType>:在ServletContextHandler中声明的。public FilterHolder addFilter(Class<? extends Filter> filterClass,String pathSpec,EnumSet<DispatcherType> dispatches) - Dirk Schumacher
没错。在9.x版本中,许多API已经发生了变化。 - Καrτhικ
你能在同一路径上添加多个过滤器吗? - Gobliins
显示剩余2条评论

5

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 );

0

已更新为Java 11,不再使用javax,改用Jakarta,并使用11.0.3版Jetty。

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));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接