AJAX

1. 响应正文

在SpringMVC中,处理完请求之后,默认的响应方式是转发或重定向,这种操作会导致用户看到的界面会发生变化(将看到另一个页面),这种做法的缺陷在于:

  1. 用户体验较差,例如操作失败时,不能直接在当前页面提示错误,只能用另一个页面来提示,当用户尝试再次操作时,需要先返回到原有页面,才可以进行下一次操作;

  2. 产生的流量消耗较大,用于提示错误的页面,也是一个完整的页面,相对于只响应正文而言,流量的消耗会大很多,直接导致用户体验较差,并且流量费会增加;

  3. 对多平台设备的兼容较差,如果服务器端响应的是一个html页面(含JSP),可能不适用于在手机端、平板电脑等其它设备上直接显示。

目前,主流的开发模式是服务器端处理完请求之后,只向客户端响应正文(客户端应该得到的数据),由客户端(前端页面、Android APP、iOS APP及其它客户端软件)组织并呈现这些数据。

如果需要服务器端处理请求时能响应正文,需要在处理请求的方法之前添加@ResponseBody注解,并在Spring的配置文件中,添加注解驱动<mvc:annotation-driven />

添加了@ResponseBody注解的方法,其返回值就是将响应到客户端的数据。

2. 响应正文的数据格式

服务器端响应给客户的数据应该是有数据格式的,否则,当客户端接收到响应结果时,可能无法分析出其中的数据意义,例如当客户端请求的是某个用户的资料,其中应该包含用户的名称、年龄、手机号码、电子邮箱等,这些数据如果组织在1个字符串中,没有特定的数据格式的话,客户端将无从解析,从中得到哪些是用户的名称,哪些是年龄等。

早期推荐使用XML组织数据的格式,例如:

<data>
    <username>root</username>
    <age>16</age>
    <email>root@tedu.cn</email>
</data>

当客户端接收到以上XML格式的字符串时,通过XML解析技术,就可以得到其中的用户名、年龄、邮箱。

目前推荐使用更加轻量级的JSON格式的数据,例如:

{
    "username":"root",
    "age":16,
    "email":"root@tedu.cn"
}

相比下之,JSON数据的优点在于:

  1. 数据量较小;

  2. 解析方便;

3. JSON数据格式

1. 整个JSON数据是1个对象,必须使用 {} 框住

2. JSON对象中可以有多个属性,每个属性的名称使用引号框住,属性值根据类型决定是否需要添加引号,数值型和布尔型的不需要添加引号,属性名与属性值之间使用冒号分隔,多个属性之间使用逗号分隔

{
    "username":"root",
    "age":16,
    "email":"root@tedu.cn",
    "is_delete":false
}

3. 整个JSON中无视多余的空白(含若干数量的空格、换行、空白制表位等)

4. JSON数据中,某个属性的值可以是另一个对象,任何对象都使用大括号框住

{
    "username":"root",
    "age":16,
    "email":"root@tedu.cn",
    "is_delete":false,

    "department": {
        "id":9527,
        "name":"UI"
    }
}

5. JSON数据中,某个属性的值可以是一系列的数据,即数组,都使用中括号框住

{
    "username":"root",
    "age":16,
    "email":"root@tedu.cn",
    "is_delete":false,
    "department": {
        "id":9527,
        "name":"UI"
    },
    "phones": ["13800138000","13800138001","13800138002"]
}

6. 各种复合类型的值可以互相嵌套,例如数组的元素也可以是对象,对象中再包含数组等

4. 在HTML页面中处理JSON

JavaScript语言支持读取JSON数据,例如:

<script type="text/javascript">
var json = { 
    "username":"root",
    "age":18,
    "hobby":["game","coding","run"],
    "department":{
        "id":7,
        "name":"RD"
    }
};

var username = json.username;
var age = json.age;

console.log("username=" + username);
console.log("age=" + age);

for (var i = 0; i < json.hobby.length; i++) {
    console.log("hobby=" + json.hobby[i]);
}

console.log("department name=" + json.department.name)
</script>

对于客户端而言,往往得到的并不一定是JSON对象,而是服务器给回的JSON格式的字符串!通过JSON.parse(str)就可以把字符串类型的str数据转换回JSON对象。

5. 在服务器端向客户端响应JSON数据

在服务器端添加jackson-databind依赖:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>

当服务器端的控制器处理请求时,添加了@ResponseBody,即表示响应正文,则SpringMVC框架会根据匹配的converter将处理请求的方法的返回值转换为正文,如果返回值是String类型,则会自动使用StringHttpMessageConverter,还有一些其它内置的converter,如果方法的返回值类型不是SpringMVC默认就支持的(例如自定义的数据类型),则会自动使用jackson框架中的converter,而jackson框架中的converter就会将返回的对象组织为JSON格式。

应用jackson框架并不需要编写任何代码,也不需要添加任何配置。

通常,某个应用中,向客户端响应的数据格式应该是相对固定的,也就是说,无论是用户登录成功、登录失败、注册成功、注册失败、发表文章成功等任何操作,服务器向客户端响应的JSON的格式是相对固定的,都会包含某些特定的属性,表达特定的意义,以便于客户端处理。

所以,通常会在服务器端创建一个类,专门用于表示向客户端响应的数据的类型:

public class ResponseResult {

    private Integer state;
    private String message;

    public Integer getState() {
        return state;
    }

    public void setState(Integer state) {
        this.state = state;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

6. 异步请求

在页面中引用jQuery,然后,调用$.ajax()函数,即可发出请求,并获取响应结果!

    $("#btn-reg").click(function(){
    // 发出异常请求,并处理结果
    // url:将请求提交到哪里去
    // data:提交的请求参数,例如 username=root&password=1234
    // type:提交方式
    // dataType:服务器端即将响应的数据的类型,取值可以是"json"、"xml"、"text",例如服务器端响应的可能是application/json
    // 该属性值应该是"json"
    // success:当服务器成功响应时(Http响应码是2xx)的回调函数
    $.ajax({
        "url":"user/reg.do",
        "data":"username=" + $("#username").val(),
        "type":"POST",
        "dataType":"json",
        "success":function(json) {
            alert(json.message);
        }
    });
});