laiwanwanyihao 2019-06-26
终于来到了Web项目了。今天来介绍一下Spring MVC的工作原理和常见用法。
学习技术最好的方式当然还是上手练。通过最简单的可运行代码一步步添加复杂功能。但是直接学习别人的代码还是有问题——你无法知道项目是怎么从零到现在的。因此,兜了一圈,我发现还是只能通过写博客来帮助自己学习。
Spring MVC是一个Web框架,基于Model-View-Controller这个出名的Web模式实现。而作为Java Web应用,它仍然离不开Servlet容器。
下图来自嘟嘟的博客
DispatcherServlet接口:
Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。
HandlerMapping接口:
能够完成客户请求到Controller映射。也就是所谓的“Controller路由”功能。
Controller接口:
需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。
Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。
从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。
ViewResolver接口:
Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。
DispatcherServlet是整个Spring MVC的核心。它负责接收HTTP请求组织协调Spring MVC的各个组成部分。其主要工作有以下三项:
我们先来看看最熟悉的XML方式。
在传统的Java Web应用中都会有个重要的web/WEB-INF/web.xml
文件,其中定义Servlet与URL的映射关系。而要如下是一个常见的开启了Spring MVC配置的web.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--加载springmvc配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <!--配置文件的地址 如果不配置contextConfigLocation,默认查找的配置文件名称是classpath下的:servlet名称+"-servlet.xml"即springmvc-servlet.xml--> <param-value>classpath:config/spring/springmvc.xml</param-value> </init-param> </servlet> <!--配置spring容器监听器--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/config/spring/applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
把DispatcherServlet
类映射到了根路径,便可以启用Spring MVC. DispatcherServlet
在加载时可以根据contextConfigLocation
中配置的springmvc.xml初始化Spring应用上下文。
Spring Web也依赖于Spring容器,而Spring容器的入口是Spring应用上下文。在之前的文章中,我们介绍了使用Spring容器的方式就是显式地new一个Spring应用上下文。然而在Web应用中,我们并没有交代应该怎么做。
细心者会发现上面的配置还有个listener
的配置,它也会加载Spring的应用上下文。没错,listener是Web应用加载Spring容器的默认方式,受到Servlet容器支持。而有了Spring MVC后,这两种配置所加载的Spring上下文实际上可以共存。而它们的推荐使用方式是各有分工:
当然,以上只是推荐,实际上可以抛弃掉listener,只用DispatcherServlet.
其实,我们现在甚至不需要WebApp
这个文件夹,自然也不需要web.xml
配置文件了。只需要扩展AbstractAnnotationConfigDispatchServletInitializer
这个抽象类即可。这个类是Spring提供的,而Servlet 3.0之后的容器都能间接地找到这个类,并根据它的配置初始化Spring MVC。它的三个方法又恰好对应上面XML文件的配置:
getServletMappings()
:返回DispatcherServlet要映射到哪些路径上。getServletConfigClasses()
:返回DispatcherServlet所要创建的Spring应用上下文的配置类。getRootConfigClasses()
:返回通过ContextLoaderListener创建的Spring应用上下文的配置类。Spring MVC可以使用注解来配置各种Web组建,这也是它当初领先于Struts的一个地方。如今通过注解配置Web已经深入人心,XML就不再考虑。
要启用Spring MVC注解,只需要在Java Config类中加入@EnableWebMVC
注解即可。这里的config类就是前面指定的DispatcherServlet所要创建的Spring应用上下文的配置类。
此外,还可以在此文件中添加配置ViewResolver的类等等。而让这个类继承自WebMvcConfigurerAdapter
,则可以提供更多配置,如静态资源处理等等。
最后,别忘了使用@ComponentScan
启用组件扫描。
@Controller
:声明一个Controller,这是一个bean,并且Dispatcher会通过HandlerMapping查找它。@RequestMapping
: 配置请求URL的映射。根据路径和请求动作定位方法。返回视图名称:return 一个字符串。即controller方法的返回值是String
类型。
传递模型数据到视图中: 两种方法:
Model
参数,然后在返回前调用model.addAttribute(key, value)
添加数据。接受请求的输入:
@RequestParam
注解。URI中的路径参数:需要两处配置:
@PathVariable
注解。@RequestMapping
路径中添加占位符。如:@RequestMapping("/{userId}")
。本段内容来自嘟嘟的博客。
支持的方法参数类型:
支持的返回类型:
Spring MVC自带很多种视图解析器。比如常见的:
视图解析器 | 描述 |
---|---|
InternalResourceViewResolver | 将试图解析为Web应用的内部资源(一般为JSP) |
FreeMarkerViewResolver | 将试图解析FreeMarker模板 |
ContentNegotiatingViewResolver | 根据客户请求的内容类型委托给对应的视图解析器 |
使用Java配置:声明Bean即可。例如:
@bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setPrefix("/WEB-INF/views/"); resolver.setSuffix(".jsp"); return resolver; }
使用XML配置:就是简单的创建bean。此处略过。
@Service
: 声明一个service组件。它和@Controller
一样都是构造型注解,基于@Component
。@Repository
: 声明一个数据层组件。