四、SpringMVC获取请求参数
1、通过ServletAPI获取
首先,我们从浏览器发送的请求首先会被@RequestMapping这个注解进行匹配,如果匹配成功,那么就会由我们的控制器方法来处理请求,但是也说过,我们在之前web.xml中注册前端控制器,我们浏览器发出的请求先要被前端控制器处理,之后又执行了相对应的控制器方法,所以说将我们的请求与@RequestMapping进行匹配,来找到我们的控制器方法这个过程,就是由DispatcherServlet所完成的,所以说当我们的DispatcherServlet间接调用控制器方法(中间还有其他组件),在我们的DispatcherServlet中封装了许多数据,当我们调用当前的控制器方法的时候,就会根据我们当前的控制器方法的参数,然后来为当前的方法去注入这个参数(为参数赋值)
@RequestMapping标注的方法就为控制器方法,由DispatcherServlet调用,根据你的形参如HttpServletRequest的对象,DispatcherServlet既可以将表示当前请求的Request对象赋值给这个参数
@RequestMapping("/testServletAPI")
//形参位置上的request表示当前请求
public String testServletAPI(HttpServletRequest request){
}
怎么传输请求参数呢?要么在后面写问号,要么写小括号
<a th:href="@{/testServletAPI(username='admin',password=123456)}">测试使用servletAPI获取请求参数</a>
此时方法里有了request(当前请求),此时处理犹如的得心应手,直接request.getParameter()(这个方法是根据name获取value)获取请求参数就OK了
public String testServletAPI(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username"+username+",password:"+password);
return "success";
}
我们在使用SpringMVC的时候,能不用原生API就不用,因为我们要操作的这些数据,我们的SpringMVC已经帮我们获取过了,并给我们提供了一些简单的方式去获取,我们根本没有必要用原生的ServletAPI(侮辱了SpringMVC手动狗头)
2、通过控制器方法的形参来获取参数
咱们只要能保证方法的形参名与请求参数的名字保持一致就可以自动的将我们的请求参数赋给它所对应的形参
@RequestMapping("/testParam")
public String testParam(String username,String password){
System.out.println("username="+username+",password="+password);
return "success";
}
这时候就来了,我们要是有多个重名的请求参数(如复选框)该怎么办呢,上面原生ServletAPI就得用request.getParameterValues方法(返回的是一个String类型的数组),里面就包含参数的值,而SpringMVC可以直接用字符串或者字符串数组都可以,用字符串为参数此重名参数返回的所有值通过逗号来进行拼接,用字符串数组为参数输出则为[a,b,c]
@RequestMapping("/testParam")
public String testParam(String username,String password,String hobby){
System.out.println("username="+username+",password="+password+",hobby:"+hobby);
return "success";
}
@RequestMapping("/testParam")
public String testParam(String username,String password,String[] hobby){
System.out.println("username="+username+",password="+password+",hobby:"+ Arrays.toString(hobby));
return "success";
}
问题:如果遇到请求参数的参数名与形参的参数名不一致怎么办呢,例如请求参数中名为username改为user_name,这时候没办法获取这个值,如果这样的话就得在控制器中加上一个SpingMVC提供的@RequestParam注解,将我们的请求参数跟我们的形参来创建映射关系的,就是说你需要拿哪一个请求参数对应哪一个形参。
@RequestParam源码中有value,required,defaultValue属性,首先是xml文件装配Bean,能装就装,装不了拉倒,而使用注解自动装配如果装配不了,就是说在当前IOC容器中没有任何一个Bean为当前的属性自动赋值,会报no such bean 错误,是因为自动装配的@autowierd注解里面也有一个属性,叫做required(),默认值也是true,就是说必须自动装配,装配不了就报错,@RequestParam中required()中默认为true,就是必须要在浏览器中传输参数数值,可以用defaultValue默认数值防止报错(没输入值或者输入空字符串时)。
@RequestParam(value = "user_name",required = false,defaultValue = "hehe") String username
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
两种会话技术的关系,Session依赖于Cookie,Cookie是客户端的会话技术,Session是服务器端的会话技术,当调用getSession方法的时候,本质上会创建一个键为JSESSIONID的Cookie
例子:如第一次进入,那么就会第一次创建HttpSession对象,将Session放在服务器所维护的Map集合中,并且去创建的Cookie,Cookie的键是固定的,是JSESSIONID,它的值是一个随机序列,在响应头中,作为Map集合的键,然后把咱们的Session对象作为Map集合的值进行存储,存储在服务器的内部,再把Cookie响应到浏览器,此时是在响应(报文)头中,从此之后JSESSIONID的Cookie从此之后就会在请求头(报文)中,因为Cookie也是这样的工作原理,服务器创建响应到浏览器之后,以后每一次浏览器向服务器发送请求都会携带Cookie。
3、通过POJO获取请求参数
在我们获取请求参数的过程中,有的时候请求参数非常的多,比如添加修改的功能,使用mysql数据库,我们所添加的这些数据就要所对应当前数据库中的字段,我们数据库同样对应我们的实体类对象,我们也可以说在我们页面中添加的这些数据跟咱们的实体类对象中的属性也是一一对应的,SpringMVC给我们提供了一个非常简单的方式,如果当前我从浏览器发送的请求所提交的这些请求参数然后他跟我们当前实体类对象里的属性一一对应,那我们就可以直接在形参位置直接去写一个实体类型的对象,只需要保证我们请求参数的名字跟我们实体类对象中的属性名保持一致就可以自动通过实体类对象收集这些请求参数。省去了从rep中取值,再new对象,进行赋值的过程。
tips:框架里面用到的好多技术都是反射,通过反射创建类型对象的时候,默认的使用是无参构造
如果不学习通过实体类获取请求参数的话,那就需要在控制器方法中写好多好多的参数,就像第二个通过控制器方法的形参获取参数一样,所以可以直接通过我们的User对象进行获取
@RequestMapping("/testBean")
public String testBean(User user){
System.out.println(user);
return "success";
}
4、乱码问题(用过滤器处理)
如果出现乱码(字符串编码不一致),原来出现乱码是使用request.setCharacterEncoding(针对post请求的乱码问题),那我们现在想要处理乱码问题,因为没有用Request对象(有也没用),因为在设置请求对象编码的时候,有一个前提条件,如果说在这之前,你已经获取了咱们的某一个请求参数,那么之后设置编码是没有任何效果的,再上一个阶段,如果在BaseServlet已经对我们request设置了编码,然后在通过BaseServlet在访问我们具体处理方法的请求的时候,就不会出现乱码问题,如果把编码放在具体处理方法里面,是没有任何效果的。get请求的乱码是由Tomcat造成的,我们要想解决get的乱码需要改tomcat中的server.xml文件中的端口号的地方加上属性URLEncoding编码改为UTF-8,八版本以后默认UTF-8。
Dispatcher获取请求参数在前获取Request对象设置编码在后,所以说就算有在SpringMVC中获取Request对象也没用,所以要想找到一种技术或者一种组件,在Dispathcer后去请求参数前就设置编码,服务器中三大组件(过滤器,监听器,Servlet),ServletContextListener(监听器)加载时间最早,之后是过滤器,在之后是Servlet,监听器只是监听Servlet的创建和销毁,只要我们设置了过滤路径(当前所访问的请求地址满足过滤路径),都会由过滤器进行过滤,SpringMVC已经为我们提供好了,所以说要想过滤器生效,只需要在web.xml中进行注册(配置)。
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
此时仍不能设置编码的成功,因为没有设置编码格式,所以翻到源码CharacterEncodingFilter找到执行过滤的方法,可以找有没有FilterChain,放行就是用的这个参数,没这个参数放不了行。找到后发现
需要设置里面的encoding属性的值并且里面的if中forceRequestEncoding为true(默认为false)或request.getCharacterEncoding为null(没设置默认为null)才可以设置请求编码,所以我们用
所以说根据上面的源码要想在设置响应编码,还需要一个<init-param>中设置forceResponseEncoding(源码里的属性)设置为true
小知识点:响应浏览器的方式除了我们的转发重定向,还有response.getwriter.writer(),响应浏览器数据。