2020-08-01
JAVASPRING

Spring 打造一個 RESTful Web Service

就是 Spring 官方網站 guides 導讀。

og-spring

既然學習 Spring 那就要去一下 Spring 的官方網站看一下人家的教程。 這篇就是其中的一篇 Building a RESTful Web Service


我們這次將建立一個在 http://localhost:8080/greeting 接受 HTTP Get 方法的服務,接到請求後會回傳一個 JSON 格式的歡迎訊息。

{
  "id": 1,
  "content": "Hello, World!"
}

我們也可以選擇是否要在網址內傳入 name 參數,像是這樣。

http://localhost:8080/greeting?name=User

若是有收到 name 參數,便會覆蓋掉預設值 World 字串。

{
  "id": 1,
  "content": "Hello, User!"
}

我們可以從頭開始一步一步地慢慢完成專案,或者我們可以跳過一些我們已經相當熟悉了的設定,不管是哪種方法,我們都是可以完成專案的。

使用 Spring CLI 初始化專案

ok!到這邊我們開始就跟 Spring.io 他們的官方教程有一點點不一樣了,官方教程是用一個叫做 Spring Initializr 的工具來初始化專案,但我們這邊用 Spring CLI 來建立專案! ( 別誤會呀!Spring Initializr 是很好用的工具 我的入門工具也是它。 但是我現在喜歡用 Spring CLI 而已,事實上 Spring CLI 也是打要求過去 https://start.spring.io 的 )

我們建立專案只要簡單這行:

# 相依性只要簡單地 web 就好了!
$ spring init -d web my-app.zip

解壓縮 zip 檔案之後我們的專案就建立起來了。

先來看看我們的專案設定檔。

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!-- ... 略過 ... -->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

          <!-- ... 略過 ... -->
    </dependencies>
    <!-- ... 略過 ... -->
</project>

這邊只要看到這個相依性就好了,我們只有一個額外的相依性, 就是剛剛使用 Spring CLI 的 -d 參數加入的 web 所加入相依性。


建立資源表示類別 ( Resource Representation Class )

這個翻譯的比較蹩腳,簡單說就是我們剛才不是說要建立這樣的回傳格式。

{
  "id": 1,
  "content": "Hello, World!"
}

那在 Java 裡面就要建立一個有這兩個成員的類別出來。

package com.example.myapp;

public class Greeting {
    private final long id;
    private final String content;

    public Greeting(long id, String content) {
        this.id = id;
        this.content = content;
    }

    public long getId() {
        return id;
    }

    public String getContent() {
        return content;
    }
}

這是一個非常乾淨的 POJO 類別,就是兩個唯獨的成員 id, content 而已。

Spring 預設是以 Jackson JSON 來解析類別為 JSON 字串, 以本例來說就會用 Jackson 將 Greeting 物件轉為 JSON 字串,所以我們不用特別做序列化的動作。

建立 Greeting 頁面控制器 ( Controller )

控制器雖然是滿常見的翻譯,但我自己還是覺得挺蹩腳的,還是講 Controller。

package com.example.myapp.web;

import com.example.myapp.Greeting;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

@RestController
public class GreetingController {
    private static final String template = "Hello, %s";
    private final AtomicLong counter = new AtomicLong();

    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }
}

重點有以下幾個:

  • @RestController - 就是 @Controller 加 @ResponseBody
  • @Controller - 會告訴 Spring 自己這個類別是一個控制器,當 Spring 知道他是控制器之後,便會把收到的要求轉發到這個控制器
  • @ResponseBody - 顧名思義 表示會將回傳的內容直接透過 HTTP 打回去。若是只有 @Controller 通常會將回傳值解析為跳轉路徑,不直接回傳。
  • @GetMapping - 就是處理 HTTP Get 方法 @GetMapping("/greeting") 就是處理使用 HTTP Get 方法 對 /greeting 的請求

這樣就設定完了。可以直接把專案跑起來了,執行 DemoApplication 的 main() 方法。

再來訪問 http://localhost:8080/greeting http://localhost:8080/greeting?name=User 就可以看到不同的結果了。