zoukankan      html  css  js  c++  java
  • Java Web系列:Spring MVC基础

    1.Web MVC基础

    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作为前段控制器。

    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)前端控制器DispatcherServlet初始化:AbstractAnnotationConfigDispatcherServletInitializer

    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一样,写一个MvcInitializer

     1 package s4s;
     2 
     3 import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
     4 
     5 public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
     6 
     7     @Override
     8     protected Class<?>[] getRootConfigClasses() {
     9         return new Class[] { };
    10     }
    11 
    12     @Override
    13     protected Class<?>[] getServletConfigClasses() {
    14         return new Class[] { MvcConfig.class };
    15     }
    16 
    17     @Override
    18     protected String[] getServletMappings() {
    19         return new String[] { "/" };
    20     }
    21 
    22 }

    (2)URL和View的映射:WebMvcConfigurerAdapter

    ASP.NET的RazorViewEngine内置了View的Path和扩展名.cshtml的规则。Spring MVC的internalResourceViewResolver没有提供默认值,一般我们会指定将View放置在统一的视图目录中,使用特定的扩展名。Spring同样提供了内置的WebMvcConfigurerAdapter,我们只需写一个自己的MvcConfig继承它,重写configureViewResolvers方法即可。

     1 package s4s;
     2 
     3 import org.springframework.context.annotation.ComponentScan;
     4 import org.springframework.context.annotation.Configuration;
     5 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
     6 import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
     7 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
     8 import org.springframework.web.servlet.view.InternalResourceViewResolver;
     9 
    10 @EnableWebMvc
    11 @ComponentScan
    12 @Configuration
    13 public class MvcConfig extends WebMvcConfigurerAdapter {
    14 
    15     @Override
    16     public void configureViewResolvers(ViewResolverRegistry registry) {
    17         InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    18         viewResolver.setPrefix("/WEB-INF/views/");
    19         viewResolver.setSuffix(".jsp");
    20         registry.viewResolver(viewResolver);
    21     }
    22 }

    4.Spring MVC的Controller、Model和View

    (1)URL和Controller的映射:

    Spring MVC和ASP.NET MVC的不同,不通过IController接口标识Controller,也不通过RouteCollection定义URL和Controller,取而代之的是两个注解:Controller和RequestMapping。因此我们在普通的POJO类上应用@Controller和@RequestMapping即可。

     1 package s4s;
     2 
     3 import javax.validation.Valid;
     4 import org.springframework.security.access.prepost.PreAuthorize;
     5 import org.springframework.security.core.context.SecurityContextHolder;
     6 import org.springframework.stereotype.Controller;
     7 import org.springframework.validation.BindingResult;
     8 import org.springframework.web.bind.annotation.ModelAttribute;
     9 import org.springframework.web.bind.annotation.RequestMapping;
    10 import org.springframework.web.bind.annotation.RequestMethod;
    11 import org.springframework.web.bind.annotation.RequestParam;
    12 import org.springframework.web.bind.annotation.ResponseBody;
    13 
    14 @Controller
    15 public class MyController {
    16 
    17     @ResponseBody
    18     @RequestMapping(value = "/")
    19     public String home() {
    20         return "home";
    21     }
    22 
    23     @RequestMapping(value = "/register")
    24     public String register(@ModelAttribute("model") RegisterUserModel model) {
    25         return "register";
    26     }
    27 
    28     @RequestMapping(value = "/register", method = RequestMethod.POST)
    29     public String register(@ModelAttribute("model") @Valid RegisterUserModel model, BindingResult result) {
    30         if (!result.hasErrors()) {
    31             return "redirect:/account";
    32         }
    33         return "register";
    34     }
    35 }

    (2)Model:

    通过使用@ModelAttribute、@Valid和BindingResult参数,我们可以指定Model的Name是否参与验证并获取验证结果。为在Model上使用注解验证,还需要引入validation-api和hibernate-validator。

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

    Spring MVC中没有ViewResult类型。在Spring MVC中,我们一般返回String类型,可以有多种含义:

        a.返回View的名称。

        b.返回文本:在Action上应用@ResponseBody注解时。

        c.返回跳转:以"redirect:"开头时。如:return "redirect:/success"

    模型的验证:

    (1)在Model字段上使用JSR-303定义的注解(需要引入hibernate validator)。

    (2)在Controller的Model参数上应用@ModelAttribute、@Valid

    (3)在View中使用<form:errors>标签

    Spring MVC需要添加jstl和spring的tag支持才能完成模型相关的操作。由于Spring MVC中的View和ASP.NET MVC中的区别较大,没有办法指定View持有的Model类型也就没有了智能提示和错误检测的优势。

     1 package s4s;
     2 
     3 import javax.validation.constraints.NotNull;
     4 import javax.validation.constraints.Size;
     5 
     6 public class RegisterUserModel {
     7     @Size(max = 20, min = 5)
     8     private String userName;
     9     @Size(max = 20, min = 5)
    10     private String password;
    11     @NotNull
    12     private String confirmPassword;
    13 
    14     public String getUserName() {
    15         return userName;
    16     }
    17 
    18     public void setUserName(String userName) {
    19         this.userName = userName;
    20     }
    21 
    22     public String getPassword() {
    23         return password;
    24     }
    25 
    26     public void setPassword(String password) {
    27         this.password = password;
    28     }
    29 
    30     public String getConfirmPassword() {
    31         return confirmPassword;
    32     }
    33 
    34     public void setConfirmPassword(String confirmPassword) {
    35         this.confirmPassword = confirmPassword;
    36     }
    37 }

    register.jsp

     1 <%@ page language="java" pageEncoding="UTF-8"%>
     2 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
     3 <%@ taglib uri="http://www.springframework.org/tags" prefix="s"%>
     4 <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
     5 <!DOCTYPE HTML>
     6 <html>
     7 <head>
     8 <title>Getting Started: Serving Web Content</title>
     9 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    10 </head>
    11 <body>
    12     <h2>Register</h2>
    13     <form:form modelAttribute="model">
    14         <s:bind path="*">
    15             <c:if test="${status.error}">
    16                 <div id="message" class="error">Form has errors</div>
    17             </c:if>
    18         </s:bind>
    19         <div>
    20             <form:label path="userName">userName</form:label>
    21             <form:input path="userName" />
    22             <form:errors path="userName" cssClass="error" />
    23         </div>
    24         <div>
    25             <form:label path="password">password</form:label>
    26             <form:password path="password" />
    27             <form:errors path="password" cssClass="error" />
    28         </div>
    29         <div>
    30             <form:label path="confirmPassword">confirmPassword</form:label>
    31             <form:password path="confirmPassword" />
    32             <form:errors path="confirmPassword" cssClass="error" />
    33         </div>
    34         <input type="submit" value="submit">
    35     </form:form>
    36 </html>

    5.Spring MVC的初始化机制

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

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

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

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

    5.Spring MVC的Action Filter

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

    总结

    (1)MVC实现的要点是前端控制器、URL和Controller的映射、URL和View的映射

    (2)MvcHandler和DispatcherServlet

    (3)ServletContainerInitializer和HttpApplication.Application_Start

    (4)RazorViewEngine和internalResourceViewResolver

    (5)IMvcFilter和HandlerInterceptor

    目前没有找到类似ASP.NET中的从特性(注解)生成客户端JavaScript验证的方式,如果大家有相关资料分享,提前谢谢大家。

    参考:

    (1)http://www.ibm.com/developerworks/cn/java/j-lo-jsr303/index.html

    (2)http://spring.oschina.mopaas.com/validation.html#validation-binder

    (3)http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/

  • 相关阅读:
    第五周作业
    作业4
    20182302 2019-2020-1 《数据结构与面向对象程序设计》实验3报告
    作业四
    实验二
    实验一
    排序大集合java
    阿里面试——运筹优化工程师
    树的子结构判断
    剑指offer——合并两个排序的链表——对象、引用和赋值初接触
  • 原文地址:https://www.cnblogs.com/easygame/p/5082647.html
Copyright © 2011-2022 走看看