From 05975805fb5499c500070c60daf9b2f1cdc842f0 Mon Sep 17 00:00:00 2001 From: Tong Li <31761981+litongjava@users.noreply.github.com> Date: Tue, 24 Dec 2024 17:31:01 -1000 Subject: [PATCH] Tio server (#8659) * add tio-server * add simple docker file * fix docker file * chage log level to info * add template and activate record * add cache * update reupadme.md * update cache query * test on windows * chage to EnviormentUtils * add java run with jdb info * add EnviormentUtils * change to JDBC_URL * add mysql run cmd * update dockerfile add jdbc info * fix jdbc info error * fix Unterminated quoted string on dockerfile * fix jdb_user error * add "database": "MySQL", * chage in to Integer of Fortune * add #escape to avoid xxs * remove caffeine and add ehcache * failed to test native * change to cached_query_url * add native arg * remove unused file for tio-http-server * add dockerignore * update jar name to tio-http-server-benchmark * update version * fix all query * update docker file * update docker file and plugin * update docker file * update dockerfile * update tio-http-server version * remove native support * update tio-http-server version * update jdbc info * update docker file --------- Co-authored-by: litongjava --- frameworks/Java/tio-http-server/.dockerignore | 19 ++ frameworks/Java/tio-http-server/.gitignore | 3 + frameworks/Java/tio-http-server/README.md | 114 +++++++++ .../api/tio-server-benchmark.md | 227 ++++++++++++++++++ .../tio-http-server/benchmark_config.json | 29 +++ frameworks/Java/tio-http-server/config.toml | 19 ++ frameworks/Java/tio-http-server/pom.xml | 209 ++++++++++++++++ .../litongjava/tio/http/server/MainApp.java | 66 +++++ .../server/config/EhCachePluginConfig.java | 12 + .../http/server/config/EnjoyEngineConfig.java | 22 ++ .../tio/http/server/config/MysqlDbConfig.java | 31 +++ .../server/controller/CacheController.java | 41 ++++ .../http/server/controller/DbController.java | 127 ++++++++++ .../server/controller/IndexController.java | 40 +++ .../tio/http/server/model/Fortune.java | 23 ++ .../tio/http/server/model/Message.java | 12 + .../tio/http/server/model/World.java | 32 +++ .../tio/http/server/services/CacheName.java | 50 ++++ .../server/services/CacheNameService.java | 17 ++ .../http/server/utils/BeanConverterUtils.java | 31 +++ .../tio/http/server/utils/RandomUtils.java | 36 +++ .../src/main/resources/app.properties | 9 + .../src/main/resources/ehcache.xml | 9 + .../src/main/resources/logback.xml | 52 ++++ .../main/resources/templates/fortunes.html | 20 ++ .../tio/http/server/MainAppTest.java | 15 ++ .../tio-server-native.dockerfile | 9 + .../tio-http-server/tio-server.dockerfile | 19 ++ 28 files changed, 1293 insertions(+) create mode 100644 frameworks/Java/tio-http-server/.dockerignore create mode 100644 frameworks/Java/tio-http-server/.gitignore create mode 100644 frameworks/Java/tio-http-server/README.md create mode 100644 frameworks/Java/tio-http-server/api/tio-server-benchmark.md create mode 100644 frameworks/Java/tio-http-server/benchmark_config.json create mode 100644 frameworks/Java/tio-http-server/config.toml create mode 100644 frameworks/Java/tio-http-server/pom.xml create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/CacheController.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/DbController.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/IndexController.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/BeanConverterUtils.java create mode 100644 frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java create mode 100644 frameworks/Java/tio-http-server/src/main/resources/app.properties create mode 100644 frameworks/Java/tio-http-server/src/main/resources/ehcache.xml create mode 100644 frameworks/Java/tio-http-server/src/main/resources/logback.xml create mode 100644 frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html create mode 100644 frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java create mode 100644 frameworks/Java/tio-http-server/tio-server-native.dockerfile create mode 100644 frameworks/Java/tio-http-server/tio-server.dockerfile diff --git a/frameworks/Java/tio-http-server/.dockerignore b/frameworks/Java/tio-http-server/.dockerignore new file mode 100644 index 00000000000..cba5dfe3c3b --- /dev/null +++ b/frameworks/Java/tio-http-server/.dockerignore @@ -0,0 +1,19 @@ +.github +.git +.DS_Store +docs +kubernetes +node_modules +/.svelte-kit +/package +.env +.env.* +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +__pycache__ +.env +_old +uploads +.ipynb_checkpoints +**/*.db +_test \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/.gitignore b/frameworks/Java/tio-http-server/.gitignore new file mode 100644 index 00000000000..2f089945614 --- /dev/null +++ b/frameworks/Java/tio-http-server/.gitignore @@ -0,0 +1,3 @@ +/target/ +logs +.settings \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/README.md b/frameworks/Java/tio-http-server/README.md new file mode 100644 index 00000000000..bb1539e7db1 --- /dev/null +++ b/frameworks/Java/tio-http-server/README.md @@ -0,0 +1,114 @@ +# t-io Benchmarking Test + +This is the tio-server portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +## Controller + +These implementations use the tio-server's controller. + +### Plaintext Test + +* [Plaintext test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### JSON Serialization Test + +* [JSON test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### Database Query Test + +* [Database Query test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Database Queries Test + +* [Database Queries test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Database Update Test + +* [Database Update test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Template rendering Test + +* [Template rendering test source](src/main/java/com/litongjava/tio/http/server/controller/DbController.java)) + +### Cache Query Test +* [Cache query test source](src/main/java/com/litongjava/tio/http/server/controller/CacheController.java)) + + +## Versions +3.7.3.v20231218-RELEASE (https://gitee.com/litongjava/t-io) + +## Test URLs + +All implementations use the same URLs. + +### Plaintext Test + + http://localhost:8080/plaintext + +### JSON Encoding Test + + http://localhost:8080/json + +### Database Query Test + + http://localhost:8080/db + +### Database Queries Test + + http://localhost:8080/queries?queries=5 + +### Cache Query Test + + http://localhost:8080/cacheQuery?queries=10000 + +### Template rendering Test + + http://localhost:8080/fortunes + +### Database Update Test + + http://localhost:8080/updates?queries=5 + + ## Hot to run + ### install mysql 8 + - 1.please instal mysql 8.0.32,example cmd + ``` + docker run --restart=always -d --name mysql_8 --hostname mysql \ +-p 3306:3306 \ +-e 'MYSQL_ROOT_PASSWORD=robot_123456#' -e 'MYSQL_ROOT_HOST=%' -e 'MYSQL_DATABASE=hello_world' \ +mysql/mysql-server:8.0.32 \ +--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 + ``` + - 2.create database schema hello_world + - 3.create tablle,[example](sql/hello_world.sql) + - 4.import data + + ### docker + ``` + docker build -t tio-server-benchmark -f tio-server.dockerfile . +``` +The run is to specify the mysql database +``` +docker run --rm -p 8080:8080 \ +-e JDBC_URL="jdbc:mysql://192.168.3.9/hello_world" \ +-e JDBC_USER="root" \ +-e JDBC_PSWD="robot_123456#" \ +tio-server-benchmark +``` + +### windows + +-windows +``` +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar --JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false --JDBC_USER=root --JDBC_PSWD=robot_123456# +``` +or +``` +set JDBC_URL=jdbc:mysql://192.168.3.9/hello_world +set jdbc.user=root +set JDBC_PSWD=robot_123456# +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar +``` + + + diff --git a/frameworks/Java/tio-http-server/api/tio-server-benchmark.md b/frameworks/Java/tio-http-server/api/tio-server-benchmark.md new file mode 100644 index 00000000000..1d302df2d5d --- /dev/null +++ b/frameworks/Java/tio-http-server/api/tio-server-benchmark.md @@ -0,0 +1,227 @@ +--- +title: tio-server-benchmark v1.0.0 +language_tabs: + - shell: Shell + - http: HTTP + - javascript: JavaScript + - ruby: Ruby + - python: Python + - php: PHP + - java: Java + - go: Go +toc_footers: [] +includes: [] +search: true +code_clipboard: true +highlight_theme: darkula +headingLevel: 2 +generator: "@tarslib/widdershins v4.0.17" + +--- + +# tio-server-benchmark + +> v1.0.0 + +Base URLs: + +# Authentication + +# Default + +## GET plaintext + +GET /plaintext + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET json + +GET /json + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET db + +GET /db + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|id|query|string| 否 |none| + +> 返回示例 + +> 200 Response + +```json +{ + "id": 0, + "randomNumber": 0 +} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|true|none||none| +|» randomNumber|integer|true|none||none| + +## GET updates + +GET /updates + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|queries|query|string| 否 |none| + +> 返回示例 + +> 成功 + +```json +[ + { + "id": 28, + "randomNumber": 5399, + "randomnumber": 1498 + } +] +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|false|none||none| +|» randomNumber|integer|false|none||none| +|» randomnumber|integer|false|none||none| + +## GET fortunes + +GET /fortunes + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +## GET cacheQuery + +GET /cacheQuery + +### 请求参数 + +|名称|位置|类型|必选|说明| +|---|---|---|---|---| +|queries|query|string| 否 |none| + +> 返回示例 + +> 200 Response + +```json +[ + { + "id": 0, + "randomNumber": 0 + } +] +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +状态码 **200** + +|名称|类型|必选|约束|中文名|说明| +|---|---|---|---|---|---| +|» id|integer|false|none||none| +|» randomNumber|integer|false|none||none| + +## GET cacheList + +GET /cacheList + +> 返回示例 + +> 200 Response + +```json +{} +``` + +### 返回结果 + +|状态码|状态码含义|说明|数据模型| +|---|---|---|---| +|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|成功|Inline| + +### 返回数据结构 + +# 数据模型 + diff --git a/frameworks/Java/tio-http-server/benchmark_config.json b/frameworks/Java/tio-http-server/benchmark_config.json new file mode 100644 index 00000000000..5cd4c92b275 --- /dev/null +++ b/frameworks/Java/tio-http-server/benchmark_config.json @@ -0,0 +1,29 @@ +{ + "framework": "tio-server", + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "cached_query_url" : "/cachedQuery?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "MySQL", + "framework": "tio-server", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "t-io", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "tio-server", + "notes": "tio-server", + "versus": "t-io" + } + }] +} diff --git a/frameworks/Java/tio-http-server/config.toml b/frameworks/Java/tio-http-server/config.toml new file mode 100644 index 00000000000..93dddb241c9 --- /dev/null +++ b/frameworks/Java/tio-http-server/config.toml @@ -0,0 +1,19 @@ +[framework] +name = "t-io" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +urls.cached_query = "/cachedQuery?queries=" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "t-io" +webserver = "None" +versus = "t-io" diff --git a/frameworks/Java/tio-http-server/pom.xml b/frameworks/Java/tio-http-server/pom.xml new file mode 100644 index 00000000000..60c75e68fd5 --- /dev/null +++ b/frameworks/Java/tio-http-server/pom.xml @@ -0,0 +1,209 @@ + + 4.0.0 + com.litongjava + tio-http-server-benchmark + 1.0 + ${project.artifactId} + + UTF-8 + 1.8 + ${java.version} + ${java.version} + 23.1.1 + com.litongjava.tio.http.server.MainApp + + + + com.litongjava + tio-http-server + 3.7.3.v20240919-RELEASE + + + com.litongjava + java-db + 1.2.6 + + + junit + junit + 4.12 + test + + + + + + + + + com.alibaba.fastjson2 + fastjson2 + 2.0.52 + + + + net.sf.ehcache + ehcache-core + 2.6.11 + + + + mysql + mysql-connector-java + 5.1.46 + + + + com.zaxxer + HikariCP + 4.0.3 + + + + + + + development + + true + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + + + production + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.7.4 + + ${main.class} + org.projectlombok + + + + + + repackage + + + + + + + + + + assembly + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-assembly-plugin + 3.1.1 + + + + ${main.class} + + + + jar-with-dependencies + + false + + + + make-assembly + package + + single + + + + + + + + + native + + + + org.slf4j + slf4j-jdk14 + 1.7.31 + + + + org.graalvm.sdk + graal-sdk + ${graalvm.version} + provided + + + + ${project.artifactId} + + + org.graalvm.nativeimage + native-image-maven-plugin + 21.2.0 + + + + native-image + + package + + + + false + ${project.artifactId} + ${main.class} + + -H:+RemoveSaturatedTypeFlows + --allow-incomplete-classpath + --no-fallback + + + + + + + + \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java new file mode 100644 index 00000000000..43a6bfc5804 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java @@ -0,0 +1,66 @@ +package com.litongjava.tio.http.server; + +import com.litongjava.tio.http.common.HttpConfig; +import com.litongjava.tio.http.common.handler.ITioHttpRequestHandler; +import com.litongjava.tio.http.server.config.EhCachePluginConfig; +import com.litongjava.tio.http.server.config.EnjoyEngineConfig; +import com.litongjava.tio.http.server.config.MysqlDbConfig; +import com.litongjava.tio.http.server.controller.CacheController; +import com.litongjava.tio.http.server.controller.DbController; +import com.litongjava.tio.http.server.controller.IndexController; +import com.litongjava.tio.http.server.handler.DefaultHttpRequestDispatcher; +import com.litongjava.tio.http.server.router.DefaultHttpReqeustRouter; +import com.litongjava.tio.http.server.router.HttpRequestRouter; +import com.litongjava.tio.server.ServerTioConfig; +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MainApp { + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + EnvUtils.load(); + // add route + IndexController controller = new IndexController(); + + HttpRequestRouter simpleHttpRoutes = new DefaultHttpReqeustRouter(); + simpleHttpRoutes.add("/", controller::index); + simpleHttpRoutes.add("/plaintext", controller::plaintext); + simpleHttpRoutes.add("/json", controller::json); + + DbController dbQueryController = new DbController(); + simpleHttpRoutes.add("/db", dbQueryController::db); + simpleHttpRoutes.add("/queries", dbQueryController::queries); + simpleHttpRoutes.add("/updates", dbQueryController::updates); + simpleHttpRoutes.add("/fortunes", dbQueryController::fortunes); + + CacheController cacheController = new CacheController(); + simpleHttpRoutes.add("/cachedQuery", cacheController::cachedQuery); + + // config server + HttpConfig httpConfig = new HttpConfig(8080, null, null, null); + httpConfig.setUseSession(false); + httpConfig.setWelcomeFile(null); + httpConfig.setCheckHost(false); + httpConfig.setCompatible1_0(false); + + ITioHttpRequestHandler requestHandler = new DefaultHttpRequestDispatcher(httpConfig, simpleHttpRoutes); + HttpServerStarter httpServerStarter = new HttpServerStarter(httpConfig, requestHandler); + ServerTioConfig serverTioConfig = httpServerStarter.getServerTioConfig(); + // close Heartbeat + serverTioConfig.setHeartbeatTimeout(0); + serverTioConfig.statOn = false; + // start server + try { + new MysqlDbConfig().init(); + new EnjoyEngineConfig().engine(); + new EhCachePluginConfig().ehCachePlugin(); + httpServerStarter.start(); + long end = System.currentTimeMillis(); + System.out.println((end - start) + "ms"); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + + } +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java new file mode 100644 index 00000000000..f949432cd5b --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java @@ -0,0 +1,12 @@ + package com.litongjava.tio.http.server.config; + +import com.litongjava.ehcache.EhCachePlugin; + +public class EhCachePluginConfig { + + public EhCachePlugin ehCachePlugin() { + EhCachePlugin ehCachePlugin = new EhCachePlugin(); + ehCachePlugin.start(); + return ehCachePlugin; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java new file mode 100644 index 00000000000..b40c74c448d --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java @@ -0,0 +1,22 @@ +package com.litongjava.tio.http.server.config; + +import com.jfinal.template.Engine; + +public class EnjoyEngineConfig { + + private final String RESOURCE_BASE_PATH = "/templates/"; + + public Engine engine() { + Engine engine = Engine.use(); + engine.setBaseTemplatePath(RESOURCE_BASE_PATH); + engine.setToClassPathSourceFactory(); + // 支持模板热加载,绝大多数生产环境下也建议配置成 true,除非是极端高性能的场景 + // engine.setDevMode(true); + // 配置极速模式,性能提升 13% + Engine.setFastMode(true); + // jfinal 4.9.02 新增配置:支持中文表达式、中文变量名、中文方法名、中文模板函数名 + Engine.setChineseExpression(true); + return engine; + } + +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java new file mode 100644 index 00000000000..8a547854783 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java @@ -0,0 +1,31 @@ +package com.litongjava.tio.http.server.config; + +import com.litongjava.db.activerecord.ActiveRecordPlugin; +import com.litongjava.db.activerecord.OrderedFieldContainerFactory; +import com.litongjava.db.hikaricp.HikariCpPlugin; +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MysqlDbConfig { + + public void init() { + // start active recored + String jdbcUrl = EnvUtils.get("JDBC_URL"); + // String jdbcUrl = "jdbc:mysql://192.168.3.9/hello_world"; + + String jdbcUser = EnvUtils.get("JDBC_USER"); + // String jdbcUser = "root"; + + String jdbcPswd = EnvUtils.get("JDBC_PSWD"); + // String jdbcPswd = "robot_123456#"; + HikariCpPlugin hikariCpPlugin = new HikariCpPlugin(jdbcUrl, jdbcUser, jdbcPswd); + + ActiveRecordPlugin arp = new ActiveRecordPlugin(hikariCpPlugin); + arp.setContainerFactory(new OrderedFieldContainerFactory()); + + // arp.setShowSql(true); + + hikariCpPlugin.start(); + boolean start = arp.start(); + System.out.println("db started:" + start); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/CacheController.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/CacheController.java new file mode 100644 index 00000000000..6ecd7664ac1 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/CacheController.java @@ -0,0 +1,41 @@ +package com.litongjava.tio.http.server.controller; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.alibaba.fastjson2.JSON; +import com.litongjava.db.activerecord.Db; +import com.litongjava.db.activerecord.Record; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.utils.RandomUtils; + +public class CacheController { + // private Logger log = LoggerFactory.getLogger(this.getClass()); + + public HttpResponse cachedQuery(HttpRequest request) { + String queries = request.getParam("queries"); + List> recordMaps = RandomUtils.randomWorldNumbers() + // limit + .limit(RandomUtils.parseQueryCount(queries)) // 限制查询数量 + .mapToObj(id -> findByIdWithCache("world", id)) // 使用 mapToObj 将 int 映射为对象 + .filter(Objects::nonNull) // 过滤掉 null 值 + .map(Record::toMap) // 将每个 Record 对象转换为 Map + .collect(Collectors.toList()); // 收集到 List + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(recordMaps)); + return httpResponse; + + } + + private Record findByIdWithCache(String tableName, int id) { + String sql = "SELECT id, randomNumber FROM world WHERE id = ?"; + return Db.findFirstByCache(tableName, id, sql, id); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/DbController.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/DbController.java new file mode 100644 index 00000000000..699b313bd69 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/DbController.java @@ -0,0 +1,127 @@ +package com.litongjava.tio.http.server.controller; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.alibaba.fastjson2.JSON; +import com.jfinal.template.Engine; +import com.jfinal.template.Template; +import com.litongjava.db.activerecord.Db; +import com.litongjava.db.activerecord.Record; +import com.litongjava.ehcache.EhCache; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.model.Fortune; +import com.litongjava.tio.http.server.util.Resps; +import com.litongjava.tio.http.server.utils.BeanConverterUtils; +import com.litongjava.tio.http.server.utils.RandomUtils; + +public class DbController { + + public HttpResponse db(HttpRequest request) { + Integer id = request.getInt("id"); + if (id == null) { + id = RandomUtils.randomWorldNumber(); + } + + //System.out.println("id:" + id); + HttpResponse httpResponse = new HttpResponse(request); + + // int id = 11; + // String sql="SELECT id, randomNumber FROM world WHERE id = ?"; + + Record recored = Db.findById("world", id); + if (recored != null) { + httpResponse.setBody(JSON.toJSONBytes(recored.toMap())); + } else { + httpResponse.setBody("{}".getBytes()); + } + + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + + return httpResponse; + } + + // @GetMapping("/queries") + public HttpResponse queries(HttpRequest request) { + String queries = request.getParam("queries"); + List> recordMaps = RandomUtils.randomWorldNumbers() + // limit + .limit(RandomUtils.parseQueryCount(queries)) // 限制查询数量 + .mapToObj(id -> Db.findById("world", id)) // 使用 mapToObj 将 int 映射为对象 + .filter(Objects::nonNull) // 过滤掉 null 值 + .map(Record::toMap) // 将每个 Record 对象转换为 Map + .collect(Collectors.toList()); // 收集到 List + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(recordMaps)); + return httpResponse; + } + +//@GetMapping("/updates") + public HttpResponse updates(HttpRequest request) { + String queries = request.getParam("queries"); + + EhCache.removeAll("world"); + + List> updatedRecords = RandomUtils.randomWorldNumbers()// random numbers + // limit + .limit(RandomUtils.parseQueryCount(queries)) + // map + .mapToObj(id -> Db.findById("world", id)) + // not null + .filter(Objects::nonNull).map(record -> { + int currentRandomNumber = record.getInt("randomNumber"); // "randomnumber" + int newRandomNumber; + do { + newRandomNumber = RandomUtils.randomWorldNumber(); + } while (newRandomNumber == currentRandomNumber); + + record.set("randomnumber", newRandomNumber); + Db.update("world", "id", record); // update + return record; + }) + // tomap + .map(Record::toMap) + // to List + .collect(Collectors.toList()); + + HttpResponse httpResponse = new HttpResponse(request); + httpResponse.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + httpResponse.setBody(JSON.toJSONBytes(updatedRecords)); + return httpResponse; + } + + public HttpResponse fortunes(HttpRequest request) throws IllegalAccessException, InstantiationException { + List records = Db.find("SELECT * FROM fortune"); + + List fortunes = new ArrayList<>(records.size()); + for (Record record : records) { + fortunes.add(BeanConverterUtils.toBean(record.toMap(), Fortune.class)); + } + // 添加额外的 Fortune + fortunes.add(new Fortune(0L, "Additional fortune added at request time.")); + + // 按照消息排序 + fortunes.sort(Comparator.comparing(Fortune::getMessage)); + + Map viewData = new HashMap<>(); + viewData.put("fortunes", fortunes); + + // 转换为 HTML + Engine engine = Engine.use(); + String filename = "fortunes.html"; + Template template = engine.getTemplate(filename); + String html = template.renderToString(viewData); + + return Resps.html(request, html); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/IndexController.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/IndexController.java new file mode 100644 index 00000000000..cf87426dda3 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/IndexController.java @@ -0,0 +1,40 @@ +package com.litongjava.tio.http.server.controller; + +import com.alibaba.fastjson2.JSON; +import com.litongjava.tio.http.common.HeaderName; +import com.litongjava.tio.http.common.HeaderValue; +import com.litongjava.tio.http.common.HttpRequest; +import com.litongjava.tio.http.common.HttpResponse; +import com.litongjava.tio.http.server.model.Message; +import com.litongjava.tio.http.server.util.Resps; + +/** + * ab -k -n1000000 -c10 http://127.0.0.1:8080/json + * ab -k -n1000000 -c10 http://127.0.0.1:8080/plaintext + */ +public class IndexController { + private static final String HELLO_WORLD = "Hello, World!"; + + private static final byte[] HELLO_WORLD_BYTES = HELLO_WORLD.getBytes(); + + public HttpResponse index(HttpRequest request) { + return Resps.txt(request, "tio-server"); + } + + public HttpResponse plaintext(HttpRequest request) { + // 更高性能的写法 + HttpResponse ret = new HttpResponse(request); + ret.setBody(HELLO_WORLD_BYTES); + ret.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_TXT); + return ret; + } + + // 在IndexController中添加 + public HttpResponse json(HttpRequest request) { + // 更高性能的写法 + HttpResponse ret = new HttpResponse(request); + ret.setBody(JSON.toJSONString(new Message(HELLO_WORLD)).getBytes()); + ret.addHeader(HeaderName.Content_Type, HeaderValue.Content_Type.TEXT_PLAIN_JSON); + return ret; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java new file mode 100644 index 00000000000..728db88b837 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java @@ -0,0 +1,23 @@ +package com.litongjava.tio.http.server.model; + +public final class Fortune { + + public Long id; + public String message; + + public Fortune() { + } + + public Fortune(Long id, String message) { + this.id = id; + this.message = message; + } + + public Long getId() { + return id; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java new file mode 100644 index 00000000000..2ad66214e0f --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java @@ -0,0 +1,12 @@ +package com.litongjava.tio.http.server.model; +public final class Message { + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java new file mode 100644 index 00000000000..06c4ed9a22b --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java @@ -0,0 +1,32 @@ +package com.litongjava.tio.http.server.model; + +public final class World { + + public int id; + public int randomnumber; + + protected World() { + } + + public World(int id, int randomnumber) { + this.id = id; + this.randomnumber = randomnumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomnumber() { + return randomnumber; + } + + public void setRandomnumber(int randomnumber) { + this.randomnumber = randomnumber; + } + +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java new file mode 100644 index 00000000000..5707d4f05d4 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java @@ -0,0 +1,50 @@ +package com.litongjava.tio.http.server.services; + +public class CacheName { + // `cacheName`(缓存名称) + private String name; + // `timeToLiveSeconds`(生存时间)和`timeToIdleSeconds`(闲置时间)。 + private Long timeToLiveSeconds; + private Long timeToIdleSeconds; + + public CacheName() { + } + + public CacheName(String name, Long timeToLiveSeconds, Long timeToIdleSeconds) { + super(); + this.name = name; + this.timeToLiveSeconds = timeToLiveSeconds; + this.timeToIdleSeconds = timeToIdleSeconds; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getTimeToLiveSeconds() { + return timeToLiveSeconds; + } + + public void setTimeToLiveSeconds(Long timeToLiveSeconds) { + this.timeToLiveSeconds = timeToLiveSeconds; + } + + public Long getTimeToIdleSeconds() { + return timeToIdleSeconds; + } + + public void setTimeToIdleSeconds(Long timeToIdleSeconds) { + this.timeToIdleSeconds = timeToIdleSeconds; + } + + @Override + public String toString() { + return "CacheName [name=" + name + ", timeToLiveSeconds=" + timeToLiveSeconds + ", timeToIdleSeconds=" + + timeToIdleSeconds + "]"; + } + +} \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java new file mode 100644 index 00000000000..5ab5d7e58e6 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java @@ -0,0 +1,17 @@ +package com.litongjava.tio.http.server.services; + +import java.util.ArrayList; +import java.util.List; + +import com.litongjava.model.time.Time; + +public class CacheNameService { + private CacheName demo = new CacheName("world", null, Time.MINUTE_1 * 10); + + public List cacheNames() { + List list = new ArrayList<>(); + list.add(demo); + return list; + } + +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/BeanConverterUtils.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/BeanConverterUtils.java new file mode 100644 index 00000000000..11796feeb0f --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/BeanConverterUtils.java @@ -0,0 +1,31 @@ +package com.litongjava.tio.http.server.utils; + +import java.lang.reflect.Field; +import java.util.Map; + +public class BeanConverterUtils { + + /** + * Map to to bean + */ + public static T toBean(Map map, Class beanClass) + throws IllegalAccessException, InstantiationException { + + T bean = beanClass.newInstance(); // 创建 Bean 的实例 + + for (Field field : beanClass.getDeclaredFields()) { + field.setAccessible(true); // 确保私有字段也可以访问 + + if (map.containsKey(field.getName())) { + Object value = map.get(field.getName()); + + // 如果字段类型与值类型兼容,则设置字段的值 + if (value != null && field.getType().isAssignableFrom(value.getClass())) { + field.set(bean, value); + } + } + } + + return bean; + } +} diff --git a/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java new file mode 100644 index 00000000000..e18e98ef880 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java @@ -0,0 +1,36 @@ +package com.litongjava.tio.http.server.utils; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +public class RandomUtils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; +// private static final int MAX_WORLD_NUMBER_PLUS_ONE = 30; + + public static int randomWorldNumber() { + return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); + } + + public static IntStream randomWorldNumbers() { + return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE) + // distinct() allows us to avoid using Hibernate's first-level cache in + // the JPA-based implementation. Using a cache like that would bypass + // querying the database, which would violate the test requirements. + .distinct(); + } + + public static int parseQueryCount(String textValue) { + if (textValue == null) { + return 1; + } + int parsedValue; + try { + parsedValue = Integer.parseInt(textValue); + } catch (NumberFormatException e) { + return 1; + } + return Math.min(500, Math.max(1, parsedValue)); + } +} diff --git a/frameworks/Java/tio-http-server/src/main/resources/app.properties b/frameworks/Java/tio-http-server/src/main/resources/app.properties new file mode 100644 index 00000000000..b73b6ff144d --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/app.properties @@ -0,0 +1,9 @@ +http.response.header.showServer=true + +#JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false&allowPublicKeyRetrieval=true +#JDBC_USER=root +#JDBC_PSWD=robot_123456# + +JDBC_URL=jdbc:mysql://tfb-database/hello_world +JDBC_USER=benchmarkdbuser +JDBC_PSWD=benchmarkdbpass \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/resources/ehcache.xml b/frameworks/Java/tio-http-server/src/main/resources/ehcache.xml new file mode 100644 index 00000000000..79b79e49479 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/ehcache.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/frameworks/Java/tio-http-server/src/main/resources/logback.xml b/frameworks/Java/tio-http-server/src/main/resources/logback.xml new file mode 100644 index 00000000000..aff0c711191 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/logback.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + ${LOG_HOME}/project-name-%d{yyyy-MM-dd}.log + + 180 + + + + 10MB + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html b/frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html new file mode 100644 index 00000000000..1f6817df007 --- /dev/null +++ b/frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + #for(fortune : fortunes) + + + + + #end +
idmessage
#(fortune.id)#escape(fortune.message)
+ + diff --git a/frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java b/frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java new file mode 100644 index 00000000000..e469fa256ef --- /dev/null +++ b/frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java @@ -0,0 +1,15 @@ +package com.litongjava.tio.http.server; + +import org.junit.Test; + +import com.litongjava.tio.utils.environment.EnvUtils; + +public class MainAppTest { + + @Test + public void test() { + boolean boolean1 = EnvUtils.getBoolean("native", false); + System.out.println(boolean1); + } + +} diff --git a/frameworks/Java/tio-http-server/tio-server-native.dockerfile b/frameworks/Java/tio-http-server/tio-server-native.dockerfile new file mode 100644 index 00000000000..8dd0f012ea0 --- /dev/null +++ b/frameworks/Java/tio-http-server/tio-server-native.dockerfile @@ -0,0 +1,9 @@ +FROM litongjava/maven:3.8.8-graalvm-jdk-21-slim +WORKDIR /t-io +COPY pom.xml pom.xml +COPY src src +RUN mvn package -Pnative -q + +EXPOSE 8080 + +CMD ["/t-io/target/tio-http-server-benchmark", " --native=true"] diff --git a/frameworks/Java/tio-http-server/tio-server.dockerfile b/frameworks/Java/tio-http-server/tio-server.dockerfile new file mode 100644 index 00000000000..e9218a84790 --- /dev/null +++ b/frameworks/Java/tio-http-server/tio-server.dockerfile @@ -0,0 +1,19 @@ +FROM litongjava/maven:3.8.8-jdk8u391 AS builder +WORKDIR /app + +COPY pom.xml pom.xml +RUN mvn dependency:go-offline -q + +COPY src src +RUN mvn package -Passembly -q +RUN ls -l && ls -l target + +FROM litongjava/jre:8u391-stable-slim + +WORKDIR /app + +COPY --from=builder /app/target/tio-http-server-benchmark-1.0.jar /app/target/tio-http-server-benchmark-1.0.jar + +EXPOSE 8080 + +CMD ["java","-jar", "/app/target/tio-http-server-benchmark-1.0.jar"] \ No newline at end of file