本文主要依据《Spring实战》第七章内容进行总结
前两节中,我们主要介绍了Spring MVC的控制器和视图解析器,通过上面两节内容,我们对Spring MVC已经有了一个初步的了解,也能够使用Spring MVC进行基本的Web层编程了,但是Spring MVC的知识还远未结束,在本节,我们将继续介绍Spring MVC的一些高级技术。
1、Spring MVC配置的替代方案
1.1、自定义DispatcherServlet配置
在 Spring MVC(一) 小节中,我们介绍了如何使用Java代码配置DispatcherServlet,我们只需要扩展AbstractAnnotationConfigDispatcherServletInitializer类即可,我们重载了三个abstract方法,实际上还有更多的方法可以进行重载,从而实现额外的配置,其中一个方法就是customizeRegistration()。
在AbstractAnnotationConfigDispatcherServletInitializer将DispatcherServlet注册到Servlet容器中后,就会调用customizeRegistration()方法,并将Servlet注册后得到的ServletRegistration.Dynamic传递进来。通过重载customizeRegistration()方法,我们就可以对DispatcherServlet进行额外的配置,例如,通过调用Dynamic的setLoadOnStartup()设置load-on-startup优先级,通过调用setInitParameter()设置初始化参数,还有可以通过调用setMultipartConfig()来设置对multipart的支持,我们可以看如下的代码:
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement("f://tmp"));
}
上面这段代码就是通过调用Dynamic的setMultipartConfig()来设置对multipart的支持,并设置上传文件的临时目录为f://tmp,具体的multipart功能我们在后面的内容会进行介绍。
1.2、添加其他的Servlet和Filter
按照AbstractAnnotationConfigDispatcherServletInitializer的定义,它会创建DispatcherServlet和ContextLoaderListener,但是如果我们想要注册其他的Servlet、Filter和Listener,那该怎么办呢?
基于Java的初始化器(initializer)的一个好处就在于我们可以定义任意数量的初始化器类。因此,如果我们想往Web容器中注册其他组件的话,只需要创建一个新的初始化器就可以了。最简单的方式就是实现Spring的WebApplicationInitializer接口。例如:
public class MyServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext)
throws ServletException {
//1、注册Servlet
Dynamic d = servletContext.addServlet("myServlet", MyServlet.class);
//2、添加映射
d.addMapping("/myservlet/**");
}
}
上面这段代码就是新注册一个名为myServlet的Servlet,然后将其映射到一个路径上。我们也可以通过这种方式手动注册DispatcherServlet,但是这并没有必要,因为AbstractAnnotationConfigDispatcherServletInitializer能够很好地完成这项任务。
同样的,我们也可以使用这种方式来注册Filter、Listener:
public class MyFilterInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext)
throws ServletException {
//1、注册Filter
Dynamic d = servletContext.addFilter("myFilter", MyFilter.class);
//2、添加映射路径
d.addMappingForUrlPatterns(null, false, "/");
}
}
需要注意的是,上面通过实现WebApplicationInitializer来注册Servlet、Filter、Listener只在Servlet 3.0以后的版本中才适用,如果容器不支持Servlet 3.0及以上的版本,我们不能通过以上的方式注册组件。在上面的例子中,我们注册了一过滤器MyFilter,如果这个Filter只会映射到DispatcherServlet上的话,AbstractAnnotationConfigDispatcherServletInitializer提供了一个更为快捷的方式,就是重载getServletFilters()方法:
@Override
protected Filter[] getServletFilters() {
return new Filter[] {
new MyFilter()};
}
这个方法返回一个Filter的数组,这个数组中的所有Filter都会映射到DispatcherServlet上。
1.3、在web.xml中声明DispatcherServlet
在典型的Spring MVC应用中,我们会需要DispatcherServlet和ContextLoaderListener,AbstractAnnotationConfigDispatcherServletInitializer会自动注册它们,但如果我们使用web.xml来进行配置的话,我们就需要手动注册它们了。下面的实例是一个简单的web.xml文件,它按照传统的方式搭建了DispatcherServelt和ContextLoaderListener。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- 设置根上下文配置文件位置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:root.xml</param-value>
</context-param>
<!-- 注册ContextLoaderListener -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 注册DispathcherServlet -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 将DispatcherServlet映射到/ -->
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在这个配置文件中,上下文参数contextConfigLocation指定了一个XML文件的地址,这个文件定义了根应用上下文,它会被ContextLoaderListener加载。DispatcherServlet会根据Servlet的名字找到一个文件,并基于该文件加载应用上下文,在上面的例子中,Servlet的名字是appServlet,所以DispatcherServlet会从“/WEB-INF/appServlet-servlet.xml”文件中加载其应用上下文。
如果需要指定DIspatcherServlet配置文件的位置的话,那么可以在Servlet上指定一个contextConfigLocation初始化参数,例如:
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:appServlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
在上面的例子中,DispatherServlet将会去类路径下的appServlet.xml中加载应用上下文的bean。
在上面的两个例子里,我们都是通过xml的形式配置Spring应用上下文的bean的,如果我们使用Java配置的形式配置bean,然后再在web.xml配置DispathcerServlet和ContextLoaderListener,那么它们该如何加载Java配置中的bean呢?
要在Spring MVC中使用基于Java的配置,我们需要告诉DipathcerServlet和ContextLoaderListener使用AnnotationConfigWebApplicationContext,这是一个WebApplicationContext的实现类,它会加载Java配置类,而不是使用XML,我们可以设置contextClass上下文参数以及DispatcherServlet的初始化参数。
下面的web.xml配置就是基于Java配置的Spring MVC:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"