搭建一個(gè) Spring Boot 應(yīng)用
這不是一個(gè)玩具,用以下方法建的 Spring Boot 應(yīng)用是可以直接在工業(yè)應(yīng)用中的使用的谱净。我們需要以下三個(gè)文件擅威,在 Spring Boot getting started 找就可以了郊丛。
- pom.xml
- src/main/java/com/example/springboot/Application.java
- src/main/java/com/example/springboot/HelloController.java
獲取 HTTP 請求
- 從HTTP請求中提取 query string
查詢參數(shù)一般有如下格式: interface?param1=value1¶m2=value2。
使用@RequestParam
進(jìn)行接受导盅。@RequestParam
注解 require 參數(shù)默認(rèn)為true揍瑟,表示這個(gè)查詢參數(shù)一定要存在绢片,我們可以設(shè)置為 false恩急,這個(gè)查詢參數(shù)就可以不存在纪蜒。
@RestController
public class HelloController {
@RequestMapping("/search")
public String search(@RequestParam("q") String param,
@RequestParam(value = "charset", required = false) String charset) {
return "you are searching" + param + charset;
}
}
- 獲取路徑信息
@RequestMapping
可以放在METHOD
或者TYPE
上面此叠,放在TYPE
上灭袁,一般表示以此為根目錄。
我們使用@PathVariable
來匹配路徑倦炒。
@DeleteMapping("...")
可以替換成@RequestMapping(value = "...", method = RequestMethod.DELETE)
软瞎。
此時(shí)我們用 postman 模擬 DELTE 操作涤浇,訪問接口 localhost:8080/repos/golang/lazyben/123。
@RestController
@RequestMapping("repos")
public class IssueController {
@DeleteMapping("/{owner}/{repo}/{issueNumber}")
public void unlock(@PathVariable("owner") String owner,
@PathVariable("repo") String repo,
@PathVariable("issueNumber") String issueNumber) {
System.out.println(owner);
System.out.println(repo);
System.out.println(issueNumber);
}
}
- 從 POST 的負(fù)載中獲取數(shù)據(jù)
使用@RequestBody
獲取負(fù)載的內(nèi)容著恩。我們接受的類只要符合 JavaBean 約定就可以了喉誊,Spring 會自動將拿到的 client 傳來的數(shù)據(jù)并生成我們需要類的實(shí)例纵顾。
@RestController
@RequestMapping("repos")
public class IssueController {
@PostMapping("/{owner}/{repo}/issues")
public void create(@PathVariable("owner") String owner,
@PathVariable("repo") String repo,
@RequestBody User obj) {
System.out.println(obj);
}
}
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
我們用 postman 模擬 POST 請求片挂,發(fā)送了一段 JSON 信息。
{
"name": "lazyben",
"age": 23
}
得到了錯(cuò)誤415沪饺,如下所示整葡。這里犯了一個(gè)小錯(cuò)誤讥脐,也是很容易出錯(cuò)的地方啼器。這是由于 client 在向 server 發(fā)的 request 中的 header 沒有指明 Media Type端壳。解決辦法很簡單枪蘑,只需要聲明 Content-Type:application/json 即可岳颇。
{
"timestamp": "2021-01-05T10:31:29.406+00:00",
"status": 415,
"error": "Unsupported Media Type",
"message": "",
"path": "/repos/golang/lazyben/issues"
}
對于比較少的數(shù)據(jù),我們可以直接用表單來傳栗精,此時(shí) Content-Type:application/x-wwwform-urlencoded 瞻鹏,并使用 @RequestParam
新博。Spring 只需要提取 body 中的參數(shù)即可,下面是一個(gè)例子:
@RestController
@RequestMapping("repos")
public class IssueController {
@PostMapping("/login")
public void login(@RequestParam("username") String username,
@RequestParam("password") String password) {
System.out.println(username);
System.out.println(password);
}
}
最后我們對從POST請求中獲取參數(shù)做一個(gè)總結(jié)寥殖。
場景 | Content-Type | 使?注解 | 適?于 |
---|---|---|---|
提取整個(gè)body中的對象 | application/json | @RequestBody | JSON |
提取body中的參數(shù) | application/x-wwwform-urlencoded | @RequestParam | 表單 |
生成 HTTP 響應(yīng)
- 直接操作 HttpServletRespnse 對象
一個(gè) WebApp 監(jiān)聽80端口嚼贡,從這個(gè)端口進(jìn)來的 HTTP 請求粤策,是怎么變成 Java 對象的呢误窖?在 WebApp 更底層的地方,還存在著 Servlet 容器柔吼。Servlet 容器是 Java 世界處理 Web 應(yīng)用的標(biāo)準(zhǔn)丙唧,它可以從機(jī)器的端口上面讀取字節(jié)流,把它封裝成 Java 對象方便上層進(jìn)行處理溪厘。上層處理完之后牌柄,把結(jié)果丟給 Servlet 容器珊佣,Servlet 容器又可以將其變成字節(jié)流,返回給端口。因此 Servlet 容器扮演的是從字節(jié)流到 Java 對象轉(zhuǎn)換的中間層僻爽。它的核心接口就是HttpServletRequest
和HttpServletResponse
胸梆。如下代碼所示,為什么我們可以直接寫在參數(shù)里呢兢卵?因?yàn)镾ervlet 容器已經(jīng)幫我們封裝好了 Java 對象秽荤。
@RestController
public class HelloController {
@RequestMapping("/")
public String index(HttpServletRequest request, HttpServletResponse response) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return "Greetings from Spring Boot!";
}
}
可以看見的是柠横,我們成功顯示了 Greetings from Spring Boot! 牍氛,但也拿到了 error 400。
我們來看一下
HttpServletRequest
和 HttpServletResponse
這兩個(gè)對象到底是什么紊扬。他們兩個(gè)代表了當(dāng)前正在進(jìn)行的 HTTP 請求和 HTTP 響應(yīng)餐屎。打上斷點(diǎn)玩祟,來看一看里面有些什么。request 中有 header
庆聘,cookies
等伙判。我們可以用 response.getWriter.write("...")
直接寫一些東西回去±漳В總的來說這個(gè)方式比較偏向底層冠绢、原始常潮、簡單喊式、粗暴。- 直接返回HTML字符串
@RestController
public class HelloController {
@RequestMapping("/")
public String index() {
return "<h1>hello word!</h1>";
}
}
- 返回對象,并自動格式化成JSON
這是一個(gè)比較常用的方式献联。對應(yīng)的我們要寫上@ResponseBody
@RestController
public class HelloController {
@RequestMapping("/")
@ResponseBody
public Object index() {
Map<String, Object> result = new HashMap<>();
result.put("result", Arrays.asList("aaa", "bbb", "ccc"));
return result;
}
}
下面是我們得到的結(jié)果里逆,可以發(fā)現(xiàn)它被自動格式化為了JSON格式。
{"result":["aaa","bbb","ccc"]}
- 模版引擎渲染
常用的模版引擎有JSP/Velocity/Freemaker龄减。
RESTful API
- 使?HTTP動詞來代表動作
- GET:獲取資源
- POST:新建資源
- PUT:更新資源
- DELTE:刪除資源
- 使?URL(名詞)來代表資源
- 資源??沒有動詞
- 使?復(fù)數(shù)來代表資源列表
github api 設(shè)計(jì)是業(yè)界的標(biāo)桿