1. Introduction
1.导言
One of the most important capabilities of backend HTTP API development is the ability to resolve request query parameters passed by the frontend.
后端 HTTP API 开发最重要的功能之一是解析前端传递的请求查询参数。
In this tutorial, we’ll introduce several ways to get the query parameters from HttpServletRequest directly, and some concise ways provided by Spring MVC.
在本教程中,我们将介绍直接从 HttpServletRequest 获取查询参数的几种方法,以及 Spring MVC 提供的一些简洁方法。
2. Methods in HttpServletRequest
2.HttpServletRequest 中的方法
First, let’s see the parameter-related methods provided by HttpServletRequest.
首先,让我们来看看 HttpServletRequest 提供的与参数相关的方法。
2.1. HttpServletRequest#getQueryString()
2.1 HttpServletRequest#getQueryString()
This example shows what we can get from the URL directly by invoking the method HttpServletRequest#getQueryString():
本例展示了通过调用方法 HttpServletRequest#getQueryString() 直接从 URL 获取的信息:
@GetMapping("/api/byGetQueryString")
public String byGetQueryString(HttpServletRequest request) {
return request.getQueryString();
}
When we send a GET request using curl with several parameters to this API, the method getQueryString() just returns all the characters after ‘?’:
当我们使用 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
Note that if we change @GetMapping to @RequestMapping, it will return the same response when we send the request by POST/PUT/PATCH/DELETE HTTP method. This means HttpServletRequest will always obtain the query string no matter what the HTTP method is. So, we can just focus on the GET request in this tutorial. To simplify our demonstration of the methods provided by HttpServletRequest, we’ll also use the same request parameters in each of the following examples.
请注意,如果我们将 @GetMapping 更改为 @RequestMapping,那么当我们使用 POST/PUT/PATCH/DELETE HTTP 方法发送请求时,它将返回相同的响应。这意味着,无论使用何种 HTTP 方法,HttpServletRequest 都将始终获得查询字符串。因此,在本教程中我们可以只关注 GET 请求。为了简化对 HttpServletRequest 所提供方法的演示,我们还将在以下示例中使用相同的请求参数。
2.2. HttpServletRequest#getParameter(String)
2.2 HttpServletRequest#getParameter(字符串)</em
To simplify parameter resolution, the HttpServletRequest provides a method getParameter to get the value by parameter name:
为了简化参数的解析,HttpServletRequest 提供了一个方法 getParameter 来根据参数名称获取值:
@GetMapping("/api/byGetParameter")
public String byGetParameter(HttpServletRequest request) {
String username = request.getParameter("username");
return "username:" + username;
}
When we send a GET request with a query string of username=bob, the call getParameter(“username”) returns bob.
当我们发送一个查询字符串为 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)
2.3. HttpServletRequest#getParameterValues(String)
The method getParameterValues acts similar to the getParameter method, but it returns a String[] instead of a String. This is due to the HTTP specification allowing to pass multiple parameters with the same name.
方法 getParameterValues 的作用与 getParameter 方法类似,但它返回的是 String[] 而不是 String。这是因为 HTTP 规范允许传递多个同名参数。
@GetMapping("/api/byGetParameterValues")
public String byGetParameterValues(HttpServletRequest request) {
String[] roles = request.getParameterValues("roles");
return "roles:" + Arrays.toString(roles);
}
So when we pass the value with parameter roles twice, we should get two values in the array:
因此,当我们将参数 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()
2.4 HttpServletRequest#getParameterMap()
Let’s say we have the following UserDto POJO as part of the following JSON API examples:
假设我们有以下 UserDto POJO 作为以下 JSON API 示例的一部分:
public class UserDto {
private String username;
private List<String> roles;
// standard getter/setters...
}
As we can see, it is possible to have several different parameter names with one or more values. For these cases, HttpServletRequest provides another method, getParameterMap(), which returns a Map<String, String[]>. This method allows us to get the parameter values using a Map.
正如我们所看到的,有可能有几个不同的参数名称,并带有一个或多个值。针对这些情况,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;
}
We’ll get a JSON response for this example:
在这个示例中,我们将得到一个 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. Get Parameters with Spring MVC
3.使用 Spring MVC 获取参数
Let’s see how Spring MVC improves the coding experience when resolving the query string.
让我们看看 Spring MVC 如何改善解析查询字符串时的编码体验。
3.1. Parameter Name
3.1 参数名称
With the Spring MVC framework, we do not have to manually resolve the parameters ourselves using the HttpServletRequest directly. For the first case, we define a method with two parameters with the query parameter names username and roles and remove the usage of HttpServletRequest, which is handled by Spring MVC.
有了 Spring MVC 框架,我们就不必直接使用 HttpServletRequest 手动解析参数了。对于第一种情况,我们定义了一个包含两个参数的方法,这两个参数的查询参数名称分别为 username 和 roles ,并删除了 HttpServletRequest 的使用,该参数由 Spring MVC 处理。
@GetMapping("/api/byParameterName")
public UserDto byParameterName(String username, String[] roles) {
UserDto userDto = new UserDto();
userDto.setUsername(username);
userDto.setRoles(Arrays.asList(roles));
return userDto;
}
This will return the same result as the last example since we use the same model:
由于我们使用了相同的模型,因此返回的结果将与上一个示例相同:
$ 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
3.2 @RequestParam
If the HTTP query parameter name and Java method parameter name are different, or if the method parameter names won’t be retained in the compiled bytecode, we can configure annotation @RequestParam on the method parameter name for this situation.
如果 HTTP 查询参数名和 Java 方法参数名不同,或者编译字节码中不会保留方法参数名,我们可以在方法参数名上配置注解 @RequestParam 以应对这种情况。
In our case, we use @RequestParam(“username”) and @RequestParam(“roles”) as follows:
在我们的例子中,我们使用 @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;
}
and test it:
并进行测试:
$ 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
3.3.POJO
More simply, we can use a POJO as the parameter type directly:
更简单地说,我们可以直接使用 POJO 作为参数类型:
@GetMapping("/api/byPojo")
public UserDto byPojo(UserDto userDto) {
return userDto;
}
Spring MVC can resolve the parameters, create the POJO instance, and fill it with the required parameters automatically.
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"]}
Finally, we check with a unit test to make sure that the last four methods provide exactly the same features.
最后,我们通过单元测试来确保最后四个方法提供的功能完全相同。
@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. Conclusion
4.结论
In this article, we have introduced how to get the parameters from a HttpServletRequest using Spring MVC. From these examples, we can see that a lot of code can be reduced when using Spring MVC to parse parameters.
在本文中,我们介绍了如何使用 Spring MVC 从 HttpServletRequest 中获取参数。从这些示例中我们可以看出,使用 Spring MVC 解析参数可以减少大量代码。
As usual, all code snippets presented in this article are available over on GitHub.
与往常一样,本文中介绍的所有代码片段均可在 GitHub 上获取。