Spring MVC 数据绑定与表单标签库
本小记学习目标
-
数据绑定介绍
-
表单标签库介绍
-
数据绑定的相关应用介绍
-
JSON数据交互
一、数据绑定
Spring MVC所谓的数据绑定主要是从如下几个方面来体现:
1.绑定请求参数输入值到领域模型
2.模型数据到视图的绑定
3.模型数据到表单元素的绑定
二、表单标签库
表单标签库中包含了可以用在JSP页面中渲染HTML元素的标签。在JSP页面使用Spring表单标库时,需要使用taglib把相应的标签库引入
相应的指令如下:
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
相关标签介绍
标签
|
说明
|
form
|
渲染表单元素
|
input
|
渲染<input type="text">元素
|
password
|
渲染<input type="password">元素
|
hidden
|
渲染<input type="hidden">元素
|
textarea
|
渲染textarea元素
|
checkbox
|
渲染一个<input type="checkbox">元素
|
checkboxes
|
渲染多个<input type="checkbox">元素
|
radiobutton
|
渲染一个<input type="radiobutton">元素
|
radiobuttons
|
渲染多个<input type="radiobutton">元素
|
select
|
渲染一个选择元素
|
option
|
渲染一个选项元素
|
options
|
渲染多个选项元素
|
errors
|
在span元素中渲错误
|
表单标签的语法格式
<form:form modelAttribute="xxx" method="post" action="xxx">
……
</form:form>
表单元素除了HTML表单元素外还可以有如下的属性:
acceptCharset:定义服务器接受字符编码列表
commandName:暴露表单对象的模型属性名称,默认为command
cssClass:定义应用到form元素的CSS类
cssStyle:定义应用到form元素的CSS样式
htmlEscape:表示是否进行HTML转义,可以为true、false
modelAttribute:暴露form backing object的模型属性名称,默认为command
input标签:
语法格式:
<form:input path="xxx"/>
这个标签除了cssClass、cssStyle、htmlEscape属性外,还有一个重要的属性path
path属性,它用来把文本框中输入的值绑定到form backing object的一个属性
password标签
语法格式:
<form:password path="xxx">
这个标签与input标签类似
hidden标签
语法格式:
<form:hidden path="xxx">
这个标签也与input标签类似,但是它是不显示的因而也就是不支持cssClass和cssStyle属性的
textarea标签
语法格式:
<form:textarea path="xxx">
这个标签本质上就是一个支持多行输入的input,它也类似于input
checkbox标签
语法格式:<form:checkbox path="xxx" value="xxx">
当多个checkbox的path相同的时候表示它们是一组checkbox,支持多选,这个标签的值绑定到一个数组属性
checkboxes标签
语法格式:<form:checkboxes items="xxx" path="xxx">
checkboxes标签渲染多个复选框,是一个选项组,也就是多个path相同的checkbox
它有如下三个重要的属性items,itemLabel,itemValue
items:用来生成input元素的Collention,Map或Array
itmeLabel:items属性中指定的集合对象的属性,为每个input元素提供label
itemValue:items属性中指定的集合对象的属性,为每个input元素提供value
radiobutton标签
语法格式:<form:radiobutton path="xxx" value="xxx">
多个path相同的radiobutton标签,归于同一组选项,只允许单选
radiobuttons标签
语法格式:<form:radiobuttons items="xxx" path="xxx">
这个标签用来渲染多个radio标签,是一个选项组,等价于多个path相同的radiobutton标签
select标签
语法格式:
<form:select path="xxx" items="xxx">
<form:select path="xxx" items="xxx">
<option value="xxx">xxx</options>
</form:select>
<form:select path="xxx">
<form:options items=“xxx">
</form:select>
select标签的选项可能来自其属性items指定的集合,或来自一个嵌套option标签或options标签
options标签
它用来生成一个select标签的选项列表,它是需要与select标签一起使用的
errors标签
语法格式:
<form:errors path="*">
<form:errors path="xxx">
渲染一个或者多个span元素,每个span元素包含一个错误消息,它可以用于显示一个特定的错误消息,也可以显示所有错误消息
当path指定为*时表示显示所有错误信息;指定为xxx表示由xxx指定的特定错误消息
三、数据绑定实例应用
新增一个Maven的war工程,如果在Eclipse中在生成中如果未自动生成WebContent,这个时候项目会带上一个红叉,可以点击工程右键--->Properties--->Project Facets,把Dynamic Web Module取消掉后重新选中并应用
Web工程需要把运行环境添加进来
pom.xml中添加如下jar包的依赖
<
dependencies
>
<!-- context -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-context
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- Spring MVC -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-
webmvc
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- Spring web -->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-web
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<!-- commons-logging -->
<
dependency
>
<
groupId
>commons-logging
</
groupId
>
<
artifactId
>commons-logging
</
artifactId
>
<
version
>1.2
</
version
>
</
dependency
>
<!-- spring-
aop
-->
<
dependency
>
<
groupId
>org.springframework
</
groupId
>
<
artifactId
>spring-
aop
</
artifactId
>
<
version
>5.0.2.RELEASE
</
version
>
</
dependency
>
<
dependency
>
<
groupId
>javax.servlet
</
groupId
>
<
artifactId
>
jstl
</
artifactId
>
<
version
>1.2
</
version
>
</
dependency
>
</
dependencies
>
在classpath路径下新增一个spring的配置文件springmvc.xml
配置web工程的web.xml(1.DispatcherServlet;2:设置编码防止中文乱码)
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
<
web-app
xmlns:xsi=
"
http://www.w3.org/2001/XMLSchema-instance
"
xmlns=
"
http://java.sun.com/xml/ns/javaee
"
xsi:schemaLocation=
"
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd
"
id=
"WebApp_ID"
version=
"2.5"
>
<!-- 前端核心
servlet
的配置(DispatcherServlet) -->
<
servlet
>
<
servlet-name
>springDispatcherServlet
</
servlet-name
>
<
servlet-class
>org.springframework.web.servlet.DispatcherServlet
</
servlet-class
>
<
init-param
>
<
param-name
>contextConfigLocation
</
param-name
>
<
param-value
>classpath:springmvc.xml
</
param-value
>
</
init-param
>
<
load-on-startup
>1
</
load-on-startup
>
</
servlet
>
<!-- Map all requests to the DispatcherServlet for handling -->
<
servlet-mapping
>
<
servlet-name
>springDispatcherServlet
</
servlet-name
>
<
url-pattern
>/
</
url-pattern
>
</
servlet-mapping
>
<!-- 配置解决
psot
请求中文乱码问题 -->
<
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
>forceEncoding
</
param-name
>
<
param-value
>true
</
param-value
>
</
init-param
>
</
filter
>
<
filter-mapping
>
<
filter-name
>CharacterEncodingFilter
</
filter-name
>
<
url-pattern
>/*
</
url-pattern
>
</
filter-mapping
>
</
web-app
>
新增数据绑定中对应的数据模型实体类:com.xiaoxie.pojo.User
package com.xiaoxie.pojo;
public
class User {
private String
userName;
private String[]
hobby;
//用户兴趣爱好
private String
sex;
//性别
private String
vocation;
//职业标签
private String
city;
//居住城市
private String
remark;
//备注
/*setter getter方法*/
public String getUserName() {
return
userName;
}
public
void setUserName(String
userName) {
this.
userName =
userName;
}
public String[] getHobby() {
return
hobby;
}
public
void setHobby(String[]
hobby) {
this.
hobby =
hobby;
}
public String getSex() {
return
sex;
}
public
void setSex(String
sex) {
this.
sex =
sex;
}
public String getVocation() {
return
vocation;
}
public
void setVocation(String
vocation) {
this.
vocation =
vocation;
}
public String getCity() {
return
city;
}
public
void setCity(String
city) {
this.
city =
city;
}
public String getRemark() {
return
remark;
}
public
void setRemark(String
remark) {
this.
remark =
remark;
}
@Override
public String toString() {
return
"User[userName=" +
userName +
"]";
}
}
新增一个Service(M层)主要是与Dao进行交互,com.xiaoxie.service.UserService、com.xiaoxie.service.impl.UserServiceImpl
userService:
package com.xiaoxie.service;
import java.util.ArrayList;
import com.xiaoxie.pojo.User;
/*service的接口,定义了关于用户新增与用户查询的两个接口方法*/
public
interface UserService {
boolean addUser(User
user);
ArrayList<User> getUsers();
}
userServiceImpl:
package com.xiaoxie.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Service;
import com.xiaoxie.pojo.User;
import com.xiaoxie.service.UserService;
@Service
public
class UserServiceImpl
implements UserService {
//这里定义一个关于用户的ArrayList集合
private List<User>
users =
new ArrayList<User>();
@
Override
public
boolean addUser(User
user) {
if(
user!=
null && !
"".equals(
user.getUserName()) && !
user.getUserName().contains(
"@")) {
users.add(
user);
return
true;
}
else {
return
false;
}
}
@
Override
public ArrayList<User> getUsers() {
return (ArrayList<User>)
users;
}
}
新增Controller层,com.xiaoxie.controller.UserController
package com.xiaoxie.controller;
import java.util.HashMap;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import com.xiaoxie.pojo.User;
import com.xiaoxie.service.UserService;
@Controller
@RequestMapping(
"/user")
public
class UserController {
//log记录日志
private
static
final Log
logger = LogFactory.
getLog(UserController.
class);
//把service自动注入进来
@Autowired
private UserService
userService;
@RequestMapping(
"/input")
public String inputUser(Model
model) {
HashMap<String,String>
hobbys =
new HashMap<String,String>();
hobbys.put(
"旅游",
"旅游");
hobbys.put(
"唱歌",
"唱歌");
hobbys.put(
"看书",
"看书");
hobbys.put(
"电竞",
"电竟");
model.addAttribute(
"user",
new User());
model.addAttribute(
"hobbys",
hobbys);
model.addAttribute(
"vocation",
new String[] {
"学生一族",
"职场白领",
"程序猿",
"其他"});
model.addAttribute(
"city",
new String[] {
"北京",
"上海",
"广州",
"深圳",
"其他"});
model.addAttribute(
"sex",
new String[] {
"男",
"女"});
return
"userAdd";
}
@RequestMapping(
"/save")
public String addUser(
@ModelAttribute User
user,Model
model) {
if(
userService.addUser(
user)) {
logger.info(
"新增人员信息成功!");
return
"redirect:/user/list";
}
else {
logger.info(
"新增人员信息失败!");
//直到转发到input页面
return inputUser(
model);
}
}
@RequestMapping(
"/list")
public String listUser(Model
model) {
List<User>
users =
userService.getUsers();
model.addAttribute(
"users",
users);
return
"listUser";
}
}
在Spring的配置文件springmvc.xml中添加如下内容
<?
xml
version=
"1.0"
encoding=
"UTF-8"
?>
xsi:schemaLocation=
"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
"
>
<!-- spring自动抛描的包 -->
<
context:component-scan
base-package=
"com.xiaoxie.controller"
/>
<
context:component-scan
base-package=
"com.xiaoxie.service"
/>
<!-- 配置视图解析器 -->
<
bean
class=
"org.springframework.web.servlet.view.InternalResourceViewResolver"
id=
"viewResolver"
>
<!-- 拼接前缀 -->
<
property
name=
"
prefix"
value=
"/WEB-INF/jsp/"
/>
<!-- 拼接后缀 -->
<
property
name=
"
suffix"
value=
".jsp"
/>
</
bean
>
</
beans
>
View图层jsp页面的添加
首页:index.jsp:它的目的是提供一个链接跳转到/user/input请求,这个请求直接把封装好的model数据带入到userAdd.jsp
<%@
page
language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!
DOCTYPE
html
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"
http://www.w3.org/TR/html4/loose.dtd
"
>
<
html
>
<
head
>
<
meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<
title
>Insert title here
</
title
>
</
head
>
<
body
>
<
h1
><
a
href=
"${pageContext.request.contextPath }
/user/input"
>添加用户
</
a
></
h1
>
</
body
>
</
html
>
userAdd.jsp页面:录入用户信息并提交
<%@
page
language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!
DOCTYPE
html
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"
http://www.w3.org/TR/html4/loose.dtd
"
>
<
html
>
<
head
>
<
meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<
title
>Insert title here
</
title
>
</
head
>
<
body
>
<
form:form
modelAttribute=
"user"
method=
"post"
action=
"${pageContext.request.contextPath }
/user/save"
>
<
fieldset
>
<
legend
>添加用户
</
legend
>
<
p
>
<
label
>姓名:
</
label
>
<
form:input
path=
"userName"
/>
</
p
>
<
P
>
<
label
>性别:
</
label
>
<
form:radiobuttons
path=
"sex"
items=
"${sex }
"
/>
</
P
>
<
p
>
<
label
>爱好:
</
label
>
<
form:checkboxes
items=
"${hobbys }
"
path=
"hobby"
/>
</
p
>
<
p
>
<
label
>职业:
</
label
>
<
form:select
path=
"vocation"
>
<
form:options
items=
"${vocation }
"
/>
</
form:select
>
</
p
>
<
p
>
<
label
>所在城市:
</
label
>
<
form:select
path=
"city"
>
<
form:options
items=
"${city }
"
/>
</
form:select
>
</
p
>
<
p
>
<
label
>描述:
</
label
>
<
form:textarea
path=
"remark"
rows=
"5"
/>
</
p
>
<
p
id=
"buttons"
>
<
input
id=
"reset"
type=
"reset"
/>
<
input
id=
"submit"
type=
"submit"
value=
"提交"
/>
</
p
>
</
fieldset
>
</
form:form
>
</
body
>
</
html
>
listUser.jsp页面:展示用户信息
<%@
page
language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!
DOCTYPE
html
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"
http://www.w3.org/TR/html4/loose.dtd
"
>
<
html
>
<
head
>
<
meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<
title
>Insert title here
</
title
>
</
head
>
<
body
>
<
h1
>用户列表
</
h1
>
<
a
href=
"
<
c:url
value=
"/user/input"
/>
"
>继续添加
</
a
>
<
table
border=
"1"
cellspacing=
"0"
>
<
tr
>
<
th
>姓名
</
th
>
<
th
>性别
</
th
>
<
th
>爱好
</
th
>
<
th
>职业
</
th
>
<
th
>所在城市
</
th
>
<
th
>描述
</
th
>
</
tr
>
<!-- 遍历信息 -->
<
c:forEach
items=
"${users }
"
var=
"user"
>
<
tr
>
<
td
>${user.userName }
</
td
>
<
td
>${user.sex }
</
td
>
<
td
>
<
c:forEach
items=
"${user.hobby }
"
var=
"hobby"
>
${hobby }
</
c:forEach
>
</
td
>
<
td
>${user.vocation }
</
td
>
<
td
>${user.city }
</
td
>
<
td
>${user.remark }
</
td
>
</
tr
>
</
c:forEach
>
</
table
>
</
body
>
</
html
>
四、JSON数据交互
JSON的认识
JSON(JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式。与xml一样,json也是基于纯文本的数据格式。它有对象结构和数组结构两种数据结构。
1.对象结构
以“{”开头,以“}”结尾
中间部分以0个或多个以“,”分隔的key/value对构成,key与value之间以":"分隔
对象结构示例
{
key1:value1,
key2:value2,
……
}
注意:key必须是String类型,value的类型可以为:String,Number,Object,Array……
如下所示表示person的JSON对象结构
{
"name":"张飞",
"address":"汉中",
"age":35
}
2.数组结构
以"["开头,以"]"结尾
中间由0个或多个以","分隔的值的列表组成
数组结构示例
[
value1,
value2,
……
]
上面说了两种数结构,也可以由两种结构组合成为复杂的结构。
如下所示student的json表示形式:
{
"sno":"202012210001",
"sname":"张三",
"hobby":["唱歌","看书"],
"college":{
"cname":"西安交通大学",
"city":"西安"
}
}
JSON数据转换
Spring MVC中为了实现浏览器与控制器类之间JSON数据交互,提供了MappingJackson2HttpMessageConverter实现类来默认处理JSON格式请求响应。
它使用的是Jackson开源包来读写JSON数据,这个开源包的主要作用是实现JSON对象与Java对象之间的转换。
在使用注解开发时需要使用到两个重要的JSON格式转换注解
@RequestBody
把请求体中的数据绑定到方法的形参中,这个注解应用到方法的形参上
@ResponseBody
用于直接返回return对象,这个注解应用在方法上
添加对json操作的开源包jackson,在pom.xml中加上如下依赖
<!--
jackson
-core -->
<
dependency
>
<
groupId
>com.fasterxml.jackson.core
</
groupId
>
<
artifactId
>
jackson-core
</
artifactId
>
<
version
>2.9.4
</
version
>
</
dependency
>
<!--
jackson
-
databind
-->
<
dependency
>
<
groupId
>com.fasterxml.jackson.core
</
groupId
>
<
artifactId
>
jackson-
databind
</
artifactId
>
<
version
>2.9.4
</
version
>
</
dependency
>
<!--
jackson
-annotations -->
<
dependency
>
<
groupId
>com.fasterxml.jackson.core
</
groupId
>
<
artifactId
>
jackson-annotations
</
artifactId
>
<
version
>2.9.4
</
version
>
</
dependency
>
在pojo中添加实体Pseron,com.xiaoxie.pojo.Person
package com.xiaoxie.pojo;
public
class Person {
private String
name;
private String
address;
private Integer
age;
public String getName() {
return
name;
}
public
void setName(String
name) {
this.
name =
name;
}
public String getAddress() {
return
address;
}
public
void setAddress(String
address) {
this.
address =
address;
}
public Integer getAge() {
return
age;
}
public
void setAge(Integer
age) {
this.
age =
age;
}
@Override
public String toString() {
return
"Person[name="+
name+
"]";
}
}
在Spring的配置文件中添加如下信息,对静态资源的开放访问
<
mvc:annotation-driven
/>
<!-- 配置静态资源,允许
js
目录下的文件可见 -->
<
mvc:resources
location=
"/js/"
mapping=
"/js/**"
/>
修改index.jsp页面
<%@
page
language=
"java"
contentType=
"text/html; charset=UTF-8"
pageEncoding=
"UTF-8"
%>
<!
DOCTYPE
html
PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd"
>
<
html
>
<
head
>
<
meta
http-equiv=
"Content-Type"
content=
"text/html; charset=UTF-8"
>
<
title
>Insert title here
</
title
>
<
script
type=
"text/javascript"
src=
"${pageContext.request.contextPath }
/js/jquery-3.2.1.min.js"
></
script
>
<
script
type=
"text/javascript"
>
function testJson(){
var name = $(
"#name").val();
var address = $(
"#address").val();
var age = $(
"#age").val();
$.ajax({
//请求路径
url:
"${pageContext.request.contextPath }/testJson",
//请求类型
type:
"post",
//data表示发送的数据
data:JSON.stringify({name:name,address:address,age:age}),
//定义发送请求的格式为JSON字符串
contentType:
"application/json;charset=utf-8",
//定义响应的数据格式为json字符串
dataType:
"json",
//成功响应的结果
success:
function(data){
if(data!=
null){
alert(
"输入的用户名:" + data.name +
",地址:" + data.address +
",年龄:" + data.age);
}
}
});
}
</
script
>
</
head
>
<
body
>
<
h1
><
a
href=
"${pageContext.request.contextPath }
/user/input"
>添加用户
</
a
></
h1
><
br
>
<
hr
/>
<
form
action=
""
>
姓名:
<
input
type=
"text"
id=
"name"
name=
"name"
/><
br
/>
地址:
<
input
type=
"text"
id=
"address"
name=
"address"
/><
br
/>
年龄:
<
input
type=
"text"
id=
"age"
name=
"age"
/><
br
/>
<
input
type=
"button"
value=
"提交"
onclick=
"testJson();"
/>
</
form
>
</
body
>
</
html
>
新增一个controller实现类 com.xiaoxie.controller.TestJsonController
package com.xiaoxie.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.xiaoxie.pojo.Person;
@Controller
public
class TestJsonController {
@RequestMapping(
"/testJson")
@ResponseBody
public Person testJson(
@RequestBody Person
person) {
//打印JSON数据
System.
out.println(
"name=" +
person.getName() +
",address=" +
person.getAddress() +
",age=" +
person.getAge());
//返回JSON格式响应
return
person;
}
}
访问应用,则可以看到录入信息后会在页面上alert出JSON的信息,在控制台也可以打印出转化为java对象后取出的信息