当前位置: 首页 > news >正文

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请求参数还会不会出现乱码问题

这时候不会出现了。  

相关文章:

  • [Spring Cloud 项目] Spring cloud 实现房源查询功能
  • golang设计模式——结构模式
  • CF803G Periodic RMQ Problem【动态开点线段树+ST表】
  • 【业务知识】发票系统设计知识学习二
  • Basic Facilities of a Virtio Device (二)
  • redis五种数据类型对应的底层数据结构
  • Linux 必会基础语句 软硬连接区别 Linux文件类型
  • 【PAT甲级】1141 PAT Ranking of Institutions
  • JAVA基础(三十二)——反射之创建对象
  • java优秀毕业生推荐系统ssm
  • Group DETR
  • 设计模式 工厂方法模式
  • 自动控制原理7.3---z变换理论
  • 基于ISO14229协议的安全访问系列_1
  • 自动控制原理7.4---离散系统的数学模型
  • 自己简单写的 事件订阅机制
  • 【每日笔记】【Go学习笔记】2019-01-10 codis proxy处理流程
  • Android交互
  • C# 免费离线人脸识别 2.0 Demo
  • Docker: 容器互访的三种方式
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • passportjs 源码分析
  • Python - 闭包Closure
  • Spring声明式事务管理之一:五大属性分析
  • Swoft 源码剖析 - 代码自动更新机制
  • use Google search engine
  • 高度不固定时垂直居中
  • 提醒我喝水chrome插件开发指南
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • Semaphore
  • ​香农与信息论三大定律
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #if和#ifdef区别
  • #includecmath
  • ${factoryList }后面有空格不影响
  • (30)数组元素和与数字和的绝对差
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (转)http协议
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .libPaths()设置包加载目录
  • .mat 文件的加载与创建 矩阵变图像? ∈ Matlab 使用笔记
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .NET MVC第三章、三种传值方式
  • .Net Remoting常用部署结构
  • .Net Web窗口页属性
  • .NET业务框架的构建
  • @德人合科技——天锐绿盾 | 图纸加密软件有哪些功能呢?
  • [04] Android逐帧动画(一)
  • [⑧ADRV902x]: Digital Pre-Distortion (DPD)学习笔记