转载

Java Web系列:Spring MVC 基础

1.Web MVC基础

MVC的本质是表现层模式,我们以视图模型为中心,将视图和控制器分离出来。就如同分层模式一样,我们以业务逻辑为中心,把表现层和数据访问层代码分离出来是一样的方法。框架只能在技术层面上给我们帮助,无法在思考和过程上帮助我们,而我们很多人都不喜欢思考和尝试。

Java Web系列:Spring MVC 基础

2.实现Web MVC的基础

实现Web MVC基础可以概括为1个前段控制器和2个映射。

(1)前端控制器FrontController

ASP.NET和JSP都是以Page路径和URL一一对应,Web MVC要通过URL映射Controller和View,就需要一个前端控制器统一接收和解析请求,再根据的URL将请求分发到Controller。由于ASP.NET和Java分别以IHttpHandler和Servlet作为核心,因此ASP.NET MVC和Spring MVC分别使用实现了对应接口的 MvcHandlerDispatcherServlet 作为前段控制器。

Java Web系列:Spring MVC 基础

ASP.NET中通过HttpModule的实现类处理URL映射,UrlRoutingModule根据URL将请求转发给前端控制器MvcHandler。Spring MVC中,则根据URL的配置,直接将请求转发给前端控制器DispatcherServlet。

(2)URL和Contrller的映射

ASP.NET MVC将URL和Controller的映射规则存储在 RouteCollection 中,前端控制器MvcHandler通过 IController 接口查找控制器。Spring MVC则通过 RequestMappingController 注解标识映射规则,无需通过接口依赖实现控制i器。

(3)URL和View的映射

ASP.NET MVC 默认通过 RazorViewEngine 来根据URL和视图名称查找视图,核心接口是 IViewEngine 。Spring MVC 通过 internalResourceViewResolver 根据URL和视图名称查找视图,核心接口是 ViewResolver

3.Spring MVC快速上手

(1)Spring MVC初始化

ASP.NET MVC初始化需要我们在HttpApplication.Application_Start方法中注册默认的URL和Controller规则,Spring MVC由于采用注解映射URL和Controller,因此没有对应的步骤。ASP.NET在根web.config中配置了UrlRoutingModule可以将请求转发给MvcHandler,Spring MVC我们需要我们配置DispatcherServlet以及其对应的URL来达到接管所有请求的目的,Spring已经利用Servlet3.0定义的ServletContainerInitializer机制,为我们提供了默认的AbstractAnnotationConfigDispatcherServletInitializer,只要只需要像继承HttpApplication的MvcApplication一样,写一个MyWebApplicationInitializer。

(2)URL和View的映射

ASP.NET的RazorViewEngine内置了View的Path和扩展名.cshtml的规则。Spring MVC的internalResourceViewResolver没有提供默认值,因此如果我们如果不定义Path和扩展名,只需要MyWebApplicationInitializer即可。一般我们会指定将View放置在统一的视图目录中,使用特定的扩展名。Spring同样提供了DelegatingWebMvcConfiguration,我们只需写一个自己的AppConfig继承它,重写configureViewResolvers方法即可。完整的代码如下:

 package s4s;  import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration; import org.springframework.web.servlet.config.annotation.ViewResolverRegistry; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import org.springframework.web.servlet.view.InternalResourceViewResolver;  public class MyWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {      @Override     protected Class<?>[] getRootConfigClasses() {         return new Class[] { AppConfig.class };     }      @Override     protected Class<?>[] getServletConfigClasses() {         return new Class[] { AppConfig.class };     }      @Override     protected String[] getServletMappings() {         return new String[] { "/" };     }  }  @Configuration @ComponentScan class AppConfig extends DelegatingWebMvcConfiguration {      @Override     protected void configureViewResolvers(ViewResolverRegistry registry) {         InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();         viewResolver.setPrefix("/WEB-INF/views/");         viewResolver.setSuffix(".jsp");         registry.viewResolver(viewResolver);     } } 

(3)URL和Controller的映射

上文提到过Spring MVC和ASP.NET MVC的不同,不通过IController接口标识Controller,也不通过RouteCollection定义URL和Controller,取而代之的是两个注解:Controller和RequestMapping。我们简单的定义一个POJO MyController以及其简单的Home方法。并应用上述注解:

 package s4s;  import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;  @Controller public class MyController {      @RequestMapping("/")     public String Home() {         return "home";     } } 

添加/WEB-INF/views/home.jsp视图文件,就完成了最简单的示例。无需web.xml的任何配置。

(4)使用Model

ASP.NET将视图最终编译为WebViewPage<object>,View和Model是一一对应并且类型匹配的,Model可以是任意的POCO。Spring MVC中View和Model是一对多的,提供了ModelMap和其子类ModelAndView提供类似ASP.NET MVC中ViewResult的功能。ModelMap的基类是LinkedHashMap<String, Object>。

我们修改MyController的代码,使用ModelAndView来传递一个简单UserModel模型,作为参数的UserModel对象model和ASP.NET MVC中一样,会自动将请求参数映射到model的属性。返回值ModelAndView时和ASP.NET MVC的return View(viewName,model)类似。只不过因为Spring MVC模型是多个模型的列表,我们还需要指定返回模型的Name。

 package s4s;  import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView;  @Controller public class MyController {     @RequestMapping("/")     public ModelAndView Home(@ModelAttribute UserModel model) {         model.setUserName(model.getUserName() + "~");         return new ModelAndView("home", "model", model);     } }  class UserModel {     String userName = "";      public String getUserName() {         return userName;     }      public void setUserName(String userName) {         this.userName = userName;     } } 

(5)使用View

修改home.jsp,添加jstl和spring的tag支持。由于Spring MVC中的View和ASP.NET MVC中的区别较大,没有办法指定View持有的Model类型也就没有了智能提示和错误检测的优势,一切回归到了脚本语言的时代。

 <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Getting Started: Serving Web Content</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body>     <h2>spring tag</h2>     <form action="<%=request.getContextPath()%>" method="get">         <spring:bind path="model.userName">             <input type="text" name="userName" value="${status.value}" />         </spring:bind>         <input type="submit" value="submit">     </form>     <h2>spring form tag</h2>     <form:form modelAttribute="model" method="get">         <form:input path="userName" />         <input type="submit" value="submit">     </form:form> </html> 

附上pom.xml。其中junit是可选的,jstl是View中使用jstl语法需要引入的。

  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">     <modelVersion>4.0.0</modelVersion>     <groupId>me.test</groupId>     <artifactId>s4s</artifactId>     <packaging>war</packaging>     <version>0.0.1-SNAPSHOT</version>     <name>s4s Maven Webapp</name>     <url>http://maven.apache.org</url>     <dependencies>         <dependency>             <groupId>junit</groupId>             <artifactId>junit</artifactId>             <version>3.8.1</version>             <scope>test</scope>         </dependency>         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>javax.servlet-api</artifactId>             <version>3.1.0</version>         </dependency>         <dependency>             <groupId>org.springframework</groupId>             <artifactId>spring-webmvc</artifactId>             <version>4.2.4.RELEASE</version>         </dependency>         <dependency>             <groupId>javax.servlet</groupId>             <artifactId>jstl</artifactId>             <version>1.2</version>         </dependency>     </dependencies>     <build>         <finalName>s4s</finalName>         <plugins>             <plugin>                 <groupId>org.apache.maven.plugins</groupId>                 <artifactId>maven-compiler-plugin</artifactId>                 <version>3.3</version>                 <configuration>                     <source>1.8</source>                     <target>1.8</target>                 </configuration>             </plugin>         </plugins>     </build> </project>  View Code

4.Spring MVC的初始化机制

(1)应用初始化:

Spring实现了Servlet 3.0规范定义的javax.servlet.ServletContainerInitializer接口并通过javax.servlet.annotation.HandlesTypes注解引用了WebApplicationInitializer接口。因此在Servlet容器初始化时,在当前class path路径下的WebApplicationInitializer实现类的onStartup方法会自动执行(这和ASP.NET的Application_Start作用类似,在系列中的Java Web基础时曾经提到过)。

(2)依赖注入的初始化:

ASP.NET中我们在Application_Start中初始化依赖注入容器。在Spring MVC中,我们实现WebApplicationInitializer接口同样可以执行依赖注入的初始化。在Web环境中,我们使用的ApplicationContext接口的实现类为基于注解的AnnotationConfigWebApplicationContext(在系列中的Spring依赖注入基础中曾经提到过),但我们无需直接实现WebApplicationInitializer并手动初始化AnnotationConfigWebApplicationContext对象,因为Spring已经定义了AbstractAnnotationConfigDispatcherServletInitializer作为WebApplicationInitializer接口的实现类,已经包含了AnnotationConfigWebApplicationContext的初始化。

(3)依赖注入配置:

采用基于Annotation注解时可以通过@ Configurateion 指定POJO来替代web.xml配置依赖注入。同样,@ComponentScan可以替代web.xml中的扫描配置功能,使用ComponentScan配合Configurateion可以达到0xml配置的方式。上文中提到的Contrller相关的注解,都是启用ComponentScan后才会被扫描生效。

(4)DispatcherServlet的初始化:

AbstractAnnotationConfigDispatcherServletInitializer类的父类AbstractDispatcherServletInitializer中已经包含DispatcherServlet的初始化。相关类图如下:

Java Web系列:Spring MVC 基础

5.Spring MVC的Action Filter

.NET MVC提供了众多Filter接口和一个ActionFilterAttribute抽象类作为Filter的基础,其中以实现了IAuthorizationFilter接口的AuthorizeAttribute拦截器最为我们熟知。Spring MVC则提供了基于HandlerInterceptor接口的众多接口、抽象类和实现类,其中也有和.NET MVC类似的权限验证UserRoleAuthorizationInterceptor拦截器。内置的拦截器可以满足大部分需求,为了省事图就画在一张上了,上面是Spring MVC的,下面是.NET MVC的。 Java Web系列:Spring MVC 基础

关于模型验证和权限验证的部分以后再续。

正文到此结束
Loading...