Spring in Action 之WEB篇
2017-06-07 10:04
127 查看
Spring in Action 之WEB篇
配置DispatcherServlet
使用JavaConfig的方式创建DispatcherServlet:import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import spittr.web.WebConfig; public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[]{RootConfig.class}; } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[]{WebConfig.class}; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
注意:Spring的应用上下文会处在应用程序的Servlet上下文之中。
在Servlet3.0容器中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果能发现,就会用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现实现WebApplicationInitializer的类并将配置的任务交给他们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,也就是AbstractAnnotationConfigDispatcherServletInitializer。当部署到Servlet3.0容器中的时候,容器会自动发现它,并用它来配置Servlet上下文。
实际上,AbstractAnnotationConfigDispatcherServletInitializer会同时创建DispatcherServlet和ContextLoaderListener。
启动Spring MVC
以前我们使用< mvc:annotation-driven>启动注解驱动的SpringMVC.如果我们没有配置视图解析器,Spring会默认使用BeanNameViewResolver,这个视图解析器会查找ID与视图名称匹配的bean,并且查找的bean要实现View接口,它以这种方式来解析视图。
WebConfig:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration @EnableWebMvc @ComponentScan("spittr.web") public class WebConfig extends WebMvcConfigurerAdapter { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); return resolver; } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); } }
注意点:通过调用DefaultServletHandlerConfigurer的enable()方法,我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上。
在SpringMVC中,控制器只是方法上添加了@Controller注解的类,这个注解声明了他们所要处理的请求。
针对Controller的测试:
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import static org.springframework.web.bind.annotation.RequestMethod.GET; @Controller @RequestMapping("/") public class HomeController { @RequestMapping(method = GET) public String home(Model model) { return "home"; } }
import org.junit.Test; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; public class HomeControllerTest { @Test public void testHomePage() throws Exception { HomeController controller = new HomeController(); MockMvc mockMvc = standaloneSetup(controller).build(); mockMvc.perform(get("/")).andExpect(view().name("home")); } }
高阶controller测试:
import org.junit.Test; import org.springframework.test.web.servlet.MockMvc; i 4000 mport org.springframework.web.servlet.view.InternalResourceView; import spittr.Spittle; import spittr.data.SpittleRepository; import java.util.ArrayList; import java.util.Date; import java.util.List; import static org.hamcrest.Matchers.hasItems; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; public class SpittleControllerTest { @Test public void houldShowRecentSpittles() throws Exception { List<Spittle> expectedSpittles = createSpittleList(20); SpittleRepository mockRepository = mock(SpittleRepository.class); when(mockRepository.findSpittles(Long.MAX_VALUE, 20)).thenReturn(expectedSpittles); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = standaloneSetup(controller) .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp")) .build(); mockMvc.perform(get("/spittles")) .andExpect(view().name("spittles")) .andExpect(model().attributeExists("spittleList")) .andExpect(model().attribute("spittleList", hasItems(expectedSpittles.toArray()))); } @Test public void shouldShowPagedSpittles() throws Exception { List<Spittle> expectedSpittles = createSpittleList(50); SpittleRepository mockRepository = mock(SpittleRepository.class); when(mockRepository.findSpittles(238900, 50)) .thenReturn(expectedSpittles); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = standaloneSetup(controller) .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp")) .build(); mockMvc.perform(get("/spittles?max=238900&count=50")) .andExpect(view().name("spittles")) .andExpect(model().attributeExists("spittleList")) .andExpect(model().attribute("spittleList", hasItems(expectedSpittles.toArray()))); } @Test public void testSpittle() throws Exception { Spittle expectedSpittle = new Spittle("Hello", new Date()); SpittleRepository mockRepository = mock(SpittleRepository.class); when(mockRepository.findOne(12345)).thenReturn(expectedSpittle); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = standaloneSetup(controller).build(); mockMvc.perform(get("/spittles/12345")) .andExpect(view().name("spittle")) .andExpect(model().attributeExists("spittle")) .andExpect(model().attribute("spittle", expectedSpittle)); } @Test public void saveSpittle() throws Exception { SpittleRepository mockRepository = mock(SpittleRepository.class); SpittleController controller = new SpittleController(mockRepository); MockMvc mockMvc = standaloneSetup(controller).build(); mockMvc.perform(post("/spittles") .param("message", "Hello World") // this works, but isn't really testing what really happens .param("longitude", "-81.5811668") .param("latitude", "28.4159649") ) .andExpect(redirectedUrl("/spittles")); verify(mockRepository, atLeastOnce()).save(new Spittle(null, "Hello World", new Date(), -81.5811668, 28.4159649)); } private List<Spittle> createSpittleList(int count) { List<Spittle> spittles = new ArrayList<>(); for (int i = 0; i < count; i++) { spittles.add(new Spittle("Spittle " + i, new Date())); } return spittles; } }
Spring MVC允许以多种方式将客户端中的数据传送到控制器的处理器方法中,包括:
查询参数(Query Parameter)
表单参数(Form Parameter)
路径变量(Path Variable)
Controller代码样例:
@Controller @RequestMapping("/spittles") public class SpittleController { private static final String MAX_LONG_AS_STRING = "9223372036854775807"; private SpittleRepository spittleRepository; @Autowired public SpittleController(SpittleRepository spittleRepository) { this.spittleRepository = spittleRepository; } // 查询参数 @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 = "/{spittleId}", method = RequestMethod.GET) public String spittle(@PathVariable("spittleId") long spittleId, Model model) { model.addAttribute(spittleRepository.findOne(spittleId)); return "spittle"; } @RequestMapping(method = RequestMethod.POST) public String saveSpittle(SpittleForm form, Model model) throws Exception { spittleRepository.save(new Spittle(null, form.getMessage(), new Date(), form.getLongitude(), form.getLatitude())); return "redirect:/spittles"; } }
校验对象:
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< a9b6 /span> 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"); } }
对应注册校验的controller:
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 spittr.Spitter; import spittr.data.SpitterRepository; import javax.validation.Valid; import static org.springframework.web.bind.annotation.RequestMethod.GET; import static org.springframework.web.bind.annotation.RequestMethod.POST; @Controller @RequestMapping("/spitter") public class SpitterController { private SpitterRepository spitterRepository; @Autowired public SpitterController(SpitterRepository spitterRepository) { this.spitterRepository = spitterRepository; } @RequestMapping(value = "/register", method = GET) public String showRegistrationForm() { return "registerForm"; } @RequestMapping(value = "/register", method = 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 = GET) public String showSpitterProfile(@PathVariable String username, Model model) { Spitter spitter = spitterRepository.findByUsername(username); model.addAttribute(spitter); return "profile"; } }
注意:Errors参数要紧跟在带有@Valid注解的参数后面,@Valid注解所标注的就是要校验的参数。
校验相关注解:
Annotation | Description |
---|---|
@AssertFalse | The annotated element must be a Boolean type and be false. |
@AssertTrue | The annotated element must be a Boolean type and be true. |
@DecimalMax | The annotated element must be a number whose value is less than or equal toa given BigDecimalString value. |
@DecimalMin | The annotated element must be a number whose value is greater than orequal to a given BigDecimalString value. |
@Digits | The annotated element must be a number whose value has a specified num-ber of digits. |
@Future | The value of the annotated element must be a date in the future. |
@Max | The annotated element must be a number whose value is less than or equal toa given value. |
@Min | The annotated element must be a number whose value is greater than orequal to a given value. |
@NotNull | The value of the annotated element must not be null. |
@Null | The value of the annotated element must be null. |
@Past | The value of the annotated element must be a date in the past. |
@Pattern | The value of the annotated element must match a given regular expression. |
@Size | The value of the annotated element must be either a String, a collection, oran array whose length fits within the given range. |
相关文章推荐
- SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-003-示例项目用到的类及配置文件
- SPRING IN ACTION 第4版笔记-第六章Rendering web views-001- Spring支持的View Resolver、InternalResourceViewResolver、JstlView
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-007-设置LDAP server比较密码(contextSource、root()、ldif()、)
- Spring in Action之WEB篇
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-011-把敏感信息请求转为https(requiresChannel())
- SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-004-以query parameters的形式给action传参数(@RequestParam、defaultValue)
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-002-把用户数据存在memory里(AuthenticationManagerBuilder、 UserDetailsManagerConfigurer.UserDetailsBuilder)
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-008-使用非关系型数据库时如何验证用户(自定义UserService)
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-004-对密码加密passwordEncoder
- Spring in action--Part2-Spring On The Web
- SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-006-处理表单数据(注册、显示用户资料)
- SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-001- DispatcherServlet的高级配置(ServletRegistration.Dynamic、WebApplicationInitializer)
- SPRING IN ACTION 第4版笔记-第六章RENDERING WEB VIEWS-003- SPRING的GENERAL TAG LIBRARY简介及用<s:message>和ReloadableResourceBundleMessageSource实现国际化
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-009-拦截请求()
- SPRING IN ACTION 第4版笔记-第五章Building Spring web applications-001-SpringMVC介绍
- SPRING IN ACTION 第4版笔记-第五章BUILDING SPRING WEB APPLICATIONS-007-表单验证@Valid、Error
- SPRING IN ACTION 第4版笔记-第六章RENDERING WEB VIEWS-005- 使用ApacheTiles(TilesConfigurer、TilesViewResolver、<put-attribute>、<t:insertAttribute>)
- SPRING IN ACTION 第4版笔记-第六章RENDERING WEB VIEWS-006- 使用thymeleaf(TemplateResolver、SpringTemplateEngine、ThymeleafViewResolver、th:include、th:object、th:field="*{firstName}")
- Spring In Action 05 ---渲染Web视图
- SPRING IN ACTION 第4版笔记-第九章Securing web applications-010-拦截请求