[[toc]]

第一节 Ajax

1、实验一

请求:发送普通请求参数
handler 方法:使用 @RequestParam 注解接收请求参数
响应:服务器端返回普通文本

①引入 JavaScript 库

01 Ajax - 图1


②前端代码

new Vue({
“el”:”#btnSpan”,
“methods”:{
“experimentOne”:function () {

  1. // 请求:发送普通请求参数<br /> // 响应:普通文本<br /> axios({<br /> "method":"post",<br /> "url":"ajax/experiment/one",<br /> "params":{<br /> "userName":"tom",<br /> "password":"123456"<br /> }<br /> }).then(function (response) {
  2. // response接收服务器端返回的响应数据<br /> console.log(response);<br /> }).catch(function (response) {<br /> console.log(response);<br /> });
  3. }<br /> }<br />});

③后端代码

// 使用@ResponseBody注解告诉 SpringMVC:请你拿当前方法的返回值作为响应体,不要再找视图了
// 方法返回值类型有两种情况:
// 情况一:简单类型。SpringMVC 会直接作为响应体数据。
// 情况二:复杂类型。SpringMVC 会把它转换为 JSON 然后再作为响应体。此时需要 Jackson 的支持。
@ResponseBody
@RequestMapping(“/ajax/experiment/one”)
public String experimentOne(

    // Ajax请求发过来的请求参数,对服务器端来说没有区别,还是像以前一样正常接收<br />        @RequestParam("userName") String userName,<br />        @RequestParam("password") String password<br />) {

logger.debug("userName = " + userName);<br />    logger.debug("password = " + password);

// 服务器端给Ajax程序的响应数据通过handler方法的返回值提供<br />    return "message from handler as response[来自服务器的问候]";<br />}

2、实验二

请求:让整个请求体就是一个 JSON 数据
handler 方法:使用 @RequestBody 标记的实体类接收请求体数据
响应:返回普通文本

①前端代码

“experimentTwo”:function () {

axios({<br />        "method":"post",<br />        "url":"ajax/experiment/two",

    // data属性中指定一个 JSON 数据作为请求体<br />        "data":{<br />            "stuId": 55,<br />            "stuName": "tom",<br />            "subjectList": [<br />                {<br />                    "subjectName": "java",<br />                    "subjectScore": 50.55<br />                },<br />                {<br />                    "subjectName": "php",<br />                    "subjectScore": 30.26<br />                }<br />            ],<br />            "teacherMap": {<br />                "one": {<br />                    "teacherName":"tom",<br />                    "teacherAge":23<br />                },<br />                "two": {<br />                    "teacherName":"jerry",<br />                    "teacherAge":31<br />                },<br />            },<br />            "school": {<br />                "schoolId": 23,<br />                "schoolName": "atguigu"<br />            }<br />        }<br />    }).then(function (response) {<br />        console.log(response);<br />    }).catch(function (error) {<br />        console.log(error);<br />    });

}

②后端代码

[1]导入依赖



com.fasterxml.jackson.core
jackson-databind
2.12.1

如果忘记导入这个依赖,会看到下面的错误页面:
01 Ajax - 图2

关于 SpringMVC 和 Jackson jar包之间的关系,需要注意:当 SpringMVC 需要解析 JSON 数据时就需要使用 Jackson 的支持。但是 SpringMVC 的 jar 包并没有依赖 Jackson,所以需要我们自己导入。
我们自己导入时需要注意:SpringMVC 和 Jackson 配合使用有版本的要求。二者中任何一个版本太高或太低都不行。
SpringMVC 解析 JSON 数据包括两个方向:

  • 从 JSON 字符串到 Java 实体类。
  • 从 Java 实体类到 JSON 字符串。

另外,如果导入了 Jackson 依赖,但是没有开启 mvc:annotation-driven 功能,那么仍然会返回上面的错误页面。

也就是说,我们可以这么总结 SpringMVC 想要解析 JSON 数据需要两方面支持:

  • mvc:annotation-driven
  • 引入 Jackson 依赖

还有一点,如果运行环境是 Tomcat7,那么在 Web 应用启动时会抛出下面异常:
org.apache.tomcat.util.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 19
解决办法是使用 Tomcat8 或更高版本。

[2]handler 方法

@ResponseBody
@RequestMapping(“/ajax/experiment/two”)
public String experimentTwo(

    // 使用 @RequestBody 注解将请求体 JSON 数据解析出来,注入到对应的实体类中<br />        @RequestBody Student student<br />        ) {

logger.debug(student.toString());

return "message from handler as response[来自服务器的问候]";<br />}

[3]@RequestBody注解

适用 @RequestBody 注解的场景:请求体整个是一个 JSON 数据
01 Ajax - 图3

Request Payload 翻译成中文大致可以说:请求负载。

3、实验三

请求:发送普通的请求参数,请求参数整体正好对应实体类
handler 方法:使用普通实体类接收请求参数
响应:返回普通文本数据

①前端代码

“experimentThree”:function () {

axios({<br />        "method":"post",<br />        "url":"ajax/experimentThree",

    // 普通的请求参数正好对应服务器端的一个实体类<br />        "params":{<br />            "soldierId":"666",<br />            "soldierName":"tigerMan"<br />        }<br />    }).then(function (response) {<br />        console.log(response);<br />    }).catch(function (error) {<br />        console.log(error);<br />    });

}

②后端代码

@ResponseBody
@RequestMapping(“/ajax/experimentThree”)
public String experimentThree(

    // 请求参数名正好对这个实体类的属性名,可以通过 setXxx() 方法直接注入<br />        Soldier soldier) {

logger.debug(soldier.toString());

return "message from handler as response[来自服务器的问候]";<br />}

③常见错误

如果前端程序使用 axios 的 params 属性发送请求参数,那么请求参数会附着在 URL 地址后面,此时当前请求没有请求体。同时服务器端 handler 方法使用了 @RequestBody 注解,会在日志中看到下面异常信息:
HttpMessageNotReadableException: Required request body is missing:
意思是需要请求体,但是没有找到。

4、实验四

请求:不需要发送任何数据
handler 方法:返回实体类
响应:服务器端返回由实体类生成的 JSON 数据

①前端代码

“experimentFour”:function () {

axios({<br />        "method":"post",<br />        "url":"ajax/experimentFour"<br />    }).then(function (response) {<br />        console.log(response);

    // 服务器返回的响应体数据被封装到了 data 属性中<br />        console.log(response.data);<br />        console.log("response.data.soldierId = " + response.data.soldierId);<br />        console.log("response.data.soldierName = " + response.data.soldierName);<br />    }).catch(function (error) {<br />        console.log(error);<br />    });

}

②后端代码

// 使用 @ResponseBody 注解标记的方法返回实体类数据时,
// SpringMVC 需要借助 Jackson 来将实体类转换为 JSON 数据
@ResponseBody
@RequestMapping(“/ajax/experimentFour”)
public Soldier experimentFour() {

return new Soldier(333, "catMan");<br />}

浏览器控制台打印效果如下:
01 Ajax - 图4

③常见错误

[1]415 错误

01 Ajax - 图5

出现上面的错误页面,表示 SpringMVC 为了将 实体类对象转换为 JSON 数据,需要转换器。但是现在找不到转换器。它想要成功完成转换需要两方面支持:

  • mvc:annotation-driven
  • 引入 Jackson 依赖

[2]406 错误

01 Ajax - 图6

问题出现的原因:

  • 请求地址扩展名:html
  • 服务器端打算返回的数据格式:JSON

上面二者不一致。SpringMVC 要坚守一个商人的良心,不能干『挂羊头,卖狗肉』的事儿。解决办法有三种思路:

  • 第一种方法:不使用请求扩展名
  • 第二种方法:使用和实际返回的数据格式一致的扩展名


    dispatcherServlet
    .html
    .json

  • 第三种方法:使用一个 HTTP 协议中没有被定义的扩展名,例如:*.atguigu

5、@RestController

①提取@ResponseBody

如果类中每个方法上都标记了 @ResponseBody 注解,那么这些注解就可以提取到类上。

②合并

类上的 @ResponseBody 注解可以和 @Controller 注解合并为 @RestController 注解。所以使用了 @RestController 注解就相当于给类中的每个方法都加了 @ResponseBody 注解。

③@RestController源码

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

/**<br />     * The value may indicate a suggestion for a logical component name,<br />     * to be turned into a Spring bean in case of an autodetected component.<br />     * @return the suggested component name, if any (or empty String otherwise)<br />     * @since 4.0.1<br />     */<br />    @AliasFor(annotation = Controller.class)<br />    String value() default "";

}

6、SpringMVC 4 版本响应体字符集设置

// 当返回响应体数据包含乱码时,在@RequestMapping注解中设置
// produces属性给响应体设置内容类型
@ResponseBody
@RequestMapping(value = “/ajax/get/message”, produces = “text/html;charset=UTF-8”)
public String getMessage() {
return “message from server:你好”;
}

// 如果返回 JSON 数据时遇到乱码问题,那么内容类型应设置为:application/json;charset=UTF-8
// 这里需要注意:JSON 属于 application 这个大类,不属于 text
@ResponseBody
@RequestMapping(value = “/ajax/get/entity”, produces = “application/json;charset=UTF-8”)
public Emp getEntity() {

Emp emp = new Emp();

emp.setEmpName("舔狗");

return emp;<br />}

回目录 下一节