【项目地址】 从零开始学习springmvc
二、请求参数的绑定
2.1 准备工作
本节我们会用到HttpServletRequest、HttpServletResponse等关于servlet请求的类,需要引入servlet-api包依赖,这里有必要说明一点的是,java EE规范在2018年更名为Jakarta EE,相应的我们之前使用的包名由javax.xx
更名为jakarta.xx
。为了适应新标准,我们更新了spring最新版本5.3.13,并引入jakarta.servlet-api
。
<properties>
<spring.version>5.3.13</spring.version>
<thymeleaf.version>3.0.12.RELEASE</thymeleaf.version>
<servlet-api.version>4.0.4</servlet-api.version>
<annotation-api.version>1.3.5</annotation-api.version>
</properties>
<dependencies>
<!--servlet api-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<!-- Spring依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<!--annotation-->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>${annotation-api.version}</version>
</dependency>
</dependencies>
-
可能遇到的问题
-
@Resource注解无法import,或者注入为空
添加
annotation-api
的依赖,并确认版本号 -
无法启动Tomcat org.apache.catalina.LifecycleException: 子容器启动失败
解决方法:确认是不是部署的war包存在多个不同版本的spring-web组件,并清理冗余jar包。
https://blog.csdn.net/AIMINdeCSDN/article/details/103590010
-
2.2 参数绑定三种方法
2.2.1 通过servlet-api获取参数
我们可以在controller的方法上加参数HttpServletRequest
和HttpServletResponse
,然后通过getParameter()
方法获取请求参数,示例代码如下:
- Controller层
创建一个GET请求/user
,并有一个QueryParam参数为id,请求为
GET /user?id=00112233
@Controller
public class UserController {
@Resource
private UserService userService;
@RequestMapping(value = "/user")
@ResponseBody
public String getUser(HttpServletRequest request, HttpServletResponse response) {
String id = request.getParameter("id");
return userService.getUserName(id);
}
}
- Service层
这里我们用hashmap模拟dao层查询数据库操作,查询id为00112233的user为"zhangsan"
@Service
public class UserService {
private final Map<String, String> userMap = new HashMap<String, String>(){{
put("00112233", "Zhang San");
put("00112234", "Yan Si");
}};
public String getUserName(String userId) {
return userMap.get(userId);
}
}
我们利用postman测试接口,可以看到
我们简单介绍一下常用的方法
// 1.获取QueryParam参数
// 指定参数名的参数值,如果不存在则返回null
request.getParameter(String paramter);
// 获取所有的参数,如果有多个参数用&连接,形如id=00112233&name=zhangsan
request.getQueryString();
// 2.获取url路径参数
// 获取与Servlet中的“url-pattern”中完全匹配的部分
request.getServletPath()
2.2.2 通过注解获取(推荐)
由于springmvc的使用,一般获取参数是通过注解获取,常用的注解如下:
- @PathVariable 获取路径参数
- value:绑定URL路径参数的名称
- name:同value
- requried:是否必选参数,默认为true,必选。
- @RequestParam 获取QueryParam参数
- value:绑定请求中的参数名称
- name:同value
- requried:是否必选参数,默认为true,必选。
- defaultValue:参数如果未传时的默认值。
- @RequestBody 获取body请求体参数,可以将传入的参数序列化为一个对象
下面通过修改上面的示例User示例来演示一下:
增加pojo对象User
@Getter
@Setter
@ToString
public class User {
private String id;
private String name;
}
Controller层三个请求
- 查询一个用户:GET /user?id=00112233
- 添加多个用户:POST /users
- 删除一个用户:DELETE /user/{user_id}
@Controller
public class UserController {
@Resource
private UserService userService;
@RequestMapping(value = "/user")
@ResponseBody
public String getUser(@RequestParam(value = "id") String id) {
return userService.getUserName(id);
}
@RequestMapping(value = "/users")
@ResponseBody
public String getUser(@RequestBody List<User> users) {
System.out.println(users);
return "success";
}
@RequestMapping(value = "/user/{user_id}")
@ResponseBody
public String deleteUser(@PathVariable(value = "user_id") String userId) {
System.out.println(userId);
return "success";
}
}
由于我们使用了post请求,并且将参数序列化为List<User>
对象,计划使用json进行序列化和反序列化,所以这里引入json序列化依赖jackson
pom.xml中引入jackson依赖
<jackson.version>2.13.0</jackson.version>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
-
注意
如果请求发现响应码为415,则可能时未引入jackson所致,所以必须引入相关序列化依赖。
为了测试上述三个接口,分别构造请求为:
-
GET /user?id=00112233
-
POST /users
[ { "id": 11223344, "name": "Zhang San" }, { "id": 55667788, "name": "Li Si" } ]
-
DELETE /user/00112233
利用postman工具测试结果如下:
2.2.3 QueryParam同名参数绑定
SpringMvc提供了QueryParam同名参数绑定的机制,对于QueryParam参数,springmvc会自动寻找Controller方法上的同名参数或者实体类的同名属性进行绑定。简单示例如下:
我们修改之前的HelloController,增加两个接口如下:
- 查询指定用户名用户:GET /hello?userName=ZhangSan
- 查询指定user用户:GET /hello?id=00112233&name=ZhangSan
@Controller
public class HelloController {
@RequestMapping("/hello")
@ResponseBody
public String helloUser(String userName) {
return "Hi, " + userName;
}
@RequestMapping("/hello/user")
@ResponseBody
public String helloUser(User user) {
System.out.println("hello world");
return "Hi, " + user.getName();
}
}
上述示例中我们为对String userName
加@RequestParam
注解,经过测试结果如下:
第一个示例中,我们请求参数是userName=ZhangSan
,但是未加@RequestParam
注解,ZhangSan也能绑定到userName上;同样第二个示例请求的name值也能绑定到user.name上。下面再看两个示例可以看出同名绑定机制:
可以看到上述userName
和user.getName()
值都为null
,可以看出SpringMVC的同名参数绑定机制。而@RquestParam
和@PathVariable
的value
属性正是解决前后端参数不一致问题。前端的参数一般是带下划线的Kernel风格(user_name),后端一般是小驼峰风格(userName)。而且同名参数绑定机制不易于维护,所以一般推荐通过注解来进行参数绑定。