Java:带有 Vaadin 11 框架的 Jetty 服务器

Java: Jetty server with Vaadin 11 framework

我的目标是配置 Jetty 服务器以使用 Vaadin 11 框架。
我正在尝试的是以下内容:

public static void main(final String[] args) {
    final Server server = new Server();
    final ServerConnector httpConnector = new ServerConnector(server);
    httpConnector.setPort(8080);
    final ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
    contextHandler.setContextPath("/");
    final ServletHolder servletHolder = new ServletHolder(new VaadinServlet());
    contextHandler.addServlet(servletHolder, "/*");
    final WebAppContext context = new WebAppContext();
    context.setServer(server);
    context.setContextPath("/");
    context.setClassLoader(Thread.currentThread().getContextClassLoader());
    server.addConnector(httpConnector);
    server.setHandler(contextHandler);
    server.setHandler(context);

    try {
        server.start();
    } catch (final Exception e) {
        e.printStackTrace();
    }
}


@Route("/")
public class MainView extends Div {
    public MainView() {
        System.out.println("main");
        setText("aha bye");
    }
}

但是从未调用 MainView。 我如何告诉 Jetty 将请求转发给 Vaadin?

server.setHandler(contextHandler);
server.setHandler(context);

您用该代码用 context 替换了 contextHandler

试试这个...

HandlerList handlers = new HandlerList();
handlers.addHandler(contextHandler);
handlers.addHandler(context);
handlers.addHandler(new DefaultHandler()); // to report errors if nothing above matches
server.setHandler(handlers);    

但这仍然无法如您所愿。 为什么?因为在同一个 contextPath /.

上有 2 个不同的上下文(contextHandlercontext

将使用您 HandlerList 中的第一个上下文,而永远不会调用下一个。 为什么?因为一旦进入上下文,就不会退出(该上下文必须提供响应,甚至是错误)。

您可以修改 WebAppContext 以包含 VaadinServlet(完全不需要 ServletContextHandler

例如:

final WebAppContext context = new WebAppContext();
final ServletHolder servletHolder = new ServletHolder(new VaadinServlet());
context.addServlet(servletHolder, "/*");

但是,这似乎又回到了wards,因为您的 WebAppContext 没有资源库或 war 声明,所以它在您的示例代码中没有为您做任何事情。

如果是我,我正在使用 ,我会完全避免使用 WebAppContext,只坚持使用 ServletContextHandler

在这里回答我自己的问题。

But this will still not work as you expect. Why? Because you have 2 different contexts (contextHandler and context) on the same contextPath /.

But again, this seems backwards, as your WebAppContext has no resource base or war declared, so it's not doing anything for you in your sample code.

Joakim Erdfelt完全正确。我用两个上下文 弄乱了代码 我必须设置资源库或 war 文件。非常感谢您指出了解决方法!

也感谢 Leif Åstrand 提示找到所有带有 @Route 注释的 类!

我将服务器代码与“客户端”代码分开,并为码头服务器构建 war 文件。

我使用的工作解决方案如下:

final WebAppContext context = new WebAppContext();
context.setServer(httpServer);
context.setContextPath("/");
context.addServlet(new ServletHolder(new TestServlet()), "/*");
context.setWar(warFile.getAbsolutePath());
context.setExtractWAR(true);
context.setClassLoader(Thread.currentThread().getContextClassLoader());
context.setInitParameter("ui", MainUI.class.getCanonicalName());
httpServer.setHandler(context);

Testservlet(扩展VaadinServlet)我有以下两种方法:

@SuppressWarnings("unchecked")
private void findRouteClasses() {
    final Set<Class<?>> routeClasses = ReflectionUtils.findClassesWithAnnotation(Route.class,
    "com.example.myproject");

    this.routeClasses = new HashSet<>();

    for (final Class<?> clazz : routeClasses)
        this.routeClasses.add((Class<? extends Component>) clazz);
}

@Override
protected void servletInitialized() throws ServletException {
    final ServletContext context = getServletContext();
    final Object routeRegistryObject = context.getAttribute(RouteRegistry.class.getName());

    if (routeRegistryObject == null)
        throw new ServletException("routeRegistryObject is null");

    if ((routeRegistryObject instanceof RouteRegistry) == false)
        throw new ServletException("routeRegistryObject is not of type RouteRegistry");

    final RouteRegistry routeRegistry = (RouteRegistry) routeRegistryObject;
    findRouteClasses();

    try {
        routeRegistry.setNavigationTargets(routeClasses);
    } catch (final InvalidRouteConfigurationException e) {
        throw new ServletException(e);
    }

    super.servletInitialized();
}

所有类注解com.vaadin.flow.router.Route被搜索然后设置为导航目标。