文档章节

笔记25 传递模型数据到视图中

o
 osc_z1hvg4cu
发布于 2018/04/24 20:29
字数 1746
阅读 0
收藏 0

精选30+云产品,助力企业轻松上云!>>>

在 Spittr应用中,我们需要有一个页面展现最近提交的Spittle列表。因此,我们需要一个新的方法来处理这个页面。

 

1.首先,需要定义一个数据访问的Repository。为了实现解耦以及避免 陷入数据库访问的细节之中,我们将Repository定义为一个接口,并在稍后实现它我们只需要一个能够获取Spittle 列表的Repository,如下所示的SpittleRepository.java

findSpittles()方法接受两个参数。其中max参数代表所返回的 Spittle中,Spittle ID属性的最大值,而count参数表明要返回多少个Spittle对象,调用时以findSpittles(Long.MAX_VALUE,20)这样的方式。

 1 package spittr.data;
 2 
 3 import java.util.List;
 4 
 5 import org.springframework.stereotype.Component;
 6 
 7 import spittr.spittle.Spittle;
 8 
 9 @Component
10 public interface SpittleRepository {
11     List<Spittle> findSpittles(long max, int count);
12 
13 }

2.然后创建它的实现类JdbcSpittleRepository.java用来访问数据库,然后读取数据,但是目前还不需要对数据库进行操作,所以需要自己做一下假数据。

 1 package spittr.data;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Date;
 5 import java.util.List;
 6 
 7 import spittr.spittle.Spittle;
 8 
 9 public class JdbcSpittleRepository implements SpittleRepository {
10 
11     private List<Spittle> createSpittleList(int count) {
12         List<Spittle> spittles = new ArrayList<Spittle>();
13         for (int i = 0; i < count; i++) {
14             spittles.add(new Spittle("Spittle" + i, new Date()));
15         }
16         return spittles;
17     }
18 
19     @Override
20     public List<Spittle> findSpittles(long max, int count) {
21         // TODO Auto-generated method stub
22 
23         return createSpittleList(count);
24     }
25 
26 }

有一个createSpittleList方法,根据传入的数值,创建相应条目的数据。然后由findSpittles进行返回。

3.创建Spittle类,包含消息内容、时间戳和位置信息

 1 package spittr.spittle;
 2 
 3 import java.util.Date;
 4 
 5 import org.apache.commons.lang3.builder.EqualsBuilder;
 6 import org.apache.commons.lang3.builder.HashCodeBuilder;
 7 
 8 public class Spittle {
 9     private final Long id;
10     private final String message;
11     private final Date time;
12     private Double latitude;
13     private Double longitude;
14 
15     public Spittle(String message, Date time) {
16         this(message, time, null, null);
17     }
18 
19     public Spittle(String message, Date time, Double latitude, Double longitude) {
20         this.id = null;
21         this.message = message;
22         this.time = time;
23         this.latitude = latitude;
24         this.longitude = longitude;
25     }
26 
27     public long getId() {
28         return id;
29     }
30 
31     public String getMessage() {
32         return message;
33     }
34 
35     public Date getTime() {
36         return time;
37     }
38 
39     public Double getLongitude() {
40         return longitude;
41     }
42 
43     public Double getLatitude() {
44         return latitude;
45     }
46 
47     @Override
48     public boolean equals(Object that) {
49         return EqualsBuilder.reflectionEquals(this, that, "id", "time");
50     }
51 
52     @Override
53     public int hashCode() {
54         return HashCodeBuilder.reflectionHashCode(this, "id", "time");
55     }
56 }

4.创建控制器,SpittleController.java

 1 package spittr.web;
 2 
 3 import java.util.List;
 4 
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.stereotype.Controller;
 7 import org.springframework.ui.Model;
 8 import org.springframework.web.bind.annotation.RequestMapping;
 9 import org.springframework.web.bind.annotation.RequestMethod;
10 
11 import spittr.data.JdbcSpitterRepository;
12 import spittr.data.SpittleRepository;
13 import spittr.spittle.Spittle;
14 
15 @Controller
16 
17 public class SpittleController {
18     private SpittleRepository spittleRepository;
19 
20     @Autowired
21     public SpittleController(SpittleRepository spittleRepository) { // 注入SpittleRepository
22         this.spittleRepository = spittleRepository;
23     }
24 
25     @RequestMapping(value = "spittles", method = RequestMethod.GET)
26     public String spittles(Model model) {
27         // 将spittle添加到模型中
28         SpittleRepository spittleRepository = new JdbcSpittleRepository();
29         List<Spittle> data = spittleRepository.findSpittles(Long.MAX_VALUE, 20);
30         model.addAttribute(data);
31         return "spittles"; // 返回视图名
32     }
33 
34 }

到SpittleController有一个构造器,这个构造器使 用了@Autowired注解,用来注入SpittleRepository。这 个SpittleRepository随后又用在spittles()方法中,用来获 取最新的spittle列表。在spittles()方法中给定了一个Model作为参数。这样,spittles()方法就能将Repository中获取到的 Spittle列表填充到模型中。Model实际上就是一个Map(也就是 key-value对的集合),它会传递给视图,这样数据就能渲染到客户端 了。当调用addAttribute()方法并且不指定key的时候,那么key会 根据值的对象类型推断确定。在本例中,因为它是一 个List<Spittle>,因此,键将会推断为spittleList。spittles()方法所做的最后一件事是返回spittles作为视图的名字,这个视图会渲染模型。也可以显式声明模型的key,如下代码:

1     public String spittles(Model model) {
2         // 将spittle添加到模型中
3         SpittleRepository spittleRepository = new JdbcSpittleRepository();
4         List<Spittle> data = spittleRepository.findSpittles(Long.MAX_VALUE, 20);
5         model.addAttribute("spittleList", data);
6         return "spittles"; // 返回视图名
7     }

也可以用java.util.Map来代替Model。

1 @RequestMapping(value = "spittles", method = RequestMethod.GET)
2     public String spittles(Map<String, List<Spittle>> model) {
3         SpittleRepository spittleRepository = new JdbcSpittleRepository();
4         List<Spittle> data = spittleRepository.findSpittles(Long.MAX_VALUE, 20);
5         model.put("spittles", data);
6         return "spittles";
7     }

不管你选择哪种方式来编写spittles()方法,所达成的结果都是相同的。模型中会存储一个Spittle列表,key为spittleList,然 后这个列表会发送到名为spittles的视图中。按照我们配 置InternalResourceViewResolver的方式,视图的JSP将会 是“/WEB-INF/views/spittles.jsp”。 

5.创建模型视图spittles.jsp

 1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
 2 <%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
 3 <%@ taglib prefix="s" uri="http://www.springframework.org/tags"%>
 4 <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
 5 
 6 
 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 8 <html>
 9   <head>
10     <title>Spitter</title>
11     <link rel="stylesheet" type="text/css" href="<c:url value="/resources/style.css" />" >
12   </head>
13   <body>
14     <div class="spittleForm">
15       <h1>Spit it out...</h1>
16       <form method="POST" name="spittleForm">
17         <input type="hidden" name="latitude">
18         <input type="hidden" name="longitude">
19         <textarea name="message" cols="80" rows="5"></textarea><br/>
20         <input type="submit" value="Add" />
21       </form>
22     </div>
23     <div class="listTitle">
24       <h1>Recent Spittles</h1>
25       <ul class="spittleList">
26         <c:forEach items="${spittleList}" var="spittle" >
27           <li id="spittle_<c:out value="spittle.id"/>">
28             <div class="spittleMessage"><c:out value="${spittle.message}" /></div>
29             <div>
30               <span class="spittleTime"><c:out value="${spittle.time}" /></span>
31               <span class="spittleLocation">(<c:out value="${spittle.latitude}" />, <c:out value="${spittle.longitude}" />)</span>
32             </div>
33           </li>
34         </c:forEach>
35       </ul>
36 
37     </div>
38   </body>
39 </html>

6.测试

单元测试:

单元测试类SpittleControllerTest.java

 1 package spittr.test;
 2 
 3 import static org.hamcrest.CoreMatchers.hasItems;
 4 import static org.mockito.Mockito.mock;
 5 import static org.mockito.Mockito.when;
 6 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
 7 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
 8 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
 9 
10 import java.util.ArrayList;
11 import java.util.Date;
12 import java.util.List;
13 
14 import org.junit.Test;
15 import org.springframework.test.web.servlet.MockMvc;
16 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
17 import org.springframework.web.servlet.view.InternalResourceView;
18 
19 import spittr.data.SpittleRepository;
20 import spittr.spittle.Spittle;
21 import spittr.web.SpittleController;
22 
23 public class SpittleControllerTest {
24 
25     @Test
26     public void shouldShowRecentSpittles() throws Exception {
27         List<Spittle> expectedSpittles = createSpittleList(20);
28         SpittleRepository mockRepository = mock(SpittleRepository.class);
29         when(mockRepository.findSpittles(Long.MAX_VALUE, 20)).thenReturn(expectedSpittles);
30 
31         SpittleController controller = new SpittleController(mockRepository);
32 
33         MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller)
34                 .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp")).build();
35         mockMvc.perform(get("/spittles")).andExpect(view().name("spittles"))
36                 .andExpect(model().attributeExists("spittleList"))
37                 .andExpect(model().attribute("spittleList", hasItems(expectedSpittles.toArray())));
38     }
39 
40     private List<Spittle> createSpittleList(int count) {
41         List<Spittle> spittles = new ArrayList<Spittle>();
42         for (int i = 0; i < count; i++) {
43             spittles.add(new Spittle("Spittle" + i, new Date()));
44         }
45         return spittles;
46     }
47 }

这个测试首先会创建SpittleRepository接口的mock实现,这个 实现会从它的findSpittles()方法中返回20个Spittle对象。然后,它将这个Repository注入到一个新的SpittleController 实例中,然后创建MockMvc并使用这个控制器。

与HomeController不同,这个测试在MockMvc构 造器上调用了setSingleView()。这样的话,mock框架就不用解析 控制器中的视图名了。在很多场景中,其实没有必要这样做。但是对 于这个控制器方法,视图名与请求路径是非常相似的,这样按照默认 的视图解析规则时,MockMvc就会发生失败,因为无法区分视图路 径和控制器的路径。

在这个测试中,构建InternalResourceView 时所设置的实际路径是无关紧要的,但我们将其设置为 与InternalResourceViewResolver配置一致。这个测试对“/spittles”发起GET请求,然后断言视图的名称为spittles并 且模型中包含名为spittleList的属性,在spittleList中包含 预期的内容。 

服务器上测试:

结果

7.配置文件RootConfig.java、SpittrWebAppInitializer.java、WebConfig.java参照笔记23

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

Java线程池

前言 Java中对线程池的抽象是ThreadPoolExecutor类,Executors是一个工具类,内置了多种创建线程池的方法: newFixedThreadPool:固定长度线程池 newCachedThreadPool :可缓存线程池 newSin...

nullpointerxyz
33分钟前
35
0
Python笔记:用Python制作二维码

这些年,二维码在我国的日常使用频率特别大。因为其具有简单及安全性吧!除了用网络工具制作二维码,其实用JavaScript或Python也可以制作二维码,而且更有个性。 示例一(制作普通黑白二维码...

tengyulong
45分钟前
0
0
Redis-初体验/数据结构

定义: Redis 是 C 语言开发的一个开源的(遵从 BSD 协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。它是一种 NoSQL(not-only sql,泛指非关系型数据库...

心田已荒
48分钟前
15
0
如何在保留订单的同时从列表中删除重复项? - How do you remove duplicates from a list whilst preserving order?

问题: Is there a built-in that removes duplicates from list in Python, whilst preserving order? 是否有内置的程序在保留顺序的同时从Python列表中删除重复项? I know that I can us...

fyin1314
今天
29
0
以太坊智能合约开发常见的10个安全问题

本文介绍CheckMarx安全研究小组通过扫描公开的以太坊智能合约所发现的Solidity智能合约开发中常见的十大安全问题,其中__未检查的外部调用__ 和 高成本循环 分列排行榜前两名。该安全问题排行...

区块链教程
今天
19
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部