前言

上一节我们在SpringBoot中启用了Spring MVC最终输出了HelloWorld,本节我们来讲讲Spring MVC中的模型绑定,这个名称来源于.NET或.NET Core,不知是否恰当,我们暂且这样理解吧。

@RequestParam VS  @PathVariable

一看注解名称应该非常好理解,注解@RequestParam主要用来获取查询字符串参数,而注解@PathVaruable用于获取路由参数,下面我们来看如下一个例子:

    @ResponseBody
@RequestMapping(value = "/demo1", method = RequestMethod.GET)
public String demo1(@RequestParam(value = "param1", required = true, defaultValue = "jeffcky") String param1,
@RequestParam(value = "param2", required = false) String param2) {
return param1 + "," + param2;
}

如上我们获取查询字符串参数param1和param2,同时呢,我们要求参数param1必须提供,若为空,我们给定默认值为jeffcky,而参数param2可不提供,则为其默认值,比如如下:

我们知道无论是注解@RequestParam还是注解@PathVariable,都有属性required,若为false,则此参数无需提供,难道事实真的如此吗,我们看看如下示例:

    @ResponseBody
@RequestMapping(value = "/demo3/{id}", method = RequestMethod.GET)
public String demo3(@RequestParam(value = "id") String param1, @PathVariable(value = "id", required = false) String param2) {
return param1 + "," + param2;
}

我们设置了路由上的变量id为可选,当我们请求时我们也并未提供该参数,但是结果却是404,这也证明:注解@RequestParam获取查询字符串,而注解@PathVariable获取路由参数,虽然二者注解提供参数(required)可选,但是针对注解@PathVariable该参数无效,而且参数必须提供,否则返回404。

深入探讨注解@RequestParam

上述是我们针对路由和查询字符串注解的对比,接下来我们来看看对于查询字符串注解各种姿势,看看Spring是如何进行处理的呢,比如我们有两个根据注解@RequestParam的请求参数和方法一样,此时将会发生什么呢?,如下:

    @RequestMapping(value = "/user", method = RequestMethod.GET)
@ResponseBody
public String say() {
return "hello world";
} @RequestMapping(value = "/user", method = RequestMethod.GET)
public ModelAndView user() {
User user = new User();
user.setGender("M");
ModelAndView modelAndView = new ModelAndView("user", "command", user);
return modelAndView;
}

很显然会启动程序后会抛出上述异常,意为不明确有两个相同的映射,那么要是我们将say方法的请求方法给去掉,此时将表明可此方法的请求不受限制,如此这样会报错吗?如若不报错,那么会首先匹配到哪个呢?

    @RequestMapping(value = "/user")
@ResponseBody
public String say() {
return "hello world";
} @RequestMapping(value = "/user", method = RequestMethod.GET)
public ModelAndView user() {
User user = new User();
user.setGender("M");
ModelAndView modelAndView = new ModelAndView("user", "command", user);
return modelAndView;
}

由此我们可以知道:注解@RequestParam用于查询字符串,若请求参数一致, 但一个请求方法未指定(接收所有方法),一个指定对应请求方法,结果将匹配到指定对应的请求方法。那么要是我们想让其匹配到say方法,我们应该肿么办呢?注解@RequestParam的参数为数组,接下来我们将say方法进行如下修改即可(参数顺序可颠倒):

    @RequestMapping(value = {"/user", "*"})
@ResponseBody
public String say() {
return "hello world";
}

@ModelAttribute VS ModelMap VS ModelAndView

既然涉及到参数绑定,那么我们就得学习Spring MVC表单提交,顺着这个思路我们来学习Spring MVC表单相关内容,如上图其实我已经给大家展示了对应方法和视图,接下来我们来通过表单提交来讲讲三者的区别,为了有些童鞋可能需要亲自动手实践,这里我们先给出整个结构,如下:

我们创建如下进行表单提交的用户实体类

package com.demo.springboot.model;

public class User {
private String firstName;
private String lastName;
private String gender;
private String email;
private String userName;
private String password; public String getFirstName() {
return firstName;
} public void setFirstName(String firstName) {
this.firstName = firstName;
} public String getLastName() {
return lastName;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public void setLastName(String lastName) {
this.lastName = lastName;
} public String getEmail() {
return email;
} public void setEmail(String email) {
this.email = email;
} 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;
}
}

接下来我们需要在控制器文件目录下创建UserController控制器,然后呢,我们返回用户视图,如下方法:

    @RequestMapping(value = "/user", method = RequestMethod.GET)
public ModelAndView user() {
User user = new User();
user.setGender("M");
ModelAndView modelAndView = new ModelAndView("user", "command", user);
return modelAndView;
}

在前面内容我们通过字符串的形式返回的视图,然后加上通过配置文件中视图存放位置和加上后缀查找视图,但是利用ModelAndView才是最友好的方式,通过其名称添加模型和返回视图应该就很清楚了,就像.NET MVC中的View方法一样,我们可以返回模型数据,同时指定视图名称是一个道理。上述我们设置了性别的默认值为字符串M,我们暂且先说到这里,待会还要回过头再次进行讲解的,接下来我们去创建user.jsp,如下:

<%@ page language="java" contentType="text/html;" pageEncoding="utf-8" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<html> <head>
<title>Spring MVC Form</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/bootstrap-theme.min.css" rel="stylesheet">
</head> <body>
<div class="container">
<div class="col-md-offset-2 col-md-7">
<h2 class="text-center">Spring MVC 5 Form</h2>
<div class="panel panel-info">
<div class="panel-heading">
<div class="panel-title">Sign Up</div>
</div>
<div class="panel-body">
<form:form action="addUser" class="form-horizontal"
method="post" modelAttribute="user"> <div class="form-group">
<label for="firstName" class="col-md-3 control-label">First
Name</label>
<div class="col-md-9">
<form:input path="firstName" class="form-control"/>
</div>
</div>
<div class="form-group">
<label for="lastName" class="col-md-3 control-label">Last
Name</label>
<div class="col-md-9">
<form:input path="lastName" class="form-control"/>
</div>
</div>
<div class="form-group">
<form:label path="gender" class="col-md-3 control-label">gender</form:label>
<div class="col-md-9">
<form:radiobutton path="gender" value="M" label="Male"/>
<form:radiobutton path="gender" value="F" label="Female"/>
</div>
</div>
<div class="form-group">
<label for="userName" class="col-md-3 control-label">User
Name </label>
<div class="col-md-9">
<form:input path="userName" class="form-control"/>
</div>
</div> <div class="form-group">
<label for="password" class="col-md-3 control-label">Password</label>
<div class="col-md-9">
<form:password path="password" class="form-control"/>
</div>
</div>
<div class="form-group">
<label for="email" class="col-md-3 control-label">Email</label>
<div class="col-md-9">
<form:input path="email" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-3 col-md-9">
<form:button class="btn btn-primary">Submit</form:button>
</div>
</div> </form:form>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="/static/js/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.min.js"></script>
</body>
</html>

首先我们必须在其顶部添加如下这一行表明我们要使用spring framework框架中的表单,且前缀为form:

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>

在spring framework框架中对于表单中各个标签的使用通过冒号隔开,如下:

<form:input path="firstName"/>
<form:input path="lastName"/>

最终在浏览器中将渲染成HTML标签,还是非常简单,这里我们只是稍微过一下,没有太多复杂的东西,我们只要知道规则即可

<input name="firstName" type="text" value=""/>
<input name="lastName" type="text" value=""/>

我们在后台方法中返回模型即user,最终利用spring框架将模型上的属性绑定到表单标签上,那么接下来我们提交表单后,我们在后台怎么获取到模型数据呢,其实我们在spring框架的表单标签上定义了属性modelAttribute,如下:

接下来我们在后台接收表单中的数据,如下:

    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String addUser(@ModelAttribute("user") User user,
ModelMap model) {
model.addAttribute("firstName", user.getFirstName());
model.addAttribute("lastName", user.getLastName());
model.addAttribute("email", user.getEmail());
model.addAttribute("userName", user.getUserName());
model.addAttribute("password", user.getPassword());
return "users";
}

在后台我们同样通过注解@ModelAttribute("user")与表单上定义的属性modelAttribute="user"匹配,从而获取数据,最终将获取到的数据添加到ModelMap中,并返回视图users.jsp中,如下:

<%@ page language="java" contentType="text/html;" pageEncoding="utf-8" %>
<%@taglib uri = "http://www.springframework.org/tags/form" prefix = "form"%>
<html> <head>
<title>Spring MVC Form Handling</title>
</head> <body>
<h2>Submitted User Information</h2>
<table>
<tr>
<td>firstName</td>
<td>${firstName}</td>
</tr>
<tr>
<td>lastName</td>
<td>${lastName}</td>
</tr>
<tr>
<td>Email</td>
<td>${email}</td>
</tr>
<tr>
<td>userName</td>
<td>${userName}</td>
</tr>
<tr>
<td>Password</td>
<td>${password}</td>
</tr>
<tr>
</tr>
</table>
</body>
</html>

当我们启动程序时发现报错了,根据我们一路的解释,似乎没有任何毛病,这是何缘故, 上述异常大概是表明特性user出了问题,其实原因出在后台获取用户视图上,如下这一行上:

ModelAndView modelAndView = new ModelAndView("user", "command", user);

如上构造函数中的第一个参数代表要渲染的视图名称,而第三个参数是在视图中要绑定的模型,那么第二个参数是个什么鬼呢?一般情况下这个值都会默认设置成command,据查资料这个字符串在spring框架是一个常量,那么它的作用是什么呢?我个人猜测如果默认设置成该值,那么就代表注解@ModelAttribute的参数值就是实体类名称,比如我们实体类为User,那么默认ModelAttribute参数名就是user,我们无需在上述表单上指定modelAttribute的值,即使指定为user也会抛出上述异常。如果在表单上显式定义了modelAttribute的值,那么在实例化模型视图类时,第二个参数必须与其值相等,我们将上述command修改为user即可解决问题,不信的话,你可以试试。同时在接收表单提交的参数时,经过测试,后台的注解@ModelAttribute可去除参数名称也可绑定。最终根据我们填写表单的内容和渲染结果,如下:

上述我们是通过ModelAndView返回模型和视图,这只是实现方式之一,其他实现将又会引来问题,接下来我们直接返回该模型,此时将以该模型名称作为作为表单上属性modelAttribute的名称,此时必须显式设置modelAttribute="user",如下:

    @RequestMapping(value = "/user", method = RequestMethod.GET)
public User user() {
User user = new User();
user.setGender("M");
user.setFavorites(new String[]{"乒乓球", "羽毛球", "台球"});
return user;
}

如若在上述表单上没有显式设置modelAttribute="user"且值不能为其他值,否则将抛出如下异常:

若我们想将上述表单上的属性modelAttribute的值user,设置为其他值,比如modelAttribute="User",此时必须在该视图对应方法上通过注解@ModelAttribute显式设置名称为User,否则同样将抛出上述异常,如下:

    @ModelAttribute("User")
@RequestMapping(value = "/user", method = RequestMethod.GET)
public User user() {
User user = new User();
user.setGender("M");
user.setFavorites(new String[]{"乒乓球", "羽毛球", "台球"});
return user;
}

到此为止我们学习到了ModelAndView用来设置模型和视图名称,而注解@ModelAttribute则是控制器和视图绑定数据的桥梁,该注解既可作为方法参数接收视图模型数据,也可修饰控制器方法将模型数据绑定到视图。ModelMap则是映射模型数据,当然也支持集合和合并特性等等。我们再来演示通过对方法进行注解@ModelAttribute,然后绑定到视图中,在User类中我们再定义一个属性country,如下:

    private String country;

    public String getCountry() {
return country;
} public void setCountry(String country) {
this.country = country;
}

在控制器中通过注解@ModelAttribute定义国家元数据,并绑定到视图上,如下:

    @ModelAttribute("countryList")
public Map<String, String> getCountryList() {
Map<String, String> countryList = new HashMap<>();
countryList.put("CHI", "中国");
countryList.put("CH", "英国");
countryList.put("SG", "新加坡");
return countryList;
}
<div class="form-group">
<label for="country" class="col-md-3 control-label">Country</label>
<div class="col-md-9">
<form:select path = "country">
<form:option value = "无" label = "请选择"/>
<form:options items = "${countryList}" />
</form:select>
</div>
</div>

在视图中我们通过$符号渲染数据,当然我么也可以在视图中写Java代码,这和.NET或.NET Core中的Razor视图一样,只不过在JSP中通过<%  代码 %>来写代码,我们同样也来演示下,在User中再定义一个数组,如下:

    private String[] favorites;

    public  String[] getFavorites(){
return favorites;
} public void setFavorites(String[] favorites) {
this.favorites = favorites;
}

在获取user.jsp视图对应后台方法中,我们设置上述定义的爱好列表默认值,如下:

user.setFavorites(new String[]{"乒乓球", "羽毛球", "台球"});

同时在控制器中我们定义爱好列表,然后绑定到视图中,对默认设置的爱好列表通过checkbox进行选中

    @ModelAttribute("favorites")
public Object[] getfavoriteList() {
List<String> favorites = new ArrayList<>();
favorites.add("足球");
favorites.add("乒乓球");
favorites.add("羽毛球");
favorites.add("台球");
return favorites.toArray();
}

再在user.jsp视图中,添加对爱好列表数据的绑定和选中,如下:

<div class="form-group">
<label for="favorites" class="col-md-3 control-label">Favorites</label>
<div class="col-md-9">
<form:checkboxes class="f" items = "${favorites}" path = "favorites" />
</div>
</div>

然后在获取提交表单的方法中,获取上述我们添加的城市和选中的爱好列表,如下:

最后在渲染提交表单的视图users.jsp中,当获取爱好列表时,此时通过代码的形式进行渲染,如下:

 <tr>
<td>Country</td>
<td>${country}</td>
</tr>
<tr>
<td>
<% String[] favorites = (String[])request.getAttribute("favorites");
for(String favorite: favorites) {
out.println(favorite);
}
%>
</td>
</tr>

总结

本节我们详细分析了在Spring MVC中对于参数的绑定,最需要注意的是在模型绑定到视图中的问题,这里我们下个结论: 若通过ModelAndView设置模型和视图时,若此时第二个参数为command,则表单上的属性modelAttribute默认值为模型名称,此时若显式设置值为模型名称将抛出异常,若显式设置该属性的值不为模型名称,此时需要将command设置与其一样,否则将抛出异常。若直接返回模型时,此时表单上的属性modelAttribute的值必须显式设置为模型名称,否则将抛出异常,若表单上的属性modelAttribute值不为模型名称时,此时必须在该视图对应方法上显式设置注解@ModelAttribute其名称与其一致,否则将抛出异常。其他的地方我们只需要了解对应使用规则没有什么难点,好了,本节的内容我们到此为止,下一节我们陆续开始于数据库打交道,感谢您的阅读,我们下节见。

Spring MVC系列之模型绑定(SpringBoot)(七)的更多相关文章

  1. Spring MVC中的模型数据处理

    一.综述 Spring MVC 提供了以下途径来输出模型数据: 1.ModelAndView 当处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据到请求域. 2.Ma ...

  2. ASP.NET MVC学习之模型绑定(1)

    一.前言 下面我们将开始学习模型绑定,通过下面的知识我们将能够理解ASP.NET MVC模型的模型绑定器是如何将http请求中的数据转换成模型的,其中我们重点讲述的是表单数据. 二.正文 1.简单类型 ...

  3. [转]ASP.NET MVC 4 (九) 模型绑定

    本文转自:http://www.cnblogs.com/duanshuiliu/p/3706701.html 模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C ...

  4. Asp.net Mvc 中的模型绑定

    asp.net mvc中的模型绑定可以在提交http请求的时候,进行数据的映射. 1.没有模型绑定的时候 public ActionResult Example0() { ) { string id ...

  5. 【Spring MVC系列】--(4)返回JSON

    [Spring MVC系列]--(4)返回JSON 摘要:本文主要介绍如何在控制器中将数据生成JSON格式并返回 1.导入包 (1)spring mvc 3.0不需要任何其他配置,添加一个jackso ...

  6. .NET MVC学习之模型绑定

    ASP.NET MVC学习之模型绑定(2)   继ASP.NET MVC学习之模型绑定继续 3.手工调用模型绑定 很多情况下我们都是通过形参的方式接收来自http流中的数据,这看似是完美的,但是缺少了 ...

  7. Spring mvc系列一之 Spring mvc简单配置

    Spring mvc系列一之 Spring mvc简单配置-引用 Spring MVC做为SpringFrameWork的后续产品,Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块 ...

  8. ASP.NET MVC 4 (九) 模型绑定

    模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C#间起着桥梁的作用.模型绑定的一个最简单的例子是带参数的控制器action方法,比如我们注册这样的路径映射: ...

  9. spring mvc(4)处理模型数据

    处理模型数据 Spring MVC 提供了以下几种途径输出模型数据: – ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加 模型数据 – Map ...

随机推荐

  1. HTML静态网页--JavaScript-Window.document对象

    1.Window.document对象 一.找到元素: docunment.getElementById("id"):根据id找,最多找一个:    var a =docunmen ...

  2. 基于BERT预训练的中文命名实体识别TensorFlow实现

    BERT-BiLSMT-CRF-NERTensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tuni ...

  3. 最全Pycharm教程(43)——Pycharm扩展功能之UML类图使用 代码结构

    版权声明:本文为博主原创文章,转载时麻烦注明源文章链接,谢谢合作 https://blog.csdn.net/u013088062/article/details/50353202 1.什么是UML ...

  4. Python--day65--模板语言之变量相关语法

    Django的模板语言: 1.目前已经学过的模板语言: 2,模板语言总结: 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 在Djan ...

  5. Django入门7--博客撰写页面开发

  6. http header详解,HTTP头、请求头、响应头、实体头

    Content-Language,Content-Length,Content-Type,Content-Encoding,mime分析 Accept 指定客户端能够接收的内容类型 Accept:te ...

  7. 列表内容自动向上滚动(原生JS)

    效果展示 (鼠标移入,滚动停止:鼠标移出,滚动继续) 实现原理 1. html结构:核心是ul > li,ul外层包裹着div.因为想要内容循环滚动无缝衔接,所以在原有ul后面还要有一个一样内容 ...

  8. 2019-3-1-获取-Nuget-版本号

    title author date CreateTime categories 获取 Nuget 版本号 lindexi 2019-3-1 9:27:6 +0800 2019-02-25 15:51: ...

  9. 2018-8-10-win10-uwp-修改Pivot-Header-颜色

    title author date CreateTime categories win10 uwp 修改Pivot Header 颜色 lindexi 2018-08-10 19:17:19 +080 ...

  10. vue-learning:12 - 2 - 区分:outerHTML - innerTHML - outerText - innerText - textContent

    区分:outerHTML - innerTHML - outerText - innerText - textContent 获取值 <div id="outer"> ...