返回介绍

5.2.3 传递模型数据到视图中

发布于 2024-08-17 00:45:50 字数 4389 浏览 0 评论 0 收藏 0

到现在为止,就编写超级简单的控制器来说,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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文