1. 概述
本教程將教您如何使用 RestExpress 構建 RESTful 微服務。
RestExpress 是一個開源 Java 框架,它使我們能夠快速、輕鬆地構建 RESTful 微服務。它基於 Netty 框架,旨在減少樣板代碼並加快 RESTful 微服務的開發。
此外,它還採用插件架構,允許我們向我們的微服務添加功能。它支持緩存、安全和持久性等常用功能的插件。
2. RestExpress 樣板
RestExpress 樣板 是一個輔助項目,它提供了一套 Maven 樣板,用於創建 RestExpress 項目。
在寫作時,有三種樣板可用:
- 最小化 (minimal) – 包含創建 RESTful 項目所需的最低代碼。 它包含主類、一個屬性文件和示例 API。
- MongoDB – 創建一個帶有 MongoDB 支持的 RESTful 項目。 此外,它還包含 最小化 (minimal) 樣板,幷包含一個 MongoDB 層。
- Cassandra – 類似於 MongoDB 樣板,將一個 Cassandra 層添加到 最小化 (minimal) 樣板中。
每個樣板都附帶一組插件,用於為我們的微服務添加功能:
- CacheControlPlugin – 添加對 Cache-Control 標頭的支持
- CORSPlugin – 添加對 CORS 的支持
- MetricsPlugin – 添加對 Metrics 的支持
- SwaggerPlugin – 添加對 Swagger 的支持
- HyperExpressPlugin – 添加對 HATEOAS 的支持
默認情況下,僅啓用 MetricsPlugin,並且它使用 Dropwizard Metrics。我們可以通過向其中一個實現添加依賴來啓用其他插件。我們還需要添加屬性來配置和啓用某些插件。
在下一部分中,我們將探討如何使用 MongoDB 樣板創建項目。我們將學習如何配置應用程序,然後我們將查看生成的代碼的某些方面。
2.1. 使用 Archetype 創建項目
讓我們使用 mongodb archetype 創建一個項目。
在終端中,請導航到您想要創建項目的目錄。我們將使用 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這會創建一個包含一些示例代碼和配置的項目。
原型自動為我們創建了一些組件。它使用默認配置創建了一個服務器。這些配置位於 environment.properties 文件中。
在 objectid 和 uuid 包中,有 兩個 CRUD API 集合。每個集合包含一個實體、一個控制器、一個服務和一個倉庫類。
Configuration, Server, Main, Routes 類有助於在服務器啓動時配置服務器。
我們將在下一部分中探討這些生成的類。
3. 生成代碼
讓我們來探索生成的代碼。我們將重點關注主類、API 方法和 DB 層。這將幫助我們瞭解如何使用 RestExpress 創建一個簡單的 CRUD 應用程序。
3.1. 主類
主類是我們的應用程序的入口點。它負責啓動服務器並配置應用程序。
讓我們看一下主類中的 <em >main()</em> 方法:
public static void main(String[] args) throws Exception {
Configuration config = Environment.load(args, Configuration.class);
Server server = new Server(config);
server.start().awaitShutdown();
}
讓我們詳細瞭解一下代碼:
- The Environment.load() 方法從 environment.properties 文件加載配置,並創建一個 Configuration 對象。
- Server 類負責啓動服務器。它需要一個 Configuration 對象來設置服務器。在下一部分,我們將查看 Configuration 和 Server 類。
- start() 方法啓動服務器,awaitShutdown() 方法等待服務器關閉。
3.2. 讀取屬性
<em>environment.properties</em> 文件包含應用程序的配置信息。要讀取這些屬性,<em>Configuration</em> 類會自動創建。
讓我們來看看 <em>Configuration</em> 類的不同部分。
<em>Configuration</em> 類繼承了 <em>Environment</em> 類。這使得我們能夠從環境中讀取屬性。它為了此目的覆蓋了 <em>Environment</em> 類的 <em>fillValues()</em> 方法:
@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. 初始化控制器和存儲庫
“initialize()”方法負責初始化控制器和存儲庫。
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 API
在上一節中,我們瞭解瞭如何使用 Configuration 類初始化控制器。現在,讓我們來看 SampleUuidEntityController 類,以瞭解如何創建 API 方法。
該控制器包含用於 create()、read()、readAll()、update() 和 delete() 方法的有效代碼。 每個方法內部都會調用相應服務類和倉庫類的對應方法。
接下來,讓我們查看一些方法,以瞭解它們的工作原理。
4.1. 創建
讓我們來看一下 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
- 將 location 頭部添加到響應中
- 返回新創建的實體
如果我們查看服務類,我們會發現它執行驗證並調用存儲類中的 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 類。 Server 類啓動應用程序。它定義了路由以及這些路由的控制器。它還使用指標和其他插件配置服務器。
5.1. 創建服務器
讓我們來看一下<em>Server</em>類的構造函數:
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 服務器。當我們在 Main 類中調用 start() 方法時,該服務器將被啓動。
- 它調用 Routes.define() 方法來定義路由。我們將在下一部分中查看 Routes 類。
- 它定義了實體之間的關係,根據提供的屬性配置插件,並將某些內部異常映射為應用程序已處理的異常。
5.2. 路由
<em Routes.define()</em> 方法定義了路由以及為每個路由調用的控制器方法。
以下是 <em SampleOidEntityController</em> 的路由:
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 中路徑參數。
GET、PUT 和 DELETE 方法分別映射到 read()、update() 和 delete() 方法,這是 Netty 服務器的默認行為。
為路由分配一個名稱,以便可以通過名稱檢索路由。 server.getRouteUrlsByName() 方法可以在需要時使用。
上述模式適用於 read()、update() 和 delete(),因為它們都需要一個 ID。 對於 create() 和 readAll(),我們需要使用不同的模式,該模式不需要 ID。
讓我們看一下第二個路由定義。 模式 /samples/oid.{format} 映射到 SampleOidEntityController。
action() 方法用於將方法名稱映射到 HTTP 方法。 在這種情況下,readAll() 方法映射到 GET 方法。
POST 方法允許在模式上,並默認映射到 create() 方法。 就像之前一樣,為路由分配一個名稱。
需要注意的是,如果我們在控制器中定義了更多方法或更改標準方法的名稱,則需要使用 action() 方法將它們映射到各自的 HTTP 方法。
任何需要定義的 URL 模式都必須添加到 Routes.define() 方法中。
6. 運行應用程序
讓我們運行應用程序並對實體執行一些操作。我們將使用 curl 命令來執行這些操作。
讓我們通過運行 Main 類啓動應用程序。應用程序將在端口 8081 上啓動。
默認情況下,<em>SampleOidEntity</em> 不包含任何字段,除了 ID 和時間戳。讓我們為實體添加一個名為 <em>name</em> 的字段:
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 -X GET http://localhost:8081/samples/oid/63a5d983ef1e572664c148fd.json這應該返回與之前相同的實體。
7. 結論
在本文中,我們探討了如何使用 RestExpress 創建 REST API 的方法。
我們使用 RestExpress 的 mongodb 模式創建了一個項目。然後,我們查看了項目結構和生成的類。最後,我們運行了應用程序並執行了一些操作以測試 API。