2.1 用Java来搭建Spring MVC(需要Servlet 3.0环境)
配置DispatcherServlet和ContextLoaderListener
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
//对应ContextLoaderListener
@Override
protected Class>[] getRootConfigClasses() {
return new Class>[] { RootConfig.class };
}
//对于DispatcherServlet
@Override
protected Class>[] getServletConfigClasses() {
return new Class>[] { WebConfig.class };//指定配置类
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };//将DispatcherServlet映射到"/"
}
}
AbstractAnnotationConfigDispatcherServletInitializer剖析
在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果发现的话,就会用它来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个两类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,也就是AbstractAnnotationConfigDispatcherServletInitializer。因为我们的SpittrWebAppInitializer扩展了AbstractAnnotationConfigDispatcherServletInitializer(同时也实现了WebApplicationInitializer),因此当部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。
AbstractAnnotationConfigDispatcherServletInitializer会同时创建DispatcherServlet和ContextLoaderListener。getRootConfigClasses方法返回的带有@Configuration注解的类将用来定义ContextLoaderListener应用上下文的Bean。getServletConfigClasses方法返回的带有@Configuration注解的类将用来定义DispatcherServlet应用上下文的Bean。我们希望DispatcherServlet加载包含Web组件的Bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他Bean。这些Bean通常是驱动应用后端的中间层和数据层组件。
配置Spring MVC
package spittr.config;
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.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc //启用Spring MVC
@ComponentScan("spittr.web") //启用组件扫描
public class WebConfig
extends WebMvcConfigurerAdapter{
/**
* 配置JSP视图解析器
* @return
*/
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
/**
* 配置静态资源的处理,要求DispatcherServlet将对静态资源的请求转发到Servlet
* 容器默认的Servlet上,而不是使用DispatcherServlet本身来处理此类请求
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
自定义DispatcherServlet配置
在SpittrWebAppInitializer中我们重写了三个方法来配置DispatcherServlet,实际上有更多的方法可以进行重载从而实现对DispatcherServlet额外的配置。
方法之一就是customizeRegistration(),在AbstractAnnotationConfigDispatcherServletInitializer将DispatcherServlet注册到Servlet容器之后,就会调用customizeRegistration(),并将Servlet注册后得到的Registration.Dynamic传递进来。通过重载customizeRegistration()方法,我们可以对DispatcherServlet进行额外的配置。例如设置MultipartConfigElement:
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spittr/uploads"));
}
至于这个设置到底是很忙我们将会在Spring上传中介绍。
添加其他的Servlet和Filter
如果我们想在web容器中注册其他的Servlet、Filter或者Listener,我们可以通过实现Spring的WebApplicationInitializer(我们前面说过Servlet3.0容器会自动寻找它的实现类并用来配置servlet容器)。例如注入一个servlet和一个Filter:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.springframework.web.WebApplicationInitializer;
public class MyServletInitializer implements WebApplicationInitializer{
public void onStartup(ServletContext servletContext) throws ServletException {
//注册Servlet
javax.servlet.ServletRegistration.Dynamic myServlet =
servletContext.addServlet("myServlet", MyServlet.class);
myServlet.addMapping("/custom/**");//映射Servlet
javax.servlet.FilterRegistration.Dynamic myFilter =
servletContext.addFilter("myFilter", MyFilter.class);
myFilter.addMappingForUrlPatterns(null, false, "/custom/**");//添加Filter的映射路径
}
}
如果你只是注册Filter并将其映射到DispatcherServlet上的话,在AbstractAnnotationConfigDispatcherServletInitializer中还有一种便捷的方法——重载getServletFilters()方法:
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new MyFilter() };
}
2.2 在web.xml中配置Spring MVC:
web.xml:
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
http://www.springmodules.org/schema/cache/springmodules-cache.xsd
http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:dispatcherServlet-context.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
applicationContext.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="test" class="spittr.web.Test" />
<context:component-scan base-package="spittr" />
beans>
dispatcherServlet-context.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">/WEB-INF/property>
<property name="suffix">.jspproperty>
bean>
beans>
2.3 让web.xml使用Java配置而不是XML配置
也即是说让Spring MVC在启动的时候,从带有@Configuration注解的类上加载配置,我们需要告诉DispatcherServlet和ContextLoaderListener使用AnnotationConfigWebApplicationContext,这是一个WebApplicationContext的实现类,它会加载Java配置类,而不是使用XML。要实现这种配置,我们只需要设置contextClass上下文参数以及DispatcherServlet的初始化参数。
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
http://www.springmodules.org/schema/cache/springmodules-cache.xsd
http://www.springmodules.org/schema/cache/springmodules-ehcache.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>contextClassparam-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContextparam-value>
context-param>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>spittr.config.RootConfigparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>dispatcherServletservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextClassparam-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContextparam-value>
init-param>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>spittr.config.WebConfigparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dispatcherServletservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
占位符
Spring MVC允许我们在@RequestMapping路径中添加占位符。占位符的名称要用大括号(“{”和”}”)括起来。路径中的其他部分要与所处理的请求完全匹配,但是占位符部分是任意的值。
package spittr.web;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
public class Spittler {
@RequestMapping("/{spittleId}")
public String spittle(
@PathVariable("spittleId") long spittleId){
System.out.println(spittleId);
return "page";
}
}
这样,在请求路径中,不管占位符部分的值是什么都会传递到处理器方法的spittleId参数中。
如果@PathVariable中没有value属性的话,它会假设占位符的名称与方法的参数名相同。
重定向和前往指定的URL路径
return "redirect:/spitter/";//重定向
return "forward:/spitter";//前往指定的URL路径
表单检验
从Spring3.0开始,Spring MVC中提供了对Java 校验API的支持。
public class User {
@NotNull
@Size(min=5,max=16)
private String userName; //非空,5-16个字符
@NotNull
@Size(min=6, max=10)
private String password;//非空,6-10个字符
}
package spittr.web;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import spittr.entity.User;
public class Spittler {
@RequestMapping("/login")
public String spittle(
@Validated User user,//校验输入
Errors errors){
if(errors.hasErrors()){
return "registerForm";//如果校验出现错误,则重新返回表单。
}
return "redirect:/spitter/";
}
}
Errors参数要紧跟在带有校验注解的参数后面。