Giter VIP home page Giter VIP logo

blade's Introduction

Based on Java8 + Netty4 to create a lightweight, high-performance, simple and elegant Web framework 😋

Spend 1 hour to learn it to do something interesting, a tool in addition to the other available frameworks.

🐾 Quick Start | 🌚 Documentation | 📗 Guidebook | 💰 Donate | 🇨🇳 简体中文


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 😊

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 and XSS defense
  • Basic Auth and Authorization
  • 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

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>

Render API

Redirects

@GET("redirect")
public void redirectToGithub(RouteContext ctx){
    ctx.redirect("https://github.com/hellokaton");
}

Redirect API

Write Cookie

@GET("write-cookie")
public void writeCookie(RouteContext ctx){
    ctx.cookie("hello", "world");
    ctx.cookie("UID", "22", 3600);
}

Cookie API

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

See Here

Contact

Contributors

Thanks goes to these wonderful people

contributors.svg

Contributions of any kind are welcome!

Licenses

Please see Apache License

blade's People

Contributors

aimerneige avatar andrea-ligios avatar crossoverjie avatar dependabot[bot] avatar dongm2ez avatar dqinyuan avatar eas5 avatar fishlikewater avatar frederick-s avatar hellokaton avatar itszhengkun avatar kuangcp avatar kugin avatar linuxea avatar littlestrokesfellgreatoaks avatar otuta avatar psh686868 avatar schneems avatar seguri avatar stqp avatar strogiyotec avatar unafraid avatar vzardlloo avatar windbelike avatar wuma2020 avatar yai-dev avatar ydq avatar yuxino avatar zaoangod avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blade's Issues

Add a new branch dev?

I think it's better to add a new branch dev to distinguish developed codes and published codes(master).

UMD Research Study

Hi there,
We are researchers from the University of Maryland conducting a study about software code reuse. If you are interested in helping us in this study​ through ​a short interview about this project, please contact us on ​[email protected]​ for more information​. You will be ​compensated for your time.

Thanks
Ahmed

blade2.0 plan

  1. 内置tomcat/jetty容器
  2. 支持打jar包运行
  3. 真正0配置
  4. aop增强
  5. 取消默认jsp引擎,构造静态文件访问

小问题

  1. PatternKit.javaisMobile加上170的手机号,曾经不少网站出现这个bug .
  2. 建议把environment(环境变量)纳入底层,内部定义好三个环境,根据不同(环境+机器)判断加载不同配置文件等。
  3. http://bladejava.com/ 网址下的爬虫能力下面的查看详细代码地址应该是改了!

Advice

代码里的注解用英文写吧,有利于国际化。中文在不同的编码下有可能乱码

Blade plugin API broken

The change in ebdb2e1 broke how plugins can be used

Sql2oPlugin sql2oPlugin = blade.plugin(Sql2oPlugin.class);
sql2oPlugin.config(url, user, pass).run();

sql2o

Missing some dependencies


SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/http/HttpSessionIdListener
    at org.eclipse.jetty.server.session.SessionHandler.<clinit>(SessionHandler.java:54)
    at org.eclipse.jetty.servlet.ServletContextHandler.newSessionHandler(ServletContextHandler.java:241)
    at org.eclipse.jetty.servlet.ServletContextHandler.getSessionHandler(ServletContextHandler.java:334)
    at org.eclipse.jetty.servlet.ServletContextHandler.relinkHandlers(ServletContextHandler.java:180)
    at org.eclipse.jetty.servlet.ServletContextHandler.<init>(ServletContextHandler.java:157)
    at org.eclipse.jetty.servlet.ServletContextHandler.<init>(ServletContextHandler.java:117)
    at org.eclipse.jetty.servlet.ServletContextHandler.<init>(ServletContextHandler.java:105)
    at com.blade.server.Server.start(Server.java:60)
    at com.blade.Blade.start(Blade.java:629)
    at com.blade.Blade.start(Blade.java:639)
    at App.main(App.java:13)

StringKit.trim方法逻辑有问题

private static String trim(String str, String stripChars, int mode)

此方法逻辑有问题

stripChars.indexOf(str.charAt(start)) != -1

此行并不能判定字符串顺序,例如

String a = "abcdefgbac";
System.out.println(trim(a, "abc", 0)); //结果defg

trim方法会匹配abc,同时也会匹配acb、bac、cba等等

Cross-site Request Forgery broken?

The documentation at http://bladejava.com/docs/modules/csrf does not match the current blade API.

How should CSRF be configured with the new Blade API? I tried to update the example but we can see from the log that it does not handle CSRF errors correctly. The second request in to the server should be aborted but it still reach the "login" request handler.

import blade.kit.log.Logger;
import com.blade.Blade;
import com.blade.verify.CSRFTokenManager;
import com.blade.web.http.HttpMethod;

public class CrossSite {
    public static void main(String[] args) {
        Logger log = Logger.getLogger(CrossSite.class);

        Blade blade = Blade.me();
        blade.before("/login", (request, response) -> {
            if (HttpMethod.POST.equals(request.httpMethod())) {
                if (!CSRFTokenManager.verifyAsForm(request, response)) {
                    response.text("csrf error!!!");
                    log.info("POST csrf error");
                    return;
                }
                log.info("POST request");
            }
        });

        blade.post("/login", (request, response) -> {
            log.info("go login");
        });

        blade.start();
    }
}
 $ curl -b /tmp/cookies.txt -c /tmp/cookies.txt -X POST http://localhost:9000/login 

 2015-12-26 15:44:40,800 INFO [qtp1642360923-14] com.blade.IocApplication | Add Object:com.blade.web.DispatcherServlet$1=com.blade.web.DispatcherServlet$1@2dc32c12
 2015-12-26 15:44:40,802 INFO [qtp1642360923-14] com.blade.web.DispatcherServlet | blade init complete!
 2015-12-26 15:44:40,804 DEBUG [qtp1642360923-13] com.blade.web.AsynRequestHandler | Request : POST /login
 2015-12-26 15:44:40,815 INFO [qtp1642360923-13] com.blade.verify.CSRFTokenManager | create csrf_token:qNlQgEJoXxKAjzyEeyN9NARBP7ken83j
 2015-12-26 15:44:40,815 INFO [qtp1642360923-13] CrossSite | POST request
 2015-12-26 15:44:40,815 INFO [qtp1642360923-13] CrossSite | go login

 $  curl -b /tmp/cookies.txt -c /tmp/cookies.txt -X POST http://localhost:9000/login 

 2015-12-26 15:45:06,580 DEBUG [qtp1642360923-13] com.blade.web.AsynRequestHandler | Request : POST /login
 2015-12-26 15:45:06,582 INFO [qtp1642360923-13] CrossSite | POST csrf error
 2015-12-26 15:45:06,582 INFO [qtp1642360923-13] CrossSite | go login

CSS 因 Mime 类型不匹配而被忽略 引发的问题

ie9 错误:
SEC7113: CSS 因 Mime 类型不匹配而被忽略
main.min.css?ver=0.1.3

chrome:
Resource interpreted as Stylesheet but transferred with MIME type text/plain: "http://localhost:8678/java-china/assets/styles/main.min.css?ver=0.1.3".

百度了一下,此问题,应该需要在response的按照 后缀名 (.css) 设置 contextType的 text/css

研究了一下源码:

DispatcherHandler 中 print 的时候设置一下?是否正确?还需要作者考虑一下。

方案:
可以根据web.xml里的配置来进行设置。

css text/css

不知道能否修正这个问题,如果加载远程的css (配置成您官方的https://java-china.org/assets/styles/main.min.css 不会出现问题)是没有问题的,但放到本地加载会出现此问题。

谢谢!!!!!

Support PathVariable parameters

支持类似spring控制器中的pathvariable方式获取path参数,支持动态注入请求响应对象,非必须写。

Request queryAsInt is null

Caused by: java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:592)
    at java.lang.Integer.valueOf(Integer.java:766)
    at com.blade.web.http.wrapper.ServletRequest.queryAsInt(ServletRequest.java:304)

request url has space

If the request url contains control will quote null pointer exception in the middle

blade-1.6.0新特性

  1. 更简化的配置(提供默认配置)
  2. 支持非web应用开发
  3. 优化代码
  4. 重构数据库操作
  5. 内置数据库连接池
  6. 更灵活的路由操作
  7. 重新修订官网文档
  8. 暂时去除servlet3x异步
  9. 去除多余繁杂的配置,追求精简实用
  10. 提供易扩展的IOC,路由接口

JSON序列化异常

java.lang.StackOverflowError
    at blade.kit.json.JSONObject.put(JSONObject.java:48)

获取注册的bean

获取注册的bean,怎么写?

spring容器可以SpringContextListener.getApplicationContext().getBean(beanName)

isAsyn 判断错误

com.blade.Blade 没有获取是不是异步的设置

com.blade.web.DispatcherServlet 中:
boolean isAsync = httpRequest.isAsyncSupported();
请求都会当做异步来处理

boolean isAsync =Blade.isAsyn()

Support form object acquisition

<from>
   <input name="person.name">
   <input name="person.phone">
   <input name="person.cardNo">
   ......
</from>
Person person = getModel("person", Person.class);

Not specify arg2,default person -> Person

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.