從 HttpServletRequest 取得查詢字串參數
一、簡介
後端HTTP API開發最重要的能力之一就是能夠解析前端傳遞過來的請求查詢參數。
在本教學中,我們將介紹幾種直接從HttpServletRequest
取得查詢參數的方法,以及 Spring MVC 提供的一些簡潔方法。
HttpServletRequest
中的方法
首先我們來看看HttpServletRequest.
2.1. HttpServletRequest#getQueryString()
這個範例展示了我們可以透過呼叫方法HttpServletRequest#getQueryString()
直接從 URL 取得什麼:
@GetMapping("/api/byGetQueryString")
public String byGetQueryString(HttpServletRequest request) {
return request.getQueryString();
}
當我們使用帶有多個參數的curl向此API發送GET請求時,方法getQueryString()
僅傳回「?」之後的所有字元:
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byGetQueryString?username=bob&roles=admin&roles=stuff'
username=bob&roles=admin&roles=stuff
請注意,如果我們將@GetMapping
更改為@RequestMapping
,那麼當我們透過 POST/PUT/PATCH/DELETE HTTP 方法發送請求時,它將傳回相同的回應。這意味著無論 HTTP 方法是什麼, HttpServletRequest
都會始終取得查詢字串。因此,我們在本教程中可以只專注於 GET 請求。為了簡化HttpServletRequest
提供的方法的演示,我們也會在以下每個範例中使用相同的請求參數。
2.2. HttpServletRequest#getParameter(String)
為了簡化參數解析, HttpServletRequest
提供了getParameter
方法來透過參數名稱取得值:
@GetMapping("/api/byGetParameter")
public String byGetParameter(HttpServletRequest request) {
String username = request.getParameter("username");
return "username:" + username;
}
當我們傳送帶有username=bob
查詢字串的 GET 請求時,呼叫getParameter(“username”)
回傳bob
。
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byGetParameter?username=bob&roles=admin&roles=stuff'
username:bob
2.3. HttpServletRequest#getParameterValues(String)
getParameterValues
方法的作用與getParameter
方法類似,但它傳回String[]
而不是String
。這是由於 HTTP 規範允許傳遞多個具有相同名稱的參數。
@GetMapping("/api/byGetParameterValues")
public String byGetParameterValues(HttpServletRequest request) {
String[] roles = request.getParameterValues("roles");
return "roles:" + Arrays.toString(roles);
}
因此,當我們兩次傳遞帶有參數roles
的值時,我們應該在陣列中得到兩個值:
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byGetParameterValues?username=bob&roles=admin&roles=stuff'
roles:[admin, stuff]
2.4. HttpServletRequest#getParameterMap()
假設我們有以下UserDto
POJO 作為以下 JSON API 範例的一部分:
public class UserDto {
private String username;
private List<String> roles;
// standard getter/setters...
}
正如我們所看到的,可以有多個不同的參數名稱和一個或多個值。對於這些情況, HttpServletRequest
提供了另一種方法getParameterMap(),
它傳回Map<String, String[]>
。此方法允許我們使用Map
獲取參數值。
@GetMapping("/api/byGetParameterMap")
public UserDto byGetParameterMap(HttpServletRequest request) {
Map parameterMap = request.getParameterMap();
String[] usernames = parameterMap.get("username");
String[] roles = parameterMap.get("roles");
UserDto userDto = new UserDto();
userDto.setUsername(usernames[0]);
userDto.setRoles(Arrays.asList(roles));
return userDto;
}
我們將獲得此範例的 JSON 回應:
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byGetParameterMap?username=bob&roles=admin&roles=stuff'
{"username":"bob","roles":["admin","stuff"]}
3.使用Spring MVC取得參數
讓我們看看 Spring MVC 如何改善解析查詢字串時的編碼體驗。
3.1.參數名稱
使用 Spring MVC 框架,我們不必直接使用HttpServletRequest
手動解析參數。對於第一種情況,我們定義一個具有兩個參數的方法,查詢參數名稱為username
和roles
HttpServletRequest,
的使用。
@GetMapping("/api/byParameterName")
public UserDto byParameterName(String username, String[] roles) {
UserDto userDto = new UserDto();
userDto.setUsername(username);
userDto.setRoles(Arrays.asList(roles));
return userDto;
}
由於我們使用相同的模型,這將返回與上一個範例相同的結果:
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byParameterName?username=bob&roles=admin&roles=stuff'
{"username":"bob","roles":["admin","stuff"]}
3.2. @RequestParam
如果HTTP查詢參數名和Java方法參數名稱不同,或者編譯後的字節碼中不會保留方法參數名,我們可以在方法參數名上配置註解@RequestParam
來應對這種情況。
在我們的範例中,我們使用@RequestParam(“username”)
和@RequestParam(“roles”)
如下所示:
@GetMapping("/api/byAnnoRequestParam")
public UserDto byAnnoRequestParam(@RequestParam("username") String var1, @RequestParam("roles") List<String> var2) {
UserDto userDto = new UserDto();
userDto.setUsername(var1);
userDto.setRoles(var2);
return userDto;
}
並測試它:
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byAnnoRequestParam?username=bob&roles=admin&roles=stuff'
{"username":"bob","roles":["admin","stuff"]}
3.3.波喬
更簡單的是,我們可以直接使用 POJO 作為參數類型:
@GetMapping("/api/byPojo")
public UserDto byPojo(UserDto userDto) {
return userDto;
}
Spring MVC 可以解析參數,建立 POJO 實例,並自動填入所需的參數。
$ curl 'http://127.0.0.1:8080/spring-mvc-basics/api/byPojo?username=bob&roles=admin&roles=stuff'
{"username":"bob","roles":["admin","stuff"]}
最後,我們透過單元測試進行檢查,以確保最後四種方法提供完全相同的功能。
@ParameterizedTest
@CsvSource(textBlock = """
/api/byGetParameterMap
/api/byParameterName
/api/byAnnoRequestParam
/api/byPojo
""")
public void whenPassParameters_thenReturnResolvedModel(String path) throws Exception {
this.mockMvc.perform(get(path + "?username=bob&roles=admin&roles=stuff"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("bob"))
.andExpect(jsonPath("$.roles").value(containsInRelativeOrder("admin", "stuff")));
}
4。結論
在本文中,我們介紹如何使用 Spring MVC 從HttpServletRequest
取得參數。從這些例子我們可以看到,使用Spring MVC解析參數時可以減少很多程式碼。
與往常一樣,本文中提供的所有程式碼片段都可以在 GitHub 上找到。