在Spring 4中我们已经可以通过全配置来配置Spring MVC了。首先配置文件需要继承AbstractAnnotationConfigDispatcherServletInitializer,怎么样这个类的名字够长吧?
下面是博主的配置。
package com.ssm.chapter15.config; import javax.servlet.MultipartConfigElement; import javax.servlet.ServletRegistration.Dynamic; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { // Spring IoC容器配置 @Override protected Class<?>[] getRootConfigClasses() { // 可以返回Spring的Java配置文件数组 return new Class<?>[] {}; } // DispatcherServlet的URI映射关系配置 @Override protected Class<?>[] getServletConfigClasses() { // 可以返回Spring的Java配置文件数组 return new Class<?>[] { WebConfig.class }; } // DispatchServlet拦截请求匹配 @Override protected String[] getServletMappings() { return new String[] { "*.do" }; } }
这里有三个方法:
getRootConfigClasses:是一个可以配置Spring IoC容器的方法,你可以往它哪里加载Java配置类,这里可以配置数据库,Redis,MyBatis/Hibernate等信息。
getServletConfigClasses:是一个加载Spring MVC配置类的方法,你也可以加载Java配置类,主要配置关于Spring MVC的内容
getServletMappings:是一个配置DispactherServlet拦截的正则式,相当于我们Servlet的拦截配置。
注意,这个类不需要使用web.xml配置加载,它会由Spring MVC的机制加载,或许你会惊讶,它为什么会自动加载呢?那是因为在spring 3.1之后,它给了我们一个类,SpringServletContainerInitializer,那么这个类就继承了Servlet规范的ServletContainerInitializer,按照Servlet的规范,Java Web容器启动的时候,就会加载实现这个类的方法,于是在Java Web容器初始化的时候,这个类就会被我们加载进来了。那么让我们看看它的源码:
package org.springframework.web; import java.lang.reflect.Modifier; import java.util.LinkedList; import java.util.List; import java.util.ServiceLoader; import java.util.Set; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.HandlesTypes; import org.springframework.core.annotation.AnnotationAwareOrderComparator; @HandlesTypes(WebApplicationInitializer.class) public class SpringServletContainerInitializer implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException { //WebApplicationInitializer的实现类列表 List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>(); if (webAppInitializerClasses != null) { for (Class<?> waiClass : webAppInitializerClasses) { // Be defensive: Some servlet containers provide us with invalid classes, // no matter what @HandlesTypes says... //找到WebApplicationInitializer 的实现类,并创建它们的实例 if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) { try { initializers.add((WebApplicationInitializer) waiClass.newInstance()); } catch (Throwable ex) { throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex); } } } } if (initializers.isEmpty()) { servletContext.log("No Spring WebApplicationInitializer types detected on classpath"); return; } servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath"); AnnotationAwareOrderComparator.sort(initializers); //调用onStartup方法 for (WebApplicationInitializer initializer : initializers) { initializer.onStartup(servletContext); } } }
从源码中,可以看到它主要查找WebApplicationInitializer接口的类,进行创建,然后调用onStartup方法进行初始化。显然AbstractAnnotationConfigDispatcherServletInitializer和WebApplicationInitializer存在着必然的某种联系,它们的关系下图所示。
这样大家清楚了实际上AbstractAnnotationConfigDispatcherServletInitializer也是实现了WebApplicationInitializer,所以当我们继承它,那么久可以配置Spring MVC的两个上下文了。于是在没有任何配置的情况下Spring MVC就能自动的发现你继承了 AbstractAnnotationConfigDispatcherServletInitializer的配置类,把它加载进来。
从博主的配置中,大家可以看到加载了一个类——WebConfig,让我们看看它的庐山真面目:
package com.ssm.chapter15.config; import java.util.ArrayList; import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.view.InternalResourceViewResolver; @Configuration //定义Spring MVC扫描的包 @ComponentScan("com.*") //启动Spring MVC配置 @EnableWebMvc public class WebConfig { /*** * 通过注解 @Bean 初始化视图解析器 * @return ViewResolver 视图解析器 */ @Bean(name="internalResourceViewResolver") public ViewResolver initViewResolver() { InternalResourceViewResolver viewResolver =new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/jsp/"); viewResolver.setSuffix(".jsp"); return viewResolver; } /** * 初始化RequestMappingHandlerAdapter,并加载Http的Json转换器 * @return RequestMappingHandlerAdapter 对象 */ @Bean(name="requestMappingHandlerAdapter") public HandlerAdapter initRequestMappingHandlerAdapter() { //创建RequestMappingHandlerAdapter适配器 RequestMappingHandlerAdapter rmhd = new RequestMappingHandlerAdapter(); // HTTP JSON转换器 MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter(); //MappingJackson2HttpMessageConverter接收JSON类型消息的转换 MediaType mediaType = MediaType.APPLICATION_JSON_UTF8; List<MediaType> mediaTypes = new ArrayList<MediaType>(); mediaTypes.add(mediaType); //加入转换器的支持类型 jsonConverter.setSupportedMediaTypes(mediaTypes); //往适配器加入json转换器 rmhd.getMessageConverters().add(jsonConverter); return rmhd; } }
注意类上面的注解,博主也写了其内容,这里初始化了两个bean,一个视图解析器(ViewResolver),不知道啥的视图解析器的自己去打屁股,跟着还初始化了一个RequestMappingHandlerAdapter,这个是Spring 目前默认的HanlderAdapter,用来运行我们控制的东西,比较底层,改天在和大家谈谈。大家还可以看到博主还创建了一个MappingJackson2HttpMessageConverter,它是一个HttpMessageConverter接口的实现类,其中注册mediaType为JSON其意思就是,当我们的控制器的方法上注解了@ResponseBody的时候,Spring MVC就会把响应的消息类型转换为JSON,然后运行控制器,最后控制器返回的结果,通过mediaType的判断就能够找到MappingJackson2HttpMessageConverter,然后通过它就能够转换为JSON了(貌似这段文字没什么其他人讲过,是博主调试源码得来的,觉得赞的给我文章点个赞吧)。
跟着就可以测试了,让我们新建一个控制器。
package com.ssm.chapter15.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; /** * @author ykzhen2015 */ @Controller @RequestMapping("/test") public class TestController { @RequestMapping("/printRole") //处理器打印JSON数据 @ResponseBody public Role printRole() { Role role = new Role(); role.setId(1L); role.setRoleName("role_name_1"); role.setNote("note_1"); return role; } //内部类 class Role { Long id; String roleName; String note; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } } }
好了,这个就是控制器了,妥妥通过@ResponseBody将其响应类型变为了JSON,根据mediaType的匹配,等着返回后被MappingJackson2HttpMessageConverter转换为JSON。
我们对其进行测试,如下图:
怎么样还算简单吗?你学会了吗?学不会记得买笔者的新书《Java EE互联网轻量级框架整合开发——Spring + Spring MVC + MyBatis(SSM框架)和Redis实现》
预计8月份左右上市哦。