SpringMVC从入门到精通

SpringMVC 从入门到精通

  最近暂停Spring的源码学习,主要是路神讲的有点难,消化起来太慢了,为了知识的迅速扩张,决定开始穿插SpringMVC的学习,等SpringMVC的几节课听完(预计两周)之后继续Spring源码的学习,之后再学SpringBoot,tomcat。

从传统的web项目说起。

  • 其实距离学习传统的JavaWeb已经过去了三年多了,中间也没有用过,只能通过idea新建的web项目来找找目录结构。
    SpringMVC从入门到精通

  • 经典的MVC项目的结构图与target展开图如下:
    SpringMVC从入门到精通
      从中可以看出resources文件夹下面的文件在打包之后直接在classes目录下,也就是我们常说的classpath,但是webapp文件夹下的会直接进war包的WEB-INF目录下面。(这里webapp其实是后来通过手动方式添加成为web source directory的),我们都知道WEB-INF中的文件只能通过服务端进行访问,而客户端不能够直接对其进行访问。
    SpringMVC从入门到精通

  • web.xml作为Servlet的规范也是整个Web项目的启动器。

web.xml
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>

    <!--listener作用:在web应用启动的时候能够加载Spring 环境-->

    <!--<listener>-->
        <!--<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
    <!--</listener>-->
    <!--<context-param>-->
        <!--<param-name>contextConfigLocation</param-name>-->
        <!--<param-value>spring.xml</param-value>-->
    <!--</context-param>-->

    <!--<servlet>-->
        <!--<servlet-name>springmvc</servlet-name>-->
        <!--<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>-->
        <!--<init-param>-->
            <!--<param-name>contextConfigLocation</param-name>-->
            <!--<param-value>spring-mvc.xml</param-value>-->
        <!--&lt;!&ndash;</init-param>&ndash;&gt;-->
        <!--<load-on-startup>1</load-on-startup>-->
    <!--</servlet>-->


    <!--<servlet-mapping>-->
        <!--<servlet-name>springmvc</servlet-name>-->
        <!--<url-pattern>*.do</url-pattern>-->
    <!--</servlet-mapping>-->


</web-app>
  • spring-mvc.xml中一般配置一些controller的映射信息。
spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
      name:给当前控制器取的一个名字,相当于Servlet中的资源名称,以便浏览器访问,必须以斜杠/开头
      建议使用 name属性,不要使用id,因为早期版本 id 不支持特殊字符 如 /斜杠
     -->
    <bean name="/hello/hello.do" class="abc.moxi.mvc.controller.helloController" />
    <bean name="/hh.do" class="abc.moxi.mvc.controller.regularController"/>
</beans>

Servlet3.0规范

  • tomcat作为一个web容器,其必须实现的就是Servlet的规范。而规范中的启动时就要从下图的文件夹中加载类。
    SpringMVC从入门到精通
      里面写的是org.springframework.web.SpringServletContainerInitializer
SpringServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

	@Override
	public void onStartup(@Nullable Set\\<Class\\<\\?\\>\\> webAppInitializerClasses, ServletContext servletContext)
			throws ServletException {

		List<WebApplicationInitializer> initializers = new LinkedList<>();

		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)
								ReflectionUtils.accessibleConstructor(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);
		for (WebApplicationInitializer initializer : initializers) {
			initializer.onStartup(servletContext);
		}
	}

}

  • 这里就用到了这个规范。在tomcat启动的时候会加载这个类执行onStartup方法,将@HandlerType注解中的所有实现类均加载进来执行它们的onStartup方法。

  • 那么就可以利用这一点来去掉web.xml。

0配置原理
public class MyWebApplicationInitializer implements WebApplicationInitializer {


   
    //实现0xml
    //写一个类 实现spring 的接口:WebApplicationInitializer


    //tomcat 启动的时候会调用 onStartup方法 为什么?

    //传入一个ServletContext : web上下文对象   web.xml能做的 ServletContext都能做
    //因为servlet 3.0的一个新规范   为什么不是tomcat规范而是servlet规范
    //SPI “你”
    @Override
    public void onStartup(ServletContext servletCxt) {
        //初始化spring 容器  以注解的方式
        AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
        ac.register(AppConfig.class);
//        ac.setServletContext(servletCxt);
//        ac.refresh();
        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet);
        registration.setLoadOnStartup(1);
//        registration.setInitParameter("contextConfigLocation","spring mvc.xml 的地址");
        registration.addMapping("*.do");
}
}
- 0XML中也可以加载springmvc.xml来进行配置,但是既然都0XML了,Springmvc.xml怎么能够还存在呢?当然是在AppConfig类当中进行配置啦!!!
AppConfig
@Configuration
@ComponentScan("com")
@EnableWebMvc  // <annotation:driver>
public class AppConfig implements WebMvcConfigurer  {

    //这接口里面的方法贯穿了所有spring mvc的配置

//    @Bean

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {

    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {

    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {

    }

    @Override
    public void addFormatters(FormatterRegistry registry) {

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {

    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {

    }

    /**
     * 在这里配置视图解析器
     * @param registry
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/page/",".html");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {

    }

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {

    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
//        for (HttpMessageConverter<?> converter : converters) {
//            System.out.println(converter);
//        }
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter
                = new FastJsonHttpMessageConverter();
        converters.add(fastJsonHttpMessageConverter);
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {

    }

    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {

    }

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {

    }

    @Override
    public Validator getValidator() {
        return null;
    }

    @Override
    public MessageCodesResolver getMessageCodesResolver() {
        return null;
    }


//    @Bean
//    public TestController user(){
//         return  new TestController();
//    }



}
上一篇:2019级软件工程应用与实践-人工智能快递柜(代码分析2)


下一篇:interface接口的自定义泛型