SpirngMVC获取请求参数
目录
1. 原生Servlet获取请求参数
2. 通过控制器方法的形参获取请求参数
3. @RequestParam
4. @ReuqestHeader
5. @CookieValue
6. 通过POJO获取请求参数
7. 解决获取请求参数的乱码问题
1. 原生Servlet获取请求参数
这里我们创建一个控制器,以及一个用于跳转成功的页面
@RequestMapping("/param")
public String param(){
return "test_param";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试请求参数</title>
</head>
<body>
<h1>测试请求参数</h1>
<a th:href="@{/testServletAPI(username='admin',password=123456)}">测试使用servletAPI获取请求参数</a><br>
</body>
</html>
@Controller
public class ParamController {
@RequestMapping("/testServletAPI")
// 形参位置的request表示当前请求
public String testServletAPI(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
}
一开始去访问http://localhost:8080/springMVC/param这个地址,然后跳转到test_param页面,点击里面的超链接,携带参数跳转到success页面,这是用ServletAPI做到的,但是我们在SpringMVC中基本是不用这种方式来实现。
注:
我们在使用SpringMVC的时候,能不用原生API就不用,因为我们当前操作的数据,SpringMVC就已经帮助我们获取过了,而且它还会给我们提供更简单的方式让我们获取,没有必要使用原生的ServletAPI
2. 通过控制器方法的形参获取请求参数
既然我们不适用原生ServletAPI进行获取参数,当然,SpringMVC也有自己获取请求参数的方式
前端代码还是这样:
<a th:href="@{/testParam(username='admin',password=123456)}">测试获取请求参数-->/testParam</a><br>
@RequestMapping("/testParam")
public String testParam(String username, String password){
System.out.println("username:"+username+",password:"+password);
return "success";
}
那么我们还有一种情况,当前传过来有多个同名的请求参数,这个时候又要如何处理?
<form th:action="@{/testParam}" method="get">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
爱好: <input type="checkbox" name="hobby" value="a">a
<input type="checkbox" name="hobby" value="b">b
<input type="checkbox" name="hobby" value="c">c <br>
<input type="submit" value="测试使用控制器的形参来获取请求参数">
</form>
@RequestMapping("/testParam")
public String testParam(String username,String password,String[] hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ Arrays.toString(hobby));
return "success";
}
这时候我们是用一个表单里面有爱好来测试多个同名的请求参数,这个是字符串数组形式的输出结果
现在我们来测试用字符串输出结果
@RequestMapping("/testParam")
public String testParam(String username,String password,String hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ hobby);
return "success";
}
3. @RequestParam
我们之前是在方法里面的设置形参,然后让形参跟前端的请求参数名进行匹配,最终获得参数,但是如果前端的参数值和形参名不匹配会发生什么?
这时候我们把username改成user_name
<form th:action="@{/testParam}" method="get">
用户名: <input type="text" name="user_name"><br>
密码: <input type="password" name="password"><br>
爱好: <input type="checkbox" name="hobby" value="a">a
<input type="checkbox" name="hobby" value="b">b
<input type="checkbox" name="hobby" value="c">c <br>
<input type="submit" value="测试使用控制器的形参来获取请求参数">
</form>
方法这边的形参名还是用username来接收
@RequestMapping("/testParam")
public String testParam(String username,String password,String hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ hobby);
return "success";
}
可以看到username并没有获取到,也就是说只要是请求参数名和形参名不一致,那就没办法获取值,那么此时就要用到一个注解——@RequestParam。
@RequestMapping("/testParam")
public String testParam(
@RequestParam("user_name") String username,
String password,
String hobby){
System.out.println("username:"+username+",password:"+password+",hobby:"+ hobby);
return "success";
}
这个注解的用处就是将请求参数和形参建立映射关系,那么这里就是将请求参数user_name和形参username对应,此时就可以获取到值了
4. @ReuqestHeader
这里要注意:@RequestParam、@ReuqestHeader、@CookieValue这三个注解所拥有的属性基本都是一模一样的,这三个注解都拥有value、required、defaultValue这三个属性,作用是一样的,只不过这三个属性所操作的内容不一样,比如说@RequestParam是将请求参数和形参进行建立映射关系,而@ReuqestHeader是将请求头信息与形参建立映射关系,@CookieValue是将Cookie与形参进行建立映射关系。
请求头信息也是键值对,所以这里可以通过@RequestHeader然后指定一个请求头的键,然后就可以将指定的请求头信息和形参进行绑定
@RequestMapping("/testParam")
public String testParam(
@RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
String password,
String hobby,
@RequestHeader("Host") String host
){
System.out.println("username:"+username+",password:"+password+",hobby:"+ hobby);
System.out.println("host:"+host);
return "success";
}
那么此时会把请求头信息打印出来。
当然,里面还有required和defaultValue属性,当required为false时,如果没有请求头信息,则不处理,赋null值,如果为true则进行报错。
defaultValue属性,当没有请求头信息时,自动设置为我们自己设置的默认值。
@RequestMapping("/testParam")
public String testParam(
@RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
String password,
String hobby,
@RequestHeader(value = "sayHaha",required = true,defaultValue = "Haha") String host
){
System.out.println("username:"+username+",password:"+password+",hobby:"+ hobby);
System.out.println("host:"+host);
return "success";
}
5. @CookieValue
当去调用getSession方法的时候,就会创建一个键JSESSIONID的cookie。
@RequestMapping("/testServletAPI")
// 形参位置的request表示当前请求
public String testServletAPI(HttpServletRequest request){
HttpSession session = request.getSession();
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username:"+username+",password:"+password);
return "success";
}
由于是会话技术,生命周期是浏览器开启到浏览器关闭,所以只要是浏览器不关闭,cookie将一直存在。
由于我们是第一次访问getSession方法,Cookie是存在于当前的响应报文中
第一次执行getSession方法的时候,会去检测请求报文中是否携带JSESSIONID的Cookie,如果没有就说明在这一次的会话中,是第一次创建Session对象,所以就会去创建一个Session对象,然后将Session放在服务器所维护的Map集合中,并且去创建一个Cookie,这个Cookie的键是固定的,是JSESSIONID,值则是一个随机序列,然后还会将这个HttpSession对象存储到当前的服务器所维护的Map集合中,以JSESSIONID的Cookie的值,也就是这个随机序列,作为Map集合的键,把Session对象作为Map的值进行存储,存储在服务器内部,这时候再把Cookie响应到浏览器。所以说第一次去访问浏览器getSession方法的时候,JSESSIONID是会存在于响应报文中,从此之后将存在于请求报文中,因为Cookie就是这个工作原理。
第一次JESSIONID存在于响应报文中
我们对页面进行刷新,这时候响应报文中已经没有了,存在于请求报文中。
此时的请求报文中也有携带Cookie
@RequestMapping("/testParam")
public String testParam(
@RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username,
String password,
String hobby,
@RequestHeader(value = "sayHaha",required = true,defaultValue = "Haha") String host,
@CookieValue("JSESSIONID") String JSESSIONID
){
System.out.println("username:"+username+",password:"+password+",hobby:"+ hobby);
System.out.println("host:"+host);
System.out.println("JSESSIONID:"+JSESSIONID);
return "success";
}
6. 通过POJO获取请求参数
有时候请求参数很多,比如说添加和修改功能等,将数据添加到数据库,那我们这些添加的数据就要对应数据库字段,而数据库同样对应实体类对象,所以说在页面中添加的数据,跟实体类对象属性也是一一对应。
这个时候SpringMVC又为我们提供了一种很简单的方式,也就是当表单里面的name跟实体类里面的属性对应,那么我们可以在形参位置去写实体类的形参,这个时候只要保证请求参数的名字,跟实体类中的属性名保持一致,就可以自动通过实体类对象收集这些请求参数。
<form th:action="@{/testbean}" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
性别:<input type="radio" name="sex" value="男">男<input type="radio" name="sex" value="女">女<br>
年龄:<input type="text" name="age"><br>
邮箱:<input type="text" name="email"><br>
<input type="submit" value="使用实体类接收请求参数">
</form>
public class User {
private Integer id;
private String username;
private String password;
private Integer age;
private String sex;
private String email;
public User(Integer id, String username, String password, Integer age, String sex, String email) {
this.id = id;
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
this.email = email;
}
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
}
@RequestMapping("/testbean")
public String testBean(User user){
System.out.println(user);
return "success";
}
可以看到我们确实是接受到了,但是sex是乱码,出现乱码原因就是因为字符编码不一致而造成的
7. 解决获取请求参数的乱码问题
在我们设置编码之前,已经获取了请求参数,再设置编码,这样是没有任何作用的,那么处理这种请求参数乱码的问题有2种,一种是GET请求,一种是POST请求
我们先尝试一下将表单的method设置为get
可以看到,用GET请求并不会出现乱码的问题,这个问题是Tomcat造成的,也就是说GET请求造成的乱码是由Tomcat来处理的,我们需要去找Tomcat那边去找个配置文件server.xml
这里要注意,Tomcat8以上是不需要改的,没有URIEncoding="UTF-8"也会解析为这个编码。
那么我们前面也说了,如果是已经获取完请求参数,再设置编码,是没有用的,DispatcherServlet里面已经获取了请求参数,所以我们应该在DispatcherServlet获取请求参数之前设置编码
那么是什么组件比Servlet执行更早的呢?
服务器中三大组件:监听器,过滤器,Servlet
监听器执行最早,然后是过滤器,最后是Servlet。
但是监听器是监听作用,监听ServletContext创建和销毁,所以这两个方法都是只执行一次。
过滤器,只要我们设置了过滤路径,访问的请求地址满足过滤路径,都会被过滤器进行过滤。
通过过滤器设置编码,每一次请求都要经过过滤器进行处理,再交给DispatcherServlet处理,当然,这个过滤器我们也不用写,因为SpringMVC已经为我们提供好了。
<!--配置springMVC的编码过滤器-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
那么过滤器配置完了,我们再来试一下POST请求参数还会不会出现乱码问题
这时候不会出现了。