之前我们的spring mvc应用搭建尽管有一部分可以使用spring注解,但环境的创建仍然要依赖xml配置文件,本节介绍利用servlet3新特性和spring的@configuration等注解来实现一个完全没有xml配置的spring mvc应用
(一)概述
之前的应用对xml配置文件的依赖主要有两块:
1. web.xml,用于创建web应用的容器也就是servlet上下文,并且在当前web应用中声明spring mvc的核心servlet–DispatcherServlet,这个文件可以利用servlet3.x的编程式创建web容器的特性来替代,具体实现是可以通过spring3.1提供的WebApplicationInitializer接口来完成。
2. spring mvc的核心配置文件,该文件主要配置要自动扫描的package,视图解析器等,该文件可以通过spring3以后提供的@Configuration,@ComponentScan,@Bean等注解用编程的方式替代。
(二)实现WebApplicationInitializer接口替代web.xml
自定义一个web应用初始化类,比如叫MyWebInitializer,实现spring的org.springframework.web.WebApplicationInitializer接口。该接口是spring用来封装servlet3.x配置的接口,其实现类在运行时将会被SpringServletContainerInitializer获取并自动调用WebApplicationInitializer实现类的onStartup方法,所以我们的初始化web容器的操作都定义在MyWebInitializer重写的onStartup方法中。代码如下:
public class MyWebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// 创建spring容器
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMVCConfig.class);// 在spring容器中加载spring mvc配置类
ctx.setServletContext(servletContext);// 将spring容器放置在web容器中加载
// 设置spring mvc核心控制器(DispatcherServlet)
Dynamic springmvc = servletContext.addServlet(“springmvc”, new DispatcherServlet(ctx));
springmvc.addMapping(“/”);
springmvc.setLoadOnStartup(1);
}
}
可以看到,web.xml中的所有配置都以编码方式一一替代,具体来说:
1. spring mvc核心控制器的声明和URL映射
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
由这段代码替代:
Dynamic springmvc = servletContext.addServlet(“springmvc”, new DispatcherServlet(ctx));springmvc.addMapping(“/”);
这里使用了servlet3.0的ServletRegistration(具体是用其内部类Dynamic),用于向web容器即Servlet上下文动态注册一个servlet。
2. spring mvc核心配置文件的加载
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
由这段代码替代:
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMVCConfig.class);// 在spring容器中加载spring mvc配置类
其中SpringMVCConfig是我们自定义的用于替代spring mvc配置文件的类,也就是说该xml文件也将以编码方式替换,该类的实现稍后讲解。
3. DispatcherServlet启动加载优先级(用于在web容器启动时自动加载DispatcherServlet)
<load-on-startup>1</load-on-startup>
由这段代码替代:
springmvc.setLoadOnStartup(1);
(三)借助spring注解以编码方式替代spring mvc配置文件
刚才在配置Web容器时,我们为AnnotationConfigWebApplicationContext注册了一个叫SpringMVCConfig的自定义类,该类就是用来替代spring mvc核心配置文件的配置类,代码如下:
@Configuration
@EnableWebMvc
@ComponentScan(“controller”)
public class SpringMVCConfig {
@Bean
public InternalResourceViewResolver internalResourceViewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix(“/WEB-INF/jsp/”);
viewResolver.setSuffix(“.jsp”);
return viewResolver;
}
}
可以看到,该类是一个POJO,没有实现任何接口或继承任何基类,完全是依靠spring的几个注解完成功能。对比下之前的配置文件,可以分成这几个部分:
1. spring配置文件的根节点<beans>,该节点用类上的@Configuration来替代
2. 用于配置自动扫描的<context:component-scan base-package=“x.x”/>元素,在配置类中使用类上的@ComponentScan注解来替代
3.声明了一个InternalResourceViewResolver的spring bean,用于视图解析,在配置类中,每个<bean>元素的声明由一个方法+@Bean注解来替代。比如这个类,返回类型就是我们的视图解析器,并且以方法名作为bean的id。(所以这里的方法名看起来有点奇怪)
4. 最后还要在类上加上一个@EnableWebMvc注解,表示这是一个spring 的web容器的配置
有了这两个配置类,我们就可以告别web.xml和spring mvc的配置文件了。
(四)修改POM文件
由于maven打WAR包时默认要去找web.xml,现在我们已经没有这个文件了,build时就会报错,需要增加一个maven-war-plugin插件,并将failOnMissingWebXml节点设为false,让其打包时不去寻找web.xml即可
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
(五)静态资源处理
同xml方式配置类似,由于DispatherServlet拦截了所有请求,无法请求到静态资源,如html,css,js等,解决方法为:让我们的spring mvc配置类继承spring提供的WebMvcConfigurerAdapter抽象类,并重写其addResourceHandlers方法实现对静态资源路径的映射
注意,addResourceHandler方法用于声明客户端方法的路径样式,参数/html/**用了ant样式路径,表示客户端请求web应用下html开头的任何路径都可以访问到。而addResourceLocations方法是声明静态资源实际存放的路径,其中的参数/html/表示资源放在web应用下的html目录下,这是一个公开目录,当然你也可以放在web-inf及其子目录下。
(六)响应时的中文乱码问题
同xml配置方式一样,如果直接将方法返回值作为响应体输出,也就是用@ResponseBody注解的方法(通常用在AJAX,JSON中)中文不能正常编码,原因是spring mvc的StringHttpMessageConverter默认编码方式为ISO-8859-1,这在上一节已经说过。当时我们是采用在配置文件中增加一个StringHttpMessageConverter的bean声明,并且修改器mediatype来覆盖默认编码。使用纯编码方式配置方式同样可以实现,而且本质上跟配置文件的原理是一样的。具体做法为重写WebMvcConfigurerAdapter的另一个方法public void configureMessageConverters(List<HttpMessageConverter<?>> converters),在方法中以编码方式替换原有的媒体类型,代码如下:
这段代码等同于这段配置:
<mvc:message-converters>
<bean class=”org.springframework.http.converter.StringHttpMessageConverter”>
<property name=”supportedMediaTypes”>
<list>
<!– <value>application/json;charset=UTF-8</value> –>
<value>text/html;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
当然mediaType的子类型也可以是plain,这里只是为了在浏览器中测试方便才使用了html。
(七)总结
本节介绍了利用spring3和servlet3的新特性,0配置实现spring mvc基本功能的具体做法。xml的方式和纯编程的方式实现spring容器各有优缺点,到底使用哪种方式还是更多考虑项目组的习惯,目前无所谓孰优孰劣。但是编程的方式至少有两个好处:一是促使我们更深入去学习spring mvc的源码,思考实现的原理,而不是仅仅记住一堆配置文件;而是为学习spring boot做铺垫,spring boot框架正是采用了0配置方式实现spring容器及其他容器从而达到一个极速开发的目标。从这个角度讲,纯编程的方式应该是将来的发展趋势。
原文 : http://songdi5403.iteye.com/blog/2351395