一、消息转换器—HttpMessageConverter接口
客户端不同的请求,HttpServletRequest中数据的MediaType可能会不同,如果想将HttpServletRequest中的数据转换成指定对象,或者将对象转换成指定格式的数据,就需要使用对应的消息转换器来实现。Spring中提供了一个HttpMessageConverter接口作为消息转换器。因为数据的类型有多种,所以Spring中提供了多个HttpMessageConverter接口的实现类,其中MappingJackson2HttpMessageConverter是HttpMessageConverter接口的实现类之一,在处理请求时,可以将请求的JSON报文绑定到处理器的形参对象,在响应请求时,将处理器的返回值转换成JSON报文。
二、HttpMessageConverter与Converter类型转换器的区别
需要注意的是,HttpMessageConverter消息转换器和之前所学习的Converter类型转换器是有区别的。HttpMessageConverter消息转换器用于将请求消息中的报文数据转换成指定对象,或者将对象转换成指定格式的报文进行响应;Converter类型转换器用于对象之间的类型转换。
接下来通过一个异步提交商品信息案例,演示Spring MVC中的JSON数据绑定,案例具体实现步骤如下。
1、在项目的pom.xml文件中导入Jackson的依赖。
<!--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>
2、在项目中导入jQuery文件
由于本次演示的是异步数据提交,需要使用jQuery,所以需要将jQuery文件导入到项目中,以便发送ajax请求。在项目的/webapp文件夹下创建名称为js的文件夹,在js文件夹中导入jQuery文件。
3、创建一个商品信息页面product.jsp,在product.jsp中创建一个表单用于填写商品信息,表单提交时,表单发送异步请求将表单的商品信息发送到处理器。product.jsp的部分代码如下所示。
<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);} }); }
</script>
4、修改ProductController.java类,在ProductController类中新增getProduct()方法和getProductList()方法,分别用于获取客户端提交的单个商品信息和多个商品信息。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<html>
<head><title>异步提交商品</title><script type="text/javascript"src="${pageContext.request.contextPath }/js/jquery-3.6.0.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>
5、在项目的web.xml文件中配置的DispatcherServlet会拦截所有URL,导致项目中的静态资源(如css、jsp、js等)也被DispatcherServlet拦截。如果想放行静态资源,可以在Spring MVC的配置文件中进行静态资源配置。Spring MVC配置文件的部分配置代码如下所示。
<!-- 配置要扫描的包 --><context:component-scan base-package="com.test.controller"/><!-- 配置视图解析器 --><bean class= “org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/pages/"/><property name="suffix" value=".jsp"/></bean><!-- 配置注解驱动 --><mvc:annotation-driven /><!--配置静态资源的访问映射,此配置中的文件,将不被前端控制器拦截 --><mvc:resources mapping="/js/**" location="/js/" />
三、<mvc:resources …/>的两个重要属性
属性 | 说明 |
location | 用于定位需要访问的本地静态资源文件路径,具体到某个文件夹 |
mapping | 匹配静态资源全路径,其中“/**”表示文件夹及其子文件夹下的某个具体文件 |
6、启动chapter12项目,在浏览器中访问商品信息页面product.jsp,访问地址为http://localhost:8080/chapter12/product.jsp。
7、在product.jsp的显示效果图所示的页面中,单击右侧“提交单个商品”按钮,product.jsp表单中的单个商品信息以JSON格式异步发送到服务器端getProduct()方法中。提交单个商品时控制台打印信息如图所示。
获取到的Id为1名称为三文鱼的商品
从图中所示的打印信息可以得出,客户端异步提交的JSON数据,按照形参product属性的格式进行关联映射,并赋值给product对应的属性,完成了JSON数据的绑定。
8、在product.jsp的显示效果图所示的页面中,单击“提交多个商品”按钮,product.jsp表单中的2个商品信息以JSON格式异步发送到服务器端getProductList()方法中。提交多个商品时控制台打印信息如图所示。
获取到的Id为1名称为三文鱼的商品
获取到的Id为2名称为红牛的商品
从图中所示的打印信息可以得出,客户端异步提交的JSON数据,按照形参products的存储结构进行关联映射,并赋值给products中对象的对应属性,完成了JSON数据的绑定。
四、JSON转换器配置和静态资源访问配置
JSON转换器配置和静态资源访问配置,除了之前讲解的配置方案之外,还可以通过其他方式完成,下面讲解两种配置方式,使用<bean>元素配置JSON转换器和静态资源访问的配置方式。
(一)使用<bean>元素配置JSON转换器
在配置JSON转换器时,除了常用的<mvc:annotation-driven />元素,还可以使用<bean>元素进行显示的配置,<bean>元素配置JSON转换器方式具体如下所示。
<!-- 使用<bean>元素配置注解方式的处理器映射器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<!-- 使用<bean>元素配置注解方式的处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"><property name="messageConverters"><list><!-- 配置JSON转换器 --><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></list></property>
</bean>
(二)静态资源访问的配置方式
除了使用<mvc:resources>元素实现对静态资源的访问外,Spring MVC还提供了另外2种静态资源访问的配置方式。
(1)使用<mvc:default-servlet-handler>配置静态资源
在Spring MVC的配置文件中,使用<mvc:default-servlet-handler>元素配置静态资源,也可以实现对静态资源的访问。配置静态资源的具体代码如下:
<mvc:default-servlet-handler />
在Spring MVC的配置文件中配置<mvc:default-servlet-handler />后,Spring MVC会在Spring MVC上下文中定义一个默认的Servlet请求处理器DefaultServletHttpRequestHandler,该处理器会对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web服务器默认的Servlet处理,默认的Servlet会对静态资源放行;如果不是静态资源的请求,就由DispatcherServlet继续处理。
(2)激活Tomcat默认的Servlet来处理静态资源访问
在web.xml文件中激活Tomcat默认的Servlet去处理对应的静态资源,web.xml配置代码如下所示:
<servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.js</url-pattern>
</servlet-mapping><servlet-mapping><servlet-name>default</servlet-name><url-pattern>*.css</url-pattern>
</servlet-mapping> ...
在上述代码中, <servlet-mapping>元素可以激活Tomcat默认的Servlet来处理静态文件。在配置时,可以根据需要继续追加<servlet-mapping>。此种配置方式和第(1)种方式本质上是一样的,都是使用Web服务器默认的Servlet来处理静态资源文件的访问。