参数传递是Web开发的基础内容,前端页面和后端服务通过请求和返回的参数来判断所执行的业务逻辑,因此参数的传递和接收是Web开发中最基础却非常重要的功能。Spring Boot支持多种参数接收方式,通过提供注解来帮助限制请求的类型、接收不同格式的参数等,接下来我们通过示例介绍。
在Web应用中,最常用的参数传递方式就是URL传参,也就是将参数放在请求的URL中。例如微博上不同用户的个人主页应该对应不同的URL:http://weibo.com/user/1、http://weibo.com/user/2。我们不可能对每个用户都定义一个@RequestMapping注解的方法来映射URL请求。对于相同模式的URL,可以采用同一种规则进行处理。
@RequestMapping注解使用{}来声明URL变量。
例如@RequestMapping(“/user/{username}”)。其中,{username}是定义的变量规则,username是变量的名字。此URL路由可以匹配下列任意URL请求:
/user/tianmaying
/user/ricky
/user/tmy1234
在@RequestMapping中定义变量规则后,Spring Boot提供的@PathVariable注解帮助我们获取URL中定义的变量参数,示例如下:
@RequestMapping("/user/{username}")
@ResponseBody
public String userProfile(@PathVariable String username) {
return "user:" + username;
}
在上面的示例中,Spring Boot会自动将URL中定义的变量传递给userProfile方法的username参数(同名赋值),例如当HTTP请求为/users/lxml时,URL变量username的值lxml会被赋给函数参数username,返回的数据为user:lxml。
需要注意的是,在默认情况下,变量参数不能包含URL的分隔符“/”,也就是说上面定义的URL路由不能匹配/users/lxml/zhang,即使lxml/zhang是一个存在的用户名。
上面介绍了传递单个变量的例子,那么多个变量呢?同样,@RequestMapping支持定义包含多个URL变量的路由,示例如下:
@RequestMapping("/user/{username}/blog/{blogId}")
@ResponseBody
public String getuserBlog(@PathVariable String username, @PathVariable String blogId) {
return "user:" + username + "blog" + blogId;
}
在上面的示例中
@RequestMapping(“/user/{username}/blog/{blogId}”)传入{username}和{blogId}两个参数,然后使用@PathVariable映射对应的变量参数。
在多变量参数的情况下,Spring Boot能够根据变量名自动赋值对应的函数参数值,也可以在@PathVariable中显式声明具体的URL变量名。
在默认情况下,@PathVariable注解的参数支持自动转换一些基本的数据类型,如int、long、date、string等,Spring Boot能够根据URL变量的具体值以及函数参数的数据类型来进行转换,例如/user/lxml/blog/1会将“lxml”的值赋给username,而1赋给int类型的变量blogId。
虽然@RequestMapping路由支持URL变量,但是很多时候需要对URL变量进行更加精确的定义和限制,例如用户名只包含小写字母、数字、下划线:
/user/fpc是一个合法的URL
/user/#不是一个合法的URL
这种情况下,简单定义{username}变量就无法满足需求了。没关系,@RequestMapping注解同样支持正则表达式匹配,可以通过定义正则表达式更精确地控制,定义语法是{变量名:正则表达式},示例代码如下:
@RequestMapping("/user/{username:[a-zA-Z0-9_]+}/blog/{blogId}")
@ResponseBody
public String getuserBlog(@PathVariable String username, @PathVariable String blogId) {
return "user:" + username + "blog" + blogId;
}
在上面的示例中,使用[a-zA-Z0-9_]+正则表达式来限定username参数值只能包含小写字母、大写字母、数字、下划线。如此设置URL变量规则后,不合法的URL不会被处理,直接返回404Not Found。
针对参数较多的表单提交,Spring Boot可以通过创建一个JavaBean对象来接收HTTP传入的表单参数。需要注意的是,JavaBean对象中必须含有默认的构造函数,同时,需要设置属性字段必须有setter方法。
首先,增加表单对应的实体类,具体代码如下:
public class Student {
private String fristName;
private String lastName;
//省略set和get
}
上面的示例定义了Student数据实体类。
在StudentController控制器中增加save()方法,接收前台传来的数据。定义save()方法的示例代码如下:
@RequestMapping("/save")
public String save(Student student) {
String fristName = student.getFristName();
String lastName = student.getLastName();
return fristName +" "+ lastName;
}
在浏览器中提交表单数据时,Spring Boot会自动把提交的表单数据转为Student对象,然后传递给save()方法。
@RequestBody主要是将前端传入的JSON数据对象映射成后端的实体对象。比如,前端传入JSON格式的数据后,@RequestBody注解会自动将JSON数据反序列化成Student对象。使用时需要注意以下两点:
1)前端传递的对象属性和类型必须与后端对应。比如后端定义的user属性为“int id,String name”,前端必须使用相同的数据类型和字段来定义。
2)要使用JSON数据集进行传递,也就是设置为contentType:“application/json”。
下面通过示例代码演示如何使用@RequsetBody接收JSON数据:
@PostMapping(path = "/save2")
public String save2(@RequestBody Student student) {
String fristName = student.getFristName();
String lastName = student.getLastName();
return fristName +" "+ lastName;
}
@PostMapping注解包含consumes参数,默认为application/json,表示前台需要传入JSON格式的参数。另外,Spring Boot会根据名称一一对应,将数据转换成相应的数据类型。例如JSON数据中有int或date类型,前台传过来都是字符串,Spring Boot会自动将其转换成实体类中的数据类型。
我们可以将@ModelAttribute注解放置在控制器(Controller)中的某个方法上。当请求这个控制器中的某个URL时,会首先调用这个被注解的方法并将该方法的结果作为公共模型的属性,然后调用对应URL的处理方法,前端页面通过模型获取返回的数据。
@ModelAttribute标注的方法会在Controller类的每个映射URL的控制执行方法之前执行。使用方法如下面的示例代码所示:
@ModelAttribute
public void findUserById(@PathVariable("userId")Long userId, Model model) {
model.addAttribute("user",userService.findUserById(userId));
}
@GetMapping("/user/{userId}")
public String findUser(Model model) {
System.out.println(model.containsAttribute("user"));
return "success !";
}
在上面的示例中,当我们请求接口/user/1时,会先调用findUserById()方法,在方法内通过userId查询到对应的User对象放置到Model中。如果仅仅添加一个对象到Model中,上面的代码可以再精练一些:
@ModelAttribute
public User findUserById(@PathVariable("userId") Long userId) {
return UserService.findUserById(userId);
}
通过上述代码返回的User对象会被自动添加到Model中,相当于手动调用了model.addAttribute(user)方法。
Model通过addAttribute()方法向页面传递参数。@ModelAttribute修饰的方法会先于login调用,它把请求的参数值赋给对应的变量。可以向方法中的Model添加对象,前提是在方法中加入一个Model类型的参数。
需要注意的是,被@ModelAttribute注释的方法会在此控制器的每个方法执行前被执行,因此对于一个控制器映射多个URL,要谨慎使用。
ModelAndView也是Spring MVC中常用的数据返回对象。当控制器处理完请求时,通常会将包含视图对象和数据的ModelAndView对象一起返回前台。它的作用类似于request对象的setAttribute()方法。
ModelAndView对象有两个作用:
1)设置转向地址(这也是ModelAndView和ModelMap的主要区别)。
2)将后台数据传回到前台页面。
ModelAndView使用起来也特别简单,在控制器中把前台页面需要的数据放到ModelAndView对象中,然后返回mv对象。下面通过示例演示使用ModelAndView对象返回数据到前台页面:
@RequestMapping(value="/detail/{id}")
public ModelAndView detail(@PathVariable Long id) {
ModelAndView mv = new ModelAndView();
User user = UserService.getUserById(id);
// 设置user对象的username属性
mv.addObject("user", "user");
// 地址跳转,设置返回的视图名称
mv.setViewName("detail");
return mv;
}
上面的示例中,先获取用户数据,然后将数据和对象一起返回到前台detail页面。这样Spring MVC将使用包含的视图对模型数据进行渲染。