Browse Source

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 <[email protected]>
Tong Li 7 months ago
parent
commit
05975805fb
28 changed files with 1293 additions and 0 deletions
  1. 19 0
      frameworks/Java/tio-http-server/.dockerignore
  2. 3 0
      frameworks/Java/tio-http-server/.gitignore
  3. 114 0
      frameworks/Java/tio-http-server/README.md
  4. 227 0
      frameworks/Java/tio-http-server/api/tio-server-benchmark.md
  5. 29 0
      frameworks/Java/tio-http-server/benchmark_config.json
  6. 19 0
      frameworks/Java/tio-http-server/config.toml
  7. 209 0
      frameworks/Java/tio-http-server/pom.xml
  8. 66 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/MainApp.java
  9. 12 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EhCachePluginConfig.java
  10. 22 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/EnjoyEngineConfig.java
  11. 31 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/config/MysqlDbConfig.java
  12. 41 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/CacheController.java
  13. 127 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/DbController.java
  14. 40 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/controller/IndexController.java
  15. 23 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Fortune.java
  16. 12 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/Message.java
  17. 32 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/model/World.java
  18. 50 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheName.java
  19. 17 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/services/CacheNameService.java
  20. 31 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/BeanConverterUtils.java
  21. 36 0
      frameworks/Java/tio-http-server/src/main/java/com/litongjava/tio/http/server/utils/RandomUtils.java
  22. 9 0
      frameworks/Java/tio-http-server/src/main/resources/app.properties
  23. 9 0
      frameworks/Java/tio-http-server/src/main/resources/ehcache.xml
  24. 52 0
      frameworks/Java/tio-http-server/src/main/resources/logback.xml
  25. 20 0
      frameworks/Java/tio-http-server/src/main/resources/templates/fortunes.html
  26. 15 0
      frameworks/Java/tio-http-server/src/test/java/com/litongjava/tio/http/server/MainAppTest.java
  27. 9 0
      frameworks/Java/tio-http-server/tio-server-native.dockerfile
  28. 19 0
      frameworks/Java/tio-http-server/tio-server.dockerfile

+ 19 - 0
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

+ 3 - 0
frameworks/Java/tio-http-server/.gitignore

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

+ 114 - 0
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
+```
+
+
+

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

+ 29 - 0
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"
+    }
+  }]
+}

+ 19 - 0
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"

+ 209 - 0
frameworks/Java/tio-http-server/pom.xml

@@ -0,0 +1,209 @@
+<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-http-server-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>
+    <graalvm.version>23.1.1</graalvm.version>
+    <main.class>com.litongjava.tio.http.server.MainApp</main.class>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>com.litongjava</groupId>
+      <artifactId>tio-http-server</artifactId>
+      <version>3.7.3.v20240919-RELEASE</version>
+    </dependency>
+    <dependency>
+      <groupId>com.litongjava</groupId>
+      <artifactId>java-db</artifactId>
+      <version>1.2.6</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+
+
+    <!-- https://mvnrepository.com/artifact/com.jfinal/activerecord -->
+    <!--
+    <dependency>
+      <groupId>com.jfinal</groupId>
+      <artifactId>activerecord</artifactId>
+      <version>5.1.6</version>
+    </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>
+  <profiles>
+    <!-- 开发环境 -->
+    <profile>
+      <id>development</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-classic</artifactId>
+          <version>1.2.3</version>
+        </dependency>
+      </dependencies>
+    </profile>
+
+    <!-- 生产环境 -->
+    <profile>
+      <id>production</id>
+      <dependencies>
+        <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-classic</artifactId>
+          <version>1.2.3</version>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-maven-plugin</artifactId>
+            <version>2.7.4</version>
+            <configuration>
+              <mainClass>${main.class}</mainClass>
+              <excludeGroupIds>org.projectlombok</excludeGroupIds>
+            </configuration>
+            <!-- 设置执行目标 -->
+            <executions>
+              <execution>
+                <goals>
+                  <goal>repackage</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <!-- assembly -->
+    <profile>
+      <id>assembly</id>
+      <dependencies>
+        <dependency>
+          <groupId>ch.qos.logback</groupId>
+          <artifactId>logback-classic</artifactId>
+          <version>1.2.3</version>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jar-plugin</artifactId>
+            <version>3.2.0</version>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-assembly-plugin</artifactId>
+            <version>3.1.1</version>
+            <configuration>
+              <archive>
+                <manifest>
+                  <mainClass>${main.class}</mainClass>
+                </manifest>
+              </archive>
+              <descriptorRefs>
+                <descriptorRef>jar-with-dependencies</descriptorRef>
+              </descriptorRefs>
+              <appendAssemblyId>false</appendAssemblyId>
+            </configuration>
+            <executions>
+              <execution>
+                <id>make-assembly</id>
+                <phase>package</phase>
+                <goals>
+                  <goal>single</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <profile>
+      <id>native</id>
+      <dependencies>
+        <!-- GraalVM 环境使用 jdk log -->
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-jdk14</artifactId>
+          <version>1.7.31</version>
+        </dependency>
+        <!-- GraalVM -->
+        <dependency>
+          <groupId>org.graalvm.sdk</groupId>
+          <artifactId>graal-sdk</artifactId>
+          <version>${graalvm.version}</version>
+          <scope>provided</scope>
+        </dependency>
+      </dependencies>
+      <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+          <plugin>
+            <groupId>org.graalvm.nativeimage</groupId>
+            <artifactId>native-image-maven-plugin</artifactId>
+            <version>21.2.0</version>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>native-image</goal>
+                </goals>
+                <phase>package</phase>
+              </execution>
+            </executions>
+            <configuration>
+              <skip>false</skip>
+              <imageName>${project.artifactId}</imageName>
+              <mainClass>${main.class}</mainClass>
+              <buildArgs>
+                -H:+RemoveSaturatedTypeFlows
+                --allow-incomplete-classpath
+                --no-fallback
+              </buildArgs>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>

+ 66 - 0
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);
+    }
+
+  }
+}

+ 12 - 0
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;
+  }
+}

+ 22 - 0
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;
+  }
+
+}

+ 31 - 0
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);
+  }
+}

+ 41 - 0
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<Map<String, Object>> 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);
+  }
+}

+ 127 - 0
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<Map<String, Object>> 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<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(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<Record> records = Db.find("SELECT * FROM fortune"); 
+
+    List<Fortune> 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<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-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;
+  }
+}

+ 23 - 0
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;
+  }
+}

+ 12 - 0
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;
+	}
+}

+ 32 - 0
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;
+  }
+
+}

+ 50 - 0
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 + "]";
+  }
+
+}

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

+ 31 - 0
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> T toBean(Map<String, Object> map, Class<T> 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;
+  }
+}

+ 36 - 0
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));
+  }
+}

+ 9 - 0
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

+ 9 - 0
frameworks/Java/tio-http-server/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-http-server/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-http-server/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-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);
+  }
+
+}

+ 9 - 0
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"]

+ 19 - 0
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"]