SpringMVC 从入门到精通
最近暂停Spring的源码学习,主要是路神讲的有点难,消化起来太慢了,为了知识的迅速扩张,决定开始穿插SpringMVC的学习,等SpringMVC的几节课听完(预计两周)之后继续Spring源码的学习,之后再学SpringBoot,tomcat。
从传统的web项目说起。
-
其实距离学习传统的JavaWeb已经过去了三年多了,中间也没有用过,只能通过idea新建的web项目来找找目录结构。
-
经典的MVC项目的结构图与target展开图如下:
从中可以看出resources文件夹下面的文件在打包之后直接在classes目录下,也就是我们常说的classpath,但是webapp文件夹下的会直接进war包的WEB-INF目录下面。(这里webapp其实是后来通过手动方式添加成为web source directory的),我们都知道WEB-INF中的文件只能通过服务端进行访问,而客户端不能够直接对其进行访问。 -
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>-->
<!--<!–</init-param>–>-->
<!--<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的规范。而规范中的启动时就要从下图的文件夹中加载类。
里面写的是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");
}
}
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();
// }
}