[Spring]SpringMVC

MVC理论基础

WE中的三重架构:

  • 每一层都有着各自的职责。
  • 最关键的当属表示层,相当于直接与用户的浏览器打交道的一层,并且所有的请求都会进过它的解析,然后再告知业务层进行处理,任何页面的返回和数据填充也全靠表示层来完成,因此它实际上是整个三层架构中最关键的一层。
  • 但需要编写大量的Servlet(也就是表示层实现)来处理来自浏览器的各种请求,但是我们发现,仅仅是几个很小的功能,以及几个很基本的页面,我们都要编写将近十个Servlet。
  • 业务层负责数据处理。
  • SpringMVC正是为了解决这种问题而生的,它是一个非常优秀的表示层框架,采用MVC思想设计实现。

MVC解释如下:

  • M是指业务模型(Model):通俗的讲就是我们之前用于封装数据传递的实体类。
  • V是指用户界面(View):一般指的是前端页面。
  • C则是控制器(Controller):控制器就相当于Servlet的基本功能,处理请求,返回响应。

  • SpringMVC正是希望这三者之间进行解耦,实现各干各的,更加精细地划分对应的职责。

  • 最后再将View和Model进行渲染,得到最终的页面并返回给前端(就像之前使用Thymeleaf那样。
  • 把实体数据对象和前端页面都给到Thymeleaf,然后它会将其进行整合渲染得到最终有数据的页面,而本教程也会使用Thymeleaf作为视图解析器进行讲解)

Controller控制器

  • 它shyingDispatcherServlet替代Tomact为我们提供的默认静态资源Servlet。
  • 现在所有的请求都会经过DispatcherServlet进行处理。
  • DispatchServlet的作用:

  • 我们的请求到达Tomcat服务器之后,会交给当前的Web应用程序进行处理。
  • SpringMVC使用DispatcherServlet来处理所有请求,它被作为一个统一的访问点,所有的请求全部由它来进行调度。
  • 当一个请求经过DispatcherServlet之后,会先走HandlerMapping,它会将请求映射为HandlerExecutionChain,依次经过HandlerInterceptor有点类似于之前我们所学的过滤器,不过在SpringMVC中我们使用的是拦截器。
  • 然后再交给HandlerAdapter,根据请求的路径选择合适的控制器进行处理,控制器处理完成之后,会返回一个ModelAndView对象,包括数据模型和视图,通俗的讲就是页面中数据和页面本身(只包含视图名称即可)。
  • 返回ModelAndView之后,会交给ViewResolver(视图解析器)进行处理,视图解析器会对整个视图页面进行解析。
  • 解析完成后,就需要将页面中的数据全部渲染到View中,最后返回给DispatcherServlet一个包含所有数据的成形页面,再响应给浏览器,完成整个过程。

@RequestMapping

  • 将请求和处理请求的方法建立一个映射关系,当收到请求时就可以根据映射关系调用对应的请求处理方法,
  • 注解的定义如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Mapping
    public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
    }

    @AliasFor(“path”):别名

  • 其中最关键的是path属性(等价于value),它决定了当前方法处理的请求路径,注意路径必须全局唯一,任何路径只能有一个方法进行处理,它是一个数组,也就是说此方法不仅仅可以只用于处理某一个请求路径,我们可以使用此方法处理多个请求路径。

  • 现在我们访问/index或是/test都会经过此方法进行处理。

  • 我们接着来看下一个method属性,顾名思义,它就是请求的方法类型,我们可以限定请求方式,比如:

    1
    2
    3
    4
    @RequestMapping(value = "/index", method = RequestMethod.POST)
    public ModelAndView index(){
    return new ModelAndView("index");
    }

@RequestParam和@RequestHeader详解

  • 我们可以通过这两种方法获取请求中的参数:
  • 我们只需要为方法添加一个形式参数,并在形式参数前面添加@RequestParam注解即可:
    1
    2
    3
    4
    5
    @RequestMapping(value = "/index")
    public ModelAndView index(@RequestParam("username") String username){
    System.out.println("接受到请求参数:"+username);
    return new ModelAndView("index");
    }
  • 我们需要在@RequestParam中填写参数名称,参数的值会自动传递给形式参数,我们可以直接在方法中使用。
  • 注意,如果参数名称与形式参数名称相同,即使不添加@RequestParam也能获取到参数值。
  • 一旦添加@RequestParam,那么此请求必须携带指定参数,我们也可以将require属性设定为false来将属性设定为非必须:
    1
    2
    3
    4
    5
    @RequestMapping(value = "/index")
    public ModelAndView index(@RequestParam(value = "username", required = false) String username){
    System.out.println("接受到请求参数:"+username);
    return new ModelAndView("index");
    }
  • 我们还可以直接设定一个默认值,当请求参数缺失时,可以直接使用默认值:
    1
    2
    3
    4
    5
    @RequestMapping(value = "/index")
    public ModelAndView index(@RequestParam(value = "username", required = false, defaultValue = "伞兵一号") String username){
    System.out.println("接受到请求参数:"+username);
    return new ModelAndView("index");
    }
  • 如果我们需要使用Servlet原本的一些类,比如:
    1
    2
    3
    4
    5
    @RequestMapping(value = "/index")
    public ModelAndView index(HttpServletRequest request){
    System.out.println("接受到请求参数:"+request.getParameterMap().keySet());
    return new ModelAndView("index");
    }
  • 我们还可以直接将请求参数传递给一个实体类:
    1
    2
    3
    4
    5
    @Data
    public class User {
    String username;
    String password;
    }
  • 注意必须携带set方法或是构造方法中包含所有参数,请求参数会自动根据类中的字段名称进行匹配:
    1
    2
    3
    4
    5
    @RequestMapping(value = "/index")
    public ModelAndView index(User user){
    System.out.println("获取到cookie值为:"+user);
    return new ModelAndView("index");
    }