RESTful 微服務與 RestExpress

Java,REST
Remote
0
04:52 AM · Dec 01 ,2025

1. 概述

在本教程中,我們將學習如何使用 RestExpress 構建 RESTful 微服務。

RestExpress 是一個開源 Java 框架,它使我們能夠快速、輕鬆地構建 RESTful 微服務。基於 Netty 框架,它旨在減少樣板代碼並加快 RESTful 微服務的開發。

此外,它使用插件架構,允許我們在微服務中添加功能。它支持緩存、安全和持久性等常用功能的插件。

2. RestExpress 樣板

RestExpress 樣板 是一個支持項目,提供了一組 Maven 樣板,用於創建 RestExpress 項目。

在編寫時,有三種樣板可用:

  1. 最小化包含創建 RESTful 項目所需的最低代碼。 它包含主類、properties 文件和示例 API。
  2. mongodb創建具有 MongoDB 支持的 RESTful 項目。 此外,它還包括 最小化 樣板,其中包含 MongoDB 層。
  3. cassandra – 類似於 mongodb 樣板,將 Cassandra 層添加到 最小化 樣板

每個樣板都附帶一組插件,用於向我們的微服務添加功能:

  • CacheControlPlugin – 添加對 Cache-Control 標頭的支持
  • CORSPlugin – 添加對 CORS 的支持
  • MetricsPlugin – 添加對 Metrics 的支持
  • SwaggerPlugin – 添加對 Swagger 的支持
  • HyperExpressPlugin – 添加對 HATEOAS 的支持

默認情況下,僅啓用 MetricsPlugin,並且它使用 Dropwizard Metrics。 我們可以通過向其中一個實現添加依賴項來啓用其他插件。 此外,我們可能還需要添加屬性來配置和啓用某些插件。

在下一部分中,我們將探討如何使用 mongodb 樣板創建項目。 我們將學習如何配置應用程序,然後我們將查看生成的代碼的某些方面。

2.1. 使用樣板創建項目

讓我們使用 mongodb 樣板創建一個項目。

在終端上,讓我們導航到想要創建項目的位置。 我們將使用 mvn archetype:generate 命令:

$ mvn archetype:generate -DarchetypeGroupId=com.strategicgains.archetype -DarchetypeArtifactId=restexpress-mongodb -DarchetypeVersion=1.18 -DgroupId=com.baeldung -DartifactId=rest-express -Dversion=1.0-SNAPSHOT

這會創建一個帶有示例代碼和配置的項目。

Rest Express 項目結構

 

樣板會自動為我們創建幾個組件。 它創建了一個使用默認配置的服務器。 這些 配置存在於 environment.properties 文件中

兩個 CRUD API 組在 objectiduuid 包中。 每個包都包含一個實體、一個控制器、一個服務和一個存儲庫類。

The Configuration, Server, Main, andRoutes 類有助於在啓動時配置服務器。

我們將探索這些生成的類在下一部分中。

3. Generated Code

讓大家探索生成的代碼。我們將重點關注主類、API方法和DB層。這將幫助我們瞭解如何使用RestExpress創建一個簡單的CRUD應用程序。

3.1. Main Class

主類是我們的應用程序的入口點。它 負責啓動服務器並配置應用程序

讓我們看一下 main() 方法的 Main 類:

public static void main(String[] args) throws Exception {
    Configuration config = Environment.load(args, Configuration.class);
    Server server = new Server(config);
    server.start().awaitShutdown();
}

讓我們詳細瞭解一下這段代碼:

  • Environment.load() 方法從 environment.properties 文件中加載配置並創建 Configuration 對象。
  • Server 類負責啓動服務器。它需要一個Configuration 對象來設置服務器。我們將在下一部分中查看ConfigurationServer 類。
  • start() 方法啓動服務器,awaitShutdown() 方法等待服務器關閉。

3.2. Reading Properties

文件 environment.properties 包含我們應用程序的配置。為了讀取屬性, Configuration 類會自動創建。

讓我們看一下 Configuration 類中的不同部分。

類 Configuration 繼承 Environment 類。這允許我們 從環境讀取屬性。它覆蓋了 fillValues() 方法 來自 Environment 類:

@Override
protected void fillValues(Properties p) {
    this.port = Integer.parseInt(p.getProperty(PORT_PROPERTY, String.valueOf(RestExpress.DEFAULT_PORT)));
    this.baseUrl = p.getProperty(BASE_URL_PROPERTY, "http://localhost:" + String.valueOf(port));
    this.executorThreadPoolSize = Integer.parseInt(p.getProperty(EXECUTOR_THREAD_POOL_SIZE, DEFAULT_EXECUTOR_THREAD_POOL_SIZE));
    this.metricsSettings = new MetricsConfig(p);
    MongoConfig mongo = new MongoConfig(p);
    initialize(mongo);
}

上面的代碼從環境中讀取端口、基本 URL 和執行器線程池大小,並將這些值設置為字段。它還創建一個 MetricsConfig 對象和一個 MongoConfig 對象。

我們將在下一部分中查看 initialize() 方法。

3.3. Initializing Controllers and Repositories

初始化() 方法負責初始化控制器和存儲庫:

private void initialize(MongoConfig mongo) {
    SampleUuidEntityRepository samplesUuidRepository = new SampleUuidEntityRepository(mongo.getClient(), mongo.getDbName());
    SampleUuidEntityService sampleUuidService = new SampleUuidEntityService(samplesUuidRepository);
    sampleUuidController = new SampleUuidEntityController(sampleUuidService);

    SampleOidEntityRepository samplesOidRepository = new SampleOidEntityRepository(mongo.getClient(), mongo.getDbName());
    SampleOidEntityService sampleOidService = new SampleOidEntityService(samplesOidRepository);
    sampleOidController = new SampleOidEntityController(sampleOidService);
}

上面的代碼創建一個 SampleUuidEntityRepository 對象,使用 Mongo 客户端和數據庫名稱。 然後創建一個 SampleUuidEntityService 對象,使用該存儲庫。 最後,創建一個 SampleUuidEntityController 對象,使用該服務

相同的過程也用於 SampleOidEntityController。 這樣,API 和數據庫層就被初始化了。

類 Configuration 負責創建我們想要配置的任何對象,當服務器啓動時。 我們可以將任何其他初始化代碼添加到 initialize() 方法中。

同樣,我們可以將更多的屬性添加到 environment.properties 文件中,並在 fillValues() 方法中讀取它們

我們也可以使用我們的實現擴展 Configuration 類。 在這種情況下,我們需要更新 Main 類,以便使用我們的實現,而不是 Configuration 類。

4. RestExpress APIs

在上一節中,我們瞭解了 Configuration 類如何初始化控制器。現在,讓我們看看 SampleUuidEntityController 類,以瞭解如何創建 API 方法。

該示例控制器包含 create()read()readAll()update()delete() 方法的有效代碼。每個方法內部都會調用相應服務類的方法,隨後調用存儲類。

接下來,讓我們看看一些方法,以瞭解它們的工作原理。

4.1. Create

讓我們看看 create() 方法:

public SampleOidEntity create(Request request, Response response) {
    SampleOidEntity entity = request.getBodyAs(SampleOidEntity.class, "Resource details not provided");
    SampleOidEntity saved = service.create(entity);

    // Construct the response for create...
    response.setResponseCreated();

    // Include the Location header...
    String locationPattern = request.getNamedUrl(HttpMethod.GET, Constants.Routes.SINGLE_OID_SAMPLE);
    response.addLocationHeader(LOCATION_BUILDER.build(locationPattern, new DefaultTokenResolver()));

    // Return the newly-created resource...
    return saved;
}

上面的代碼:

  • 讀取請求主體,並將其轉換為 SampleOidEntity 對象
  • 調用服務類中的 create() 方法,並傳遞實體對象
  • 將響應代碼設置為 201 – created
  • 向響應添加位置標頭
  • 返回新創建的實體

如果我們查看服務類,我們會看到它執行驗證並調用存儲類的 create() 方法。

SampleOidEntityRepository 類繼承 MongodbEntityRepository 類,該類內部使用 Mongo Java 驅動程序來執行數據庫操作:

public class SampleOidEntityRepository extends MongodbEntityRepository<SampleOidEntity> {
    @SuppressWarnings("unchecked")
    public SampleOidEntityRepository(MongoClient mongo, String dbName) {
        super(mongo, dbName, SampleOidEntity.class);
    }
}

4.2. Read

現在,讓我們看看 read() 方法:

public SampleOidEntity read(Request request, Response response) {
    String id = request.getHeader(Constants.Url.SAMPLE_ID, "No resource ID supplied");
    SampleOidEntity entity = service.read(Identifiers.MONGOID.parse(id));

    return entity;
}

該方法從請求標頭解析 ID,並調用服務類中的 read() 方法。服務類隨後調用存儲類中的 read() 方法。存儲類檢索並返回數據庫中的實體。

5. Server and Routing

最後,讓我們看一下 Server 類。Server 類啓動應用程序。它定義了路由和路由上的控制器。它還使用指標和其他插件配置了服務器。

5.1. 創建服務器

讓我們看一下 Server 類的構造函數:

public Server(Configuration config) {
    this.config = config;
    RestExpress.setDefaultSerializationProvider(new SerializationProvider());
    Identifiers.UUID.useShortUUID(true);

    this.server = new RestExpress()
      .setName(SERVICE_NAME)
      .setBaseUrl(config.getBaseUrl())
      .setExecutorThreadCount(config.getExecutorThreadPoolSize())
      .addMessageObserver(new SimpleConsoleLogMessageObserver());

    Routes.define(config,server);
    Relationships.define(server);
    configurePlugins(config,server);
    mapExceptions(server);
}

構造函數執行一些步驟:

  • 它創建一個 RestExpress 對象,並設置名稱、基本 URL、執行線程池大小和控制枱日誌觀察者。 RestExpress 內部創建一個 Netty 服務器。 此服務器將在我們調用 start() 方法在 Main 類中啓動時啓動。
  • 它調用 Routes.define() 方法來定義路由。 我們在下一部分中將查看 Routes 類。
  • 它為實體定義關係,配置插件,基於提供的屬性進行配置,並映射某些內部異常到應用程序處理的異常。

5.2. 路由

Routes.define() 方法定義路由和為每個路由調用的控制器方法。

讓我們看一下 SampleOidEntityController 的路由:

public static void define(Configuration config, RestExpress server) {
    // other routes omitted for brevity...
        
    server.uri("/samples/oid/{uuid}.{format}", config.getSampleOidEntityController())
      .method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.DELETE)
      .name(Constants.Routes.SINGLE_OID_SAMPLE);
  
    server.uri("/samples/oid.{format}", config.getSampleOidEntityController())
      .action("readAll", HttpMethod.GET)
      .method(HttpMethod.POST)
      .name(Constants.Routes.SAMPLE_OID_COLLECTION);
}

讓我們詳細查看第一個路由定義。 uri() 方法將模式 /samples/oid/{uuid}.{format} 映射到 SampleOidEntityController{uuid}{format} 是 URL 中路徑參數。

GETPUTDELETE 方法映射到控制器的 read()update()delete() 方法, respectively。 這是 Netty 服務器的默認行為。

為路由分配名稱,以便可以使用 server.getRouteUrlsByName() 方法(如果需要)通過名稱檢索路由。

對於 create()readAll(),我們需要使用不要求 ID 的不同模式。

讓我們看一下第二個路由定義。 模式 /samples/oid.{format} 映射到 SampleOidEntityController

action() 方法用於將方法名稱映射到 HTTP 方法。 在這種情況下,readAll() 方法映射到 GET 方法。

POST 方法允許在模式上,並映射到控制器的 create() 方法,默認情況下。 並且,如之前所述,為路由分配名稱。

請注意,如果定義更多方法或更改控制器的標準方法名稱,則需要使用 action() 方法將它們映射到各自的 HTTP 方法。

必須將需要定義的任何其他 URL 模式添加到 Routes.define() 方法中。

6. 運行應用程序

讓我們運行應用程序並對實體執行一些操作。 我們將使用 curl 命令來執行這些操作。

讓我們通過運行 Main 類來啓動應用程序。 應用程序在端口 8081 上啓動。

默認情況下,SampleOidEntity 沒有除了 ID 和時間戳之外的任何字段。 讓我們向實體添加一個名為 name 的字段:

public class SampleOidEntity extends AbstractMongodbEntity implements Linkable {
    private String name;

    // constructors, getters and setters 
}

6.1. 測試 API

讓我們通過運行 curl 命令來創建一個新的實體:

$ curl -X POST -H "Content-Type: application/json" -d "{\"name\":\"test\"}" http://localhost:8081/samples/oid.json

這應該返回具有 ID 的新創建的實體:

{
  "_links": {
    "self": {
      "href": "http://localhost:8081/samples/oid/63a5d983ef1e572664c148fd"
    },
    "up": {
      "href": "http://localhost:8081/samples/oid"
    }
  },
  "name": "test",
  "id": "63a5d983ef1e572664c148fd",
  "createdAt": "2022-12-23T16:38:27.733Z",
  "updatedAt": "2022-12-23T16:38:27.733Z"
}

接下來,讓我們使用上面返回的 id 通過 curl 命令讀取創建的實體:

$ curl -X GET http://localhost:8081/samples/oid/63a5d983ef1e572664c148fd.json

這應該返回之前相同的實體。

7. 結論

在本文中,我們探討了如何使用 RestExpress 創建 REST API。

我們使用 RestExpress mongodb 模式創建了一個項目。然後,我們查看了項目結構和生成的類。最後,我們運行了應用程序並執行了一些操作以測試 API。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.