Browse Source

Tio boot (#9610)

* add tio-boot

* add server.port=8080

* update docker filename

---------

Co-authored-by: litongjava <[email protected]>
Tong Li 5 months ago
parent
commit
3bb6021694
27 changed files with 1171 additions and 0 deletions
  1. 19 0
      frameworks/Java/tio-boot/.dockerignore
  2. 3 0
      frameworks/Java/tio-boot/.gitignore
  3. 114 0
      frameworks/Java/tio-boot/README.md
  4. 227 0
      frameworks/Java/tio-boot/api/tio-server-benchmark.md
  5. 29 0
      frameworks/Java/tio-boot/benchmark_config.json
  6. 19 0
      frameworks/Java/tio-boot/config.toml
  7. 126 0
      frameworks/Java/tio-boot/pom.xml
  8. 13 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java
  9. 54 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainAppConfig.java
  10. 12 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java
  11. 22 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java
  12. 31 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java
  13. 41 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/controller/CacheHandler.java
  14. 126 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/controller/DbHandler.java
  15. 40 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/controller/IndexHandler.java
  16. 23 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Fortune.java
  17. 12 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/Message.java
  18. 32 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/model/World.java
  19. 50 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheName.java
  20. 17 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java
  21. 36 0
      frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java
  22. 9 0
      frameworks/Java/tio-boot/src/main/resources/app.properties
  23. 9 0
      frameworks/Java/tio-boot/src/main/resources/ehcache.xml
  24. 52 0
      frameworks/Java/tio-boot/src/main/resources/logback.xml
  25. 20 0
      frameworks/Java/tio-boot/src/main/resources/templates/fortunes.html
  26. 15 0
      frameworks/Java/tio-boot/src/test/java/com/litongjava/tio/http/server/MainAppTest.java
  27. 20 0
      frameworks/Java/tio-boot/tio-boot.dockerfile

+ 19 - 0
frameworks/Java/tio-boot/.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

+ 3 - 0
frameworks/Java/tio-boot/.gitignore

@@ -0,0 +1,3 @@
+/target/
+logs
+.settings

+ 114 - 0
frameworks/Java/tio-boot/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
+```
+
+
+

+ 227 - 0
frameworks/Java/tio-boot/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|
+
+### 返回数据结构
+
+# 数据模型
+

+ 29 - 0
frameworks/Java/tio-boot/benchmark_config.json

@@ -0,0 +1,29 @@
+{
+  "framework": "tio-boot",
+  "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-boot",
+      "language": "Java",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "t-io",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "tio-boot",
+      "notes": "tio-boot",
+      "versus": "t-io"
+    }
+  }]
+}

+ 19 - 0
frameworks/Java/tio-boot/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"

+ 126 - 0
frameworks/Java/tio-boot/pom.xml

@@ -0,0 +1,126 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.litongjava</groupId>
+  <artifactId>tio-boot-benchmark</artifactId>
+  <version>1.0</version>
+  <name>${project.artifactId}</name>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <java.version>1.8</java.version>
+    <maven.compiler.source>${java.version}</maven.compiler.source>
+    <maven.compiler.target>${java.version}</maven.compiler.target>
+    <tio-boot.version>1.9.1</tio-boot.version>
+
+    <main.class>com.litongjava.tio.http.server.MainApp</main.class>
+  </properties>
+  <dependencies>
+    <!-- Tio Boot 框架 -->
+    <dependency>
+      <groupId>com.litongjava</groupId>
+      <artifactId>tio-boot</artifactId>
+      <version>${tio-boot.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.litongjava</groupId>
+      <artifactId>java-db</artifactId>
+      <version>1.4.9</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+
+
+    <dependency>
+      <groupId>com.alibaba.fastjson2</groupId>
+      <artifactId>fastjson2</artifactId>
+      <version>2.0.52</version>
+    </dependency>
+
+    <dependency>
+      <groupId>net.sf.ehcache</groupId>
+      <artifactId>ehcache-core</artifactId>
+      <version>2.6.11</version>
+    </dependency>
+
+    <dependency>
+      <groupId>mysql</groupId>
+      <artifactId>mysql-connector-java</artifactId>
+      <version>5.1.46</version>
+    </dependency>
+
+    <dependency>
+      <groupId>com.zaxxer</groupId>
+      <artifactId>HikariCP</artifactId>
+      <version>4.0.3</version>
+    </dependency>
+
+  </dependencies>
+  <repositories>
+    <repository>
+      <id>central</id>
+      <name>Central Repository</name>
+      <url>https://repo.maven.apache.org/maven2</url>
+    </repository>
+    <repository>
+      <id>sonatype-nexus-snapshots</id>
+      <name>Sonatype Nexus Snapshots</name>
+      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <id>central</id>
+      <name>Central Repository</name>
+      <url>https://repo.maven.apache.org/maven2</url>
+    </pluginRepository>
+    <pluginRepository>
+      <id>sonatype-nexus-snapshots</id>
+      <name>Sonatype Nexus Snapshots</name>
+      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+    </pluginRepository>
+  </pluginRepositories>
+  <build>
+    <plugins>
+
+      <plugin>
+        <inherited>true</inherited>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.8.0</version>
+        <configuration>
+          <debug>false</debug>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>3.1.0</version>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+        </configuration>
+        <executions>
+          <execution>
+            <id>make-assembly</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>

+ 13 - 0
frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainApp.java

@@ -0,0 +1,13 @@
+package com.litongjava.tio.http.server;
+
+import com.litongjava.tio.boot.TioApplication;
+
+public class MainApp {
+
+  public static void main(String[] args) {
+    long start = System.currentTimeMillis();
+    TioApplication.run(MainApp.class, new MainAppConfig(), args);
+    long end = System.currentTimeMillis();
+    System.out.println((end - start) + "ms");
+  }
+}

+ 54 - 0
frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/MainAppConfig.java

@@ -0,0 +1,54 @@
+package com.litongjava.tio.http.server;
+
+import com.litongjava.context.BootConfiguration;
+import com.litongjava.tio.boot.server.TioBootServer;
+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.CacheHandler;
+import com.litongjava.tio.http.server.controller.DbHandler;
+import com.litongjava.tio.http.server.controller.IndexHandler;
+import com.litongjava.tio.http.server.router.HttpRequestRouter;
+import com.litongjava.tio.utils.environment.EnvUtils;
+
+public class MainAppConfig implements BootConfiguration {
+
+  @Override
+  public void config() throws Exception {
+    // add route
+    IndexHandler controller = new IndexHandler();
+
+    TioBootServer server = TioBootServer.me();
+    HttpRequestRouter requestRouter = server.getRequestRouter();
+
+    requestRouter.add("/", controller::index);
+    requestRouter.add("/plaintext", controller::plaintext);
+    requestRouter.add("/json", controller::json);
+
+    DbHandler dbQueryController = new DbHandler();
+    requestRouter.add("/db", dbQueryController::db);
+    requestRouter.add("/queries", dbQueryController::queries);
+    requestRouter.add("/updates", dbQueryController::updates);
+    requestRouter.add("/fortunes", dbQueryController::fortunes);
+
+    CacheHandler cacheController = new CacheHandler();
+    requestRouter.add("/cachedQuery", cacheController::cachedQuery);
+
+    boolean db = EnvUtils.getBoolean("db", true);
+    if (db) {
+      try {
+        new MysqlDbConfig().init();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    // start enjoy and ehcache
+    try {
+      new EnjoyEngineConfig().engine();
+      new EhCachePluginConfig().ehCachePlugin();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+}

+ 12 - 0
frameworks/Java/tio-boot/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;
+  }
+}

+ 22 - 0
frameworks/Java/tio-boot/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;
+  }
+
+}

+ 31 - 0
frameworks/Java/tio-boot/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);
+  }
+}

+ 41 - 0
frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/controller/CacheHandler.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.Row;
+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 CacheHandler {
+  // private Logger log = LoggerFactory.getLogger(this.getClass());
+
+  public HttpResponse cachedQuery(HttpRequest request) {
+    String queries = request.getParam("queries");
+    List<Map<String, Object>> recordMaps = RandomUtils.randomWorldNumbers()
+        // limit
+        .limit(RandomUtils.parseQueryCount(queries)) // 限制查询数量
+        .mapToObj(id -> findByIdWithCache("world", id)) // 使用 mapToObj 将 int 映射为对象
+        .filter(Objects::nonNull) // 过滤掉 null 值
+        .map(Row::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 Row findByIdWithCache(String tableName, int id) {
+    String sql = "SELECT id, randomNumber FROM world WHERE id = ?";
+    return Db.findFirstByCache(tableName, id, sql, id);
+  }
+}

+ 126 - 0
frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/controller/DbHandler.java

@@ -0,0 +1,126 @@
+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.Row;
+import com.litongjava.ehcache.EhCacheKit;
+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.RandomUtils;
+
+public class DbHandler {
+
+  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 = ?";
+
+    Row 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<Map<String, Object>> recordMaps = RandomUtils.randomWorldNumbers()
+        // limit
+        .limit(RandomUtils.parseQueryCount(queries)) // 限制查询数量
+        .mapToObj(id -> Db.findById("world", id)) // 使用 mapToObj 将 int 映射为对象
+        .filter(Objects::nonNull) // 过滤掉 null 值
+        .map(Row::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");
+
+    EhCacheKit.removeAll("world");
+
+    List<Map<String, Object>> 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(Row::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<Row> records = Db.find("SELECT * FROM fortune");
+
+    List<Fortune> fortunes = new ArrayList<>(records.size());
+    for (Row record : records) {
+      fortunes.add(record.toBean(Fortune.class));
+    }
+    // 添加额外的 Fortune
+    fortunes.add(new Fortune(0L, "Additional fortune added at request time."));
+
+    // 按照消息排序
+    fortunes.sort(Comparator.comparing(Fortune::getMessage));
+
+    Map<String, Object> 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);
+  }
+}

+ 40 - 0
frameworks/Java/tio-boot/src/main/java/com/litongjava/tio/http/server/controller/IndexHandler.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 IndexHandler {
+  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-boot");
+  }
+
+  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;
+  }
+}

+ 23 - 0
frameworks/Java/tio-boot/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;
+  }
+}

+ 12 - 0
frameworks/Java/tio-boot/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;
+	}
+}

+ 32 - 0
frameworks/Java/tio-boot/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;
+  }
+
+}

+ 50 - 0
frameworks/Java/tio-boot/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 + "]";
+  }
+
+}

+ 17 - 0
frameworks/Java/tio-boot/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<CacheName> cacheNames() {
+    List<CacheName> list = new ArrayList<>();
+    list.add(demo);
+    return list;
+  }
+
+}

+ 36 - 0
frameworks/Java/tio-boot/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));
+  }
+}

+ 9 - 0
frameworks/Java/tio-boot/src/main/resources/app.properties

@@ -0,0 +1,9 @@
+http.response.header.showServer=true
+server.port=8080
+#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

+ 9 - 0
frameworks/Java/tio-boot/src/main/resources/ehcache.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
+
+  <diskStore path="java.io.tmpdir/EhCache" />
+
+  <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false"
+                timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU" />
+</ehcache>

+ 52 - 0
frameworks/Java/tio-boot/src/main/resources/logback.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration>
+  <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径 -->
+  <property name="LOG_HOME" value="logs" />
+  <!--格式化输出:%d表示日期,%-6level:日志级别从左显示6个字符宽度,%m:日志消息,%n是换行符 -->
+  <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-6level%logger{0}.%M:%L - %m%n" />
+
+  <!-- 控制台输出 -->
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+      <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+    </encoder>
+  </appender>
+
+  <!-- 按照每天生成日志文件 -->
+  <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+      <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+    </encoder>
+    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+      <!--日志文件输出的文件名 -->
+      <fileNamePattern>${LOG_HOME}/project-name-%d{yyyy-MM-dd}.log</fileNamePattern>
+      <!--日志文件保留天数 -->
+      <maxHistory>180</maxHistory>
+    </rollingPolicy>
+    <!--日志文件最大的大小 -->
+    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+      <maxFileSize>10MB</maxFileSize>
+    </triggeringPolicy>
+  </appender>
+  
+  <!--专为 spring 定制 -->
+  <logger name="org.springframework" level="info" />
+  <!-- show parameters for hibernate sql 专为 Hibernate 定制 -->
+  <logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="TRACE" />
+  <logger name="org.hibernate.type.descriptor.sql.BasicExtractor" level="DEBUG" />
+  <logger name="org.hibernate.SQL" level="DEBUG" />
+  <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />
+  <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" />
+
+  <!--myibatis log configure -->
+  <logger name="com.apache.ibatis" level="TRACE" />
+  <logger name="java.sql.Connection" level="DEBUG" />
+  <logger name="java.sql.Statement" level="DEBUG" />
+  <logger name="java.sql.PreparedStatement" level="DEBUG" />
+
+  <!-- 日志输出级别 和输出源 -->
+  <root level="info">
+    <appender-ref ref="STDOUT" />
+    <appender-ref ref="FILE" />
+  </root>
+</configuration>

+ 20 - 0
frameworks/Java/tio-boot/src/main/resources/templates/fortunes.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Fortunes</title>
+</head>
+<body>
+<table>
+  <tr>
+    <th>id</th>
+    <th>message</th>
+  </tr>
+  #for(fortune : fortunes)
+  <tr>
+    <td>#(fortune.id)</td>
+    <td>#escape(fortune.message)</td>
+  </tr>
+  #end
+</table>
+</body>
+</html>

+ 15 - 0
frameworks/Java/tio-boot/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);
+  }
+
+}

+ 20 - 0
frameworks/Java/tio-boot/tio-boot.dockerfile

@@ -0,0 +1,20 @@
+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-boot-benchmark-1.0-jar-with-dependencies.jar /app/tio-boot-benchmark-1.0.jar
+
+EXPOSE 8080
+
+# java --server -XX:+UseNUMA XX:+UseParallelGC -cp target/tio-boot-benchmark-1.0-jar-with-dependencies.jar com.litongjava.tio.http.server.MainApp
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC","-cp", "/app/tio-boot-benchmark-1.0.jar","com.litongjava.tio.http.server.MainApp"]