上篇文章我们讲了SpringMVC 的请求参数的绑定和常用的注解,现在来讲SpringMVC中响应数据和结果视图
文章目录
响应数据和结果视图
对于控制器(Controller)
中方法的返回值,可以为以下其中一种:
String
字符串类型void
无返回值ModelAndView
SpringMVC 为我们提供的一种可以包含数据和视图的对象JavaBean 对象
(通过json
数据响应)
返回值为 String
-
当控制器返回值为
String
类型的时候,默认情况是返回逻辑视图名,然后被视图解析器解析为物理视图地址,最终底层通过请求转发将请求转发到对应页面。 -
前面的环境搭建大家可以去看看我之前的这篇文章 传送门
-
response.jsp
代码:
<a href="user/testString">testString</a>
- 控制器代码
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 返回值为 String ,结合 model 对象保存数据
* @param model
* @return
*/
@RequestMapping("/testString")
public String testString(Model model){
System.out.println("testString执行了。。。");
// 模拟从数据库中查询出User对象
User user = new User();
user.setUsername("老王");
user.setPassword("123");
user.setAge(30);
// model对象
model.addAttribute("user",user);
return "success";
}
}
返回值为 void
- 当使用
void
作为控制器方法的返回值时,方法执行结束后默认转发的路径为当前方法绑定的路径,也就是@RequestMapping
中的值。但是实际上这个返回值也会被视图解析器解析,所以一般都会报404
错误。譬如,此时有一个控制器方法为:
@RequestMapping("/testVoid")
public void testVoid(Model model){
System.out.println("testString执行了。。。");
}
- 如果既想使用
void
返回值,同时又想对请求做出响应,譬如请求转发或者重定向,那么我们就可以利用Servlet
提供的原生 API 作为控制器方法的参数 - 请求转发
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response)throws Exception{
System.out.println("testString执行了。。。");
// 转发是一次请求,无需加项目虚拟目录,但是因为直接通过原生api进行转发,不会经过视图解析器,所以应该写具体路径
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
// 转发或重定向后,如果还有代码,会继续执行,此时可以使用 return; 结束
return;
}
- 重定向
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response)throws Exception{
System.out.println("testString执行了。。。");
// 重定向,需要项目虚拟目录
response.sendRedirect(request.getContextPath()+"/index.jsp");
return;
}
- 直接像客户端生成响应,譬如响应 json 数据
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response)throws Exception{
System.out.println("testString执行了。。。");
// 解决中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// 直接会进行响应
response.getWriter().print("你好");
return;
}
当方法的参数中含有
HttpServletResponse
时,即使方法体中不做任何处理,方法结束后也不会跳转到别的页面。关于这点,查阅官方文档,是因为此时 SpringMVC 会认为对请求已经作出了响应,所以不会再帮我们跳转到别的页面。
返回值为 ModelAndView
-
当控制器方法返回值为
ModelAndView
的时候,其实就相当于第一种方式的返回值为String
加上参数为Model
,因为ModelAndView
也可以传入数据(在页面上直接使用 EL 表达式获取:${attributeName}
),同时还可以设置将要跳转的逻辑视图名称。 -
success.jsp
代码:
<body>
<h3>执行成功</h3>
${requestScope.user}
</body>
- 控制器方法
/**
* 返回ModelAndView
* @return
*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了...");
// 模拟从数据库中查询出User对象
User user = new User();
user.setUsername("小王");
user.setPassword("456");
user.setAge(20);
// 把user对象存储到mv对象中,也会把user对象存入到request对象
mv.addObject("user",user);
// 跳转到哪个页面
mv.setViewName("success");
return mv;
}
请求转发和重定向
- 当控制器方法的返回值为
String
的时候,默认就是请求转发,我们也可以像上面的例子一样,使用 Servlet 原生的 API 来完成请求转发或者重定向。不过,SpringMVC 还为我们提供了另一种方式,那就是使用forward:
和redirect:
关键字。
/**
* 使用关键字的方式进行转发或者重定向
* @return
*/
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect方法执行了...");
// 请求的转发 forward: 关键字转发,不会使用视图解析器
// return "forward:/WEB-INF/pages/success.jsp";
// redirect: 关键字重定向,不用加项目路径
return "redirect:/index.jsp";
}
- 对于
forward:
关键字,根据官方文档,底层也是使用 Servlet 原生 API 进行转发,也就是RequestDispatcher.forward()
,所以不会经过视图解析器,因此转发路径需要具体路径。
需要注意的是,如果用了formward:
则路径必须写成实际视图url
,不能写逻辑视图。
它相当于“request.getRequestDispatcher("url").forward(request,response)
”。使用请求转发,既可以转发到 jsp,也可以转发到其他的控制器方法。
- 对于
response:
关键字,根据官方文档,SpringMVC 会根据当前 Servlet 的上下文进行重定向,因此不需要写项目路径。
它相当于“response.sendRedirect(url)
”。需要注意的是,如果是重定向到 jsp 页面,则 jsp 页面不能写在WEB-INF
目录中,否则无法找到。
使用 @RequestBody 和 @ResponseBody 进行 json 交互
- 在开发中,很多时候都是客户端提交
json
数据,服务器接收json
数据并解析,然后生成json
响应给客户端。这个时候我们就可以使用@RequestBody
和@ResponseBody
来完成json
数据的交互。 response.jsp
代码:
<%--
Created by IntelliJ IDEA.
User: 15728
Date: 2021/2/19
Time: 20:49
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function () {
//alert("你好");
// 发送ajax请求
$.ajax({
//编写json格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"username":"一个Java小白","password":"123","age":18}',
dataType:"json",
type:"post",
success:function (data) {
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
alert(data.age);
}
});
});
});
</script>
</head>
<body>
<button id="btn">发送ajax的请求</button>
</body>
</html>
因为我们配置了前端控制器
DispatcherServlet
,因此对于所有的请求都会进行拦截,包括静态资源。为了使引入的jquery.js
不被拦截,我们需要在配置文件springmvc.xml
中配置不拦截静态资源<!--前端控制器,哪些静态资源不拦截--> <mvc:resources location="/css/" mapping="/css/**"/> <!-- 样式 --> <mvc:resources location="/images/" mapping="/images/**"/> <!-- 图片 --> <mvc:resources location="/js/" mapping="/js/**"/> <!-- javascript -->
location
属性 : 指定webapp
目录下的包mapping
属性 : 表示以/static
开头的所有请求路径
- 控制器代码
/**
* 模拟异步请求响应
*/
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了...");
// 客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
// 做响应,模拟查询数据库
user.setUsername("一个Java小白2");
user.setAge(20);
// 做响应
return user;
}
- 客户端发送了一个
json
串,服务器使用@RequestBody
获取请求体内容,并使用jackson
将json
串封装到 User 对象中;服务器使用@ResponseBody
生成响应,通过jackson
将 User 对象转成 json 串。 - SpringMVC 默认使用
MappingJacksonHttpMessageConverter
进行转换,因此需要导入jackson
的依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<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-annotations</artifactId>
<version>2.9.0</version>
</dependency>
导入出错的,老样子。传送门
- 使用 jackson 进行 json 和 JavaBean 对象的自动转换时,需要保证 json 串的键与 JavaBean 的属性名称一一对应