Last class, we made an RPC framework by ourselves. In this class, we will take on a slightly more difficult task of manually making a Web framework. I don’t like to call it an MVC framework because I didn’t think of it as an MVC when I made this little project. It was all about ease of use.
First, how easy is this Web framework to use
Hello World
import httpkids.server.KidsRequestDispatcher;
import httpkids.server.Router;
import httpkids.server.internal.HttpServer;
public class HelloWorld {
public static void main(String[] args) {
var rd = new KidsRequestDispatcher("/kids".new Router((ctx, req) -> {
ctx.html("Hello, World");
}));
new HttpServer("localhost".8080.2.16, rd).start();
}
}
http://localhost:8080/kids
Copy the code
KidsRequestDispatcher is a request dispatcher that throws the received HTTP request object to the responding RequestHandler for processing. The Router is used to build the route and is responsible for hooking up the URL rules with the RequestHandler to form a complex mapping table.
In order to simplify the implementation details, the Router does not support complex URL rules, such as RESTFUL formats that write parameters inside urls.
HttpServer is the core object of the Web server. In addition to the IP port, the HttpServer needs to provide three key parameters, namely, the number of I/O threads, the number of service threads and the request dispatker object. IO threads handle word reads and writes and are managed internally by Netty. Business threads are dedicated to handling HTTP requests and are managed by the HTTPKids framework.
A comprehensive example
import java.util.HashMap;
import httpkids.server.KidsRequestDispatcher;
import httpkids.server.Router;
import httpkids.server.internal.HttpServer;
public class HelloWorld {
public static void main(String[] args) {
var router = new Router((ctx, req) -> {
ctx.html("Hello, World"); // Plain text HTML
})
.handler("/hello.json", (ctx, req) -> {
ctx.json(new String[] { "Hello"."World" }); // JSON API
})
.handler("/hello", (ctx, req) -> {
var res = new HashMap<String, Object>();
res.put("req", req);
ctx.render("playground.ftl", res); // Template rendering
})
.handler("/world", (ctx, req) -> {
ctx.redirect("/hello"); / / 302 jump
})
.handler("/error", (ctx, req) -> {
ctx.abort(500."wtf"); / / exception
})
.resource("/pub"."/static") // Static resources
.child("/user", () - > {// Route nesting
return new Router((ctx, req) -> {
ctx.html("Hello, World");
})
.handler("/hello.json", (ctx, req) -> {
ctx.json(new String[] { "Hello"."World" });
})
.filter((ctx, req, before) -> { // filters, interceptors
if (before) {
System.out.printf("before %s\n", req.path());
} else {
System.out.printf("after %s\n", req.path());
}
return true;
});
});
var rd = new KidsRequestDispatcher("/kids", router); // Request the dispatcher
rd.templateRoot("/tpl"); // The template classpath root directory
rd.exception(500, (ctx, e) -> { // Exception handling
ctx.html("what the fuck it is".500);
})
.exception((ctx, e) -> { // General exception handling
ctx.html("mother fucker!", e.getStatus().code());
});
var server = new HttpServer("localhost".8080.2.16, rd);
server.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run(a) {
server.stop(); // Stop gracefully}}); } } http://localhost:8080/kids
http://localhost:8080/kids/hello
http://localhost:8080/kids/hello.json
http://localhost:8080/kids/world
http://localhost:8080/kids/error
http://localhost:8080/kids/pub/bootstrap.min.css
http://localhost:8080/kids/user
http://localhost:8080/kids/user/hello
Copy the code
The stack depth
Non-java programmers often complain about the complexity of Java’s framework, especially its horrible call stack. For example, this picture is widely circulated.
So here I’m going to highlight the HttpKids call stack and let’s see how deep it really is
Project code
HttpKids Web Framework based on Netty for Kids of You
RpcKids RPC Framework based on Netty for Kids of You
The big bang
Code hole