SpringMVC從入門到精通
阿新 • • 發佈:2021-10-19
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();
// }
}