使用全注解配置Spring MVC

微笑 在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 + MyBatisSSM框架)和Redis实现》

预计8月份左右上市哦。





猜你喜欢

转载自blog.csdn.net/ykzhen2015/article/details/70666623