言成言成啊 | Kit Chen's Blog

基于Netty的轻量级Web框架Jooby

发布于2023-06-17 04:07:37,更新于2024-05-06 20:59:53,标签:java  文章会持续修订,转载请注明来源地址:https://meethigher.top/blog

本文源码地址meethigher/jooby-example: 基于Netty的轻量级Web框架Jooby使用示例

一、搭建项目

创建原生maven空项目,引入依赖

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-netty</artifactId>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.12</version>
</dependency>

创建启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
import io.jooby.Jooby;

public class Application extends Jooby {

//构造函数快
{
get("/", ctx -> "Hello World");
}

public static void main(String[] args) {
runApp(args, Application.class);
}
}

二、配置文件

Jooby同样支持解析多种类型的配置文件,只记录常用的application.conf

Jooby读取配置文件优先级顺序

  1. 优先应用根目录下。即System.getProperty("user.dir")
  2. 其次类路径下,即resources下或者jar包内的。

resources添加application.conf

1
2
3
server.port = 8080
app.name = "内部"
database.url = "jdbc:mysql://localhost:3306/mydb"

示例接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import io.jooby.Jooby;
import io.jooby.MediaType;

import java.nio.charset.StandardCharsets;

public class Application extends Jooby {

//构造函数快
{
// use Decorator.
decorator(next -> ctx -> {
// get response content-type.
final MediaType responseType = ctx.getResponseType();
// if content-type is text-specific
if(responseType.isTextual())
// override response type with current media type and always use UTF-8 charset!
ctx.setResponseType(responseType, StandardCharsets.UTF_8);
// pipe next response procedure.
return next.apply(ctx);
});
get("/", ctx -> {

String appName = getConfig().getString("app.name");
return "Welcome to " + appName;
});

get("/database", ctx -> {
String dbUrl = getConfig().getString("database.url");
return "Database URL: " + dbUrl;
});
}

public static void main(String[] args) {
runApp(args, Application.class);
}
}

三、开发接口

3.1 Script API-仅支持简单路由

Script API 通常用于编写小型的、单一用途的路由处理器。

支持占位符路由规则,但是像拼参形式的就不支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import static io.jooby.Jooby.runApp;

public class ScriptAPIApplication {

public static void main(String[] args) {
//consumer函数式接口简写
runApp(args, app -> {
app.get("/param/{id}", ctx -> {
String id = ctx.path("id").value();
return id;
});
app.post("/param/{id}", ctx -> {
return ctx.path("id").value();
});
});
}
}

3.2 MVC API-支持复杂路由/静态资源/全局请求拦截/全局异常拦截

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
<!-- MVC API 核心模块 -->
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-apt</artifactId>
<version>2.16.1</version>
</dependency>
<!-- json模块 -->
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-gson</artifactId>
<version>2.16.1</version>
</dependency>

创建controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package top.meethigher.mvc.controller;

import io.jooby.MediaType;
import io.jooby.Multipart;
import io.jooby.annotations.*;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* @author chenchuancheng github.com/meethigher
* @since 2023/6/17 23:31
*/
@Path("/mvc")
public class Controller {


@GET("/get")
public String get() {
return "Hello World";
}

@GET("/pathParam/{id}")
public String pathParam(@PathParam String id) {
return id;
}

/**
* @see <a href="https://jooby.io/#context-parameters-path">正则表达式校验</a>
*/
@GET("/pathParam/{id:^[a-zA-Z0-9]{5}$}")
public String pathParamRegex(@PathParam String id) {
return id;
}

@GET("/queryParam")
public String queryParam(@QueryParam String id, @QueryParam String name) {
return name + "--->" + id;
}

/**
* form表单,支持两种形式
* application/x-www-form-urlencoded,不支持文件
* multipart/form-data,支持文件
*/
@POST("/formParam")
public String formParam(@FormParam String name, @FormParam String age, @FormParam Multipart file) {
if (file != null) {
try (InputStream is = file.file("file").stream(); FileOutputStream fos = new FileOutputStream("test.txt")) {
int b;
while ((b = is.read()) != -1) {
fos.write(b);
}
fos.flush();
} catch (IOException e) {
}
}
return name + "--->" + age;
}


@POST("/bodyParam")
@Consumes(MediaType.JSON)//可省略
@Produces(MediaType.JSON)//可省略
public Object bodyParam(Object body) {
return body;
}

@POST("/pageQuery")
public String pageQuery(PageRequest req) {
return req.toString();
}

@GET("/failure")
public String failure() {
throw new RuntimeException("测试失败");
}

@GET("/error")
public String error() {
int i = 1 / 0;
return null;
}
}

class PageRequest {
private Integer pageIndex;
private Integer pageSize;

public Integer getPageIndex() {
return pageIndex;
}

public void setPageIndex(Integer pageIndex) {
this.pageIndex = pageIndex;
}

public Integer getPageSize() {
return pageSize;
}

public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
}

注册controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import io.jooby.*;
import io.jooby.json.GsonModule;
import top.meethigher.mvc.controller.Controller;
import top.meethigher.mvc.utils.Resp;

import javax.annotation.Nonnull;
import java.nio.charset.StandardCharsets;

import static io.jooby.Jooby.runApp;

/**
* @author chenchuancheng github.com/meethigher
* @since 2023/6/17 23:30
*/
public class MVCApplication {
public static void main(String[] args) {
runApp(args, app -> {
// 配置静态资源,优先应用路径下static,其次类路径下static
app.assets("/**", "/static");
// 设置全局装饰器
app.decorator(new GlobalDecorator());
// 设置全局异常处理
app.error(new GlobalErrorHandler());
// 设置 JSON 支持
app.install(new GsonModule());
// 注册控制器
app.mvc(new Controller());
});
}
}

/**
* 全局装饰器
*
* @author chenchuancheng github.com/meethigher
* @since 2023/6/18 17:38
*/
class GlobalDecorator implements Route.Decorator {
@Nonnull
@Override
public Route.Handler apply(@Nonnull Route.Handler next) {
return ctx -> {
final MediaType responseType = ctx.getResponseType();
//设置编码为utf-8
if (responseType.isTextual()) {
ctx.setResponseType(responseType, StandardCharsets.UTF_8);
}
return next.apply(ctx);
};
}
}

/**
* 全局异常处理器
*
* @author chenchuancheng github.com/meethigher
* @since 2023/6/18 17:36
*/
class GlobalErrorHandler extends DefaultErrorHandler {
@Override
public void apply(@Nonnull Context ctx, @Nonnull Throwable cause, @Nonnull StatusCode code) {
// 处理异常并返回适当的响应
// if (cause instanceof RuntimeException) {//会存在多态问题,如继承。而我需要的是严格相等
if (cause.getClass().equals(RuntimeException.class)) {
// 处理自定义异常
ctx.setResponseType(MediaType.json, StandardCharsets.UTF_8);
ctx.send(Resp.getFailureResp(cause.getMessage()).toString());
} else {
// // 处理自定义异常
// ctx.setResponseType(MediaType.json, StandardCharsets.UTF_8);
// ctx.send(Resp.getErrorResp().toString());
super.apply(ctx, cause, code);
}
}
}

四、参考致谢

jooby:做更多! 更容易!

发布:2023-06-17 04:07:37
修改:2024-05-06 20:59:53
链接:https://meethigher.top/blog/2023/jooby/
标签:java 
付款码 打赏 分享
Shift+Ctrl+1 可控制工具栏