- 作者简介
- 内容提要
- 关于本书
- 路线图
- 代码规范与下载
- 作者在线
- 封面插图简介
- 前言
- 译者序
- 致谢
- 第1部分 Spring 的核心
- 第1章 Spring 之旅
- 第2章 装配 Bean
- 第3章 高级装配
- 第4章 面向切面的 Spring
- 第2部分 Web 中的 Spring
- 第5章 构建 Spring Web 应用程序
- 第6章 渲染 Web 视图
- 第7章 Spring MVC 的高级技术
- 第8章 使用 Spring Web Flow
- 第9章 保护 Web 应用
- 第3部分 后端中的 Spring
- 第10章 通过 Spring 和 JDBC 征服数据库
- 第11章 使用对象-关系映射持久化数据
- 第12章 使用 NoSQL 数据库
- 第13章 缓存数据
- 第14章 保护方法应用
- 第4部分 Spring 集成
- 第15章 使用远程服务
- 第16章 使用 Spring MVC 创建 REST API
- 第17章 Spring消息
- 第18章 使用 WebSocket 和 STOMP 实现消息功能
- 第19章 使用 Spring 发送 Email
- 第20章 使用 JMX 管理 Spring Bean
- 第21章 借助 Spring Boot 简化 Spring 开发
5.2.3 传递模型数据到视图中
到现在为止,就编写超级简单的控制器来说,HomeController已经是一个不错的样例了。但是大多数的控制器并不是这么简单。在Spittr应用中,我们需要有一个页面展现最近提交的Spittle列表。因此,我们需要一个新的方法来处理这个页面。
首先,需要定义一个数据访问的Repository。为了实现解耦以及避免陷入数据库访问的细节之中,我们将Repository定义为一个接口,并在稍后实现它(第10章中)。此时,我们只需要一个能够获取Spittle列表的Repository,如下所示的SpittleRepository功能已经足够了:
findSpittles()方法接受两个参数。其中max参数代表所返回的Spittle中,Spittle ID属性的最大值,而count参数表明要返回多少个Spittle对象。为了获得最新的20个Spittle对象,我们可以这样调用findSpittles():
现在,我们让Spittle类尽可能的简单,如下面的程序清单5.8所示。它的属性包括消息内容、时间戳以及Spittle发布时对应的经纬度。
程序清单5.8 Spittle类:包含消息内容、时间戳和位置信息
就大部分内容来看,Spittle就是一个基本的POJO数据对象——没有什么复杂的。唯一要注意的是,我们使用Apache Common Lang包来实现equals()和hashCode()方法。这些方法除了常规的作用以外,当我们为控制器的处理器方法编写测试时,它们也是有用的。
既然我们说到了测试,那么我们继续讨论这个话题并为新的控制器方法编写测试。如下的程序清单使用Spring的MockMvc来断言新的处理器方法中你所期望的行为。
程序清单5.9 测试SpittleController处理针对“/spittles”的GET请求
这个测试首先会创建SpittleRepository接口的mock实现,这个实现会从它的findSpittles()方法中返回20个Spittle对象。然后,它将这个Repository注入到一个新的SpittleController实例中,然后创建MockMvc并使用这个控制器。
需要注意的是,与HomeController不同,这个测试在MockMvc构造器上调用了setSingleView()。这样的话,mock框架就不用解析控制器中的视图名了。在很多场景中,其实没有必要这样做。但是对于这个控制器方法,视图名与请求路径是非常相似的,这样按照默认的视图解析规则时,MockMvc就会发生失败,因为无法区分视图路径和控制器的路径。在这个测试中,构建InternalResourceView时所设置的实际路径是无关紧要的,但我们将其设置为与InternalResourceViewResolver配置一致。
这个测试对“/spittles”发起GET请求,然后断言视图的名称为spittles并且模型中包含名为spittleList的属性,在spittleList中包含预期的内容。
当然,如果此时运行测试的话,它将会失败。它不是运行失败,而是在编译的时候就会失败。这是因为我们还没有编写SpittleController。现在,我们创建SpittleController,让它满足程序清单5.9的预期。如下的SpittleController实现将会满足以上测试的要求。
程序清单5.10 SpittleController:在模型中放入最新的spittle列表
我们可以看到SpittleController有一个构造器,这个构造器使用了@Autowired注解,用来注入SpittleRepository。这个SpittleRepository随后又用在spittles()方法中,用来获取最新的spittle列表。
需要注意的是,我们在spittles()方法中给定了一个Model作为参数。这样,spittles()方法就能将Repository中获取到的Spittle列表填充到模型中。Model实际上就是一个Map(也就是key-value对的集合),它会传递给视图,这样数据就能渲染到客户端了。当调用addAttribute()方法并且不指定key的时候,那么key会根据值的对象类型推断确定。在本例中,因为它是一个List<Spittle>,因此,键将会推断为spittleList。
spittles()方法所做的最后一件事是返回spittles作为视图的名字,这个视图会渲染模型。
如果你希望显式声明模型的key的话,那也尽可以进行指定。例如,下面这个版本的spittles()方法与程序清单5.10中的方法作用是一样的:
如果你希望使用非Spring类型的话,那么可以用java.util.Map来代替Model。下面这个版本的spittles()方法与之前的版本在功能上是一样的:
既然我们现在提到了各种可替代的方案,那下面还有另外一种方式来编写spittles()方法:
这个版本与其他的版本有些差别。它并没有返回视图名称,也没有显式地设定模型,这个方法返回的是Spittle列表。当处理器方法像这样返回对象或集合时,这个值会放到模型中,模型的key会根据其类型推断得出(在本例中,也就是spittleList)。
而逻辑视图的名称将会根据请求路径推断得出。因为这个方法处理针对“/spittles”的GET请求,因此视图的名称将会是spittles(去掉开头的斜线)。
不管你选择哪种方式来编写spittles()方法,所达成的结果都是相同的。模型中会存储一个Spittle列表,key为spittleList,然后这个列表会发送到名为spittles的视图中。按照我们配置InternalResourceViewResolver的方式,视图的JSP将会是“/WEB-INF/views/spittles.jsp”。
现在,数据已经放到了模型中,在JSP中该如何访问它呢?实际上,当视图是JSP的时候,模型数据会作为请求属性放到请求(request)之中。因此,在spittles.jsp文件中可以使用JSTL(JavaServer Pages Standard Tag Library)的<c:forEach>标签渲染spittle列表:
图5.3为显示效果,能够让你对它在Web浏览器中是什么样子有个可视化的印象。
尽管SpittleController很简单,但是它依然比HomeController更进一步了。不过,SpittleController和HomeController都没有处理任何形式的输入。现在,让我们扩展SpittleController,让它从客户端接受一些输入。
图5.3 控制器中的Spittle模型数据将会作为请求参数,并在Web页面上渲染为列表的形式
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论