数据绑定
在程序运行时,Spring MVC接收到客户端的请求后,会根据客户端请求的参数和请求头等数据信息,将参数以特定的方式转换并绑定到处理器的形参中。Spring MVC中将请求消息数据与处理器的形参建立连接的过程就是Spring MVC的数据绑定。
Spring MVC数据绑定的过程图
Spring MVC数据绑定中的信息处理过程
- Spring MVC将ServletRequest对象传递给DataBinder。
- 将处理方法的入参对象传递给DataBinder。
- DataBinder调用ConversionService组件进行数据类型转换、数据格式化等上作,并将ServletRequest对象中的消息填充到参数对象中。
- 调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验。
- 校验完成后会生成数据绑定结果BindingResult对象,Spring MVC会将BindingResult对象中的内容赋给处理方法的相应参数。
简单数据绑定
默认类型数据绑定
Spring MVC常见的默认类型
当使用Spring MVC默认支持的数据类型作为处理器的形参类型时,Spring MVC的参数处理适配器会默认识别这些类型开进行赋值。Spnng MVC常见的默认类型如下所示。
- HttpServletRequest:获取请求信息。
- HttpServletResponse:处理响应信息。
- HttpSession:获取session中存放的对象。
- Model/ModelMap : Model是一个接口,ModelMap是一个类,Model的实现类对象和ModelMap对象都可以设置model数据,model数据会填充到request域。
案例演示默认类型的数据绑定
1. 引入项目需要的依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>_20230526</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
2.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3.spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<content:component-scan base-package="cn.hdc.controller"></content:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/static/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
4.UserController
package cn.hdc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class UserController {
@RequestMapping("/findById")
public String findById(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model) {
System.out.println(response);
System.out.println(request);
//向模型中存放数据
model.addAttribute("msg", "你好");
//获取请求中参数
String userid = request.getParameter("userid");
System.out.println("根据ID查询用户信息" + userid);
return "success";
}
}
5.success.jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/26
Time: 18:31
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>hello spring-mvc</h1>
${msg}
</body>
</html>
6.运行结果:
简单数据类型绑定
简单数据类型绑定的概念
简单数据类型的绑定,就是指Java中基本类型(如int、double、String等)的数据绑定。在Spring MVC中进行简单类型的数据绑定,只需客户端请求参数的名称和处理器的形参名称一致即可,请求参数会自动映射并匹配到处理器的形参完成数据绑定.
案例演示简单数据类型的数据绑定
此案例在上一个案例的基础上修改:
1.UserController中添加方法getUserNameAndId
2.运行结果:
参数别名的设置
需要注意的是,有时候客户端请求中参数名称和处理器的形参名称不一致,这就会导致处理器无法正确绑定并接收到客户端请求中的参数。为此,Spring MVC提供了@RequestParam注解来定义参数的别名,完成请求参数名称和处理器的形参名称不一致时的数据绑定。
@RequestParam注解的属性
@RequestParam注解的使用
代码示例:
运行结果1:
运行结果2:
@PathVariable注解的两个常用属性
当请求的映射方式是REST风格时,上述对简单类型数据绑定的方式就不适用了。为此,Spring MVC提供了@PathVariable注解,通过@PathVariable注解可以将URL中占位符参数绑定到处理器的形参中。@PathVariable注解有以下两个常用属性。
- value :用于指定URL中占位符名称。
- required:是否必须提供占位符,默认值为true。
@PathVariable注解的使用
代码示例:
运行结果:
@PathVariable注解value属性可省略的情况
POJO绑定
POJO数据绑定的使用场景
在使用简单数据类型绑定时,可以很容易的根据具体需求来定义方法中的形参类型和个数,然而在实际应用中,客户端请求可能会传递多个不同类型的参数数据,如果还使用简单数据类型进行绑定,那么就需要手动编写多个不同类型的参数,这种操作显然比较繁琐。为解决这个问题,可以使用POJO类型进行数据绑定。
POJO数据绑定的概念
POJO类型的数据绑定就是将所有关联的请求参数封装在一个POJO中,然后在方法中直接使用该POJO作为形参来完成数据绑定。
代码案例:
1.创建实体类User
package cn.hdc.pojo;
public class User {
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
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;
}
}
2.UserController中创建registerUser方法
package cn.hdc.controller;
import cn.hdc.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Controller
public class UserController {
@RequestMapping("/findById")
public String findById(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model) {
System.out.println(response);
System.out.println(request);
//向模型中存放数据
model.addAttribute("msg", "你好");
//获取请求中参数
String userid = request.getParameter("userid");
System.out.println("根据ID查询用户信息" + userid);
return "success";
}
@RequestMapping("/get")
public String getUserNameAndId(String username, Integer id) {
System.out.println("用户名:" + username + " ID:" + id);
return "success";
}
@RequestMapping("/getUsername")
public String getUsername(@RequestParam(value = "name", defaultValue = "hdc") String username) {
System.out.println("用户名:" + username);
return "success";
}
@RequestMapping("/user/{name}")
public String getPathVariable(@PathVariable("name") String username) {
System.out.println(username);
return "success";
}
@RequestMapping("/registerUser")
public String registerUser(User user) {
System.out.println(user);
return "success";
}
}
register.jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/26
Time: 19:44
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>注册</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/registerUser"
method="post">
用户名:<input type="text" name="username"/><br/>
密 码:<input type="password" name="password"/>
<br/>
<input type="submit" value="注册"/>
</form>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 乱码过滤器-->
<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>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<content:component-scan base-package="cn.hdc.controller"></content:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/static/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
项目结构:
POJO绑定时参数名称问题
在POJO类型数据绑定时,客户端请求的参数名称(本例中指form表单内各元素name的属性值)必须与要绑定的POJO类中的属性名称保持一致。这样客户端发送请求时,请求数据才会自动绑定到处理器形参POJO对象中,否则处理器参数接收的值为null。
运行结果:
解决请求参数中的中文乱码问题
上述代码中,在<filter>元素中,首先使用<fillter-class>元素配置了编码过滤器类org.springframework.web.filter.CharacterEncodingFilter,然后使用<init-param>元素设置统一的编码为UTF-8。最后配置<filter-mapping>元素,拦截前端页面中的所有请求,并交由名称为CharacterEncodingFilter的编码过滤器类进行处理,将所有的请求信息内容以UTF-8的编码格式进行解析。
------------------------------------------------------------------------------------------
以上可以解决post请求乱码问题,对于get请求中文参数出现乱码,可以在使用参数之前重新编码,如String username = new String(user.getUsername().getBytes("ISO8859-1” ),"UTF-8” );,其中ISO8859-1是Tomcat默认编码,需要将Tomcat编码后的内容再按UTF-8编码。
自定义类型转换器
自定义类型转换器使用场景
Spring MVC默认提供了一些常用的类型转换器,这些类型转换器,可以将客户端提交的参数自动转换为处理器形参类型的数据。然而默认类型转换器并不能将提交的参数转换为所有的类型。此时,就需要开发者自定义类型转换器,来将参数转换为程序所需要的类型。
Converter接口的使用
Spring框架提供了org.springframework.core.convert.converter.Converter接口作为类型转换器,开发者可以通过实现Converter接口来自定义类型转换器。Converter接口的代码如下所示。
在上述代码中,泛型参数中的S表示源类型,T表示目标类型,而convert()方法将源类型转换为目标类型返回,方法内的具体转换规则可由开发者自行定义。
代码示例:
1.DateConverter
package cn.hdc.convert;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String, Date> {
@Override
public Date convert(String s) {
String dateFormatPattern = "yyyy-MM-dd";
SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatPattern);
Date date = null;
try {
date = dateFormat.parse(s);
} catch (ParseException e) {
e.printStackTrace();
System.out.println("请采用正确的格式:" + dateFormatPattern);
}
return date;
}
}
2.spring-mvc.xml中配置类型转换器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
<content:component-scan base-package="cn.hdc.controller"></content:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/static/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 基于XML配置自定义转换器实现-->
<!-- <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">-->
<!-- <property name="converters">-->
<!-- <array>-->
<!-- <bean class="cn.hdc.convert.DateConverter"></bean>-->
<!-- </array>-->
<!-- </property>-->
<!-- </bean>-->
<!-- <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>-->
<!-- 基于注解自定义转换器实现-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
3.UserController
package cn.hdc.controller;
import cn.hdc.pojo.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
@Controller
public class UserController {
@RequestMapping("/findById")
public String findById(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model) {
System.out.println(response);
System.out.println(request);
//向模型中存放数据
model.addAttribute("msg", "你好");
//获取请求中参数
String userid = request.getParameter("userid");
System.out.println("根据ID查询用户信息" + userid);
return "success";
}
@RequestMapping("/get")
public String getUserNameAndId(String username, Integer id) {
System.out.println("用户名:" + username + " ID:" + id);
return "success";
}
@RequestMapping("/getUsername")
public String getUsername(@RequestParam(value = "name", defaultValue = "hdc") String username) {
System.out.println("用户名:" + username);
return "success";
}
@RequestMapping("/user/{name}")
public String getPathVariable(@PathVariable("name") String username) {
System.out.println(username);
return "success";
}
@RequestMapping("/registerUser")
public String registerUser(User user) {
System.out.println(user);
return "success";
}
// 基于XML配置自定义转换器实现
// @RequestMapping("/getBirthday")
// public String getBirthday(Date birthday) {
// System.out.println(birthday);
// return "success";
// }
// 使用@DateTimeFormat注解完成日期类型的格式转换无需自定义转换器
@RequestMapping("/getBirthday")
public String getBirthday(@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday) {
System.out.println(birthday);
return "success";
}
}
4.其余代码同上:
项目结构:
运行结果:
日期类型的格式转换
在上述案例中,日期类型的格式转换是基于XML配置自定义转换器实现的。除了XML方式之外,还可以通过@DateTimeFormat注解来简化日期类型的格式转换。使用@DateTimeFormat注解完成日期类型的格式转换无需自定义转换器,也无需在配置文件中定义转换器工厂或格式化工厂,只需将@DateTimeFormat定义在方法的形参前面或成员变量上方,就可以为当前参数或变量指定类型转换规则。
数组绑定
数组绑定的使用场景
在实际开发中,可能会遇到客户端请求需要传递多个同名参数到服务器端的情况,这种情况采用前面讲解的简单数据绑定的方式显然是不合适的。此时,可以使用数组来接收客户端的请求参数,完成数据绑定。
代码示例:
1.ProductController
package cn.hdc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class ProductController {
@RequestMapping("/getProducts")
public String getProducts(String[] proIds) {
for (String proId : proIds) {
System.out.println("商品的id为:" + proId);
}
return "success";
}
}
2.Product
package cn.hdc.pojo;
public class Product {
private String proId;
private String proName;
@Override
public String toString() {
return "Product{" +
"proId='" + proId + '\'' +
", proName='" + proName + '\'' +
'}';
}
public String getProId() {
return proId;
}
public void setProId(String proId) {
this.proId = proId;
}
public String getProName() {
return proName;
}
public void setProName(String proName) {
this.proName = proName;
}
}
3.product.jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/26
Time: 21:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>提交商品</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/getProducts" method="post">
<table width="220px" border="1">
<tr>
<td>选择</td>
<td>商品名称</td>
</tr>
<tr>
<td>
<input name="proIds" value="1" type="checkbox">
</td>
<td>Java基础教程</td>
</tr>
<tr>
<td>
<input name="proIds" value="2" type="checkbox">
</td>
<td>JavaWeb案例</td>
</tr>
<tr>
<td>
<input name="proIds" value="3" type="checkbox">
</td>
<td>SSM框架实战</td>
</tr>
</table>
<input type="submit" value="提交商品"/>
</form>
</body>
</html>
4.其他代码和上述一样
项目结构:
运行结果:
集合绑定
集合绑定的使用
集合中存储简单类型数据时,数据的绑定规则和数组的绑定规则相似,需要请求参数名称与处理器的形参名称保持一致。不同的是,使用集合绑定时,处理器的形参名称需要使用@RequestParam注解标注。
代码示例:
把ProductController中的第一个方法复制一份,使用注解进行集合绑定
运行结果:
@RequestParam注解解决集合绑定的异常问题
如果getProducts()方法中不使用@RequestParam注解,Spring MVC默认将List作为对象处理,赋值前先创建List对象,然后将proIds作为List对象的属性进行处理。由于List是接口,无法创建对象,所以会出现无法找到构造方法异常。如果将类型更改为可创建对象的类型,如ArrayList,可以创建ArrayList对象,但ArrayList对象依旧没有prolds属性,因此无法正常绑定,数据为空。此时需要告知Spring MVC的处理器prolds是一组数据,而不是一个单一数据。通过@RequestParam注解,将参数打包成参数数组或集合后,Spring MVC才能识别该数据格式,并判定形参类型是否为数组或集合,并按数组或集合对象的形式操作数据。
复杂POJO绑定
复杂POJO数组绑定的使用场景
使用简单POJO类型已经可以完成多数的数据绑定,但有时客户端请求中传递的参数比较复杂。例如,在用户查询订单时,页面传递的参数可能包括订单编号、用户名称等信息,这就包含了订单和用户两个对象的信息。如果将订单和用户的所有查询条件都封装在一个简单POJO中,显然会比较混乱,这时可以考虑使用复杂POJO类型的数据绑定。
复杂POJO的3种属性的类型
所谓的复杂POJO,就是POJO属性的类型不止包含简单数据类型,还包含对象类型、List类型和Map类型等其他引用类型。接下来分别对复杂POJO中属性为对象类型的数据绑定、属性为List类型的数据绑定和属性为Map类型的数据绑定进行讲解。
属性为对象类型的数据绑定
1.创建一个订单类Order,用于封装订单信息
package cn.hdc.pojo;
public class Order {
private String orderId;
@Override
public String toString() {
return "Order{" +
"orderId='" + orderId + '\'' +
'}';
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
2.修改User.java类,在User类中新增Order类型的属性order,并定义相应的getter和setter方法。修改后User类的具体代码如下所示。
package cn.hdc.pojo;
public class User {
private String username;
private String password;
private Order order;
public Order getOrder() {
return order;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", order=" + order +
'}';
}
public void setOrder(Order order) {
this.order = order;
}
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;
}
}
3.在UserController.java类中定义方法findOrderWithUser( ),用于获取客户端请求中的User信息,findOrderWithUser()方法的具体代码如下所示。
package cn.hdc.controller;
import cn.hdc.pojo.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Date;
@Controller
public class UserController {
@RequestMapping("/findById")
public String findById(HttpServletRequest request,
HttpServletResponse response,
HttpSession session,
Model model) {
System.out.println(response);
System.out.println(request);
//向模型中存放数据
model.addAttribute("msg", "你好");
//获取请求中参数
String userid = request.getParameter("userid");
System.out.println("根据ID查询用户信息" + userid);
return "success";
}
@RequestMapping("/get")
public String getUserNameAndId(String username, Integer id) {
System.out.println("用户名:" + username + " ID:" + id);
return "success";
}
@RequestMapping("/getUsername")
public String getUsername(@RequestParam(value = "name", defaultValue = "hdc") String username) {
System.out.println("用户名:" + username);
return "success";
}
@RequestMapping("/user/{name}")
public String getPathVariable(@PathVariable("name") String username) {
System.out.println(username);
return "success";
}
@RequestMapping("/registerUser")
public String registerUser(User user) {
System.out.println(user);
return "success";
}
// 基于XML配置自定义转换器实现
// @RequestMapping("/getBirthday")
// public String getBirthday(Date birthday) {
// System.out.println(birthday);
// return "success";
// }
// 使用@DateTimeFormat注解完成日期类型的格式转换无需自定义转换器
@RequestMapping("/getBirthday")
public String getBirthday(@DateTimeFormat(pattern = "yyyy-MM-dd") Date birthday) {
System.out.println(birthday);
return "success";
}
@RequestMapping("/findOrderWithUser")
public String findOrderWithUser(User user) {
System.out.println("用户民" + user.getUsername());
System.out.println("订单号" + user.getOrder().getOrderId());
return "success";
}
}
4.order.jsp
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/26
Time: 22:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>订单信息</title></head>
<body>
<form action="${pageContext.request.contextPath}/findOrderWithUser" method="post">
所属用户:<input type="text" name="username"/> <br/>
订单编号:<input type="text" name="order.orderId"/><br/><input type="submit" value="查询"/>
</form>
</body>
</html>
5.项目结构:
运行结果:
复杂POJO对象绑定的格式
在复杂POJO数据绑定时,如果数据需要绑定到POJO属性对象的属性中,客户端请求的参数名(本例中指form表单内各元素name的属性值)的格式必须为“属性对象名称.属性”,其中“属性对象名称”要和POJO的属性对象名称一致,“属性”要和属性对象所属类的属性一致。
属性为List类型的数据绑定
代码示例:
1.修改User.java类,将User类中订单属性修改为List类型。由于用户一般拥有多个收货地址,在User类中新增List类型的地址属性。
package cn.hdc.pojo;
import java.util.List;
public class User {
private String username;
private String password;
private List<Order> orders;
private List<String> address;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", orders=" + orders +
", address=" + address +
'}';
}
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;
}
public List<Order> getOrders() {
return orders;
}
public void setOrders(List<Order> orders) {
this.orders = orders;
}
public List<String> getAddress() {
return address;
}
public void setAddress(List<String> address) {
this.address = address;
}
// private Order order;
// public Order getOrder() {
// return order;
// }
//
// public void setOrder(Order order) {
// this.order = order;
// }
}
2.创建一个订单处理器类OrderController,在OrderController类中定义showOrders()方法,用于展示用户的订单信息。
package cn.hdc.controller;
import cn.hdc.pojo.Order;
import cn.hdc.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
public class OrderController {
@RequestMapping("/showOrders")
public String showOrders(User user) {
List<String> address = user.getAddress();
List<Order> orders = user.getOrders();
for (int i = 0; i < orders.size(); i++) {
Order order = orders.get(i);
String addr = address.get(i);
System.out.println("订单编号:" + order.getOrderId() + "订单名称:" + order.getOrderName() + " 配送地址:" + addr);
}
return "success";
}
}
3.创建一个订单信息文件orders.jsp,在orders.jsp中创建一个表单用于提交用户的订单信息。表单提交时,表单数据分别圭装到User的订单属性orders和地址属性address中。
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/26
Time: 23:12
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>订单信息</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/showOrders" method="post">
<table width="220px" border="1">
<tr>
<td>订单号</td>
<td>订单名称</td>
<td>配送地址</td>
</tr>
<tr>
<td>
<input name="orders[0].orderId" value="1" type="text">
</td>
<td>
<input name="orders[0].orderName" value="Java基础教程" type="text">
</td>
<td><input name="address" value="北京海淀" type="text"></td>
</tr>
<tr>
<td>
<input name="orders[1].orderId" value="2" type="text">
</td>
<td>
<input name="orders[1].orderName" value="JavaWeb案例" type="text">
</td>
<td><input name="address" value="北京昌平" type="text"></td>
</tr>
<tr>
<td>
<input name="orders[2].orderId" value="3" type="text">
</td>
<td>
<input name="orders[2].orderName" value="SSM框架实战" type="text">
</td>
<td><input name="address" value="北京朝阳" type="text"></td>
</tr>
</table>
<input type="submit" value="订单信息"/>
</form>
</body>
</html>
4.项目结构:
运行结果:
复杂POJO数组绑定的编写要求
在复杂POJO数据绑定时,如果数据绑定到List类型的属性,客户端请求的参数名称(本例中指form表单内各元素name的属性值)编写必须符合以下要求。
- 如果List的泛型为简单类型,则客户端参数名称必须和POJO类中List属性所属类中的属性名称保持一致。
- 如果List的泛型参数为对象类型,则客户端参数名称必须与POJO类的层次结构名称保持一致,并使用数组格式描述对象在List中的位置,即客户端参数名称必须和最终绑定在List中的某个对象的某个属性的名称保持一致。
属性为Map类型的数据绑定
代码示例:
1.修改Order.java类,在Order类中新增HashMap类型的属性productInfo,用于封装订单中的商品信息,其中productInfo的键用来存放商品的类别,productInfo的值用来存放商品类别对应的商品。
package cn.hdc.pojo;
import java.util.HashMap;
public class Order {
private String orderId;
private HashMap<String, Product> productInfo;
@Override
public String toString() {
return "Order{" +
"orderId='" + orderId + '\'' +
", productInfo=" + productInfo +
'}';
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public HashMap<String, Product> getProductInfo() {
return productInfo;
}
public void setProductInfo(HashMap<String, Product> productInfo) {
this.productInfo = productInfo;
}
}
2.修改OrderController.java类,在OrderController类中新增getOrderInfo()方法,用于获取客户端提交的订单信息,并将获取到的订单信息打印在控制台。getOrderInfo()方法的具体代码如下所示。
package cn.hdc.controller;
import cn.hdc.pojo.Order;
import cn.hdc.pojo.Product;
import cn.hdc.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
@Controller
public class OrderController {
// @RequestMapping("/showOrders")
// public String showOrders(User user) {
// List<String> address = user.getAddress();
// List<Order> orders = user.getOrders();
//
// for (int i = 0; i < orders.size(); i++) {
// Order order = orders.get(i);
// String addr = address.get(i);
// System.out.println("订单编号:" + order.getOrderId() + "订单名称:" + order.getOrderName() + " 配送地址:" + addr);
// }
// return "success";
// }
@RequestMapping("/orderInfo")
public String getOrderInfo(Order order) {
System.out.println("订单编号:" + order.getOrderId());
HashMap<String, Product> productInfo = order.getProductInfo();
Set<String> keys = productInfo.keySet();
for (String type : keys) {
Product product = productInfo.get(type);
System.out.println("类型:" + type + "商品名称" + product.getProName());
}
return "success";
}
}
3.创建一个订单信息页面order_info.jsp,在order_info.jsp中创建一个表单用于提交订单信息。表单提交时,表单数据分别封装到Order的orderId属性和商品信息属性productInfo中。
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/26
Time: 23:45
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>订单信息</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/orderInfo" method="post">
<table border="1">
<tr>
<td colspan="2">
订单id:<input type="text" name="orderId" value="1">
</td>
</tr>
<tr>
<td>商品Id</td>
<td>商品名称</td>
</tr>
<tr>
<td>
<input name="productInfo['生鲜'].proId" value="1" type="text">
</td>
<td>
<input name="productInfo['生鲜'].proName" value="三文鱼" type="text">
</td>
</tr>
<tr>
<td>
<input name="productInfo['酒水'].proId" value="2" type="text">
</td>
<td>
<input name="productInfo['酒水'].proName" value="红牛" type="text">
</td>
</tr>
</table>
<input type="submit" value="提交"/>
</form>
</body>
</html>
4.项目结构:
运行结果:
数据绑定到Map类型的属性时的参数命名要求
在复杂POJO数据绑定时,如果数据绑定到Map类型的属性,客户端请求的参数名称(本例中指form表单内各元素name的属性值)必须与POJO类的层次结构名称保持一致,并使用键值的映射格式描述对象在Map中的位置,即客户端参数名称必须和要绑定的Map中的具体对象的具体属性的名称保持一致。
JSON数据绑定
1.引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>_20230526</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--Jackson转换核心包依赖-->
<dependency>
<groupId>
com.fasterxml.jackson.core
</groupId>
<artifactId>
jackson-core
</artifactId>
<version>
2.9.2
</version>
</dependency>
<!--Jackson转换的数据绑定包依赖-->
<dependency>
<groupId>
com.fasterxml.jackson.core
</groupId>
<artifactId>
jackson-databind
</artifactId>
<version>
2.9.2
</version>
</dependency>
<!--Jackson JSON转换注解包-->
<dependency>
<groupId>
com.fasterxml.jackson.core
</groupId>
<artifactId>
jackson-annotations
</artifactId>
<version>
2.9.0
</version>
</dependency>
</dependencies>
</project>
2.在项目中导入jQuery文件
3.创建一个商品信息页面products.jsp,在products.jsp中创建一个表单用于填写商品信息,表单提交时,表单发送异步请求将表单的商品信息发送到处理器。
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/27
Time: 0:15
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>异步提交商品</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/static/js/jquery.js"></script>
</head>
<body>
<form id="products">
<table border="1">
<tr>
<th>商品id</th>
<th>商品名称</th>
<th>提交</th>
</tr>
<tr>
<td>
<input name="proId" value="1" id="proId" type="text">
</td>
<td><input name="proName" value="三文鱼" id="proName" type="text"></td>
<td><input type="button" value="提交单个商品" onclick="sumbmitProduct()"></td>
</tr>
<tr>
<td><input name="proId" value="2" id="proId2" type="text"></td>
<td><input name="proName" value="红牛" id="proName2" type="text"></td>
<td><input type="button" value="提交多个商品" onclick="submitProducts()"></td>
</tr>
</table>
</form>
<script type="text/javascript">
function sumbmitProduct() {
var proId = $("#proId").val();
var proName = $("#proName").val();
$.ajax({
url: "${pageContext.request.contextPath }/getProduct",
type: "post",
data: JSON.stringify({proId: proId, proName: proName}),
contentType: "application/json;charset=UTF-8",
dataType: "json",
success: function (response) {
alert(response);
}
});
}
function submitProducts() {
var pro1 = {proId: $("#proId").val(), proName: $("#proName").val()}
var pro2 = {proId: $("#proId2").val(), proName: $("#proName2").val()}
$.ajax({
url: "${pageContext.request.contextPath }/getProductList",
type: "post",
data: JSON.stringify([pro1, pro2]),
contentType: "application/json;charset=UTF-8",
dataType: "json",
success: function (response) {
alert(response);
}
});
}
</script>
</body>
</html>
4.修改ProductController.java类,在ProductController类中新增getProduct()方法,用于获取客户端提交的单个商品信息。在ProductController类中新增getProductList()方法,用于获取客户端提交的多个商品信息。
package cn.hdc.controller;
import cn.hdc.pojo.Product;
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.RequestParam;
import java.util.List;
@Controller
public class ProductController {
// @RequestMapping("/getProducts")
// public String getProducts(String[] proIds) {
// for (String proId : proIds) {
// System.out.println("商品的id为:" + proId);
// }
// return "success";
// }
// @RequestMapping("/getProducts")
// public String getProducts(@RequestParam("proIds") List<String> proIds) {
// for (String proId : proIds) {
// System.out.println("商品的id为:" + proId);
// }
// return "success";
// }
@RequestMapping("/getProduct")
public String getProduct(@RequestBody Product product) {
System.out.println("单个商品:" + product);
return "success";
}
@RequestMapping("/getProductList")
public String getProductList(@RequestBody List<Product> productList) {
System.out.println("多个商品:");
productList.forEach(product -> {
System.out.println(product);
});
return "success";
}
}
5.spring-mvc.xml:在项目的web.xml文件中配置的DispatcherServlet会拦截所有URL,导致项目中的静态资源(如css、jsp、 js等)也被DispatcherServlet拦截。如果想放行静态资源可以在Spring MVC的配置文件中进行静态资源配置。增加的代码如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:content="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
<content:component-scan base-package="cn.hdc.controller"></content:component-scan>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/static/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 基于XML配置自定义转换器实现-->
<!-- <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">-->
<!-- <property name="converters">-->
<!-- <array>-->
<!-- <bean class="cn.hdc.convert.DateConverter"></bean>-->
<!-- </array>-->
<!-- </property>-->
<!-- </bean>-->
<!-- <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>-->
<!-- 基于注解自定义转换器实现-->
<mvc:annotation-driven></mvc:annotation-driven>
<mvc:resources mapping="/static/js/**" location="/static/js/"></mvc:resources>
<!-- <mvc:default-servlet-handler></mvc:default-servlet-handler>-->
</beans>
6.项目结构:(注意用的是products.jsp)
运行结果:
从图中所示的打印信息可以得出,客户端异步提交的JSON数据,按照形参product属性的格式进行关联映射,并赋值给product对应的属性,完成了JSON数据的绑定。
<mvc:resources .../>的两个重要属性
JSON转换器配置和静态资源访问配置
JSON转换器配置和静态资源访问配置,除了之前讲解的配置方案之外,还可以通过其他方式完成,下面讲解两种配置方式,使用<bean>元素配置JSON转换器和静态资源访问的配置方式。
使用<bean>元素配置JSON转换器
在配置JSON转换器时,除了常用的<mvc:annotation-driven />元素,还可以使用<bean>元素进行显示的配置,<bean>元素配置JSON转换器方式具体如下所示。
静态资源访问的配置方式
页面跳转
返回值为void类型的页面跳转到默认页面
当Spring MVC方法的返回值为void类型,方法执行后会跳转到默认的页面。默认页面的路径由方法映射路径和视图解析器中的前缀、后缀拼接成,拼接格式为“前缀+方法映射路径+后缀”。如果Spring MVC的配置文件中没有配置视图解析器,则会报HTTP Status 500错误。
代码示例:
1.创建一个页面跳转类PageController,在PageController类中定义方法showPageByVoid(),用于测试Spring MVC方法返回值为void的页面跳转。
package cn.hdc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
@RequestMapping("/register")
public void showPageByVoid() {
System.out.println("showPageByVoid running");
}
}
项目结构:
运行结果:
访问地址后,执行了showPageByVoid()方法,并且在方法执行后成功跳转到static文件夹下的register.jsp页面。页面虽然跳转了,但是浏览器地址栏没有变化,原因是Spring MVC对请求默认按转发的方式进行响应。
反回值为String类型,不携带数据的页面跳转
代码示例:
1.修改文件PageController.java,新增showPageByString()方法,用于测试返回值为String类型的页面跳转,showPageByString()方法的实现代码如下所示。
package cn.hdc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
@RequestMapping("/register")
public void showPageByVoid() {
System.out.println("showPageByVoid running");
}
@RequestMapping("/showPageByString")
public String showPageByString() {
System.out.println("showPageByString running");
return "register";
}
@RequestMapping("/showPageByForward")
public String showPageByForward() {
System.out.println("showPageByForward running");
// 视图解析器不在生效
return "forward:static/order.jsp";
}
@RequestMapping("/showPageByRedirect")
public String showPageByRedirect() {
System.out.println("showPageByRedirect running");
// 视图解析器不在生效
return "redirect:https://www.baidu.com";
}
}
项目结构:
运行结果:
返回值为String类型的页面跳转的转发方式
当方法的返回值为普通的字符串时,Spring MVC在方法执行后会默认以转发的方式响应给客户端。除了这种默认的转发方式,还可以返回指定前缀的字符串,来设定处理器执行后对请求进行转发还是重定向,设定转发和重定向的字符串格式如下所示。
- forward:需要转发到的资源路径
- redirect:需要重定向到的资源路径
注意:方法返回的字符串一旦添加了“forward:”或“redirect:”前缀,那么视图解析器不再会为
方法返回值拼接前缀和后缀了。
目标:
掌握返回值为String类型的页面跳转-携带数据,能够在程序中使用String返回值类型进行页面跳转
携带数据
在此之前,本章所有转发的案例都只是直接跳转到页面,并未在转发时携带数据到页面。在实际开发中,在转发时常常需要携带数据。在讲解Spring MVC的数据绑定时,展示了SpringMVC默认支持的数据类型,在转发时也可以通过这些默认类型的对象完成数据的携带。接下来通过一个案例演示携带数据的页面转发,该案例使用HttpServletRequest类型形参和Model类型形参进行数据传递。
代码示例:
1.修改文件PageController.java,新增showPageByRequest()方法和showPageByModel()方法。
package cn.hdc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
public class PageController {
@RequestMapping("/register")
public void showPageByVoid() {
System.out.println("showPageByVoid running");
}
@RequestMapping("/showPageByString")
public String showPageByString() {
System.out.println("showPageByString running");
return "register";
}
@RequestMapping("/showPageByForward")
public String showPageByForward() {
System.out.println("showPageByForward running");
// 视图解析器不在生效
return "forward:static/order.jsp";
}
@RequestMapping("/showPageByRedirect")
public String showPageByRedirect() {
System.out.println("showPageByRedirect running");
// 视图解析器不在生效
return "redirect:https://www.baidu.com";
}
@RequestMapping("/showPageByRequest")
public String showPageByRequest(HttpServletRequest request) {
System.out.println("showPageByRequest running");
request.setAttribute("username", "Tom");
return "register";
}
@RequestMapping("/showPageByModel")
public String showPageByModel(Model model) {
System.out.println("showPageByModel running");
model.addAttribute("username", "Tom");
return "register";
}
}
2.在register.jsp的表单中添加value属性,用于接收转发传递过来的数据。
运行结果:
返回值为ModelAndView类型的页面跳转
ModelAndView对象组成部分
使用方法的返回值可以设定跳转的逻辑视图名称,使用Model等对象实现页面跳转时传输数据。除此之外,Spring MVC还提供了兼顾视图和数据的对象ModelAndView ,ModelAndView对象包含视图相关内容和模型数据两部分,其中视图相关的内容可以设置逻辑视图的名称,也可以设置具体的View实例﹔模型数据则会在视图渲染过程中被合并到最终的视图输出。
ModelAndView设置视图和数据模型的方法
ModelAndView方法说明
setViewName()方法和setView()方法都是为ModelAndView对象设置视图的方法,其中前者使用更方便,因此setViewName()方法比较常用。后3个方法都是向ModelAndView对象中添加模型数据的,其中addObject(Object attributeValue)方法添加的attributeValue,默认名称为attributeValue类型全限定名的最后一个单词且首字母小写;addObject(String attributeName, Object attributeValue)方法可以在页面上以${attributeName}方式取出attributeValue。
代码示例:
1.修改文件PageController.java,新增showModelAndView()方法,在showModelAndView()方法中使用ModelAndView封装数据和视图,完成页面跳转时传递数据。
package cn.hdc.controller;
import cn.hdc.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@Controller
public class PageController {
@RequestMapping("/register")
public void showPageByVoid() {
System.out.println("showPageByVoid running");
}
@RequestMapping("/showPageByString")
public String showPageByString() {
System.out.println("showPageByString running");
return "register";
}
@RequestMapping("/showPageByForward")
public String showPageByForward() {
System.out.println("showPageByForward running");
// 视图解析器不在生效
return "forward:static/order.jsp";
}
@RequestMapping("/showPageByRedirect")
public String showPageByRedirect() {
System.out.println("showPageByRedirect running");
// 视图解析器不在生效
return "redirect:https://www.baidu.com";
}
@RequestMapping("/showPageByRequest")
public String showPageByRequest(HttpServletRequest request) {
System.out.println("showPageByRequest running");
request.setAttribute("username", "Tom");
return "register";
}
@RequestMapping("/showPageByModel")
public String showPageByModel(Model model) {
System.out.println("showPageByModel running");
model.addAttribute("username", "Tom");
return "register";
}
@RequestMapping("/showModelAndView")
public ModelAndView showModelAndView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", "Tom");
User user = new User();
user.setPassword("123456");
modelAndView.addObject("user", user);
modelAndView.setViewName("register");
return modelAndView;
}
}
2.修改register.jsp
运行结果:
数据回写
代码示例:
1.创建一个数据回写类DataController,在DataController类中定义showDataByResponse()方法,用于测试在Spring MVC中普通字符串的回写。
package cn.hdc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class DataController {
@RequestMapping("/showDataByResponse")
public void showDataByResponse(HttpServletResponse response) throws IOException {
response.getWriter().write("success");
}
}
运行结果:
JSON数据的回写
代码示例:
1.修改文件DataController.java,在DataController类中新增showDataByJSON()方法,用于将对象转换成JSON数据并写入输出流中完成回写。
package cn.hdc.controller;
import cn.hdc.pojo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class DataController {
@RequestMapping("/showDataByResponse")
public void showDataByResponse(HttpServletResponse response) throws IOException {
response.getWriter().write("success");
}
// @RequestMapping("/showDataByJson")
// public void showDataByJson(HttpServletResponse response) throws IOException {
// User user = new User();
// user.setUsername("tom");
// user.setPassword("12346");
// ObjectMapper objectMapper = new ObjectMapper();
// String json = objectMapper.writeValueAsString(user);
// response.getWriter().write(json);
// }
@RequestMapping("/showDataByJson")
@ResponseBody
public void showDataByJson(HttpServletResponse response) throws IOException {
User user = new User();
user.setUsername("tom");
user.setPassword("12346");
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(user);
response.getWriter().write(json);
}
}
运行结果:
由图中所示的内容可以得出,访问地址后,执行了showDataByJSON()方法,方法执行后将User对象的数据转换成JSON格式的数据输出到请求页面中了。
@ResponseBody注解的使用范围
@ResponseBody注解可以标注在方法和类上,当标注在类上时,表示该类中的所有方法均应用@ResponseBody注解。如果需要当前类中的所有方法均应用@ResponseBody注解,也可以使用@RestController注解。
@ResponseBody注解的2个使用要求
使用@ResponseBody注解,项目至少需要符合2个要求,分别如下所示。项目中有转换JSON相关的依赖。可以配置转换JSON数据的消息类型转换器。针对上述两个要求,该项目都已经满足,项目的pom.xml文件中引入了Jackson相关的依赖,可以用于转换JSON ; Spring MVC的配置文件中配置的<mvc:annotation-driven />元素默认注册了Java数据转JSON数据的消息转换器。
集合数据转换成JSON数据后的回写
代码示例:
1.修改DataController.java,在Datacontroller尖中新增getUser)方法和addProducts()方法,分别用于返回JSON类型的User信息和用于返回JSON类型的Product列表信息。
package cn.hdc.controller;
import cn.hdc.pojo.Product;
import cn.hdc.pojo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Controller
public class DataController {
@RequestMapping("/showDataByResponse")
public void showDataByResponse(HttpServletResponse response) throws IOException {
response.getWriter().write("success");
}
// @RequestMapping("/showDataByJson")
// public void showDataByJson(HttpServletResponse response) throws IOException {
// User user = new User();
// user.setUsername("tom");
// user.setPassword("12346");
// ObjectMapper objectMapper = new ObjectMapper();
// String json = objectMapper.writeValueAsString(user);
// response.getWriter().write(json);
// }
@RequestMapping("/showDataByJson")
@ResponseBody
public void showDataByJson(HttpServletResponse response) throws IOException {
User user = new User();
user.setUsername("tom");
user.setPassword("12346");
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(user);
response.getWriter().write(json);
}
@RequestMapping("/getUser")
@ResponseBody
public User getUser() {
User user = new User();
user.setUsername("tom");
user.setPassword("12346");
return user;
}
@RequestMapping("/addProducts")
@ResponseBody
public List<Product> addProduct() {
List<Product> productList = new ArrayList<>();
Product product = new Product();
product.setProId("p001");
product.setProName("三文鱼");
Product product1 = new Product();
product1.setProId("p002");
product1.setProName("茅台");
productList.add(product);
productList.add(product1);
return productList;
}
}
2.创建一个商品添加页面product_add.jsp,在product_add.jsp中创建一个表格,用于显示用户信息和添加商品信息。product_add.jsp的部分代码如下所示。
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2023/5/27
Time: 2:20
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>商品添加</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/static/js/jquery.js"></script>
</head>
<body>
<table id="products" border="1" width="60%">
<tr align="center">
<td>欢迎您:</td>
<td id="username"></td>
</tr>
<tr align="center">
<td colspan="2" align="center">
<input type="button" value="添加多个商品" onclick="addProducts()">
</td>
</tr>
<tr align="center">
<td>商品id</td>
<td>商品名称</td>
</tr>
</table>
<script type="text/javascript">
//显示当前用户名
window.onload = function () {
var url = "${pageContext.request.contextPath }/getUser";
$.get(url, function (response) {
//将处理器返回的用户信息中的用户名显示在表格中
$("#username").text(response.username);
})
}
//添加商品
function addProducts() {
var url = "${pageContext.request.contextPath }/addProducts";
$.get(url, function (products) {
//将处理器返回的商品列表信息添加到表格中
for (var i = 0; i < products.length; i++) {
$("#products").append("<tr><td>" + products[i].proId + "</td><td>" + products[i].proName + "</td></tr>");
}
})
}
</script>
</body>
</html>
运行结果:
由图中所示的内容可以得出,页面加载完,页面异步将用户的信息显示在单元格中,成功回写了User对象信息对应的JSON数据。单击上图所示的“添加多个商品”按钮,程序成功回写了List对应的JSON数据。
项目地址