学科分类
目录
SSM框架

JSON数据转换

为了实现浏览器与控制器类(Controller)之间的数据交互,Spring提供了一个HttpMessageConverter<T>接口来完成此项工作。该接口主要用于将请求信息中的数据转换为一个类型为T的对象,并将类型为T的对象绑定到请求方法的参数中,或者将对象转换为响应信息传递给浏览器显示。

Spring为HttpMessageConverter<T>接口提供了很多实现类,这些实现类可以对不同类型的数据进行信息转换。其中MappingJackson2HttpMessageConverter是Spring MVC默认处理JSON格式请求响应的实现类。该实现类利用Jackson开源包读写JSON数据,将Java对象转换为JSON对象和XML文档,同时也可以将JSON对象和XML文档转换为Java对象。

要使用MappingJackson2HttpMessageConverter对数据进行转换,就需要使用Jackson的开源包,开发时所需的开源包及其描述如下所示:

● jackson-annoations-2.8.8.jar:JSON转换注解包;

● jackson-core-2.8.8.jar:JSON转换核心包;

● jackson-databind-2.8.8.jar:JSON转换的数据绑定包。

以上3个Jackson的开源包在本书编写时的最新稳定版本为2.8.8,读者可以通过链接“http://mvnrepository.com/artifact/com.fasterxml.jackson.core”下载得到,也可以在配套资源的源代码中找到Jackson的开源包。

在使用注解式开发时,需要用到2个重要的JSON格式转换注解,分别为@RequestBody和@ResponseBody,关于这两个注解的说明如表1所示。

表1 JSON数据交互注解及说明

注解 说明
@RequestBody 用于将请求体中的数据绑定到方法的形参中。该注解用在方法的形参上。
@ResponseBody 用于直接返回return对象。该注解用在方法上。

了解了Spring MVC中JSON数据交互需要使用的类和注解后,接下来通过一个案例来演示如何进行JSON数据的交互,具体实现步骤如下。

(1)创建项目并导入相关JAR包。使用Eclipse创建一个名为chapter14的Web项目,然后将Spring MVC相关JAR包、JSON转换包添加到项目的lib目录中,并发布到类路径下。添加后的lib目录如图1所示。

图1 项目相关JAR包

(2)在web.xml中,对Spring MVC的前端控制器等信息进行配置,如文件1所示。

文件1 web.xml

 1    <?xml version="1.0" encoding="UTF-8"?>
 2    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 4              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
 5              http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 6              id="WebApp_ID" version="3.1">
 7      <display-name>chapter14</display-name>
 8      <welcome-file-list>
 9           <welcome-file>index.jsp</welcome-file>
 10      </welcome-file-list>
 11      <!-- 配置Spring MVC前端控制器 DispatcherServlet -->
 12      <servlet>
 13           <servlet-name>springmvc</servlet-name>
 14           <servlet-class>
 15               org.springframework.web.servlet.DispatcherServlet
 16           </servlet-class>
 17           <!-- 配置Spring MVC加载配置文件路径 -->
 18           <init-param>
 19              <param-name>contextConfigLocation</param-name>
 20              <param-value>classpath:springmvc-config.xml</param-value>
 21           </init-param>
 22           <!-- 配置服务器启动后立即加载Spring MVC配置文件 -->
 23           <load-on-startup>1</load-on-startup>
 24       </servlet>
 25       <servlet-mapping>
 26           <servlet-name>springmvc</servlet-name>
 27           <url-pattern>/</url-pattern>
 28       </servlet-mapping>
 29    </web-app>

(3)在src目录下,创建Spring MVC的核心配置文件springmvc-config.xml,编辑后的代码如文件2所示。

文件2 springmvc-config.xml

 1    <beans xmlns="http://www.springframework.org/schema/beans"
 2      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 3      xmlns:mvc="http://www.springframework.org/schema/mvc"
 4      xmlns:context="http://www.springframework.org/schema/context"
 5      xmlns:tx="http://www.springframework.org/schema/tx"
 6      xsi:schemaLocation="http://www.springframework.org/schema/beans 
 7      http://www.springframework.org/schema/beans/spring-beans-4.3.xsd 
 8      http://www.springframework.org/schema/mvc 
 9      http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd 
 10      http://www.springframework.org/schema/context 
 11      http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 12        <!-- 定义组件扫描器,指定需要扫描的包 -->
 13        <context:component-scan base-package="com.itheima.controller" />    
 14        <!-- 配置注解驱动 -->
 15        <mvc:annotation-driven />
 16        <!--配置静态资源的访问映射,此配置中的文件,将不被前端控制器拦截 -->
 17        <mvc:resources location="/js/" mapping="/js/**" />
 18         <!-- 配置视图解析器  -->
 19        <bean class=
 20        "org.springframework.web.servlet.view.InternalResourceViewResolver">
 21            <property name="prefix" value="/WEB-INF/jsp/" />
 22            <property name="suffix" value=".jsp" />
 23        </bean>
 24    </beans>

在文件2中,不仅配置了组件扫描器和视图解析器,还配置了Spring MVC的注解驱动<mvc:annotation-drivern />和静态资源访问映射<mvc:resources …/>。其中<mvc:annotation-drivern />配置会自动注册RequestMappingHandlerMapping和RequestMappingHandlerAdapter两个Bean,并提供对读写XML和读写JSON等功能的支持。<mvc:resources… />元素用于配置静态资源的访问路径。由于在web.xml中配置的“/”会将页面中引入的静态文件也进行拦截,而拦截后页面中将找不到这些静态资源文件,这样就会引起页面报错。而增加了静态资源的访问映射配置后,程序会自动的去配置路径下找静态的内容。

<mvc:resources …/>中有两个重要属性location和mapping,关于这两个属性的说明如表2所示。

表2 <mvc:resources>标签属性及说明

属性 说明
location 用于定位需要访问的本地静态资源文件路径,具体到某个文件夹
mapping 匹配静态资源全路径,其中“/**”表示文件夹及其子文件夹下的某个具体文件

(4)在src目录下,创建一个com.itheima.po包,并在包中创建一个User类,该类用于封装User类型的请求参数,编辑后如文件3所示。

文件3 User.java

 1    package com.itheima.po;
 2    /**
 3     * 用户POJO
 4     */
 5    public class User {
 6        private String username;
 7        private String password;
 8        public String getUsername() {
 9            return username;
 10        }
 11        public void setUsername(String username) {
 12            this.username = username;
 13        }
 14        public String getPassword() {
 15            return password;
 16        }
 17        public void setPassword(String password) {
 18            this.password = password;
 19        }
 20        @Override
 21        public String toString() {
 22         return "User [username=" + username + ", password=" + password + "]";
 23        }
 24    }

在文件3中,定义了username和password属性,及其对应的getter/setter方法,同时为了方便查询结果重写了toString()方法。

(5)在WebContent目录下,创建页面文件index.jsp来测试JSON数据交互,编辑后如文件4所示。

文件4 index.jsp

 1    <%@ page language="java" contentType="text/html; charset=UTF-8"
 2         pageEncoding="UTF-8"%>
 3    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
 4    "http://www.w3.org/TR/html4/loose.dtd">
 5    <html>
 6    <head>
 7    <title>测试JSON交互</title>
 8    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 9    <script type="text/javascript" 
 10          src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js">
 11    </script>
 12    <script type="text/javascript">
 13    function testJson(){
 14        // 获取输入的用户名和密码
 15        var username = $("#username").val();
 16        var password = $("#password").val();
 17        $.ajax({
 18            url : "${pageContext.request.contextPath }/testJson",
 19            type : "post", 
 20            // data表示发送的数据
 21            data : JSON.stringify({username:username,password:password}),
 22            // 定义发送请求的数据格式为JSON字符串
 23            contentType : "application/json;charset=UTF-8",
 24            //定义回调响应的数据格式为JSON字符串,该属性可以省略
 25            dataType : "json",
 26            //成功响应的结果
 27            success : function(data){
 28                if(data != null){                    
 29                  alert("您输入的用户名为:"+data.username+
 30                                     "密码为:"+data.password);
 31                }
 32            }
 33        });
 34    }
 35    </script>
 36    </head>
 37    <body>
 38        <form>
 39            用户名:<input type="text" name="username" id="username"><br />
 40            密&nbsp;&nbsp;&nbsp;码:
 41              <input type="password" name="password" id="password"><br />
 42             <input type="button" value="测试JSON交互" onclick=" testJson()" />
 43        </form> 
 44    </body>
 45    </html>

在文件4中,编写了一个测试JSON交互的表单,当单击按钮“测试JSON交互”时,会执行页面中的testJson()函数。在函数中使用了jQuery的AJAX方式将JSON格式的用户名和密码传递到以“/testJson”结尾的请求中。

需要注意的是,在AJAX中包含了3个特别重要的属性,其说明如下:

● data:即请求时携带的数据,当使用JSON格式时,要注意编写规范;

● contentType:当请求数据为JSON格式时,值必须为application/json;

● dataType:当响应数据为JSON时,可以定义dataType属性,并且值必须为json。其中dataType : "json"也可以省略不写,页面会自动识别响应的数据格式。

小提示:

在上述测试页面index.jsp中使用的是jQuery的AJAX进行的JSON数据提交和响应,所以还需要引入jquery.js文件。本示例是引入了WebContent目录下js文件夹中的jquery-1.11.3.min.js,读者可在所提供的源码中找到此文件。

(6)在src目录下,创建一个com.itheima.controller包,在该包下创建一个用于用户操作的控制器类UserController,编辑后的代码如文件5所示。

文件5 UserController.java

 1    package com.itheima.controller;
 2    import org.springframework.stereotype.Controller;
 3    import org.springframework.web.bind.annotation.RequestBody;
 4    import org.springframework.web.bind.annotation.RequestMapping;
 5    import org.springframework.web.bind.annotation.ResponseBody;
 6    import com.itheima.po.User;
 7    @Controller
 8    public class UserController {
 9        /**
 10         * 接收页面请求的JSON数据,并返回JSON格式结果
 11         */
 12        @RequestMapping("/testJson")
 13        @ResponseBody
 14        public User testJson(@RequestBody User user) {
 15            // 打印接收的JSON格式数据
 16            System.out.println(user);
 17            // 返回JSON格式的响应
 18            return user;
 19        }
 20    }

在文件5中,使用注解方式定义了一个控制器类,并编写了接收和响应JSON格式数据的testJson()方法,在方法中接收并打印了接收到的JSON格式的用户数据,然后返回了JSON格式的用户对象。

方法中的@RequestBody注解用于将前端请求体中的JSON格式数据绑定到形参user上,@ResponseBody注解用于直接返回User对象(当返回POJO对象时,会默认转换为JSON格式数据进行响应)。

(7)将chapter14项目发布到Tomcat服务器并启动,在浏览器中访问地址http://localhost:8080/chapter14/index.jsp,其显示效果如图2所示。

图2 index.jsp测试页面

在两个输入框中分别输入用户名“jack”和密码“123456”后,单击“测试JSON交互”按钮,当程序正确执行时,页面中会弹出显示用户名和密码的弹出框,如图3所示。

图3 index.jsp测试页面

与此同时,Eclipse的控制台中也会显示相应数据,如图4所示。

图4 运行结果

从图3和图4的显示结果可以看出,编写的代码已经正确实现了JSON数据交互,可以将JSON格式的请求数据转换为方法中的Java对象,也可以将Java对象转换为JSON格式的响应数据。

多学一招:JSON数据的其他转换配置

1. 使用<bean>标签方式的JSON转换器配置

在配置JSON转换器时,除了常用的<mvc:annotation-drivern />方式配置外,还可以使用<bean>标签的方式进行显示的配置。具体配置方式如下:

<!-- <bean>标签配置注解方式的处理器映射器和处理器适配器必须配对使用-->
<!-- 使用<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>

从上述示例可以看出,使用<bean>标签配置方式配置JSON转换器时,需要同时配置处理器映射器和处理器适配器,并且JSON转换器是配置在适配器中。

2. 配置静态资源访问的方式

除了使用<mvc:resources>元素可以实现对静态资源的访问外,还有另外2种静态资源访问的配置方式,具体分别如下:

(1)使用<mvc:default-servlet-handler>标签。

在springmvc-config.xml文件中,使用<mvc:default-servlet-handler>标签,具体如下:

<mvc:default-servlet-handler />

在springmvc-config.xml中配置<mvc:default-servlet-handler />后,会在Spring MVC上下文中定义一个org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler(即默认的Servlet请求处理器)。它会像一个检查员,对进入DispatcherServlet的URL进行筛查,如果发现是静态资源的请求,就将该请求转由Web服务器默认的Servlet处理,默认的Servlet就会对这些静态资源放行,如果不是静态资源的请求,才由DispatcherServlet继续处理。

注意:

一般Web服务器默认的Servlet名称是"default",因此DefaultServletHttpRequestHandler可以找到它。如果你使用的Web应用服务器默认的Servlet名称不是"default",则需要通过default-servlet-name属性显示指定,具体方式如下:

<mvc:default-servlet-handler  default-servlet-name="Servlet名称" />

而Web服务器的Servlet名称是由使用的服务器确定的,常用服务器及其Servlet名称如下:

● Tomcat, Jetty, JBoss, and GlassFish默认Servlet的名称—— "default";

● Google App Engine默认Servlet的名称——"_ah_default";

● Resin默认Servlet的名称——"resin-file";

● WebLogic默认Servlet的名称—— "FileServlet";

● WebSphere默认Servlet的名称——"SimpleFileServlet"。

(2)激活Tomcat默认的Servlet来处理静态文件访问。

激活Tomcat默认的Servlet时,需要在web.xml中添加以下内容:

<!--激活tomcat的静态资源拦截,需要哪些静态文件,再往下追加-->
<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>。此种配置方式和上一种方式本质上是一样的,都是使用Web服务器默认的Servlet来处理静态资源文件的访问。其中Servelt名称(即<servlet-name>元素的值)也是由使用的服务器来确定的,不同的服务器需要使用不同的名称。

以上3种静态资源访问的配置方式不同,并且各有优缺点,具体如下:

● 第一和第三种配置方式可以选择性的释放静态资源;

● 第二种配置方式配置相对简单,只需要一行代码,就可以释放所有静态资源;

● 第二和第三种配置方式会导致项目移植性较差,需要根据具体的Web服务器来更改Servlet名称;

● 第三种配置方式运行效率更高,因为服务器启动时已经加载了web.xml中的静态资源。

在实际开发中,更为常用的配置还是第一种(即案例中的)配置方式,这样就不需要考虑Web服务器的问题了。

点击此处
隐藏目录