HttpHandlers are the building blocks of Undertow. Luckily they are extremely easy to write. Here are a few different approaches that will be used throughout posts on this site.
Custom Class Implementing HttpHandler
This is generally the best option when writing middleware / filtering HttpHandlers that delegate responsibility to other handlers or handlers with lots of code or complex logic.
public class ConstantStringHandler implements HttpHandler {
private final String value;
public ConstantStringHandler(String value) {
this.value = value;
}
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send(value + "\n");
}
}
Sometimes it is nice to then couple classes with static factory methods than can reduce boiler plate or group common handlers together. This will be used extensively in later posts. This is also used in Undertow Core's Handlers.java.
/*
* Creating static factory methods to construct handlers let's you keep
* them better organized and reduce some boilerplate. This will be shown
* in future examples.
*/
public static HttpHandler constantStringHandler(String value) {
return new ConstantStringHandler(value);
}
Anonymous Handler using Java 8 Lambda
/*
* Alternate way to create constantStringHandler using an anonymous HttpHandler.
* This is fine for simple handlers but more complex ones might be better off
* in their own file.
*/
public static HttpHandler constantStringHandlerAlt(String value) {
return (HttpServerExchange exchange) -> {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send(value);
};
}
Notice this has the exact some logic as the more verbose handler above. This approach is nice for simple handlers however a separate class is preferred for more complex logic.
Implement the HttpHandler contract as a method
This is a great approach for the business logic of routes. Any handler that reads params and sends a response fits this design well. You can put multiple handlers in a single file to keep groups of handlers organized. This does not work as well for filters / middleware or handlers with multiple params. It becomes harder to pass them this way.
/*
* This is a 3rd approach to creating HttpHandlers and is heavily utilized
* in StubbornJava. We can use Java 8 method references for this approach.
* Notice how the void return type and single HttpServerExchange parameter
* fulfill the HttpHandler interface.
*
* This approach is most commonly used for the actual business logic and generally
* is responsible for sending the response. Any handlers that chain / delegate
* to other handlers are not a great fit for this style.
*/
public static void notFoundHandler(HttpServerExchange exchange) {
exchange.setStatusCode(404);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send("Page Not Found!!");
}
This can be passed anywhere a HttpHandler is accepted like so.
HttpHandler handler = RoutingHandlers::notFoundHandler;