上一节讲述了spring mvc接收客户端参数传递的方式,解决了“入”的问题,本节将要讲述服务端如何生成响应到客户端,即“出”的问题。
(一)直接返回一个字符串,指定视图名。
这是之前在例子中已经遇到的方式,比如这个方法返回"index", 即代表有一个包含该字符串的视图文件存在,再通过spring mvc配置文件中的视图解析器,为该视图名加上前缀和后缀,就获得了该视图在服务器中的路径和名称。即控制器执行完毕就转向执行该web应用下的/WEB-INF/jsp/index.jsp并将执行后生成的HTML作为响应发送给客户端接收
@RequestMapping("/queryString")
public String test1(String userName,String userPass,Integer age){
System.out.println("用户名为:"+userName+",密码为:"+userPass+"年龄为:"+age);
return "index";
}
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后缀 -->
<property name="suffix" value=".jsp" />
</bean>
在实际应用中, 直接跳转到一个视图通常是没有意义的,既然是MVC,那通常都要携带数据(即model)转向视图,那么怎么将所需数据对象放到响应中呢?可以在方法中添加一个Map类型的参数来保存我们model的部分,其key为String类型,value为Object类型。回想一下我们在servlet中跳转视图时是使用四个作用域对象来传递数据到视图,这四个作用域对象本质上就是一个以String为key,以Object为value的Map对象,所以spring mvc设计成Map完全合理,并且默认作用域是request,示例代码如下:
@RequestMapping("/test1")
public String test1(Map<String, Object> resultMap){
User user = new User();
user.setUserName("张三");
user.setAge(12);
// 将模型数据保存在结果集中
resultMap.put("user", user);
return "index";
}
注意,这里我们手工造了一个User对象,并为其赋值,实际应用中该数据对象应该来自于业务逻辑组件。那么在index.jsp中就可以使用EL来显示user对象的内容${user},当然也可以使用内嵌的java表达式<%=request.getAttribute("user")%>来打印,当然要重写下User类的toString方法,否则打印出来的就是地址。如果观察下浏览器地址栏,发现URL并没有变化,说明spring mvc默认使用服务器端跳转方式而不是响应重定向。
(二)返回ModelAndView对象
spring mvc提供了ModelAndView对象用于将视图逻辑名同模型数据部分封装在一起,这样方法可以直接返回一个封装好的ModelAndView,而不需要提供Map参数。示例如下:
@RequestMapping("/test2")
public ModelAndView test2(){
ModelAndView mav = new ModelAndView();
// 设置视图逻辑名
mav.setViewName("index");
// 构建模型数据
User user = new User();
user.setUserName("李四");
user.setAge(21);
// 将模型加入ModelAndView实例
mav.getModel().put("user", user);
return mav;
}
可以看到,其model部分依然是一个<String,Object>的Map。当然,除了单独调用其成员方法设置视图和模型以外,也可以使用ModelAndView构造器在创建对象时一次性将视图和模型绑定好,比如上面这段代码可以改成这样:
@RequestMapping("/test2")
public ModelAndView test2() {
// 构建模型数据
User user = new User();
user.setUserName("wang5");
user.setAge(24);
ModelAndView mav = new ModelAndView("index", "user", user);
return mav;
}
其效果是一样的。
(三)针对Ajax请求,返回普通字符串
如果是Ajax请求,就不能返回一个视图组件了,而是单独返回一部分数据,比如最简单的就是一个字符串,请看示例代码: @RequestMapping("/test3")
@ResponseBody
public String test3(String name) {
System.out.println("参数:"+name);
return "你的名字是:" + name;
}
可以看出,这种方式跟之前的直接跳转视图的方法结构几乎一模一样,所不同的是为方法增加了一个叫@ResponseBody的注解,该注解表示方法的返回值(字符串)不再是一个视图名,而是直接作为响应体返回给客户端,并且不需要使用HttpServletResponse,PrintWriter这些API仅仅需要增加一个注解就非常简单得完成了一个Ajax的响应。客户端的代码如下:
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
$(function(){
//按钮单击时执行
$("#testBtn").click(function(){
$.post("${pageContext.request.contextPath}/jumpToView/test3", {name:"张三" },
function (data){
$("#result").html(data);
});
});
});
</script>
</head>
<body>
<input type="button" id="testBtn" value="ajax请求" />
<span id="result"></span>
</body>
(四)返回JSON数据
对于简单的ajax请求,直接返回一个简单String尚可,但多数情况下需要返回对象或对象集合等复杂数据,这种情况往往使用Json串作为响应。另外,在移动互联网大行其道的今天,服务端同各种APP交互通常也使用Json。这一小节我们就来简单看看如何在spring mvc中将对象或对象集合转成json串,这里我们使用jackson框架来辅助转换过程。
1. 在pom中添加jackson库的依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
2. 将单个对象转成json,示例代码如下:
/**
* 使用jackson将单个对象转换为json 串返回
* @param name
* @return
*/
@RequestMapping("/test4")
@ResponseBody
public String test4(String name,Integer age) {
System.out.println("参数1:"+name+",参数2:"+age);
ObjectMapper om = new ObjectMapper();
User user = new User();
user.setUserName(name);
user.setAge(age);
// object 转出 json串
String jsonResult = "";
try {
jsonResult = om.writeValueAsString(user);
System.out.println("转换成的Json串为:"+jsonResult);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jsonResult;
}
可以看到,使用jackson实现对象与json串直接的转换非常简单,只需使用一个ObjectMapper的writeValueAsString方法即可,请大家自行观察结果。
注意:依然不要忘了@ResponseBody注解,否则spring mvc会去寻找以你的json串命名的jsp
3. 将对象集合转换为json串,没有什么区别,同样使用ObjectMapper的writeValueAsString方法:
/**
* 使用jackson将对象集合转换为json 串返回
* @param name
* @return
* @throws JsonProcessingException
*/
@RequestMapping("/test5")
@ResponseBody
public String test5() {
String jsonResult = "";
List<User> userList = new ArrayList<User>();
User u1 = new User();
User u2 = new User();
User u3 = new User();
u1.setUserName("张三");
u2.setUserName("李四");
u3.setUserName("王五");
userList.add(u1);
userList.add(u2);
userList.add(u3);
ObjectMapper om = new ObjectMapper();
try {
jsonResult = om.writeValueAsString(userList);
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jsonResult ;
}
观察结果,可以看到是以json数值的形式封装的:
[{"userName":"张三","userPass":null,"age":null},{"userName":"李四","userPass":null,"age":null},{"userName":"王五","userPass":null,"age":null}]
(五)controller之间跳转
跟servlet类似,除了可以跳转到一个页面,也可以从一个controller方法跳到另一个controller方法,当然要分服务器端跳转(foward)和客户端跳转(redirect)
1. forward跳转,即在同一个应用内部跳转,客户端只请求一次,在return语句中使用forward:跳转组件的URI关键字即可,示例代码:
/**
* 以foward方式从一个controller调到另一个controller
* 并传递客户端参数和服务端参数
* @param name
* @return
*/
@RequestMapping("/test6")
public String test6(String name,HttpServletRequest req){
req.setAttribute("key1", new String("来自于上一个controller的数据"));
return "forward:/jumpToView/test7";
}
/**
* 跳转到的组件
* @param name
* @param req
* @return
*/
@RequestMapping("/test7")
@ResponseBody
public String test7(String name,HttpServletRequest req){
System.out.println(name+","+req.getAttribute("key1"));
return "测试controller之间跳转";
}
第一个controller方法(test6)不负责响应,把控制器交给跳转到的controller方法,跳转后第二个controller方法(test7)不仅可以接收到客户端传来的请求参数,也可以接受到在第一个controller方法中定义在request作用域中的属性值,说明两个组件都在同一个请求作用域中。观察网络报文,也确实只有一次请求和一次响应。
2. redirect跳转,请求的第一个controller方法会以302状态码响应客户端请求,通知客户端重新请求另一个组件,并另一个组件的URL放入响应头的location字段中发回给客户端。在return语句中使用redirect:跳转组件的URI关键字即可,示例代码如下:
/**
* 以redirect方式跳转到另一个controller方法
* @param name
* @param req
* @return
*/
@RequestMapping("/test8")
public String test8(String name,HttpServletRequest req){
req.setAttribute("key2", new String("来自于上一个controller的数据"));
return "redirect:/jumpToView/test7";
}
观察结果可以发现,跳转成功了,但是第二个组件(test7)接收不到客户端传递给第一个组件(test8)的参数,也接收不到test8自己封装在request中的内部属性,观察HTTP报文,发现确实是生成了两次请求两次响应,所以两个组件实际上不在同一个请求作用域中(request)。
(六)两个额外的问题:
1. 静态资源映射的问题:
按照之前的配置使用spring mvc后,发现动态资源(如jsp,controller等)可以正常请求到,但是像html这种静态资源请求不到了。原因是spring mvc的核心控制器覆盖了web服务器默认对静态资源的映射,需要在springmvc相应配置文件里加入一个Handler配置即可:
<mvc:default-servlet-handler />
这个配置表示将对静态资源的处理交还给web服务器,我们这里是tomcat。
2. 返回字符串响应时的中文乱码问题
不管是普通String,还是Json,只要响应中包含了中文,都不能正常呈现。这是由于spring mvc的转换器(converter)机制对于响应中的文本类型默认采用ISO-8859-1编码,要解决此问题也很简单,在spring mvc配置文件中加入一个converter,指定响应的编码方式为UTF-8即可:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<!-- <value>application/json;charset=UTF-8</value> -->
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
关于converter的机制我们后面会介绍。
(七)总结
本节介绍了spring mvc生成响应的几种常见方式,下一节我们将介绍使用servlet3.x的特性实现0配置加载spring mvc容器的方式。
相关推荐
**Spring MVC实战系列教程(1)--Hello Spring MVC** 在本文中,我们将深入探讨Spring MVC框架,这是一个广泛使用的Java Web应用程序开发工具。Spring MVC是Spring框架的一个模块,它提供了MVC(模型-视图-控制器)...
### Spring MVC 教程知识点详解 #### Spring Web Flow 2.0 技术要点与实践应用 **一、Spring Web Flow 2.0 概览** - **Spring Web Flow** 是Spring框架的一个子项目,专注于解决多请求之间的交互问题,即用户与...
3. **WebFlux增强**:Spring WebFlux是Spring MVC的非阻塞替代品,5.2.3版本对其进行了优化,提供了更强大的路由功能和更好的错误处理机制。 4. **JPA与数据访问增强**:此版本增强了对JPA(Java Persistence API)...
【Flex4+Spring+ibatis实战系列教程】 本教程旨在引导初学者深入理解富网络应用(Rich Internet Application,简称RIA)的概念,并掌握四种不同的架构方法,这些方法均结合了Flex4、Spring和iBATIS框架。Flex4是...
SpringMVC通过一系列的组件协作将Web请求转换为模型对象,然后将其传递给视图以生成响应。SpringMVC3.0实战指南详细地介绍了如何使用SpringMVC 3.0版本进行Web开发,该指南针对初学者提供了详尽的入门知识和实战指导...
本实战教程将带你深入理解并掌握SpringBoot的核心特性,通过完整的项目实例,帮助你快速上手。 1. **Spring Boot基础** - **自动配置**:Spring Boot的核心特性之一,它根据项目中的依赖自动配置相应的Bean,减少...
在本教程中,我们主要使用的Spring技术栈包括了Spring Boot、Spring MVC、Spring Data JPA等核心组件。这些组件相互协作,为开发高效、可维护的企业级应用提供了强有力的支持。 1. **Spring Boot**: - 快速开发...
3. **Tutorials**:提供一系列教程,涵盖从基础到高级的使用场景。 4. **Appendices**:包含了常见问题解答、最佳实践和迁移指南等实用信息。 五、学习路径与实战 学习Spring Framework 4.0.1.RELEASE,首先要熟悉...
根据提供的文件信息,我们可以推断出这是一套关于Spring MVC框架与MyBatis框架结合使用的教程资源包。接下来,我们将围绕这些关键词展开详细介绍,包括Spring MVC框架的基本概念、功能特性、工作原理及其与MyBatis...
2. **简化开发**:Spring框架提供了一系列的工具和API,如Spring MVC、Spring Data等,大大简化了Web应用和数据访问层的开发工作。 3. **提高测试性**:由于依赖注入的特性,使用Spring框架可以很容易地为对象创建...
由于提供的压缩文件名为 "ch01",这可能是系列教程的第1章,通常会涵盖基础概念,如Spring的核心特性、环境设置、MVC(Model-View-Controller)架构的介绍,以及如何创建第一个Spring应用。可能的内容包括: 1. **...
【Java实战教程】08. 员工培训流程介绍及演示 在这一章节中,我们将深入探讨如何在企业级员工信息管理系统中实现一个完整的员工培训流程。这个系统是基于Java技术栈构建的,采用了Spring、Spring MVC和Hibernate这...
根据提供的文件信息,我们可以归纳出一系列与Spring框架相关的知识点,特别是针对Spring 4版本的学习资料。下面将详细介绍这些知识点,并尽可能地提供丰富的信息。 ### 一、Spring框架概述 Spring框架是一个开源的...
SpringCloud依赖于SpringBoot提供的能力,可以说SpringCloud是建立在SpringBoot之上的一系列库的集合。 ### 快速入门 #### 2.1 创建Maven工程 为了快速入门SpringBoot,推荐使用Maven作为项目构建工具。在IDEA中...
它为开发者提供了强大的MVC(Model-View-Controller)设计模式支持,使得开发人员能够更高效、更模块化地处理Web请求和响应。在这个"SpringMVC项目实战教程"中,我们将深入探讨SpringMVC的核心概念和实践技巧。 ...
本教程的视频内容可能涵盖以上各个方面,包括Spring环境搭建、MVC结构设计、数据库交互、事务管理、安全控制等,并可能提供实际的团购项目案例,让学习者能够通过实战加深理解。配合文档中的视频链接,你将能够全面...
根据标题、描述和部分内容,知识点覆盖范围主要集中在Java Web开发领域,并且包括了JSP、Servlet、Ajax以及SSH框架(Struts 2、Spring、Hibernate)的技术整合和实战案例分析。 JSP(Java Server Pages)是一种动态...
这个压缩包包含了一系列的视频教程和配套代码,旨在帮助学习者从基础到深入地理解并掌握这两项技术。 Spring MVC是Spring框架的一个模块,专门用于构建Web应用程序。它提供了模型-视图-控制器(MVC)架构模式的实现...
在这个"spring-study.zip"压缩包中,我们可以期待找到一系列关于Spring5学习的资源,包括示例代码、教程文档和可能的笔记。 首先,让我们深入了解一下Spring5的主要特性: 1. **Java 8支持**:Spring5全面支持Java...