SpringMVC系列之参数传递【前后端参数传递的方式详解】
· spring mvc参数传递的方式有哪些?
一、前端向后台传递参数的方式:
- 通过 Servlet api 中的 HttpServletRequest对象
- 基本数据类型 + String类型
- Array 数组
- Java Bean 对象
- List 集合
- Map 集合
- JSON 格式
二、后台向前端通过request域传递值的方式:
- Servlet api 中的 HttpServletRequest对象
- ModelAndView 对象
- ModelMap 对象
- Model 对象
- Map 集合
· spring mvc参数传递方式的具体代码实现?
以下代码,只给出前端页面和后端SpringMVC中Controller的具体代码实现。基本的SpringMVC配置可以另外查看专门讲解 SpringMVC配置文件 书写的文章。
一、前端向后台传递参数的方式
1.通过 Servlet api 中的 HttpServletRequest对象
这种方式想必是学习了Java Web之后,最熟悉的一种获取前端页面传递参数的方式。直接在服务器端,使用对HttpServletRequest对象进行操作即可。我们曾几何时,都是这样干的String name = request.getParameter("name");
通过request对象的getParameter()方法直接获取指定的key属性名,即可获取到对应的value属性值,然后赋值给了name变量。
在SpringMVC的Controller中,这种传统方式也是存在的。具体代码如下:
import org.springframework.stereotype.Controller;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/param")
public class ParamController{
@RequestMapping("/servlet")
public String servlet(HttpServletRequest request){
String name = request.getParameter("name");
System.out.println("name:" + name);
request.setAttribute("result", "hello " + name);
return "hello";
}
}
这种方式需要注意的点,无非就是在Controller具体的请求处理方法中,需要传入一个HttpServletRequest对象,来作为当前方法的形参,然后就可以在此方法中,使用这个request对象了,这个对象跟之前传统的方法中的request对象是一致的。通过它,可以获取到很多的内容,getSession(),getHeader(),getAttribute()等等。
在前端页面中,访问的时候,只需要指定url的路径,然后利用key=value的形式访问即可。无需书写其他的代码,例如:
http://localhost:8080/param/servlet?name=golden3young
这样,后端接收到name参数的之后,使用System.out.println("name:" + name);
即可将值打印到控制台上。至于最后两行的代码,是解析视图的内容,后续进行讲解,这里不做展开。
2. 基本数据类型 + String类型
所谓基本数据类型和String类型传值,是什么意思呢?其实就是,我们可以在SpringMVC的Controller中具体请求处理方法中,直接使用基本数据类型或者String类型的参数进行对映,只要前端页面和方法中指定的参数名称是完全一致的,这里包括大小写,那么前端这个参数名称所赋有的值,就会传递到后台的请求处理方法中。其实这其中,是SpringMVC底层的拦截器帮我们实现的,它会将请求中传来的所有参数,跟我们所定义的请求处理方法中的参数进行对比,如果发现是一模一样的,它就会从请求中把那个参数的值拿出来赋给我们处理方法中的那个变量,于是,我们就可以直接使用了。当然,这个转换的过程比较复杂,也同样存在一些问题,稍后会告诉大家。
SpringMVC的Controller中,具体的请求处理方法:
@RequestMapping("/simple")
public String simple(int id, String name, ModelMap modelMap){
System.out.println("id:" + id);
System.out.println("name:" + name);
modelMap.addAttribute("result", "Hello " + name + "," + id);
return "hello";
}
为了讲解的清晰,我将Controller类声明和导包的代码都省略了,只给出核心的请求处理方法的代码。
这里,我们可以看出,Controller中定义了,请求路径为/simple的请求,将直接执行simple()这个方法,而这个方法,我们给了3个形参,id,name,modelMap,这里,我们只关注int id, String name
即可,这两个参数的类型一个是int,属于基本数据类型之一;另一个是String字符串类型。那么这么写的意义是什么呢?其实就是前端页面在传递值的时候,如果有参数名为id或者name的属性,则会直接将属性的值赋给这两个变量。
前端页面,在访问时,只需要给出指定的url和传递指定名称的参数即可,例如:
http://localhost:8080/param/simple?id=1&name=golden3young
通过上面的url,可以看出,请求直接奔向/param/simple,而对应的方法恰好就是simple()方法,同时前端请求通过key=value的格式传递了两个参数,id 和 name, 而我们的simple()方法中,恰好就有同名的id 和 name,那么我们simple()方法中的id和name将获得前端请求传来的值,1 和 golden3young。同时,它们的类型,也会被转变成方法中定义的int和String类型。
有的同学可能发现了,前端请求在传递过程中,明明都是通过字符串格式传递的,而为什么到了Controller的simple()方法中,就变成了int和String类型?是怎么转换的?其实,这就是SpringMVC的过滤器为我们做的事情。它不光接收映射同名的参数,而且还会将类型帮助我们转换成功。但是,类型的转换,存在着问题,比如:int类型是整数类型,刚才传来的参数id就是int类型,而值恰好是1,则不会出现问题,可是如果将值改成abc等非数字的内容呢?那肯定是会报错的,因为数字格式异常,无法进行转换。同时,还有传递的时候忘记传递id属性而只传了name属性,或者id属性只给了key,而没有value值,这些情况,都会导致错误的出现。
罗列一下几种错误:
http://localhost:8080/param/simple?id=&name=golden3young
此时,id为空字符串,那么SpringMVC底层在为我们转换的时候,是将空串转成int类型,那肯定是会报错的。页面报错400.
http://localhost:8080/param/simple?name=golden3young
此时,我们没有传递id这个属性,那么SpringMVC底层在匹配的时候,一旦没有找到前端传来的属性,那么就会直接给Controller的方法中的参数赋值成null,那么把null转成int类型,同样也是会报错的。页面报错500.
那像以上几种情况,都需要大家在前端参数传递的时候,注意不要遗漏并且给出正确类型的数值。这里加一个小的拓展。有些情况,我们可能无法断定前端一定会传过来某一个属性,有可能不传,那这种情况,我们可以进行规范。使用的注解是@RequestParam,后续会介绍。
3. Array 数组
这种方式,简单来说,就是在前端页面通过发送数组格式的数据,后台Controller的处理方法中,在接收参数的时候,直接转换成数组格式。跟 基本数据类型和String类型的 思想是一样的,但是转换的类型是不同的。
那这种方式,我们在前端页面中,经常用到的地方,其实就是form表单中的多选框,因为多选框的name都是一样的,但是值有多个,传递到后端页面后,传统方式是进行截取,而现在SpringMVC可以帮助我们完成底层的工作,直接给我们一个array数组。
前端页面代码:
<form action="${pageContext.request.contextPath}/param/array" method="post">
爱好:
<input type="checkbox" name="hobby" value="唱歌" />唱歌
<input type="checkbox" name="hobby" value="跳舞" />跳舞
<input type="checkbox" name="hobby" value="书法" />书法
<input type="checkbox" name="hobby" value="滑雪" />滑雪
<br>
<input type="submit" value="提交" />
</form>
Controller中的处理方法:
@PostMapping("/array")
public String array(String[] hobby, Map<String, String> map){
for(String hobbyStr : hobby){
System.out.println(hobbyStr);
}
//使用 java.util.Map 向request域传值 【本例不必关注】
map.put("result","测试数组传参");
return "hello";
}
通过前后端代码的比对,相信大家不难看出,前端参数的name为hobby,value的值为多个不同的值,而后端Controller中的方法中,指定了同名hobby的一个String数组类型的参数,于是乎,SpringMVC底层,就把从前端传递过来的多个hobby的值,以数组的格式存放到了hobby数组中。我们使用了for循环进行了遍历打印。 后两行的代码同样无需关注。
4. Java Bean对象
通过上面3种方式的介绍,大家其实也能感觉出来,SpringMVC大大简化了我们将请求中的参数进行转换的这样一个过程,我们只需要吃现成的即可。那么同样有这样一个问题,如果前端页面一次性要传递多个参数,比如十个以上,包括:id,age,name,birthday,gender,school,city,province,area,salary,married等等参数,如果按照上面学过的方法,我们需要把这所有的参数都写在执行方法的形参位置处即可。如:
@RequestMapping("/bean")
public String testBean(int id, int age, String name, String birthday, String school,
String city, String area, double salary, boolean married){
.....
}
放眼望去,可以说是非常长,写起来同样也是非常麻烦,如果执行方法不光这一个,还有多个,都需要接收这些参数,那我们写起来就会浪费大量的无用功的时间。这时,我们就用到面向对象的编程思想,也就是创建一个对象,让这些参数都成为这个对象的属性,然后,SpringMVC就会将前端传来的这些参数的名称与我们指定的对象(Java Bean)的属性进行名称的对比,如果一致,那么就进行赋值,于是乎,我们先创建一个对象,用来存放所有的参数:
@Data
public class User{
private int id;
private int age;
private String name;
private String birthday;
private String school;
private String city;
private String area;
private double salary
private boolean married;
}
那么这样,Controller中处理方法的代码就简化成了这样:
@RequestMapping("/bean")
public String testBean(User user){
.....
}
然后,我们只需要在方法中,调用user.getter方法,来获取所有的属性值或者说参数值。
当然,这里有的同学可能会问,那底层是怎么实现的呢?SpringMVC底层其实还是将请求中的参数剥离出来,然后调用我们指定的这个对象(Java Bean)的setter方法来为同名的属性进行赋值,当我们用的时候,直接使用getter方法来用。有同学会问,那你刚才写的User类中没有写getter和setter啊,其实这里,我偷了个懒,使用的是lombok插件,它会自动为我们生成getter和setter,有兴趣的同学,可以自己学一下,非常简单。
那前端页面在传参的时候,还是保证访问指定的url,然后传递同名的参数即可,没有其他的变化,例如:
http://localhost:8080/param/bean?id=1&name=golden3young&age=18&married=false
根据我上面的url请求来看,后端springMVC在接收值的时候,只能映射到id,name,age,married这4个参数的值给User对象的同名属性,而其他的属性由于我没有传值,所以都会保持初始默认值,那这个默认值,就是Java基础部门的内容了,也就是所有Java类型的默认值。