RESTful 是種風格設計,並非是一種強制規範的標準,使用 HTTP 協定,可以支援各個平台像是: Web 、 Android 、 iOS 等,界面與資料採分離設計,加上 Cache 來達到更快的回應速度,節省伺服器的計算資源, EP 5-1 增加了範例 ,RESTful Web Services 透過 Postman 來驗證產出結果。
Table of Contents
Toggle功能簡介
RESTful 充分地使用了 HTTP 協議 ,採用 GET 、POST 、 PUT 、 DELETE 等方式,讓資源 URI 更加簡潔直觀地呈現,善用 HTTP 動詞,來對資源進行操作,並且回應 Web 所接受的資料類型: JSON 、 XML 、 YAML 等,最常見的是 JSON。
RESTful API
檔案目錄
./
+- build.gradle
+- src
+- main
+- java
+- org
+- ruoxue
+- spring_boot_168
+- sso
+- account
+- api
+- AccountAPI.java
+- model
+- Account.java
組態設定
API Design 提供 POST 、 GET 、 UPDATE 、 DELETE等操作 API 並傳回 JSON 格式。
網址:http://localhost:10000
Function | Method | Path | Content-Type | Params | Description |
新增帳號資料 | POST | /api/sso/account | application/json;charset=UTF-8 | cid | 帳號 |
password | 密碼 | ||||
Reponse | {"cid":"ruoxue","name":"player"} | ||||
取得帳號資料 | GET | /api/sso/account/cid/{cid} | application/x-www-form-urlencoded | ||
Reponse | {"cid":"ruoxue","name":"player"} | ||||
取得所有帳號資料 | GET | /api/sso/accounts | application/x-www-form-urlencoded | page | 頁碼 |
size | 筆數 | ||||
Reponse | [{"cid":"ruoxue","name":"player"},{"cid":"ruoxue2","name":"player2"}] | ||||
修改帳號資料 | UPDATE | /api/sso/account/cid/{cid} | application/x-www-form-urlencoded | name | 名稱 |
Reponse | {"cid":"ruoxue","name":"player"} | ||||
刪除帳號資料 | DELETE | /api/sso/account/cid/{cid} | application/x-www-form-urlencoded | ||
Reponse | {"cid":"ruoxue","name":"player"} |
Web 如何建立,參考此篇:
實作
Account.java
RESTful API Tutorial 新增檔案,建立 model ,做為儲存資料庫的 Entity 及 HTTP 回應 JSON 格式。
package org.ruoxue.spring_boot_168.sso.account.model;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class Account {
/** 帳號 */
private String cid;
/** 名稱 */
private String name;
/** 密码 */
private String password;
/** 密码鹽 */
private String salt;
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.JSON_STYLE);
builder.appendSuper(super.toString());
builder.append("cid", cid);
builder.append("name", name);
builder.append("password", password);
return builder.toString();
}
}
AccountAPI.java
RESTful API Tutorial 使用以下方式進行資源操作:
- POST 用於新增帳號資料。
- GET 用於取得帳號資料。
- PUT 用於更新帳號資料。
- DELETE 用於刪除帳號資料。
RESTful Wweb Services 原則上是名詞定義,相關的操作都使用 HTTP protocol 的方式來運作,盡可能地遵循此方式,會讓開發與測試更容易維護與除錯。
package org.ruoxue.spring_boot_168.sso.account.api;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.ruoxue.spring_boot_168.sso.account.ex.AccountException;
import org.ruoxue.spring_boot_168.sso.account.model.Account;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.WebRequest;
import lombok.extern.slf4j.Slf4j;
@RestController
@Slf4j
public class AccountAPI {
public AccountAPI() {
}
/**
* 新增帳號資料
*
* @param webRequest
* @param locale
* @param jsonParam
* @return
*/
@PostMapping(value = { "/api/sso/account" })
public ResponseEntity<Account> insert(WebRequest webRequest, Locale locale, @RequestBody String jsonParam) {
ResponseEntity<Account> result = null;
try {
Account account = new Account();
account.setCid("ruoxue");
account.setName("player");
account.setPassword("1111");
result = ResponseEntity.ok().body(account);
} catch (AccountException ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
}
return result;
}
/**
* 取得帳號資料
*
* @param webRequest
* @param locale
* @param cid
* @return
*/
@GetMapping(value = { "/api/sso/account/cid/{cid}" })
public ResponseEntity<Account> findByCid(WebRequest webRequest, Locale locale, @PathVariable String cid) {
ResponseEntity<Account> result = null;
try {
Account account = new Account();
account.setCid("ruoxue");
account.setName("player");
result = ResponseEntity.ok().body(account);
} catch (AccountException ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
}
return result;
}
/**
* 取得所有帳號資料
*
* @param webRequest
* @param locale
* @param cid
* @return
*/
@GetMapping(value = { "/api/sso/accounts" })
public ResponseEntity<List<Account>> findAll(WebRequest webRequest, Locale locale, @RequestParam int page,
@RequestParam int size) {
ResponseEntity<List<Account>> result = null;
try {
List<Account> list = new ArrayList<Account>();
Account account = new Account();
account.setCid("ruoxue");
account.setName("player");
list.add(account);
account = new Account();
account.setCid("ruoxue2");
account.setName("player2");
list.add(account);
result = ResponseEntity.ok().body(list);
} catch (AccountException ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
}
return result;
}
/**
* 修改帳號資料
*
* @param webRequest
* @param locale
* @param name
* @return
*/
@PutMapping(value = { "/api/sso/account/cid/{cid}" })
public ResponseEntity<Account> update(WebRequest webRequest, Locale locale, @RequestParam String name, @PathVariable String cid) {
ResponseEntity<Account> result = null;
try {
Account account = new Account();
account.setCid(cid);
account.setName(name);
result = ResponseEntity.ok().body(account);
} catch (AccountException ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
}
return result;
}
/**
* 刪除帳號資料
*
* @param webRequest
* @param locale
* @return
*/
@DeleteMapping(value = { "/api/sso/account/cid/{cid}" })
public ResponseEntity<Account> delete(WebRequest webRequest, Locale locale, @PathVariable String cid) {
ResponseEntity<Account> result = null;
try {
Account account = new Account();
account.setCid(cid);
account.setName("player");
result = ResponseEntity.ok().body(account);
} catch (AccountException ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
result = ResponseEntity.notFound().build();
}
return result;
}
}
Application.main
在主程式點右鍵執行 Run As -> Java Application,查看 console,Server 已成功啟動,監聽 10000 port。

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.7.RELEASE)
2022-04-15 15:55:41.932 INFO 10992 --- [ main] org.ruoxue.spring_boot_168.Application : Starting Application on cheng-pc with PID 10992 (D:\dev\gitlab\ruoxue\spring-boot-168\bin\main started by cheng in D:\dev\gitlab\ruoxue\spring-boot-168)
2022-04-15 15:55:41.934 INFO 10992 --- [ main] org.ruoxue.spring_boot_168.Application : No active profile set, falling back to default profiles: default
[GC (Metadata GC Threshold) 125345K->16356K(1005056K), 0.0094106 secs]
[Full GC (Metadata GC Threshold) 16356K->15540K(1005056K), 0.0171040 secs]
2022-04-15 15:55:42.691 INFO 10992 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 10000 (http)
2022-04-15 15:55:42.715 INFO 10992 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-04-15 15:55:42.715 INFO 10992 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.22]
2022-04-15 15:55:42.792 INFO 10992 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-04-15 15:55:42.793 INFO 10992 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 830 ms
2022-04-15 15:55:42.940 INFO 10992 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2022-04-15 15:55:43.074 INFO 10992 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 10000 (http) with context path ''
2022-04-15 15:55:43.077 INFO 10992 --- [ main] org.ruoxue.spring_boot_168.Application : Started Application in 1.384 seconds (JVM running for 1.674)
Postman
POST
網址:http://localhost:10000/api/sso/account

GET
網址:http://localhost:10000/api/sso/account

GET
網址:http://localhost:10000/api/sso/accounts

PUT
網址:http://localhost:10000/api/sso/account

DELETE
網址:http://localhost:10000/api/sso/account

心得分享
Designing Rest API 資訊系統若沒有特殊需求與規範時,建議依照此風格設計,規劃建置系統,尤其當需要公開 API 給多種不同平台使用時,資源定義與命名方式,API Design 採用此風格,都能夠達到簡潔重用功能。