1.springMvc基于注解版(maven项目)
1.1 先引入springMvc和Servlet3.0的依赖包
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.hxl</groupId>
<artifactId>SpringMvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- springmvc依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
<!--防止冲突 于tomcat中的servlet冲突 -->
<scope>provided</scope>
</dependency>
</dependencies>
<!-- 编译maven编译war的插件 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<!--不需要war -->
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
1.2 我们了解一下springMvc启动的原理
引入springMvc的依赖包,springMvc中的spring-web中就会找到 METAINF/services/javax.servlet.ServletContainerInitializer中可以找springMvc启动时 绑定的servlet启动类 org.springframework.web.SpringServletContainerInitializer
2.查看org.springframework.web.SpringServletContainerInitializer的如何实现的
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 {
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...
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;
}
AnnotationAwareOrderComparator.sort(initializers);
servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
}
2.1.实现了sevlet中的ServletContainerInitializer接口 重写了onStartup() Modifier 是查找方法的修饰符(抽空看一下) 主要查找出WebApplicationInitializer的实现类来继续调用onStartup()实现初始化
2.2.SpringServletContainerInitializer绑定的是@HandlesTypes({WebApplicationInitializer.class}) springMvc绑定的启动类 * 项目启动时会加载WebApplicationInitializer类以及其的实现类
*2.2.1.AbstractContextLoaderInitializer 容器初始化启动的加载的文件 * 创建一个根容器 将此容器加到servletContext的上下文中
package org.springframework.web.context;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.web.WebApplicationInitializer;
public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {
protected final Log logger = LogFactory.getLog(getClass());
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
protected void registerContextLoaderListener(ServletContext servletContext) {
//创建一个根容器
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
//如何根容器不为null 将根容器加到 ContextLoaderListener 容器的监听类中
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
//将此容器转化为spring的容器
listener.setContextInitializers(getRootApplicationContextInitializers());
//注册监听器为项目启动时加载
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
protected abstract WebApplicationContext createRootApplicationContext();
protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() {
return null;
}
}
* 2.2.2.AbstractDispatcherServletInitializer 容器实现DispatcherServlet的初始化的抽象类,主要针对于DispatcherServlet registerDispatcherServlet(servletContext); 注册dispatcherServlet
package org.springframework.web.servlet.support;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.FilterRegistration.Dynamic;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.core.Conventions;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.AbstractContextLoaderInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.FrameworkServlet;
public abstract class AbstractDispatcherServletInitializer extends
AbstractContextLoaderInitializer {
public static final String DEFAULT_SERVLET_NAME = "dispatcher";
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);
}
protected void registerDispatcherServlet(ServletContext servletContext) {
// servletName=dispatcher
String servletName = getServletName();
//非空校验
Assert.hasLength(servletName, "getServletName() must not return empty or null");
//创建 WebApplicationContext web的上下文
WebApplicationContext servletAppContext = createServletApplicationContext();
//非空判断
Assert.notNull(servletAppContext,
"createServletApplicationContext() did not return an application " +
"context for servlet [" + servletName + "]");
//创建dispatcherServlet new DispatcherServlet(servletAppContext)
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
//设置初始化参数 预留方法
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
//注册 dispatcherServlet 成为一个servlet服务
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
//非空判断
Assert.notNull(registration,
"Failed to register servlet with name '" + servletName + "'." +
"Check if there is another servlet registered under the same name.");
/**
* 注册初始化参数
* LoadOnStartup=1
* ServletMapping 映射的路径
* 异步支持
*/
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
registration.setAsyncSupported(isAsyncSupported());
//获取所有的过滤器 注册为filter服务
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
protected String getServletName() {
return DEFAULT_SERVLET_NAME;
}
protected abstract WebApplicationContext createServletApplicationContext();
protected FrameworkServlet createDispatcherServlet(WebApplicationContext servletAppContext) {
return new DispatcherServlet(servletAppContext);
}
protected ApplicationContextInitializer<?>[] getServletApplicationContextInitializers() {
return null;
}
protected abstract String[] getServletMappings();
protected Filter[] getServletFilters() {
return null;
}
protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) {
String filterName = Conventions.getVariableName(filter);
Dynamic registration = servletContext.addFilter(filterName, filter);
if (registration == null) {
int counter = -1;
while (counter == -1 || registration == null) {
counter++;
registration = servletContext.addFilter(filterName + "#" + counter, filter);
Assert.isTrue(counter < 100,
"Failed to register filter '" + filter + "'." +
"Could the same Filter instance have been registered already?");
}
}
registration.setAsyncSupported(isAsyncSupported());
registration.addMappingForServletNames(getDispatcherTypes(),false, getServletName());
return registration;
}
private EnumSet<DispatcherType> getDispatcherTypes() {
return (isAsyncSupported() ?
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) :
EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE));
}
protected boolean isAsyncSupported() {
return true;
}
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
}
}
* 2.2.3.AbstractAnnotationConfigDispatcherServletInitializer 容器配置DispatcherServlet的注解的类 集成AbstractDispatcherServletInitializer 创建带有@Component @Configuration的父子容器类
package org.springframework.web.context.support;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
public abstract class AbstractAnnotationConfigDispatcherServletInitializer
extends AbstractDispatcherServletInitializer {/**
* 创建一个AnnotationConfigWebApplicationContext
* getRootConfigClasses 将spring的信息注册进去
*
* @return
*/
@Override
protected WebApplicationContext createRootApplicationContext() {
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
rootAppContext.register(configClasses);
return rootAppContext;
}
else {
return null;
}
}
/**
* 创建一个AnnotationConfigWebApplicationContext
* getServletConfigClasses 将dispatcherservlet的配置注册进去
*
* @return
*/
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) {
servletAppContext.register(configClasses);
}
return servletAppContext;
}
protected abstract Class<?>[] getRootConfigClasses();
protected abstract Class<?>[] getServletConfigClasses();
}
1.3 进入正题,我们使用注解需要继承AbstractAnnotationConfigDispatcherServletInitializer 重新写里面的方法
package cn.itcast;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import cn.itcast.myMvcConfig.Appconfig;
import cn.itcast.myMvcConfig.RootConfig;
/**
* 继承抽象的注解的dispatcherServlet的初始化容器
* @author hxl
*
*/
public class MyAnocationDispatcherServletInitialer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
//创建根容器(spring的配置文件)
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
@Override
//创建springmvc容器(mvc的配置文件)
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{Appconfig.class};
}
@Override
//映射的路径 /拦截所有请求 包括静态资源 不包括jsp页面
// /* 包括jsp文件
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
spring父容器的配置类
package cn.itcast.myMvcConfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
/**
* spring 父容器只扫描service和dao
* 不扫描controller
*
* @author hxl
*
*/
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@ComponentScan(value="cn.itcast",excludeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})})
public class RootConfig {
}
springMvc子容器的配置类
package cn.itcast.myMvcConfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import cn.itcast.intercepter.MyInterCptor;
/**
* spring mvc 只扫描Contrller 子容器
*
* useDefaultFilters=false 禁用默认的扫描规则
* @author hxl
*
*/
@EnableWebMvc
//相当于mvc:annocation-driven 开启springmvc的高级配置
/**
* 实现web
* @author hxl
* 实现WebMvcConfigurer重新方法即可配置springmvc的各种配置
* 包括静态资源 上传下载 路径映射
* WebMvcConfigurerAdapter 和WebMvcConfigurer一样,只不过为我们
* 提供了空的实现,方便我们只配置自己想要的实现
*/
@ComponentScan(value="cn.itcast",includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})}
,useDefaultFilters=false)
public class Appconfig extends WebMvcConfigurerAdapter{
//定制功能
//视图解析器
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
//super.configureViewResolvers(registry);
registry.jsp();//==jsp("/WEB-INF/", ".jsp");
//registry.jsp("/WEB-INF/jsp/",".jsp");
}
//静态资源访问 相当于 <rerources>
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
//super.configureDefaultServletHandling(configurer);
configurer.enable();
}
//拦截器 相当于 inctecptor
@Override
public void addInterceptors(InterceptorRegistry registry) {
//super.addInterceptors(registry);
registry.addInterceptor(new MyInterCptor()).addPathPatterns("/**");
}
}
简单请求和视图解析器测试
package cn.itcast.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.itcast.service.UserService;
@Controller
public class UserController {
@RequestMapping("/hello")
@ResponseBody
public String hello(){
return "hello";
}
@RequestMapping("/sucess")
//视图解析器 返回jsp页面 跳转到WEB-INF/jsp/success.jsp
public String sucess(){
return "success";
}
}
过滤器配置类
package cn.itcast.intercepter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 自定义拦截器
* @author hxl
*
*/
public class MyInterCptor implements HandlerInterceptor {
//发放执行之前
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle=======");
//此处返回false直接结束,返回true执行request请求流程
return true;
}
//方法执行正确后执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle=======");
}
//页面相应之后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion=======");
}
}
配置完成之后如果能正常访问ok,以上我的拙略之见,如有不对欢迎雅正。