zoukankan      html  css  js  c++  java
  • 笔记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

  • 相关阅读:
    SQLServer性能杀手
    SqlServer内存瓶颈分析SQLServer:Buffer Manager
    HTML5变化 (一)
    对于using嵌套的改进
    String.IsNullOrEmpty()和String.IsNullOrWhiteSpace()
    querySelector & querySelectorAll
    Action<T> 委托
    Func<T, TResult>
    SL4.背景图片拖动
    JavaScript日志
  • 原文地址:https://www.cnblogs.com/lyj-gyq/p/8933497.html
Copyright © 2011-2022 走看看