現在前端工程當道,為了實現前後端技術分離,Web 應用程式可以提供中性的資料格式,與前端進行溝通,其中最受歡迎的格式之一就是 JSON。
Spring MVC 可以自動剖析物件傳回 JSON,為此,你需要有個轉換器,對 Spring MVC 來說,只需要在類別路徑中找得到轉換器的類別就可以了,你可以在 build.gradle 中加入:
compile 'com.fasterxml.jackson.core:jackson-databind:2.9.7'
直接來看看簡單的範例,就可以知道怎麼回應 JSON:
package cc.openhome.controller;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cc.openhome.model.Account;
@Controller
@RequestMapping("api")
public class Api {
@GetMapping("test")
@ResponseBody
public Map<String, Object> test() {
Map<String, Object> data = new HashMap<>();
data.put("a", "10");
data.put("b", 20);
data.put("c", new String[] {"foo", "orz"});
data.put("d", new Date());
return data;
}
@GetMapping("test2")
@ResponseBody
public Account test2() {
return new Account("1", "2", "3", "4");
}
@PostMapping("test3")
@ResponseBody
public Account test3(@RequestBody Account account) {
return new Account(
account.getName().toUpperCase(),
account.getEmail().toUpperCase(),
account.getPassword(),
account.getSalt()
);
}
}
若請求 /api/test,會自動加上 Content-Type: application/json;charset=UTF-8
回應標頭,而傳回的 JSON 會是:
{"a":"10","b":20,"c":["foo","orz"],"d":1543820089201}
若請求 /api/test2,傳回的 JSON 會是:
{"name":"1","email":"2","password":"3","salt":"4"}
如果要能接收 JSON,並轉換為指定的型態的話,該型態必須有無參建構式,而要設定的屬性必須有對應的 Setter,然後,只要在處理器參數上標示 @RequestBody
就可以了。
例如,可以將底下的片段,置於某個 HTML 之中,使用瀏覽器請求網站上的 HTML,就可以看到轉換為大寫後傳回的資料:
<div id="console"></div>
<script>
fetch('api/test3', {
method : 'POST',
headers : {
'Content-Type' : 'application/json;charset=UTF-8'
},
body : JSON.stringify({
name : 'caterpillar',
email : 'caterpillar@openhome.cc',
password : '12345678',
salt : '123352453253'
})
})
.then(resp => resp.json())
.then(acct => document.getElementById('console').innerHTML = `${acct.name}, ${acct.email}`);
</script>
如果實際上,控制器中的處理器都會標註 @ResponseBody
,那麼可以改在控制器上標註 @RestController
,省去個別標註 @ResponseBody
的麻煩,例如:
package cc.openhome.controller;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import cc.openhome.model.Account;
@RestController
@RequestMapping("api")
public class Api {
@GetMapping("test")
public Map<String, Object> test() {
Map<String, Object> data = new HashMap<>();
data.put("a", "10");
data.put("b", 20);
data.put("c", new String[] {"foo", "orz"});
data.put("d", new Date());
return data;
}
@GetMapping("test2")
public Account test2() {
return new Account("1", "2", "3", "4");
}
@PostMapping("test3")
public Account test3(@RequestBody Account account) {
return new Account(
account.getName().toUpperCase(),
account.getEmail().toUpperCase(),
account.getPassword(),
account.getSalt()
);
}
}