后端——框架——视图层框架——spring mvc——HelloWorld示例
本篇介绍mvc框架的重要概念,以及如何搭建spring mvc框架。包含三个部分,概念,环境搭建,示例。
1、概念
1.1 what
第一个重要的概念是what is mvc。
引用原著中对Spring MVC的定义:
Spring Web MVC is the original web framework built on the Servlet API and has been included in the spring framework from the very beginning
这段话的含义有三个部分,Spring Web MVC是一个Web 框架。它是spring框架的一部分。它是基于Servlet API。 所以学习好Spring-core,Servlet对学习Spring MVC有很大的帮助。
Parallel to Spring Web MVC,Spring Framework 5.0 introduced a reactive-stack web framework whose name “spring WebFlux”
从Spring 5.0开始,新添加了基于reactive的响应式框架spring WebFlux,本文略。
1.2 层次结构
普通的Spring项目,使用Spring框架,SpringMVC,它的层次结构是自动创建的。ApplicationContext是WebApplicationContext的父级。 在WebApplicationContext找不到Bean时,会去父级中查找Bean。
ApplicationContext是根据application-context.xml创建的,通常会注入数据源,Service的实现类,事物切面等等。
WebApplicationContext是根据app-webmvc.xml(名称随意)创建的,它会注入Controller, SpringMVC的一些核心对象,例如HandlerMapping,MultiPartResolver。
它们都处于ApplicationContext接口的类层次结构中。通常情况下,一个项目只存在一个WebApplicationContext,一个DispatcherServlet。在多层次的类结构下,一个项目存在多个WebApplicationContext,多个DispatcherServlet对象,DispacterServlet对象与WebApplicationContext的关系为一对一,改变的是ServletContext对象与WebApplicationContext对象变为1对多。
2、搭建环境
搭建环境的三个核心关键点是:
- 创建XXWebApplicationContext对象,并与ServletContext相关联。
- 创建DispatcherSerlvet对象。
- 创建XXConfig对象,它们是mvc的配置,并与XXWebApplicationContext对象关联。也可以使用xml的方式。
2.1 创建WebApplicationContext方式
环境搭建中,创建XXWebApplicationContext对象的方式有以下几种。
- 依赖Servlet:在这些方法中可以自定义创建,绑定,注册。
- 第一种方式,实现ServletContainerInitializer接口,在onStartUp方法中创建WebApplicationContext。
-
第二种方式,实现ServletContextListener接口,在contextInitialized方法中创建WebApplicationContext。
- 依赖Spring mvc:提供相关的配置项,由mvc自动实现。
- 第一种方式,实现WebApplicationInitializer接口,它本质上是实现了ServletContainerInitializer接口。
-
第二种方式,继承AbstractAnnotationConfigDispatcherServletInitializer或者是AbstractDispatcherServletInitializer。前者为注解类型的ApplicationContext,后者为XML方式的ApplicationContext。
-
第三种方式,在web.xml中配置ContextLoaderListener,并配置ServletContext的contextConfigLocation参数,指定配置文件的路径。
2.2 步骤
本篇采用实现WebApplicationInitializer接口方式。
第一步,创建WebApplicationInitializer接口的实现类,实现onStartUp方法。
public class MyWebApp implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { // 1. 创建WebApplicationContext,并绑定ServletContext对象 // 2. 创建DispatcherServlet对象 // 3. 添加mvc配置(实现WebMvcConfiger),或者是Servlet配置(Listener, Filter等) } }
第二步,创建WebApplicationContext对象,绑定ServletContext对象。
public class MyWebApp implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { // 1. 创建WebApplicationContext,并绑定ServletContext对象 // 创建Annotation类型的ApplicationContext AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); // 设置servletContext context.setServletContext(servletContext); // 注册配置类, context.register(AppConfig.class); context.refresh(); // 2. 创建DispatcherServlet对象 // 3. 添加mvc配置(实现WebMvcConfiger),或者是Servlet配置(Listener, Filter等) } }
第三步,创建DispatcherServlet对象。
public class MyWebApp implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { // 1. 创建WebApplicationContext,并绑定ServletContext对象 // 创建Annotation类型的ApplicationContext AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); // 设置servletContext context.setServletContext(servletContext); // 注册配置类, context.register(AppConfig.class); context.refresh(); // 2. 创建DispatcherServlet对象 DispatcherServlet dp = new DispatcherServlet(context); // 获取它的配置信息类,等价于在web.xml中配置servlet-name和servlet-class标签 ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcherServlet", dp); // 继续配置,配置启动的优先级,负数时延迟加载,0表示会和容器一起启动,整数值越高优先级越高 registration.setLoadOnStartup(1); // 配置URL,等价于在web.xml中配置url-pattern,其中/LearnSpringMVC为ContextPath registration.addMapping("/"); // 支持异步请求 registration.setAsyncSupported(true); // 开启记录请求详细信息的日志 registration.setInitParameter("enableLoggingRequestDetails", "true"); // 3. 添加mvc配置(实现WebMvcConfiger),或者是Servlet配置(Listener, Filter等) } }
第四步,创建WebMvc的配置类,这里命名为AppConfig。
public class AppConfig implements WebMvcConfigurer { // 1.实现相关的方法 }
第五步,Servlet配置,添加Filter,Listener等。略。
3、示例
3.1 WebApplicationInitializer实现类
public class MyWebApp implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException { // 创建Annotation类型的ApplicationContext AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); // 设置servletContext context.setServletContext(servletContext); // 注册配置类, context.register(AppConfig.class); context.refresh(); // 配置DispatcherServlet // 创建DispatcherServlet对象 DispatcherServlet dp = new DispatcherServlet(context); // 获取它的配置信息类,等价于在web.xml中配置servlet-name和servlet-class标签 ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcherServlet", dp); // 继续配置,配置启动的优先级,负数时延迟加载,0表示会和容器一起启动,整数值越高优先级越高 registration.setLoadOnStartup(1); // 配置URL,等价于在web.xml中配置url-pattern,其中/LearnSpringMVC为ContextPath registration.addMapping("/"); // 支持异步请求 registration.setAsyncSupported(true); // 开启记录请求详细信息的日志 registration.setInitParameter("enableLoggingRequestDetails", "true"); // Multipart配置对象 MultipartConfigElement multipartConfig = new MultipartConfigElement("D:\\tempDir"); registration.setMultipartConfig(multipartConfig); // 配置请求的分发类型 EnumSetdispatchers = EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.FORWARD, DispatcherType.INCLUDE); // ShallowEtagHeaderFilter ShallowEtagHeaderFilter eTagHeader = new ShallowEtagHeaderFilter(); eTagHeader.setWriteWeakETag(true); FilterRegistration.Dynamic shadowETagFilter = servletContext.addFilter("shadowETagFilter", eTagHeader); shadowETagFilter.addMappingForServletNames(dispatchers, true, "dispatcherServlet"); } }
3.2 WebMvcConfigurer实现类
@Configuration @Import(value = { ViewResolverConfig.class, ControllerConfig.class }) public class AppConfig implements WebMvcConfigurer { /** * * 添加拦截器 * @see */ @Override public void addInterceptors(InterceptorRegistry registry) { } /** * * 添加异常处理解析器 * */ @Override public void configureHandlerExceptionResolvers(Listresolvers) { } /** * * 跨域的全局配置 * */ @Override public void addCorsMappings(CorsRegistry registry) { } /** * * @Title: configureContentNegotiation * @Description:配置内容的类型 */ @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { } /** * * 配置messageConverter */ @Override public void configureMessageConverters(List > converters) { } /** * * 配置静态资源 * */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 创建CacheControl对象 CacheControl cacheControl = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform(); // 设置静态资源的请求 registry.addResourceHandler("/js/**", "/images/**") // 静态资源存放的物理路径 .addResourceLocations("/WEB-INF/js/", "/WEB-INF/images/") // 设置浏览器缓存静态资源的时间 .setCacheControl(cacheControl); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } }
至此,本篇完