1. ModelAndView
最常用的返回值类型,Model用于存储数据,最终被放置到request作用域;View代表视图,框架使用forward进行视图跳转。如果请求处理的结果既需要数据,又需要视图,那么使用ModelAndView比较方便。如果只需要数据,不需要页面跳转(例如Ajax异步响应更新局部数据);或者只需要页面跳转,不需要传递数据,此时使用ModelAndView并不合适,总有一部分是多余的。
@RequestMapping(value = "/noLimit.do")
public ModelAndView doNoLimit(){
ModelAndView modelAndView = new ModelAndView();
// 存放数据 框架会自动将数据放到request作用域
modelAndView.addObject("msg","hello-nolimit");
modelAndView.setViewName("show");
return modelAndView;
}
2. String
当框架中配置了视图解析器时,返回的String结果会被当作是逻辑视图名,经过视图解析器拼接后形成地址;如果没有配置视图解析器,那么返回的String就会被当作是视图路径。
配置了视图解析器:
<p>处理器方法返回String表示视图名称</p>
<form action="test/returnString-view.do" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
<input type="submit" value="提交">
</form>
@RequestMapping(value = "/returnString.do")
public String doReturnString(HttpServletRequest request, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age){
System.out.println("name = " + name + ", age = " + age);
// 手动将数据添加到request对象中
request.setAttribute("name",name);
request.setAttribute("age",age);
return "showProperty";
}
此时如果我们返回试图路径:
@RequestMapping(value = "/returnString.do")
public String doReturnString(HttpServletRequest request, @RequestParam(value = "name") String name, @RequestParam(value = "age") Integer age){
System.out.println("name = " + name + ", age = " + age);
// 手动将数据添加到request对象中
request.setAttribute("name",name);
request.setAttribute("age",age);
return "/WEB-INF/view/showProperty.jsp";
}
很明显,框架把我们返回的String结果当作逻辑视图名,经过了视图解析器拼接。
注意:当我们返回String类型时,如果需要同时转发数据,必须得在request对象中手动加入对象。
3.void
void用于请求处理后,不需要跳转到其他视图的场合。例如可以用于对Ajax的异步请求响应:通过HttpServletResponse输出数据,响应Ajax请求。
1. 导入jquery库文件
2. Ajax处理数据使用json格式,我们还需要导入json的依赖包,用于将字符串包装为json格式
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
3.在页面中设定发起Ajax请求的触发事件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.5.1.js"></script>
<script type="text/javascript">
$(function () {
$("button").click(function () {
$.ajax({
url:"test/returnVoid_ajax.do", // 请求路径
data:{ // 请求的数据
name:"zzt",
age:21
},
type:"post", // 请求方式
dataType:"json", // 返回数据的解析方式 json为把json格式的字符串解析为对象
success:function (resp) { // resp结果数据解析后的结果
alert(resp);
}
})
})
})
</script>
</head>
<body>
<button id="btn">发起Ajax请求</button>
</body>
</html>
4. 在处理器方法中,使用response对象传回数据
@RequestMapping(value = "/returnVoid_ajax.do")
public void doReturnVoid(HttpServletResponse response,@RequestParam("name") String name, @RequestParam("age") Integer age) throws IOException {
System.out.println("name = " + name + ", age = " + age);
// 1.(假装)调用业务方法获取数据
Student student = new Student(name, age);
// 2.将结果转换成json格式的字符串
String json = "";
if(student != null){
ObjectMapper objectMapper = new ObjectMapper();
json = objectMapper.writeValueAsString(student);
System.out.println("对象转换为json格式为 : " + json);
}
// 3.设置相应格式,响应请求
response.setContentType("application/json;charset=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.println(json);
printWriter.flush();
printWriter.close();
return;
}
5.执行结果
jquery将返回的字符串以json格式解析为对象并赋值给接收参数,当然对象中的值我们也是可以取出来的。
success:function (resp) { // resp结果数据解析后的结果
alert("name = " + resp.name + " age = " + resp.age);
}
值得注意的是dataType属性,它用于指明想要的结果类型,是在请求头的声明的:
但是我们已经在代码中,为响应头也指明了数据的格式为json字符串,jquery也会尝试解析为json对象(使用JSON.parse方法):
4.Object
在第三种方式中,对于Ajax请求的响应,我们需要固定地将对象转换为json字符串,并且用response对象回传数据。这是公共的冗余操作,当然我们也可以通过工具类的方式进行公共部分提取,但是SpringMVC也提供了另一种方式,就是使用对象作为返回值。如果我们使用这种方式,即使传回的是String类型,框架也不会把他当作是视图名或者逻辑视图名,而是只把他当作传递过来的数据。
@ResponseBody注解,会将结果数据放入到响应体中。
A. 传递普通对象类型
1. 加入jackson依赖
jaskson是SpringMVC默认的json依赖项。
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
2. 配置注解驱动<mvc:annotation-driven/>
<!--配置注解驱动-->
<mvc:annotation-driven/>
注意在Spring中也有注解驱动,这边我们要用的是SpringMVC中的注解驱动,别加错了。
<mvc:annotation-driven>在加入配置后,会自动创建HttpMessageConverter(消息转换器)接口的实现类。
我们常用的是StringHttpMessageConverter(默认创建)和MappingJackson2HttpMessageConverter(配置注解驱动后才会创建)。
HttpMessageConverter:消息转换器接口,定义了java对象转换为json、xml、二进制流等数据格式的方法,它有很多实现类,这些实现类负责实现java对象的转换。
转换步骤:1.调用接口中定义的canWrite方法,判断是否可以进行转换
2.调用接口中定义的write方法,完成数据格式的转换
这对应了我们刚刚手动实现的这一部分:
String json = "";
if(student != null){
ObjectMapper objectMapper = new ObjectMapper();
json = objectMapper.writeValueAsString(student);
System.out.println("对象转换为json格式为 : " + json);
}
3. 在处理器方法上增加@ResponseBody
@ResponseBody负责将输出放入响应体,另外具有@ResponseBody注解的方法,其返回值不会被当作逻辑视图名或者视图路径(特指String)。
@ResponseBody
@RequestMapping(value = "/returnVoid_ajax.do")
public Student doReturnVoid(HttpServletResponse response,@RequestParam("name") String name, @RequestParam("age") Integer age) throws IOException {
System.out.println("name = " + name + ", age = " + age);
Student student = new Student(name, age);
return student;
}
这对应了我们刚刚手动实现的这一部分:
response.setContentType("application/json;charset=utf-8");//响应数据格式
PrintWriter printWriter = response.getWriter();
printWriter.println(json);
printWriter.flush();
printWriter.close();
4.执行结果
5.执行步骤详解
1. 容器会用一个List用于存储所有的消息转换器ArrayList<HttpMessageConverter>(注解驱动生效后,MappingJackson2HttpMessageConverter对象会被创建并放入list)
2. 对于返回的Student对象,框架会遍历list里的所有消息转换器,调用他们的canWrite()方法,判断哪一个消息转换器实现类对象可以对该Student对象进行转换
3. 确定了消息转换器对象之后,使用它的write()方法完成转换(Student是对象,需要转换成json格式)
4. @ResponseBody注解表示将返回结果放置在response中
B.传递集合
@ResponseBody
@RequestMapping(value = "/returnVoid_ajaxList.do")
public List<Student> doReturnVoidList(HttpServletResponse response, @RequestParam("name") String name, @RequestParam("age") Integer age) throws IOException {
System.out.println("name = " + name + ", age = " + age);
List<Student> students = new ArrayList<>();
Student student = new Student(name, age);
students.add(student);
student = new Student("辅助",20);
students.add(student);
return students;
}
此时返回的是一个json字符串的数组,我们可以用jquery自带的循环函数遍历取值:
$.ajax({
url:"test/returnVoid_ajaxList.do", // 请求路径
data:{ // 请求的数据
name:"zzt",
age:21
},
type:"post", // 请求方式
dataType:"json", // 要求返回的数据类型是json格式的字符串
success:function (resp) { // resp结果数据解析后的结果
//alert("name = " + resp.name + " age = " + resp.age);
$.each(resp,function (i,student) {
alert(student.name + "--" + student.age)
})
}
})
C.传递的String只作为普通的文本数据
@ResponseBody
@RequestMapping(value = "/returnStringAjax.do")
public String doReturnStringAjax(){
return "返回的是字符串不是数据";
}
我们使用ajax提交请求:
$.ajax({
url:"test/returnStringAjax.do", // 请求路径
data:{ // 请求的数据
name:"zzt",
age:21
},
type:"post", // 请求方式
dataType:"json", // 要求返回的数据类型是json格式的字符串
success:function (resp) { // resp结果数据解析后的结果
//alert("name = " + resp.name + " age = " + resp.age);
/*$.each(resp,function (i,student) {
alert(student.name + "--" + student.age)
})*/
alert("返回文本数据:" + resp);
}
})
此时并没有任何弹窗,但是ajax请求确实成功发出也收到了响应,关键在于,由于我们设置了要求返回类型是json格式,可是我们实际返回的是String,它并不是由jackson提供的方法进行转换的,所以发生了格式的不匹配,执行中断了,解决办法就是改变dataType的值为text,表示结果为文本数据。
现在我们遇到了第二个问题,执行不出错了但是数据无法解析:
观察响应头发现,响应里的默认编码格式是ISO-8859-1,这种编码格式是没有办法正常解析中文的,我们需要手动设置编码格式为utf-8:[注]前面我们是有配置过过滤器的,但是Ajax请求返回的数据是不会经过过滤器的,因此需要手动设置。
使用@RequestMapping的produces属性设置编码格式ContentType:
@ResponseBody
@RequestMapping(value = "/returnStringAjax.do", produces = "text/plain;charset=utf-8")
public String doReturnStringAjax(){
return "返回的是字符串不是数据--SpringMVC";
}
[注]:String类型的返回值是由StringHttpMessageConverter负责完成转换的。