本章内容
This chapter covers Alternate Spring MVC configuration options Handling file uploads Handling exceptions in controllers Working with flash attributes
spring mvc的基本配置,如下示,在第5章第1节即5.1中
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Class>[] getRootConfigClasses() { return new Class>[] { RootConfig.class }; } @Override protected Class>[] getServletConfigClasses() { return new Class>[] { WebConfig.class }; } }
需求:
You may need servlets and filters in addition to DispatcherServlet. Maybe you need to do some additional configuration on DispatcherServlet itself. For pre-Servlet 3.0 container, you may need to configure DispatcherServlet in a traditional web.xml file.
7.1.1 Customizing DispatcherServlet configuration
7.1.1 自定义DispatcherServlet配置
代码5.1(原文说的是代码7.1,那是错的.)中的三个方法,如下示,是在必须重写的三个抽象方法.
getServletMappings getRootConfigClasses getServletConfigClasses
除此之外还有其它可选的重写方法.如
customizeRegistration()
对象AbstractAnnotationConfigDispatcherServletInitializer在将DispatcherServlet注册到servlet容器之后(在此过程中还生成了ServletRegistration.Dynamic对象),会调用customizeRegistration()方法,把对象ServletRegistration.Dynamic传递给该方法.
对象ServletRegistration.Dynamic是AbstractAnnotationConfigDispatcherServletInitializer在将DispatcherServlet注册到servlet容器时生成的.通过重写customizeRegistration()方法可以将自定义的配置应用到DispatcherServlet中.
举例说明,如果要启用DispatcherServlet的multipart requests(类似上传文件这样的请求,可以参考http://blog.csdn.net/five3/article/details/7181521),那么需要重写customizeRegistration方法并在方法内设置MultipartConfigElement对象,如下示
@Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads")); }
这样放到5.1里就是这样的,注意引入的包别引错了.
import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Class>[] getRootConfigClasses() { return new Class>[] { RootConfig.class }; } @Override protected Class>[] getServletConfigClasses() { return new Class>[] { WebConfig.class }; } @Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig( new MultipartConfigElement("/tmp/spittr/uploads")); } }
在把ServletRegistration.Dynamic对象当参数传递给方法customizeRegistration()之后(其实就是重写customizeRegistration这个方法之后),就可以实现下面几个功能了
1. set the load-on-startup priority by calling setLoadOnStartup()
2. set an initialization parameter by calling setInitParameter()
3. call setMultipartConfig() to configure Servlet 3.0 multipart support
7.1.2 Adding additional servlets and filters
7.1.2 配置servlet和过滤器
实现对象AbstractAnnotationConfigDispatcherServletInitializer的时候就创建了DispatcherServlet和ContextLoaderListener.但是如果要注册别的servlets, filters, or listeners,如何操作?
使用java配置的一个好处就是定义的初始化类的数量可以如你所愿.因此,当需要注册组件时,只需要创建一个初始化类即可.最简单的方式 就是实现spring的WebApplicationInitializer接口.
下面的代码显示了如何通过实现WebApplicationInitializer接口来注册一个servlet
import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.WebApplicationInitializer; public class MyServletInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { Dynamic myServlet = servletContext.addServlet("myServlet", MyServlet.class); myServlet.addMapping("/custom/**"); } }
上面的代码是一个相对比较简单的servlet注册初始化类.该类注册了一个servlet然后将其与单个路径映射.其实DispatcherServlet也可以通过这样的方式来手动注册,但是真的没有必要,因为AbstractAnnotationConfigDispatcherServletInitializer已经替我们做了很多工作.
类似地,也可以通过创建一个WebApplicationInitializer实现来注册监听器或者过滤器,下面的代码显示了如何注册一个过滤器
@Override public void onStartup(ServletContext servletContext) throws ServletException { javax.servlet.FilterRegistration.Dynamic filter = servletContext.addFilter("myFilter", MyFilter.class); filter.addMappingForUrlPatterns(null, false, "/custom/*"); }
在servlet3.0容器中,WebApplicationInitializer是一个通用的注册servlets, filters, and listeners的方式.但是如果只想要将注册的过滤器与DispatcherServlet建立映射,在AbstractAnnotationConfigDispatcherServletInitializer中有快捷方式.
要注册一个或者多个注册器,并将其与DispatchServlet映射起来,只需要重写getServletFilters() 方法即可.
@Override protected Filter[] getServletFilters() { return new Filter[] { new MyFilter() }; }
getServletFilters()这个方法在AbstractDispatcherServletInitializer中,而AbstractAnnotationConfigDispatcherServletInitializer又继承自AbstractDispatcherServletInitializer,所以就在实现AbstractAnnotationConfigDispatcherServletInitializer时候重写该方法即可.
import javax.servlet.Filter; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected String[] getServletMappings() { return new String[] { "/" }; } @Override protected Class>[] getRootConfigClasses() { return new Class>[] { RootConfig.class }; } @Override protected Class>[] getServletConfigClasses() { return new Class>[] { WebConfig.class }; } @Override protected void customizeRegistration(Dynamic registration) { registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads")); } @Override protected Filter[] getServletFilters() { return new Filter[] { new MyFilter() }; } }
观察方法Filter[] getServletFilters(),可见该方法返回的是一个javax.servlet.Filter数组,上面的示例中,只返回了一个过滤器,但实际上可以返回的过滤器数量如您所愿.这里没有必要明确声明将过滤器与DispatchServlet建立映射,由容器自动完成.
7.1.3 Declaring DispatcherServlet in web.xml
典型的创建DispatchServlet和ContextLoaderListener的xml配置
contextConfigLocation /WEB-INF/spring/root-context.xml org.springframework.web.context.ContextLoaderListener appServlet org.springframework.web.servlet.DispatcherServlet 1 appServlet /
DispatchServlet和ContextLoaderListener会分别指定对应的应用上下文,上面的配置中,ContextLoaderListener指定了应用上下文,但是DispatchServlet没有,这样的话,默认使用的是应用名后接-context.xml的文件名的方式,该文件默认放在WEB-INF目录下.
下面指定了DispatchServlet应用上下文
contextConfigLocation /WEB-INF/spring/root-context.xml org.springframework.web.context.ContextLoaderListener appServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/spring/appServlet/servlet-context.xml 1
下面的配置表示DispatcherServlet和ContextLoaderListener使用AnnotationConfigWebApplicationContext,该对象实现了WebApplicationContext,它会加载java配置类而不会加载xml文件.
contextClass org.springframework.web.context.support.AnnotationConfigWebApplicationContext contextConfigLocation com.habuma.spitter.config.RootConfig org.springframework.web.context.ContextLoaderListener appServlet org.springframework.web.servlet.DispatcherServlet contextClass org.springframework.web.context.support.AnnotationConfigWebApplicationContext contextConfigLocation com.habuma.spitter.config.WebConfigConfig 1 appServlet /