首页 > 代码库 > spring in action 4 第5章
spring in action 4 第5章
代码结构
域对象 spittle.java
package _5BuildingSpringwebapplications.domain; import java.util.Date; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; public class Spittle { private final Long id; private final String message; private final Date time; private Double latitude; private Double longitude; public Spittle(String message, Date time) { this(message, time, null, null); } public Spittle(String message, Date time, Double longitude, Double latitude) { this.id = null; this.message = message; this.time = time; this.longitude = longitude; this.latitude = latitude; } public long getId() { return id; } public String getMessage() { return message; } public Date getTime() { return time; } public Double getLongitude() { return longitude; } public Double getLatitude() { return latitude; } @Override public boolean equals(Object that) { return EqualsBuilder.reflectionEquals(this, that, "id", "time"); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this, "id", "time"); } }
dao层SpittleRepositoryImpl.java,示例中没有没有内容,但是在源码中有实际内容,即相关的sql查询,但是本章还没有涉及到系统的后端,这样的话,只能通过mockito校验controller层,不能在浏览器中操作连接.
package _5BuildingSpringwebapplications.repository; import java.util.List; import org.springframework.stereotype.Repository; import _5BuildingSpringwebapplications.domain.Spittle; @Repository public class SpittleRepositoryImpl implements SpittleRepository{ @Override public List<Spittle> findSpittles(long max, int count) { return null; } @Override public Spittle findOne(long spittleId) { // TODO Auto-generated method stub return null; } }
controller层,SpittleController.java,这里没有明确的区别controller层和service层
package _5BuildingSpringwebapplications.web; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import _5BuildingSpringwebapplications.domain.Spittle; import _5BuildingSpringwebapplications.repository.SpittleRepository; @Controller @RequestMapping({ "/spittles" }) public class SpittleController { private static final String MAX_LONG_AS_STRING = "9223372036854775807"; private SpittleRepository spittleRepository; @Autowired public SpittleController(SpittleRepository spittleRepository) { // TODO Auto-generated constructor stub this.spittleRepository = spittleRepository; } // @RequestMapping(method = RequestMethod.GET) // public String spittles(Model model) { // model.addAttribute("spittleList",spittleRepository.findSpittles(Long.MAX_VALUE, 20));/* 默认的属性名是spittleList */ // return "spittles";/*这个默认的View名就是spittles*/ // } @RequestMapping(method = RequestMethod.GET) public List<Spittle> spittles(@RequestParam(value = "max",defaultValue = MAX_LONG_AS_STRING) long max, @RequestParam(value = "count", defaultValue = "20") int count) { return spittleRepository.findSpittles(max, count); } @RequestMapping(value = "/show", method = RequestMethod.GET) public String showSpittle(@RequestParam("spittle_id") long spittleId, Model model) { model.addAttribute(spittleRepository.findOne(spittleId)); return "spittle"; } //explicit about the model key // @RequestMapping(method = RequestMethod.GET) // public String spittles(Model model) { // model.addAttribute("spittleList", // spittleRepository.findSpittles(Long.MAX_VALUE, 20)); // return "spittles"; // } //work with a non-Spring type // @RequestMapping(method = RequestMethod.GET) // public String spittles(Map model) { // model.put("spittleList", spittleRepository.findSpittles(Long.MAX_VALUE, 20)); // return "spittles"; // } //total different from the others,the model key is inferred from its type (spittleList, as in the other examples // @RequestMapping(method=RequestMethod.GET) // public List<Spittle> spittles() { // return spittleRepository.findSpittles(Long.MAX_VALUE, 20)); // } @RequestMapping(value = "/{spittleId}", method = RequestMethod.GET) public String spittle(@PathVariable("spittleId") long spittleId, Model model) { model.addAttribute(spittleRepository.findOne(spittleId)); return "spittle"; } }
对contrller层的校验,主要校验了是否能够返回正确的view名等.源码中mockito的相关方法只写了名字,eclipse不能自动识别,因为方法都是静态的,如果加上类名,即能正确识别.mokito很方便,实际上在用junit运行下面的代码时,不要求service层对应的方法有实际的内容.
package _5BuildingSpringwebapplications.web.test; import static org.hamcrest.Matchers.hasItems; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.hamcrest.Matchers; import org.junit.Test; import org.mockito.Mockito; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.servlet.view.InternalResourceView; import _5BuildingSpringwebapplications.domain.Spittle; import _5BuildingSpringwebapplications.repository.SpittleRepository; import _5BuildingSpringwebapplications.web.SpittleController; public class SpittleControllerTest { @Test public void shouldShowRecentSpittles() throws Exception { List<Spittle> expectedSpittles = createSpittleList(20); SpittleRepository mockRepository = Mockito.mock(SpittleRepository.class); Mockito.when(mockRepository.findSpittles(Long.MAX_VALUE, 20)).thenReturn(expectedSpittles); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller) .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp")).build(); mockMvc.perform(MockMvcRequestBuilders.get("/spittles")) .andExpect(MockMvcResultMatchers.view().name("spittles")) .andExpect(MockMvcResultMatchers.model().attributeExists("spittleList")).andExpect(MockMvcResultMatchers .model().attribute("spittleList", hasItems(expectedSpittles.toArray()))); } private List<Spittle> createSpittleList(int count) { List<Spittle> spittles = new ArrayList<Spittle>(); for (int i = 0; i < count; i++) { spittles.add(new Spittle("Spittle " + i, new Date())); } return spittles; } @Test public void shouldShowPagedSpittles() throws Exception { List<Spittle> expectedSpittles = createSpittleList(50); SpittleRepository mockRepository = Mockito.mock(SpittleRepository.class); Mockito.when(mockRepository.findSpittles(238900, 50)).thenReturn(expectedSpittles); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller) .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp")).build(); mockMvc.perform(MockMvcRequestBuilders.get("/spittles?max=238900&count=50")) .andExpect(MockMvcResultMatchers.view().name("spittles")) .andExpect(MockMvcResultMatchers.model().attributeExists("spittleList")).andExpect(MockMvcResultMatchers .model().attribute("spittleList", Matchers.hasItems(expectedSpittles.toArray()))); } @Test public void testSpittle() throws Exception { Spittle expectedSpittle = new Spittle("hello", new Date()); SpittleRepository mockRepository = Mockito.mock(SpittleRepository.class); Mockito.when(mockRepository.findOne(12345)).thenReturn(expectedSpittle); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); mockMvc.perform(MockMvcRequestBuilders.get("/spittles/12345")) .andExpect(MockMvcResultMatchers.view().name("spittle")) .andExpect(MockMvcResultMatchers.model().attributeExists("spittle")) .andExpect(MockMvcResultMatchers.model().attribute("spittle", expectedSpittle)); } }
junit运行结果
本示例没有贴出SpittleRepository.java即SpittleRepositoryImpl实现的接口.其实很简单,自己实现即可.
域对象spitter.java
package _5BuildingSpringwebapplications.domain; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.hibernate.validator.constraints.Email; public class Spitter { private Long id; @NotNull @Size(min = 5, max = 16) private String username; @NotNull @Size(min = 5, max = 25) private String password; @NotNull @Size(min = 2, max = 30) private String firstName; @NotNull @Size(min = 2, max = 30) private String lastName; @NotNull @Email private String email; public Spitter() { } public Spitter(String username, String password, String firstName, String lastName, String email) { this(null, username, password, firstName, lastName, email); } public Spitter(Long id, String username, String password, String firstName, String lastName, String email) { this.id = id; this.username = username; this.password = password; this.firstName = firstName; this.lastName = lastName; this.email = email; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public boolean equals(Object that) { return EqualsBuilder.reflectionEquals(this, that, "firstName", "lastName", "username", "password", "email"); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName", "username", "password", "email"); } }
spitter对象的service层SpitterRepositoryImpl.java,与spittle的dao层一样,这里的方法都没有具体的内容,即没有与数据库的交互,这不影响对本章的理解.
package _5BuildingSpringwebapplications.repository; import org.springframework.stereotype.Repository; import _5BuildingSpringwebapplications.domain.Spitter; @Repository public class SpitterRepositoryImpl implements SpitterRepository{ @Override public void save(Spitter spitter) { // TODO Auto-generated method stub } @Override public Spitter findByUsername(String username) { // TODO Auto-generated method stub return null; } }
spitter的controller层SpitterController.java
package _5BuildingSpringwebapplications.web; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.Errors; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import _5BuildingSpringwebapplications.domain.Spitter; import _5BuildingSpringwebapplications.repository.SpitterRepository; @Controller @RequestMapping("/spitter") public class SpitterController { private SpitterRepository spitterRepository; public SpitterController() { // TODO Auto-generated constructor stub } @Autowired public SpitterController(SpitterRepository spitterRepository) { this.spitterRepository = spitterRepository; } @RequestMapping(value = "/register", method = RequestMethod.GET) public String showRegistrationForm() { return "registerForm"; } @RequestMapping(value = "/register", method = RequestMethod.POST) public String processRegistration(@Valid Spitter spitter, Errors errors) { if (errors.hasErrors()) { return "registerForm"; } spitterRepository.save(spitter); return "redirect:/spitter/" + spitter.getUsername(); } @RequestMapping(value = "/{username}", method = RequestMethod.GET) public String showSpitterProfile(@PathVariable String username, Model model) { Spitter spitter = spitterRepository.findByUsername(username); model.addAttribute(spitter); return "profile"; } }
代码中没有提到model层和view层.controller直接调的dao,本章的源码中也没有model层.可能因为涉及到的请求都比较简单,不需要太复杂的逻辑运行,直接由dao层返回,由view显示即可.
本章的内容除了介绍springmvc的一些知识点外,如何对controller进行单元测试也是一大亮点.
本文出自 “梦里不知身是客” 博客,请务必保留此出处http://tenfee.blog.51cto.com/6353835/1872289
spring in action 4 第5章