{"id":13458911,"url":"https://github.com/lets-blade/blade","last_synced_at":"2025-05-08T23:34:05.029Z","repository":{"id":33527445,"uuid":"37173512","full_name":"lets-blade/blade","owner":"lets-blade","description":":rocket: Lightning fast and elegant mvc framework for Java8","archived":false,"fork":false,"pushed_at":"2025-02-11T05:23:47.000Z","size":3382,"stargazers_count":5862,"open_issues_count":12,"forks_count":1170,"subscribers_count":284,"default_branch":"v2.1.3","last_synced_at":"2025-05-08T17:02:58.554Z","etag":null,"topics":["blade","java8","mvc-framework","netty4","restful","template-engine"],"latest_commit_sha":null,"homepage":"https://lets-blade.github.io","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lets-blade.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"hellokaton","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"custom":"https://www.paypal.me/bladejava"}},"created_at":"2015-06-10T03:35:49.000Z","updated_at":"2025-05-06T12:31:39.000Z","dependencies_parsed_at":"2023-11-30T18:12:41.957Z","dependency_job_id":"98f57866-20b0-4d39-b5de-530fca0f97a5","html_url":"https://github.com/lets-blade/blade","commit_stats":{"total_commits":734,"total_committers":39,"mean_commits":18.82051282051282,"dds":"0.19891008174386926","last_synced_commit":"aa32ce91386f491a3d0cb174beb190be1505ca27"},"previous_names":["biezhi/blade"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lets-blade%2Fblade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lets-blade%2Fblade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lets-blade%2Fblade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lets-blade%2Fblade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lets-blade","download_url":"https://codeload.github.com/lets-blade/blade/tar.gz/refs/heads/v2.1.3","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253124242,"owners_count":21857614,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blade","java8","mvc-framework","netty4","restful","template-engine"],"created_at":"2024-07-31T09:00:59.623Z","updated_at":"2025-05-08T23:34:05.001Z","avatar_url":"https://github.com/lets-blade.png","language":"Java","readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://lets-blade.com\"\u003e\u003cimg src=\"https://i.loli.net/2018/09/18/5ba0cd93c710e.png\" width=\"650\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003eBased on \u003ccode\u003eJava8\u003c/code\u003e + \u003ccode\u003eNetty4\u003c/code\u003e to create a lightweight, high-performance, simple and elegant Web framework 😋\u003c/p\u003e\n\u003cp align=\"center\"\u003eSpend \u003cb\u003e1 hour\u003c/b\u003e to learn it to do something interesting, a tool in addition to the other available frameworks.\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    🐾 \u003ca href=\"#quick-start\" target=\"_blank\"\u003eQuick Start\u003c/a\u003e |\n    🌚 \u003ca href=\"https://lets-blade.github.io/\" target=\"_blank\"\u003eDocumentation\u003c/a\u003e |\n    :green_book: \u003ca href=\"https://www.baeldung.com/blade\" target=\"_blank\"\u003eGuidebook\u003c/a\u003e |\n    💰 \u003ca href=\"https://lets-blade.github.io/donate\" target=\"_blank\"\u003eDonate\u003c/a\u003e |\n    🇨🇳 \u003ca href=\"README_CN.md\"\u003e简体中文\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://travis-ci.org/lets-blade/blade\"\u003e\u003cimg src=\"https://img.shields.io/travis/lets-blade/blade.svg?style=flat-square\"\u003e\u003c/a\u003e\n    \u003ca href=\"http://search.maven.org/#search%7Cga%7C1%7Cblade-core\"\u003e\u003cimg src=\"https://img.shields.io/maven-central/v/com.hellokaton/blade-core.svg?style=flat-square\"\u003e\u003c/a\u003e\n    \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache%202-4EB1BA.svg?style=flat-square\"\u003e\u003c/a\u003e\n    \u003ca class=\"badge-align\" href=\"https://www.codacy.com/gh/lets-blade/blade/dashboard\"\u003e\u003cimg src=\"https://app.codacy.com/project/badge/Grade/1eff0e30bf694402ac1b0ebe587bfa5a\"/\u003e\u003c/a\u003e\n    \u003ca href=\"https://gitter.im/lets-blade/blade\"\u003e\u003cimg src=\"https://badges.gitter.im/hellokaton/blade.svg?style=flat-square\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.codetriage.com/lets-blade/blade\"\u003e\u003cimg src=\"https://www.codetriage.com/lets-blade/blade/badges/users.svg\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n***\n\n## What Is Blade?\n\n`Blade` is a pursuit of simple, efficient Web framework, so that `JavaWeb` development becomes even more powerful, both in performance and flexibility.\nIf you like to try something interesting, I believe you will love it.\nIf you think it's good, you can support it with a [star](https://github.com/lets-blade/blade/stargazers) or by [donating](https://ko-fi.com/hellokaton) :blush:\n\n## Features\n\n* [x] A new generation MVC framework that doesn't depend on other libraries\n* [x] Get rid of SSH's bloated, modular design\n* [x] Source is less than `500kb`, learning it is also simple\n* [x] RESTful-style routing design\n* [x] Template engine support, view development more flexible\n* [x] High performance, 100 concurrent qps 20w/s\n* [x] Run the `JAR` package to open the web service\n* [x] Streams-style API\n* [x] `CSRF` and `XSS` defense\n* [x] `Basic Auth` and `Authorization`\n* [x] Supports plug-in extensions\n* [x] Support webjars resources\n* [x] Tasks based on `cron` expressions\n* [x] Built-in a variety of commonly used middleware\n* [x] Built-in Response output\n* [x] JDK8 +\n\n## Overview\n\n» Simplicity: The design is simple, easy to understand and doesn't introduce many layers between you and the standard library. The goal of this project is that the users should be able to understand the whole framework in a single day.\u003cbr/\u003e\n» Elegance: `blade` supports the RESTful style routing interface, has no invasive interceptors and provides the writing of a DSL grammar.\u003cbr/\u003e\n» Easy deploy: supports `maven` package `jar` file running.\u003cbr/\u003e\n\n## Quick Start\n\nCreate a basic `Maven` or `Gradle` project.\n\n\u003e Do not create a `webapp` project, Blade does not require much trouble.\n\nRun with `Maven`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.hellokaton\u003c/groupId\u003e\n    \u003cartifactId\u003eblade-core\u003c/artifactId\u003e\n    \u003cversion\u003e2.1.2.RELEASE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nor `Gradle`:\n\n```sh\ncompile 'com.hellokaton:blade-core:2.1.2.RELEASE'\n```\n\nWrite the `main` method and the `Hello World`:\n\n```java\npublic static void main(String[] args) {\n    Blade.create().get(\"/\", ctx -\u003e ctx.text(\"Hello Blade\")).start();\n}\n```\n\nOpen http://localhost:9000 in your browser to see your first `Blade` application!\n\n## Contents\n\n- [**`Register Route`**](#register-route)\n    - [**`HardCode`**](#hardCode)\n    - [**`Controller`**](#controller)\n- [**`Request Parameter`**](#request-parameter)\n    - [**`URL Parameter`**](#URL-parameter)\n    - [**`Form Parameter`**](#form-parameter)\n    - [**`Path Parameter`**](#path-parameter)\n    - [**`Body Parameter`**](#body-parameter)\n    - [**`Parse To Model`**](#parse-to-model)\n- [**`Get Environment`**](#get-environment)\n- [**`Get Header`**](#get-header)\n- [**`Get Cookie`**](#get-cookie)\n- [**`Static Resource`**](#static-resource)\n- [**`Upload File`**](#upload-file)\n- [**`Download File`**](#download-file)\n- [**`Set Session`**](#set-session)\n- [**`Render To Browser`**](#render-to-browser)\n    - [**`Render Response`**](#render-json)\n    - [**`Render Text`**](#render-text)\n    - [**`Render Html`**](#render-html)\n- [**`Render Template`**](#render-template)\n    - [**`Default Template`**](#default-template)\n    - [**`Jetbrick Template`**](#jetbrick-template)\n- [**`Redirects`**](#redirects)\n- [**`Write Cookie`**](#write-cookie)\n- [**`Web Hook`**](#web-hook)\n- [**`Logging`**](#logging)\n- [**`Basic Auth`**](#basic-auth)\n- [**`Change Server Port`**](#change-server-port)\n- [**`Configuration SSL`**](#configuration-ssl)\n- [**`Custom Exception Handler`**](#custom-exception-handler)\n\n## Register Route\n\n### HardCode\n\n```java\npublic static void main(String[] args) {\n    // Create multiple routes GET, POST, PUT, DELETE using Blade instance\n    Blade.create()\n        .get(\"/user/21\", getting)\n        .post(\"/save\", posting)\n        .delete(\"/remove\", deleting)\n        .put(\"/putValue\", putting)\n        .start();\n}\n```\n\n### `Controller`\n\n```java\n@Path\npublic class IndexController {\n\n    @GET(\"/login\")\n    public String login(){\n        return \"login.html\";\n    }\n    \n    @POST(value = \"/login\", responseType = ResponseType.JSON)\n    public RestResponse doLogin(RouteContext ctx){\n        // do something\n        return RestResponse.ok();\n    }\n\n}\n```\n\n## Request Parameter\n\n### URL Parameter\n\n**Using RouteContext**\n\n```java\npublic static void main(String[] args) {\n    Blade.create().get(\"/user\", ctx -\u003e {\n        Integer age = ctx.queryInt(\"age\");\n        System.out.println(\"age is:\" + age);\n    }).start();\n}\n```\n\n**Using `@Query` annotation**\n\n```java\n@GET(\"/user\")\npublic void savePerson(@Query Integer age){\n  System.out.println(\"age is:\" + age);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X GET http://127.0.0.1:9000/user?age=25\n```\n\n### Form Parameter\n\nHere is an example:\n\n**Using RouteContext**\n\n```java\npublic static void main(String[] args) {\n    Blade.create().get(\"/user\", ctx -\u003e {\n        Integer age = ctx.fromInt(\"age\");\n        System.out.println(\"age is:\" + age);\n    }).start();\n}\n```\n\n**Using `@Form` Annotation**\n\n```java\n@POST(\"/save\")\npublic void savePerson(@Form String username, @Form Integer age){\n  System.out.println(\"username is:\" + username + \", age is:\" + age);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X POST http://127.0.0.1:9000/save -F username=jack -F age=16\n```\n\n### Path Parameter\n\n**Using RouteContext**\n\n```java\npublic static void main(String[] args) {\n    Blade blade = Blade.create();\n    // Create a route: /user/:uid\n    blade.get(\"/user/:uid\", ctx -\u003e {\n        Integer uid = ctx.pathInt(\"uid\");\n        ctx.text(\"uid : \" + uid);\n    });\n\n    // Create two parameters route\n    blade.get(\"/users/:uid/post/:pid\", ctx -\u003e {\n        Integer uid = ctx.pathInt(\"uid\");\n        Integer pid = ctx.pathInt(\"pid\");\n        String msg = \"uid = \" + uid + \", pid = \" + pid;\n        ctx.text(msg);\n    });\n    \n    // Start blade\n    blade.start();\n}\n```\n\n**Using `@PathParam` Annotation**\n\n```java\n@GET(\"/users/:username/:page\")\npublic void userTopics(@PathParam String username, @PathParam Integer page){\n    System.out.println(\"username is:\" + usernam + \", page is:\" + page);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X GET http://127.0.0.1:9000/users/hellokaton/2\n```\n\n### Body Parameter\n\n```java\npublic static void main(String[] args) {\n    Blade.create().post(\"/body\", ctx -\u003e {\n        System.out.println(\"body string is:\" + ctx.bodyToString());\n    }).start();\n}\n```\n\n**Using `@Body` Annotation**\n\n```java\n@POST(\"/body\")\npublic void readBody(@Body String data){\n    System.out.println(\"data is:\" + data);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X POST http://127.0.0.1:9000/body -d '{\"username\":\"hellokaton\",\"age\":22}'\n```\n\n### Parse To Model\n\nThis is the `User` model.\n\n```java\npublic class User {\n    private String username;\n    private Integer age;\n    // getter and setter\n}\n```\n\n**By Annotation**\n\n```java\n@POST(\"/users\")\npublic void saveUser(@Form User user) {\n    System.out.println(\"user =\u003e \" + user);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X POST http://127.0.0.1:9000/users -F username=jack -F age=16\n```\n\n**Custom model identification**\n\n```java\n@POST(\"/users\")\npublic void saveUser(@Form(name=\"u\") User user) {\n    System.out.println(\"user =\u003e \" + user);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X POST http://127.0.0.1:9000/users -F u[username]=jack -F u[age]=16\n```\n\n**Body Parameter To Model**\n\n```java\n@POST(\"/body\")\npublic void body(@Body User user) {\n    System.out.println(\"user =\u003e \" + user);\n}\n```\n\nTest it with sample data from the terminal\n\n```bash\ncurl -X POST http://127.0.0.1:9000/body -d '{\"username\":\"hellokaton\",\"age\":22}'\n```\n\n## Get Environment\n\n```java\nEnvironment environment = WebContext.blade().environment();\nString version = environment.get(\"app.version\", \"0.0.1\");\n```\n\n## Get Header\n\n**By Context**\n\n```java\n@GET(\"header\")\npublic void readHeader(RouteContext ctx){\n    System.out.println(\"Host =\u003e \" + ctx.header(\"Host\"));\n    // get useragent\n    System.out.println(\"UserAgent =\u003e \" + ctx.userAgent());\n    // get client ip\n    System.out.println(\"Client Address =\u003e \" + ctx.address());\n}\n```\n\n**By Annotation**\n\n```java\n@GET(\"header\")\npublic void readHeader(@Header String host){\n    System.out.println(\"Host =\u003e \" + host);\n}\n```\n\n## Get Cookie\n\n**By Context**\n\n```java\n@GET(\"cookie\")\npublic void readCookie(RouteContext ctx){\n    System.out.println(\"UID =\u003e \" + ctx.cookie(\"UID\"));\n}\n```\n\n**By Annotation**\n\n```java\n@GET(\"cookie\")\npublic void readCookie(@Cookie String uid){\n    System.out.println(\"Cookie UID =\u003e \" + uid);\n}\n```\n\n## Static Resource\n\nBlade builds a few static resource catalog, as long as you will save the resource file in the static directory under the classpath, and then browse http://127.0.0.1:9000/static/style.css\n\nIf you want to customize the static resource URL\n\n```java\nBlade.create().addStatics(\"/mydir\");\n```\n\nOf course you can also specify it in the configuration file. `application.properties` (location in classpath)\n\n```bash\nmvc.statics=/mydir\n```\n\n## Upload File\n\n**By Request**\n\n```java\n@POST(\"upload\")\npublic void upload(Request request){\n    request.fileItem(\"img\").ifPresent(fileItem -\u003e {\n        fileItem.moveTo(new File(fileItem.getFileName()));\n    });\n}\n```\n\n**By Annotation**\n\n```java\n@POST(\"upload\")\npublic void upload(@Multipart FileItem fileItem){\n    // Save to new path\n    fileItem.moveTo(new File(fileItem.getFileName()));\n}\n```\n\n## Download File\n\n```java\n@GET(value = \"/download\", responseType = ResponseType.STREAM)\npublic void download(Response response) throws IOException {\n    response.write(\"abcd.pdf\", new File(\"146373013842336153820220427172437.pdf\"));\n}\n```\n\n**If you want to preview certain files in your browser**\n\n```java\n@GET(value = \"/preview\", responseType = ResponseType.PREVIEW)\npublic void preview(Response response) throws IOException {\n    response.write(new File(\"146373013842336153820220427172437.pdf\"));\n}\n```\n\n## Set Session\n\nThe session is disabled by default, you must enable the session.\n\n```java\nBlade.create()\n     .http(HttpOptions::enableSession)\n     .start(Application.class, args);\n```\n\n\u003e 💡 It can also be enabled using a configuration file，`http.session.enabled=true` \n\n```java\npublic void login(Session session){\n    // if login success\n    session.attribute(\"login_key\", SOME_MODEL);\n}\n```\n\n## Render To Browser\n\n### Render Response\n\n**By Context**\n\n```java\n@GET(\"users/json\")\npublic void printJSON(RouteContext ctx){\n    User user = new User(\"hellokaton\", 18);\n    ctx.json(user);\n}\n```\n\n**By Annotation**\n\nThis form looks more concise 😶\n\n```java\n@GET(value = \"/users/json\", responseType = ResponseType.JSON)\npublic User printJSON(){\n    return new User(\"hellokaton\", 18);\n}\n```\n\n### Render Text\n\n```java\n@GET(\"text\")\npublic void printText(RouteContext ctx){\n    ctx.text(\"I Love Blade!\");\n}\n```\n\nor\n\n```java\n@GET(value = \"/text\", responseType = ResponseType.TEXT)\npublic String printText(RouteContext ctx){\n    return \"I Love Blade!\";\n}\n```\n\n### Render Html\n\n```java\n@GET(\"html\")\npublic void printHtml(RouteContext ctx){\n    ctx.html(\"\u003ccenter\u003e\u003ch1\u003eI Love Blade!\u003c/h1\u003e\u003c/center\u003e\");\n}\n```\n\nor\n\n```java\n@GET(value = \"/html\", responseType = ResponseType.HTML)\npublic String printHtml(RouteContext ctx){\n    return \"\u003ccenter\u003e\u003ch1\u003eI Love Blade!\u003c/h1\u003e\u003c/center\u003e\";\n}\n```\n\n## Render Template\n\nBy default all template files are in the templates directory; in most of the cases you do not need to change it.\n\n### Default Template\n\nBy default, Blade uses the built-in template engine, which is very simple. In a real-world web project, you can try several other extensions.\n\n```java\npublic static void main(String[] args) {\n    Blade.create().get(\"/hello\", ctx -\u003e {\n        ctx.attribute(\"name\", \"hellokaton\");\n        ctx.render(\"hello.html\");\n    }).start(Hello.class, args);\n}\n```\n\nThe `hello.html` template\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003ctitle\u003eHello Page\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\n    \u003ch1\u003eHello, ${name}\u003c/h1\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### Jetbrick Template\n\n**Config Jetbrick Template**\n\nCreate a `BladeLoader` class and load some config\n\n```java\n@Bean\npublic class TemplateConfig implements BladeLoader {\n\n    @Override\n    public void load(Blade blade) {\n        blade.templateEngine(new JetbrickTemplateEngine());\n    }\n\n}\n```\n\nWrite some data for the template engine to render\n\n```java\npublic static void main(String[] args) {\n    Blade.create().get(\"/hello\", ctx -\u003e {\n        User user = new User(\"hellokaton\", 50);\n        ctx.attribute(\"user\", user);\n        ctx.render(\"hello.html\");\n    }).start(Hello.class, args);\n}\n```\n\nThe `hello.html` template\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta charset=\"UTF-8\"\u003e\n    \u003ctitle\u003eHello Page\u003c/title\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\n    \u003ch1\u003eHello, ${user.username}\u003c/h1\u003e\n\n    #if(user.age \u003e 18)\n        \u003cp\u003eGood Boy!\u003c/p\u003e\n    #else\n        \u003cp\u003eGooood Baby!\u003c/p\u003e\n    #end\n\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n[Render API](http://static.javadoc.io/com.hellokaton/blade-core/2.1.2.RELEASE/com/hellokaton/blade/mvc/http/Response.html#render-com.ModelAndView-)\n\n## Redirects\n\n```java\n@GET(\"redirect\")\npublic void redirectToGithub(RouteContext ctx){\n    ctx.redirect(\"https://github.com/hellokaton\");\n}\n```\n\n[Redirect API](http://static.javadoc.io/com.hellokaton/blade-core/2.1.2.RELEASE/com/hellokaton/blade/mvc/http/Response.html#redirect-java.lang.String-)\n\n## Write Cookie\n\n```java\n@GET(\"write-cookie\")\npublic void writeCookie(RouteContext ctx){\n    ctx.cookie(\"hello\", \"world\");\n    ctx.cookie(\"UID\", \"22\", 3600);\n}\n```\n\n[Cookie API](http://static.javadoc.io/com.hellokaton/blade-core/2.1.2.RELEASE/com/hellokaton/blade/mvc/http/Response.html#cookie-java.lang.String-java.lang.String-)\n\n## Web Hook\n\n`WebHook` is the interface in the Blade framework that can be intercepted before and after the execution of the route.\n\n```java\npublic static void main(String[] args) {\n    // All requests are exported before execution before\n    Blade.create().before(\"/*\", ctx -\u003e {\n        System.out.println(\"before...\");\n    }).start();\n}\n```\n\n## Logging\n\nBlade uses slf4j-api as logging interface, the default implementation of a simple log package (modified from simple-logger); if you need complex logging you can also use a custom library, you only need to exclude the `blade-log` from the dependencies.\n\n```java\nprivate static final Logger log = LoggerFactory.getLogger(Hello.class);\n\npublic static void main(String[] args) {\n    log.info(\"Hello Info, {}\", \"2017\");\n    log.warn(\"Hello Warn\");\n    log.debug(\"Hello Debug\");\n    log.error(\"Hello Error\");\n}\n```\n\n## Basic Auth\n\nBlade includes a few middleware, like Basic Authentication; of course, it can also be customized to achieve more complex goals.\n\n```java\npublic static void main(String[] args) {\n    Blade.create().use(new BasicAuthMiddleware()).start();\n}\n```\n\nSpecify the user name and password in the `application.properties` configuration file.\n\n```bash\nhttp.auth.username=admin\nhttp.auth.password=123456\n```\n\n## Change Server Port\n\nThere are three ways to modify the port: hard coding it, in a configuration file, and through a command line parameter.\n\n**Hard Coding**\n\n```java\nBlade.create().listen(9001).start();\n```\n\n**Configuration For `application.properties`**\n\n```bash\nserver.port=9001\n```\n\n**Command Line**\n\n```bash\njava -jar blade-app.jar --server.port=9001\n```\n\n## Configuration SSL\n\n**Configuration For `application.properties`**\n\n```bash\nserver.ssl.enable=true\nserver.ssl.cert-path=cert.pem\nserver.ssl.private-key-path=private_key.pem\nserver.ssl.private-key-pass=123456\n```\n** Configuration using INettySslCustomizer **\n\n```bash\n#Specify any properties your customizer needs, for example\nserver.ssl.enable=true\nserver.keystore.path=fully qualified path\nserver.keystore.type=PKCS12\nserver.keystore.password=mypass\nserver.keystore.alias=optional alias\n```\n\n* Create your implementation of INettySslCustomizer\n* Register it with Blade class\n\n```java\n\t   MyNettySslCustomizer nc = new MyNettySslCustomizer();\t\n\t\tBlade.create()\n\t\t\t.setNettySslCustomizer(nc)\n\t\t\t.start(App.class, args);\n\t\t}\n```\n\nSample implementation of INettySslCustomizer\n\n```java\npublic class MyNettySSLCustomizer implements INettySslCustomizer {\n\n\tpublic SslContext getCustomSslContext(Blade blade) {\n\t\tSslContext sslctx = null;\n\n\t\t// get my custom properties from the environment\n\t\tString keystoreType = blade.getEnv(\"server.keystore.type\", null);\n\t\tString keystorePath = blade.getEnv(\"server.keystore.path\", null);\n\t\tString keystorePass = blade.getEnv(\"server.keystore.password\", null);\n\n\t\tif (verifyKeystore(keystoreType, keystorePath, keystorePass)) {\n\n\t\t\ttry (FileInputStream instream = new FileInputStream(new File(keystorePath))) {\n\n\t\t\t\t// verify I can load store and password is valid\n\t\t\t\tKeyStore keystore = KeyStore.getInstance(keystoreType);\n\t\t\t\tchar[] storepw = keystorePass.toCharArray();\n\t\t\t\tkeystore.load(instream, storepw);\n\t\t\t\t\n\t\t\t\tKeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n\t\t\t\tkmf.init(keystore, storepw);\n\t\t\t\tsslctx = SslContextBuilder.forServer(kmf).build();\n\t\t\t\t\n\t\t\t} catch (Exception ex) {\n\t\t\t\tlog.error(\"Keystore validation failed \" + ex.getMessage());\n\t\t\t}\n\t\t\t\n\t\t} else {\n\t\t\tlog.error(\"Unable to load keystore, sslContext creation failed.\");\n\t\t}\n\n\t\treturn sslctx;\n\t}\n```\n\n## Custom Exception Handler\n\nBlade has an exception handler already implemented by default; if you need to deal with custom exceptions, you can do it like follows.\n\n```java\n@Bean\npublic class GlobalExceptionHandler extends DefaultExceptionHandler {\n    \n    @Override\n    public void handle(Exception e) {\n        if (e instanceof CustomException) {\n            CustomException customException = (CustomException) e;\n            String code = customException.getCode();\n            // do something\n        } else {\n            super.handle(e);\n        }\n    }\n\n}\n```\n\nBesides looking easy, the features above are only the tip of the iceberg, and there are more surprises to see in the documentation and sample projects:\n\n+ [Blade Demos](https://github.com/lets-blade/blade-demos)\n+ [Awesome Blade](https://github.com/lets-blade/awesome-blade)\n\n## Change Logs\n\n[See Here](https://lets-blade.com/about/change-logs)\n\n## Contact\n\n- Twitter: [hellokaton](https://twitter.com/hellokaton)\n- Mail: hellokaton@gmail.com\n\n## Contributors\n\nThanks goes to these wonderful people\n\n![contributors.svg](https://opencollective.com/blade/contributors.svg?width=890\u0026button=false)\n\nContributions of any kind are welcome!\n\n## Licenses\n\nPlease see [Apache License](LICENSE)\n","funding_links":["https://github.com/sponsors/hellokaton","https://www.paypal.me/bladejava","https://ko-fi.com/hellokaton"],"categories":["Java","项目","HarmonyOS","Projects","常用框架\\\u0026第三方库","开发框架"],"sub_categories":["Web框架","Windows Manager","Web Frameworks"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flets-blade%2Fblade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flets-blade%2Fblade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flets-blade%2Fblade/lists"}