SpringMVC学习笔记

SpringMVC

1、简介

1.1 概述

Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。

我们为什么要学习SpringMVC呢? Spring MVC的特点有哪些?

  1. 轻量级,简单易学
  2. 高效 , 基于请求响应的MVC框架
  3. 与Spring兼容性好,无缝结合
  4. 约定优于配置
  5. 功能强大:RESTful、数据验证、格式化、本地化、主题等
  6. 简洁灵活

Spring的web框架围绕DispatcherServlet(Servlet调度器)设计。 DispatcherServlet的作用是将请求分发到不同的Controller。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁。

1.2 DispatcherServlet

DispatcherServlet(Servlet调度器)是SpringMVC架构中唯一的Servlet,它的作用就是用来调度不同的Controller(注意SpringMVC中的是controller,继承Controller接口而不是HttpServlet接口)的,最原始的项目模型,一个Servlet用来负责一类业务,当业务种类多起来之后,就需要一个中间层(DispatcherServlet)来负责调度,让用户始终只需要面对一个DispatcherServlet,而不需要考虑什么时候该调用什么Servlet的问题。

原本:

image

现在:

image

Spring的web框架围绕DispatcherServlet设计。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式。 Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet的本质也是一个Servlet (它继承自HttpServlet 基类)。

SpringMVC的原理如下图所示: 当发起请求时被前置的控制器拦截到请求(其实这里我觉得它就像Filter一样,拦截所有的请求并进行相应的处理),根据请求参数生成代理请求,找到请求对应的实际控制器,控制器处理请求,创建数据模型,访问数据库,将模型响应给中心控制器,控制器使用模型与视图渲染视图结果,将结果返回给中心控制器,中心控制器再将结果返回给请求者。

image

1.3 springMVC执行流程

先让我们来回顾一下MVC三层架构:

1.什么是MVC

  • MVC是模型(Model)、视图(View)、控制器(controller)的简写,是一种软件设计规范。
  • MVC不是一种设计模式,MVC是一种架构模式,不同的MVC存在差异,最经典的MVC就是JavaBean+servlet+JSP的模式。
  • MVC架构是为了降低视图和业务逻辑的双向耦合,使项目结构明了,便于维护。

2.MVC的结构划分

M即model是指模型,表示业务规则;V即View视图,是指用户看到并与之交互的界面;C即controller控制器,控制器接受用户的输入并调用模型和视图去完成用户的需求。

Model

Model层主要用来负责逻辑业务,在项目结构中Model一般包括三个结构:

  • pojo(数据实体类):用来定义封装的数据类型,其中实体类中的属性名一般对应数据库中表的列名。
  • Dao(数据处理类):专门负责定义程序与数据库之间的操作,不包含项目的业务规则,只包含数据库的增删改查。
  • Service(逻辑处理类):负责项目的逻辑业务,所有的业务规则都在Service中定义,然后根据需求调用Dao层定义好的数据库操作来处理不同的业务。

View

View层就是向用户展示的界面,负责与用户之间的交互,接收用户的指令,返回处理的结果,在项目结构中的View对应着各个jsp和html页面。

Controller

controller层(Servlet)负责接收用户从前端传输过来的数据,并且调用Service定义好的逻辑来处理这些数据,最后再根据处理结果,决定要返回给用户什么样的界面。

最经典的MVC架构就是JSP+servlet+javabean

3.servlet和controller

在java学习初期,很多人会认为controller就是servlet,这种说法在学习框架之前我一直以为是对的,但是在学习框架之后我发现他们并不是一个东西。

简单来说:在JSP+servlet+javabean模式中,servlet类充当的是MVC架构的Controller角色,这里的controller仅仅指的是架构,而不是具体的类。因为在学习框架之后你会发现,无论是在SpringMVC架构还是SpringBoot架构中,充当MVC架构中Controller角色的类就是controller类。

虽说servlet类和controller类扮演的角色差不多,作用也差不多,但是他们之间也有很大的区别。这里由于个人水平不够现在暂时不做过多介绍,等之后学到了再来补充

servlet类和controller类几个明显的区别:

  1. 继承的接口不一样,类的返回值类型也不一样
  2. servlet由servlet容器管理,controller由spring自己的IOC容器管理

4.SpringMVC的执行流程

结合上述内容,让我们来分析一下springMVC的执行流程:

image

  1. 用户与视图层发生交互,通过视图层向后台发送业务请求,假设用户发出的请求是http://localhost:8080/SpringMVC/hello。
  2. 中心控制器接收到视图层发送过来的业务请求,调用HandlerMapping。
  3. HandlerMapping根据传递过来的url查找到对应的handler
  4. HandlerExecution就是具体的handler,它的作用就是根据url查找控制器,如上请求被查找到的控制器就是hello,找到对应的控制器之后将信息返回给中心控制器。
  5. 中心控制器根据返回的信息,调用HandlerAdapter,让适配器按照特定的规则取执行Handler。
  6. Handler让具体的Controller执行
  7. controller调用Model层实现逻辑业务
  8. Model层将处理后的信息返回给controller
  9. controller将执行信息返回给HandlerAdapter,如ModelAndView
  10. HandlerAdapter将视图逻辑名或者模型传递给中心控制器
  11. 中心控制器根据视图名,调用视图解析器进行解析
  12. 视图解析器将解析后的视图路径返回给中心控制器
  13. 中心控制器根据解析的视图路径和模型参数,渲染出具体的视图
  14. 最终视图呈现给用户

2、项目构建

2.1 配置文件版

  1. 新建Moudle:springMVC-01-helloSpring,既然是MVC框架,首先要添加Web支持

  2. 导入SpringMVC依赖

        <dependencies>
            <!--servlet-->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
            </dependency>
            <!--jsp-->
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.2</version>
            </dependency>
            <!--springMVC-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.21.RELEASE</version>
            </dependency>
        </dependencies>
    
  3. 配置web.xml,在里面注册DispatcherServlet

    <?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_4_0.xsd"
             version="4.0">
    
        <!--注册dispatcherServlet-->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!--DispatcherServlet需要关联一个spring的配置文件,这里由于只为了理解MVC架构,命名为springmvc-servlet.xml-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc-servlet.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
            <!--所有的请求都先经过DispatcherServlet-->
        </servlet-mapping>
    </web-app>
    
  4. 在resources目录下编写SpringMVC专用的配置文件:springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    </beans>
    
  5. 添加HandlerMapping、HandlerAdapter和视图解析器

        <!--在springMVC的配置文件中配置号handlerMapping、handlerAdapter和视图解析器-->
        <!--1.handlerMapping-->
        <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
        <!--2.handlerAdapter-->
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
        <!--3.视图解析器-->
        <!--将DispatcherServlet返回给他的ModelAndView拼接成具体的页面路径-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
            <!--前缀-->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!--后缀-->
            <property name="suffix" value=".jsp"/>
        </bean>
    
  6. 编写controller(实现controller接口或者添加注解),controller需要返回一个ModelAndView,用来携带视图信息和数据

    public class HelloController implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
            //创建ModelAndView
            ModelAndView modelAndView = new ModelAndView();
            //封装对象,将要传递的属性封装进去
            modelAndView.addObject("msg","Hello!SpringMVC!");
            //封装要跳转的视图
            modelAndView.setViewName("hello");
            return modelAndView;
        }
    }
    
  7. 将自己的类交给SpringIOC容器,注册bean

    <!--handler-->
        <bean id="/hello" class="com.yirui.controller.HelloController"/>
    
  8. 写要跳转的jsp页面,显示ModelAndView存放的数据

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    
  9. 配置tomcat启动测试

image

报错了,查看日志排查原因:

image

  1. tomcat里面找不到DispatcherServlet类,而查看项目maven里面依赖已经导入,查看目录结构中也存在jar包,说明是由于编译时Aritifacts中没有导入相应jar包,打开项目结构查看情况。

image

  1. 发现Artifacts果然没有lib目录,说明jar包存在,但是没有导入到项目里面,在这里新建lib目录,将所有的jar包导入(项目中,同一个jar包不能放两个版本,不然Artifacts部署会报错)。

image

  1. 重启服务器,结果正常。如果第二步弄完之后,报了org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping for GET ...错误,有可能是DispatcherServlet里面的错误,比如:

    <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
            <!--所有的请求都先经过DispatcherServlet,注意这里不能用/*-->
    </servlet-mapping>
    

    原因:

    < url-pattern > / </ url-pattern >   不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。
    < url-pattern > /* </ url-pattern > 会匹配*.jsp。/,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。 
    

image

2.2 注解版

上面的配置文件版,只是为了更好的理解SpringMVC运行的原理,实际开发一般使用注解。

  1. 新建module,添加web框架支持,pom.xml中导入maven依赖

  2. 将jar包导入Artifacts

  3. 配置web.xml,注册dispatcherServlet,关联spring的配置文件

  4. resources目录下编写spring配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:mvc="http://www.springframework.org/schema/mvc"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
        <!--自动扫描包,让指定包下的注解自动生效,由IOC容器统一管理-->
        <context:component-scan base-package="com.yirui.controller"/>
        <!--让SpringMVC不处理静态资源,例如 .css .js .html .html .mp3 .mp4等后缀的文件-->
        <mvc:default-servlet-handler/>
        <!--mvc注解驱动,加了之后会配置并注入handlerMapping和handlerAdapter
            在spring中一般采用@RequestMapping注解来完成映射关系。
        -->
        <mvc:annotation-driven/>
    
        <!--视图解析器-->
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
            <!--前缀-->
            <property name="prefix" value="/WEB-INF/jsp/"/>
            <!--后缀-->
            <property name="suffix" value=".jsp"/>
        </bean>
    </beans>
    
  5. 编写controller和jsp页面

    HelloController.java

    package com.yirui.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller//使用这个注解返回的数据如果是字符串会自动被视图解析器处理,拼接前缀后缀,因此这里的返回值直接就是要跳转的页面名称
    public class HelloConller {
    
        @RequestMapping("/hello")//指定调用该方法的请求路径,即调用该方法的真实访问地址
        public String hello(Model model){
            model.addAttribute("msg","hello!springMVC-annotation");//通过model向模型中封装数据,可以在jsp页面中取出并渲染
            return "hello";
        }
    }
    
    

    hello.jsp

    <%--
      Created by IntelliJ IDEA.
      User: yirui
      Date: 2022/7/12
      Time: 15:09
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    ${msg}
    </body>
    </html>
    

image

posted @ 2022-07-12 15:44  仅有的い依靠  阅读(42)  评论(0)    收藏  举报