You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在嵌入式Jetty中实现多级路径的高级路由?

Handling Multi-Level Path Routing in Embedded Jetty

Hey there! Great question—nested path routing like /user/1234/cart/addsomething is a common need, and embedded Jetty gives you a few solid ways to pull this off. Let’s walk through the most practical approaches, depending on how you want to structure your code.

1. Servlet 3.0+ Path Matching with Manual Parameter Extraction

This is the simplest approach if you want to stick with plain old Servlets. You can use wildcard url-patterns to catch the base path, then parse the rest of the URL to extract parameters and route to the right logic.

Example Code:

First, set up your embedded Jetty server and register Servlets with wildcard patterns:

public class EmbeddedJettyServer {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);

        // Register a servlet to handle all /user/* requests
        context.addServlet(new ServletHolder(new UserServlet()), "/user/*");
        // Register a cart servlet for nested paths
        context.addServlet(new ServletHolder(new CartServlet()), "/user/*/cart/*");

        server.start();
        server.join();
    }
}

Then, in the UserServlet, extract the user ID and forward to the CartServlet if needed:

public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String pathInfo = request.getPathInfo(); // Gets "/1234/cart/addsomething"
        if (pathInfo == null || pathInfo.length() <= 1) {
            response.getWriter().write("Invalid user request");
            return;
        }

        String[] pathSegments = pathInfo.split("/");
        String userId = pathSegments[1]; // Extracts "1234"
        request.setAttribute("userId", userId); // Pass userId to downstream servlets

        // Check if the next segment is "cart" and forward
        if (pathSegments.length >= 3 && "cart".equals(pathSegments[2])) {
            String forwardPath = String.join("/", Arrays.copyOfRange(pathSegments, 2, pathSegments.length));
            request.getRequestDispatcher("/user/" + userId + "/" + forwardPath).forward(request, response);
        } else {
            response.getWriter().write("Profile for user: " + userId);
        }
    }
}

Finally, the CartServlet handles the action:

public class CartServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String userId = (String) request.getAttribute("userId");
        String pathInfo = request.getPathInfo(); // Gets "/addsomething"
        String action = pathInfo.split("/")[1]; // Extracts "addsomething"

        if ("addsomething".equals(action)) {
            response.getWriter().write("Adding item to cart for user: " + userId);
        } else {
            response.getWriter().write("Unsupported cart action: " + action + " for user " + userId);
        }
    }
}

2. Use Jetty's Built-in RoutingHandler

If you want more flexible, declarative routing without Servlets, Jetty’s RoutingHandler is perfect. It lets you define route patterns with named parameters directly.

Example Code:

public class JettyRoutingServer {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        RoutingHandler routingHandler = new RoutingHandler();

        // Match /user/{userId}/cart/{action} and handle directly
        routingHandler.addRoute(
            RouteMatchers.path("/user/{userId}/cart/{action}"),
            (request, response) -> {
                // Extract named parameters from the route
                String userId = RouteData.get(request, "userId");
                String action = RouteData.get(request, "action");

                response.setContentType("text/plain");
                response.getWriter().write("User " + userId + " performing cart action: " + action);
                return true; // Signal that the request was handled
            }
        );

        // Add another route for /user/{userId}
        routingHandler.addRoute(
            RouteMatchers.path("/user/{userId}"),
            (request, response) -> {
                String userId = RouteData.get(request, "userId");
                response.getWriter().write("User profile: " + userId);
                return true;
            }
        );

        server.setHandler(routingHandler);
        server.start();
        server.join();
    }
}

3. Integrate JAX-RS (e.g., Jersey) for RESTful Routing

If you’re building a REST API, using JAX-RS with Jersey (which integrates seamlessly with Jetty) gives you clean, annotation-driven routing for nested paths.

Example Code:

First, define your JAX-RS resource class with @Path annotations:

@Path("/user")
public class UserResource {

    @GET
    @Path("/{userId}/cart/{action}")
    public Response handleCartAction(
        @PathParam("userId") String userId,
        @PathParam("action") String action
    ) {
        String message = String.format("User %s is %s in their cart", userId, action);
        return Response.ok(message).build();
    }

    @GET
    @Path("/{userId}")
    public Response getUserProfile(@PathParam("userId") String userId) {
        return Response.ok("Profile for user: " + userId).build();
    }
}

Then set up Jetty to use Jersey:

public class JettyJerseyServer {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");

        // Register Jersey's servlet container
        ServletHolder jerseyServlet = context.addServlet(
            org.glassfish.jersey.servlet.ServletContainer.class, "/*"
        );
        jerseyServlet.setInitOrder(0);
        // Tell Jersey about your resource class
        jerseyServlet.setInitParameter(
            "jersey.config.server.provider.classnames",
            UserResource.class.getCanonicalName()
        );

        server.setHandler(context);
        server.start();
        server.join();
    }
}

Which Approach Should You Choose?

  • Plain Servlets: Best if you want minimal dependencies and already work with Servlets.
  • RoutingHandler: Great for lightweight, flexible routing without the overhead of Servlets or JAX-RS.
  • JAX-RS: Ideal for REST APIs where you want standardized, annotation-driven routing and request/response handling.

内容的提问来源于stack exchange,提问作者Mr. SoUndso

火山引擎 最新活动