RESTful API - Spring Boot 168 EP 5-1

RESTful API – Spring Boot 168 EP 5-1

RESTful 是種風格設計,並非是一種強制規範的標準,使用 HTTP 協定,可以支援各個平台像是: Web 、 Android 、 iOS 等,界面與資料採分離設計,加上 Cache 來達到更快的回應速度,節省伺服器的計算資源, EP 5-1 增加了範例 ,RESTful Web Services 透過 Postman 來驗證產出結果。

功能簡介

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 使用以下方式進行資源操作:

  1. POST 用於新增帳號資料。
  2. GET 用於取得帳號資料。
  3. PUT 用於更新帳號資料。
  4. 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 Web 執行主程式
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: 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

Spring Boot 168 EP 5-1 RESTful API POST account

GET

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

Spring Boot 168 EP 5-1 RESTful API GET account

GET

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

Spring Boot 168 EP 5-1 RESTful API GET accounts

PUT

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

Spring Boot 168 EP 5-1 RESTful API PUT account

DELETE

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

Spring Boot 168 EP 5-1 RESTful API DELETE account

心得分享

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

發佈留言