Product Promotion
0x5a.live
for different kinds of informations and explorations.
GitHub - lets-blade/blade: :rocket: Lightning fast and elegant mvc framework for Java8
:rocket: Lightning fast and elegant mvc framework for Java8 - lets-blade/blade
Visit SiteGitHub - lets-blade/blade: :rocket: Lightning fast and elegant mvc framework for Java8
:rocket: Lightning fast and elegant mvc framework for Java8 - lets-blade/blade
Powered by 0x5a.live ๐
What Is Blade?
Blade
is a pursuit of simple, efficient Web framework, so that JavaWeb
development becomes even more powerful, both in performance and flexibility.
If you like to try something interesting, I believe you will love it.
If you think it's good, you can support it with a star or by donating :blush:
Features
- A new generation MVC framework that doesn't depend on other libraries
- Get rid of SSH's bloated, modular design
- Source is less than
500kb
, learning it is also simple - RESTful-style routing design
- Template engine support, view development more flexible
- High performance, 100 concurrent qps 20w/s
- Run the
JAR
package to open the web service - Streams-style API
-
CSRF
andXSS
defense -
Basic Auth
andAuthorization
- Supports plug-in extensions
- Support webjars resources
- Tasks based on
cron
expressions - Built-in a variety of commonly used middleware
- Built-in Response output
- JDK8 +
Overview
ยป 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.
ยป Elegance: blade
supports the RESTful style routing interface, has no invasive interceptors and provides the writing of a DSL grammar.
ยป Easy deploy: supports maven
package jar
file running.
Quick Start
Create a basic Maven
or Gradle
project.
Do not create a
webapp
project, Blade does not require much trouble.
Run with Maven
:
<dependency>
<groupId>com.hellokaton</groupId>
<artifactId>blade-core</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
or Gradle
:
compile 'com.hellokaton:blade-core:2.1.2.RELEASE'
Write the main
method and the Hello World
:
public static void main(String[] args) {
Blade.create().get("/", ctx -> ctx.text("Hello Blade")).start();
}
Open http://localhost:9000 in your browser to see your first Blade
application!
Contents
Register Route
Request Parameter
Get Environment
Get Header
Get Cookie
Static Resource
Upload File
Download File
Set Session
Render To Browser
Render Template
Redirects
Write Cookie
Web Hook
Logging
Basic Auth
Change Server Port
Configuration SSL
Custom Exception Handler
Register Route
HardCode
public static void main(String[] args) {
// Create multiple routes GET, POST, PUT, DELETE using Blade instance
Blade.create()
.get("/user/21", getting)
.post("/save", posting)
.delete("/remove", deleting)
.put("/putValue", putting)
.start();
}
Controller
@Path
public class IndexController {
@GET("/login")
public String login(){
return "login.html";
}
@POST(value = "/login", responseType = ResponseType.JSON)
public RestResponse doLogin(RouteContext ctx){
// do something
return RestResponse.ok();
}
}
Request Parameter
URL Parameter
Using RouteContext
public static void main(String[] args) {
Blade.create().get("/user", ctx -> {
Integer age = ctx.queryInt("age");
System.out.println("age is:" + age);
}).start();
}
Using @Query
annotation
@GET("/user")
public void savePerson(@Query Integer age){
System.out.println("age is:" + age);
}
Test it with sample data from the terminal
curl -X GET http://127.0.0.1:9000/user?age=25
Form Parameter
Here is an example:
Using RouteContext
public static void main(String[] args) {
Blade.create().get("/user", ctx -> {
Integer age = ctx.fromInt("age");
System.out.println("age is:" + age);
}).start();
}
Using @Form
Annotation
@POST("/save")
public void savePerson(@Form String username, @Form Integer age){
System.out.println("username is:" + username + ", age is:" + age);
}
Test it with sample data from the terminal
curl -X POST http://127.0.0.1:9000/save -F username=jack -F age=16
Path Parameter
Using RouteContext
public static void main(String[] args) {
Blade blade = Blade.create();
// Create a route: /user/:uid
blade.get("/user/:uid", ctx -> {
Integer uid = ctx.pathInt("uid");
ctx.text("uid : " + uid);
});
// Create two parameters route
blade.get("/users/:uid/post/:pid", ctx -> {
Integer uid = ctx.pathInt("uid");
Integer pid = ctx.pathInt("pid");
String msg = "uid = " + uid + ", pid = " + pid;
ctx.text(msg);
});
// Start blade
blade.start();
}
Using @PathParam
Annotation
@GET("/users/:username/:page")
public void userTopics(@PathParam String username, @PathParam Integer page){
System.out.println("username is:" + usernam + ", page is:" + page);
}
Test it with sample data from the terminal
curl -X GET http://127.0.0.1:9000/users/hellokaton/2
Body Parameter
public static void main(String[] args) {
Blade.create().post("/body", ctx -> {
System.out.println("body string is:" + ctx.bodyToString());
}).start();
}
Using @Body
Annotation
@POST("/body")
public void readBody(@Body String data){
System.out.println("data is:" + data);
}
Test it with sample data from the terminal
curl -X POST http://127.0.0.1:9000/body -d '{"username":"hellokaton","age":22}'
Parse To Model
This is the User
model.
public class User {
private String username;
private Integer age;
// getter and setter
}
By Annotation
@POST("/users")
public void saveUser(@Form User user) {
System.out.println("user => " + user);
}
Test it with sample data from the terminal
curl -X POST http://127.0.0.1:9000/users -F username=jack -F age=16
Custom model identification
@POST("/users")
public void saveUser(@Form(name="u") User user) {
System.out.println("user => " + user);
}
Test it with sample data from the terminal
curl -X POST http://127.0.0.1:9000/users -F u[username]=jack -F u[age]=16
Body Parameter To Model
@POST("/body")
public void body(@Body User user) {
System.out.println("user => " + user);
}
Test it with sample data from the terminal
curl -X POST http://127.0.0.1:9000/body -d '{"username":"hellokaton","age":22}'
Get Environment
Environment environment = WebContext.blade().environment();
String version = environment.get("app.version", "0.0.1");
Get Header
By Context
@GET("header")
public void readHeader(RouteContext ctx){
System.out.println("Host => " + ctx.header("Host"));
// get useragent
System.out.println("UserAgent => " + ctx.userAgent());
// get client ip
System.out.println("Client Address => " + ctx.address());
}
By Annotation
@GET("header")
public void readHeader(@Header String host){
System.out.println("Host => " + host);
}
Get Cookie
By Context
@GET("cookie")
public void readCookie(RouteContext ctx){
System.out.println("UID => " + ctx.cookie("UID"));
}
By Annotation
@GET("cookie")
public void readCookie(@Cookie String uid){
System.out.println("Cookie UID => " + uid);
}
Static Resource
Blade 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
If you want to customize the static resource URL
Blade.create().addStatics("/mydir");
Of course you can also specify it in the configuration file. application.properties
(location in classpath)
mvc.statics=/mydir
Upload File
By Request
@POST("upload")
public void upload(Request request){
request.fileItem("img").ifPresent(fileItem -> {
fileItem.moveTo(new File(fileItem.getFileName()));
});
}
By Annotation
@POST("upload")
public void upload(@Multipart FileItem fileItem){
// Save to new path
fileItem.moveTo(new File(fileItem.getFileName()));
}
Download File
@GET(value = "/download", responseType = ResponseType.STREAM)
public void download(Response response) throws IOException {
response.write("abcd.pdf", new File("146373013842336153820220427172437.pdf"));
}
If you want to preview certain files in your browser
@GET(value = "/preview", responseType = ResponseType.PREVIEW)
public void preview(Response response) throws IOException {
response.write(new File("146373013842336153820220427172437.pdf"));
}
Set Session
The session is disabled by default, you must enable the session.
Blade.create()
.http(HttpOptions::enableSession)
.start(Application.class, args);
๐ก It can also be enabled using a configuration file๏ผ
http.session.enabled=true
public void login(Session session){
// if login success
session.attribute("login_key", SOME_MODEL);
}
Render To Browser
Render Response
By Context
@GET("users/json")
public void printJSON(RouteContext ctx){
User user = new User("hellokaton", 18);
ctx.json(user);
}
By Annotation
This form looks more concise ๐ถ
@GET(value = "/users/json", responseType = ResponseType.JSON)
public User printJSON(){
return new User("hellokaton", 18);
}
Render Text
@GET("text")
public void printText(RouteContext ctx){
ctx.text("I Love Blade!");
}
or
@GET(value = "/text", responseType = ResponseType.TEXT)
public String printText(RouteContext ctx){
return "I Love Blade!";
}
Render Html
@GET("html")
public void printHtml(RouteContext ctx){
ctx.html("<center><h1>I Love Blade!</h1></center>");
}
or
@GET(value = "/html", responseType = ResponseType.HTML)
public String printHtml(RouteContext ctx){
return "<center><h1>I Love Blade!</h1></center>";
}
Render Template
By default all template files are in the templates directory; in most of the cases you do not need to change it.
Default Template
By default, Blade uses the built-in template engine, which is very simple. In a real-world web project, you can try several other extensions.
public static void main(String[] args) {
Blade.create().get("/hello", ctx -> {
ctx.attribute("name", "hellokaton");
ctx.render("hello.html");
}).start(Hello.class, args);
}
The hello.html
template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello Page</title>
</head>
<body>
<h1>Hello, ${name}</h1>
</body>
</html>
Jetbrick Template
Config Jetbrick Template
Create a BladeLoader
class and load some config
@Bean
public class TemplateConfig implements BladeLoader {
@Override
public void load(Blade blade) {
blade.templateEngine(new JetbrickTemplateEngine());
}
}
Write some data for the template engine to render
public static void main(String[] args) {
Blade.create().get("/hello", ctx -> {
User user = new User("hellokaton", 50);
ctx.attribute("user", user);
ctx.render("hello.html");
}).start(Hello.class, args);
}
The hello.html
template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello Page</title>
</head>
<body>
<h1>Hello, ${user.username}</h1>
#if(user.age > 18)
<p>Good Boy!</p>
#else
<p>Gooood Baby!</p>
#end
</body>
</html>
Redirects
@GET("redirect")
public void redirectToGithub(RouteContext ctx){
ctx.redirect("https://github.com/hellokaton");
}
Write Cookie
@GET("write-cookie")
public void writeCookie(RouteContext ctx){
ctx.cookie("hello", "world");
ctx.cookie("UID", "22", 3600);
}
Web Hook
WebHook
is the interface in the Blade framework that can be intercepted before and after the execution of the route.
public static void main(String[] args) {
// All requests are exported before execution before
Blade.create().before("/*", ctx -> {
System.out.println("before...");
}).start();
}
Logging
Blade 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.
private static final Logger log = LoggerFactory.getLogger(Hello.class);
public static void main(String[] args) {
log.info("Hello Info, {}", "2017");
log.warn("Hello Warn");
log.debug("Hello Debug");
log.error("Hello Error");
}
Basic Auth
Blade includes a few middleware, like Basic Authentication; of course, it can also be customized to achieve more complex goals.
public static void main(String[] args) {
Blade.create().use(new BasicAuthMiddleware()).start();
}
Specify the user name and password in the application.properties
configuration file.
http.auth.username=admin
http.auth.password=123456
Change Server Port
There are three ways to modify the port: hard coding it, in a configuration file, and through a command line parameter.
Hard Coding
Blade.create().listen(9001).start();
Configuration For application.properties
server.port=9001
Command Line
java -jar blade-app.jar --server.port=9001
Configuration SSL
Configuration For application.properties
server.ssl.enable=true
server.ssl.cert-path=cert.pem
server.ssl.private-key-path=private_key.pem
server.ssl.private-key-pass=123456
** Configuration using INettySslCustomizer **
#Specify any properties your customizer needs, for example
server.ssl.enable=true
server.keystore.path=fully qualified path
server.keystore.type=PKCS12
server.keystore.password=mypass
server.keystore.alias=optional alias
- Create your implementation of INettySslCustomizer
- Register it with Blade class
MyNettySslCustomizer nc = new MyNettySslCustomizer();
Blade.create()
.setNettySslCustomizer(nc)
.start(App.class, args);
}
Sample implementation of INettySslCustomizer
public class MyNettySSLCustomizer implements INettySslCustomizer {
public SslContext getCustomSslContext(Blade blade) {
SslContext sslctx = null;
// get my custom properties from the environment
String keystoreType = blade.getEnv("server.keystore.type", null);
String keystorePath = blade.getEnv("server.keystore.path", null);
String keystorePass = blade.getEnv("server.keystore.password", null);
if (verifyKeystore(keystoreType, keystorePath, keystorePass)) {
try (FileInputStream instream = new FileInputStream(new File(keystorePath))) {
// verify I can load store and password is valid
KeyStore keystore = KeyStore.getInstance(keystoreType);
char[] storepw = keystorePass.toCharArray();
keystore.load(instream, storepw);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, storepw);
sslctx = SslContextBuilder.forServer(kmf).build();
} catch (Exception ex) {
log.error("Keystore validation failed " + ex.getMessage());
}
} else {
log.error("Unable to load keystore, sslContext creation failed.");
}
return sslctx;
}
Custom Exception Handler
Blade has an exception handler already implemented by default; if you need to deal with custom exceptions, you can do it like follows.
@Bean
public class GlobalExceptionHandler extends DefaultExceptionHandler {
@Override
public void handle(Exception e) {
if (e instanceof CustomException) {
CustomException customException = (CustomException) e;
String code = customException.getCode();
// do something
} else {
super.handle(e);
}
}
}
Besides 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:
Change Logs
Contact
- Twitter: hellokaton
- Mail: [email protected]
Contributors
Thanks goes to these wonderful people
Contributions of any kind are welcome!
Licenses
Please see Apache License
Java Resources
are all listed below.
Made with โค๏ธ
to provide different kinds of informations and resources.