На последнем занятии мы сами сделали RPC-фреймворк, а на этом уроке мы поставили перед собой чуть более сложную задачу — вручную сделать веб-фреймворк. Я неохотно называю это фреймворком MVC, потому что я не думал о том, что это за MVC, когда делал этот небольшой проект, и все было направлено на простоту использования.
Сначала давайте посмотрим, насколько легко использовать этот веб-фреймворк.
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
KidsRequestDispatcher
Является диспетчером запросов, который используется для передачи полученного объекта HTTP-запроса в ответ.RequestHandler
для обработки.Router
Используется для построения маршрутов, отвечает за объединение правил URL сRequestHandler
Подключитесь, чтобы сформировать сложную таблицу сопоставления.
Router
Чтобы упростить детали реализации, не поддерживаются сложные правила URL, такие какRESTFUL
Такая форма записи параметров в URL не поддерживается.
HttpServer
Это основной объект веб-сервера.Помимо IP-порта, HttpServer также должен предоставлять три ключевых параметра, а именно количество потоков ввода-вывода, количество бизнес-потоков и объект диспетчера запросов. Потоки ввода-вывода используются для обработки чтения и записи слов набора и управляются внутри Netty. Бизнес-потоки предназначены для обработки HTTP-запросов и управляются платформой httpkids.
исчерпывающий пример
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"); // 纯文本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); // 模版渲染
})
.handler("/world", (ctx, req) -> {
ctx.redirect("/hello"); // 302跳转
})
.handler("/error", (ctx, req) -> {
ctx.abort(500, "wtf"); // 异常
})
.resource("/pub", "/static") // 静态资源
.child("/user", () -> { // 路由嵌套
return new Router((ctx, req) -> {
ctx.html("Hello, World");
})
.handler("/hello.json", (ctx, req) -> {
ctx.json(new String[] { "Hello", "World" });
})
.filter((ctx, req, before) -> { // 过滤器、拦截器
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); // 请求派发器
rd.templateRoot("/tpl"); // 模版classpath根目录
rd.exception(500, (ctx, e) -> { // 异常处理
ctx.html("what the fuck it is", 500);
})
.exception((ctx, e) -> { // 通用异常处理
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() {
server.stop(); // 优雅停机
}
});
}
}
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
глубина стека
Не-Java-программисты всегда жалуются, что среда Java слишком сложна, и особенно любят говорить об ужасном стеке вызовов Java. Например, изображение ниже широко распространено.
Итак, здесь я собираюсь показать стек вызовов httpkids, давайте посмотрим, насколько он глубок.
код проекта
HttpKids Web Framework based on Netty for Kids of You
RpcKids RPC Framework based on Netty for Kids of You