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

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

在 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

posted @ 2018-04-24 20:29 雨落忧伤- 阅读( ...) 评论( ...) 编辑 收藏
[实验目的] 1、学习如何使用XMLSPY集成开发环境完成XML Schema相关的开发工作。 2、掌握XML Schema与DTD之间的区别,能够完成两者之间的转换;掌握在XML Schema如何定义元素和属性,如何使用限制、列表和合并派生自己的简单数据类型,如何定义复杂数据类型,全局/局部元素和数据类型之间的区别;如何将XML Schema文档关联到XML实例数据文档,并完成文档的有效性验证。 3、掌握如何准确定义数据之间的参照完整性约束,如何在模式使用多态性支持,如何在文档定义空值等等。 [实验内容和步骤] 1、使用XMLSPY集成开发环境,新建XML Schema文档,在各种不同的编辑视图尝试采用不同的方式完成XML Schema文档的编辑和查看;并使用XMLSPY提供的便利,建立XML、Schema两者之间的关联,进行XML文档的良构以及有效性验证。 2、严格按照下图给出的文档模型,在XML Schema编辑环境的Schema视图完成book.xsd的编写(不要使用Text视图进行编写): 在上图,没有指定简单类型元素和属性的数据类型,请根据合理的情况,完成数据类型的创建(至少使用到限制方式三种以上的限制方面),请在IDE的Details视图->type和Facets完成上述任务。 在上图,有三个title元素分别表示book、section和figure的标题,请定义下述类型: titleType:1-100个字符的文本; bookTitleType:titleType类型限制派生的子类型,要求取枚举值“Data On the Web”、“TCP/IP Illustrated”等; sectionTitleType:titleType类型限制派生的子类型,要求必须形如“1.xxxx”、“1-1.xxxx”等等(表示第一节、第一节下面的第一节等等,注意section是递归的形式); figureTitleType:titleType类型限制派生的子类型,要求必须形如“1-1.xxxx” 、“1-1-1.xxxx”(表示第一节的第一个图、第一节下面的第一节的第一个图等等); 然后编写book.xml,并使用多态性(即所有title的类型均为titleType,而数据实例指明具体类型),请确保通过文档有效性验证。 3、在上次的DTD实验,我们编写了SpyBase1.xml、SpyBase2.xml、以及SpyBase1.dtd和SpyBase2.dtd,这次需要完成SpyBase1.xsd和SpyBase2.xsd,建立模式与数据之间的关联,并进行文档有效性验证。在编写的XSD文档SpyBase1.xsd,要求使用key/keyref描述数据的实体完整性以及数据之间的参照完整性(SpyBase2.xml不需要,因为已经使用嵌套消除了参照关系)。 [实验思考] 与ID/IDREF相比,key/keyref有哪些优点,在使用上有何不同? 假设SpyBase1.xml的alias、mission、spy来自不同的命名空间,如何在Schema对其进行限定,请在XMLSPY完成相应的xsd文档?修改SpyBase1.xml,并验证新的SpyBase1_2.xsd是否正确? [提交时间及内容] 最后提交时间 2013年?月?日 提交内容 提交book.xsd、book.xml(使用多态)。 提交SpyBase1. xsd、SpyBase2. xsd。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值