SpringMVC

SpringMVC

1.1、定义

springMVC是基于spring的一个框架,它就是spring的一个模板,专门用来做web开发的。可以理解为是Servlet的一个升级。

web开发的底层是servlet。

1.2、DispatcherServlet

作用:接收用户所有的请求,然后转发给@controller对象(@controller注解创建的对象)去处理。

1.3、实现步骤

  1. 创建spring-web的maven项目

  2. 导入依赖

    <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.3.14</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>4.0.1</version>
                <scope>provided</scope>
            </dependency>
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>javax.servlet.jsp-api</artifactId>
                <version>2.3.3</version>
                <scope>provided</scope>
            </dependency>
    

  3. 在web.xml文件中注册DispatcherServlet对象

    1. DispatcherServlet称为中央调度器,也叫前端控制器,是一个servlet。

    2. DispatcherServlet负责接收用户请求,然后调用其他控制器对象,并把处理结果显示给用户。

        <!--  声明springmvc核心对象DispatcherServlet
                需要在tomcat启动后创建DispatcherServlet对象。
                为什么:因为在创建DispatcherServlet对象时会同时创建springmvc容器对象
                然后创建配置文件中所有的bean。
      
                DispatcherServlet在执行init方法时{
                  WebApplicationContext context =ClassPathXmlApplicationContext("applicationContext.xml");
                  getServletContext.setAttribute(key,  context);
                }
            -->
          <servlet>
              <servlet-name>springmvc</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              <!--   在tomcat启动后,创建Servlet对象
                     其中的数值(>=0)表示的是,创建对象的顺序,数值越小,创建的时间越早。
                   -->
              <!--自定义spring配置文件的位置-->
              <init-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:applicationContext.xml</param-value>
              </init-param>
              <load-on-startup>1</load-on-startup>
          </servlet>
          <servlet-mapping>
              <servlet-name>springmvc</servlet-name>
              <url-pattern>*.do</url-pattern>
          </servlet-mapping>
      

  4. 创建发起请求的页面 index.jsp

  5. 创建控制器类

    1. 在类上加@Controller注解,创建对象,并交给springmvc容器中

    2. 在类的方法上加@RequestMapping注解。

      /**
       * 在spring容器中创建对象
       * MyController也叫后端控制器
       */
      @Controller
      public class MyController {
          /**
           * 匹配请求的uri地址
           * value:需要配置的uri地址,前面通常加/
           * @return
           */
          @RequestMapping(value = "/some.do")
          //相当于Servlet中doGet方法
          //ModelAndView中保护了数据和视图路径
          public ModelAndView doSome(){
              ModelAndView modelAndView= new ModelAndView();
              //添加数据,最后框架把数据放到request作用域中
              //框架中调用了request.setAttribute(key,value);
              modelAndView.addObject("msg","欢迎使用springmvc开发");
              //指定视图的路径,相当于request.getRequestDispatcher("/show,jsp").forward(request,response)
              modelAndView.setViewName("/show.jsp");
              return modelAndView;
      
          }
      }
      

  6. 创建一个用于显示结果的jsp

  7. 创建SpringMVC配置文件(spring配置文件一样

    1. 声明组件扫描器

      <?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"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-4.0.xsd">
          <context:component-scan base-package="com.jfs"/>
      </beans>
      

    2. 声明视图解析器

      <!--  声明视图解析器,设置视图文件的位置  -->
          <bean id="view" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <!--前缀:表示的是视图的文件地址位置-->
              <property name="prefix" value="/WEB-INF/view"/>
              <!--后缀:表示文件的类型-->
              <property name="suffix" value=".jsp"/>
          </bean>
      

1.4、springmvc执行过程源代码分析

  1. tomcat启动创建容器过程,通过load-on-start标签,来创建DispatcherServlet对象,DispatcherServlet是一个servlet。

    在创建DispatcherServlet对象时,会执行init()方法。

    在init方法中有

    WebApplicationContext context =ClassPathXmlApplicationContext(“applicationContext.xml”);

    getServletContext.setAttribute(key, context);

    创建容器对象,同时创建@controller注解的对象。放到容器中。

  2. 请求处理过程

    1. 执行servlet中service方法

      protected void service(HttpServletRequest request, HttpServletResponse response) ;

      protected void doService(HttpServletRequest request, HttpServletResponse response);

      protected void doDispatch(HttpServletRequest request, HttpServletResponse response){

      ​ 在该方法中调用controller中的方法

      }

1.5、RequestMapping注解的使用

  1. @RequestMapping放到类上面,表示公共的部分。

  2. 指定请求的方式,使用属性method =RequestMethod.get。如果不指定方式,表示没有限制。

1.6、处理方法的参数

  1. HttpServletRequest
  2. HttpServletResponse
  3. HttpSession
  4. 请求中所携带的请求参数

1.6.1、接收用户提交数据的方式

1.6.1.1、逐个接收用户数据

**要求:**1. 方法的参数名和请求的参数名必须一致,和参数位置无关。

​ 2.方法的参数名和请求的参数名不一样,加注解@RequestParam(“请求参数名”),在处理器形参定义前面。

@RequestParam参数:

  1. value:用来匹配请求的参数名
  2. required:表示该参数是否是必要的,默认是true。

处理流程:

  1. 使用request对象获取参数

    String name =request.getparameter("name");
    String age =reqest.getParameter("age");
    

  2. springmvc通过调用DispatcherServlet调用相应的方法,调用方法时按照名称,给相应的参数赋值。

    框架会把String类型,转换成 int、double、long等类型。

1.6.1.2、使用对象来接收请求参数

**java对象:**处理方法的形参时java对象,请求的参数名和java对象的属性名一样,框架会创建对象,会使用set方法属性赋值

1.7、请求后出现乱码问题

**问题:**在使用get方式请求时,携带的中文参数,不会出现乱码的问题。post方式会出现乱码问题

**解决办法:**使用过滤器解决乱码问题

1.8、处理方法的返回值

1.8.1、返回ModleAndView

**使用场景:**既需要转到其他视图,也需要携带数据的时候,使用较好。

1.8.2、返回String

表示视图,可以是逻辑名称,也可以是完整的视图路径

  1. 如果是逻辑名称需要配置视图解析器
<bean id="view" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀:表示的是视图的文件地址位置-->
        <property name="prefix" value="/WEB-INF/view/"/>
        <!--后缀:表示文件的类型-->
        <property name="suffix" value=".jsp"/>
</bean>
  1. 如果返回的是完整的视图路径,则不需要加视图解析器。

1.8.3、返回void

不能表示数据,也不能表示视图。在处理ajax时,可以使用void。通过HttpSevletResponse输出数据,来相应ajax请求。

1.8.4、返回Object

返回对象,需要用到@ResponseBody注解,将转换的json数据放入到响应体中。例如:String、Integer、Map、List、Student等。返回的是数据,和视图无关。相应ajax请求。

实现步骤:

  1. 加入json的工具库依赖,springmvc默认使用的Jackson。

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.13.1</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.13.1</version>
    </dependency>
    
    

  2. 在springmvc配置文件中加入mvc:annotation-driven/驱动

    json =om.writeValueAsString(Student)

    驱动的功能是:完成java对象到json、xml、text、二进制等数据格式的转换。

    实现HttpMessageConverter接口:消息转换器

    在springmvc文件中加入mvc:annotation-driven/后,会自动创建HttpMessageConverter的7个实现类对象,

    其中包含MappingJackson2JsonView(使用jackson工具库中的ObjectMapper实现从java对象转换为json格式的字符串)

  3. 在方法上面加@ResponseBody。

    response.setContextType(“application/jason;chartset=utf-8”);

    PrintWriter pw =response.getWriter();

    pw.print(json);

    放在处理器上面,通过HttpServletResponse返回给ajax数据的

1.8.4.1、返回自定义类型
  1. 框架根据返回值Student类型,依次调用框架中的HTTPMessageConverter接口的实现类对象的canWrite()方法,确定使用哪个类。
  2. 框架调用实现类的write()方法,把Student类型转换成相应的类型
  3. 根据@ResponseBody注解,把步骤2中转换的数据输出到浏览器中,相应ajax请求。
1.8.4.2、返回list集合类型

​ 方法上加上@ResponseBody注解,返回给ajax请求的是一个json数据的数组。例如:[{name:“zhangsna”,age:18},{name:“lisi”,age:15}]

1.8.4.3 返回的是一个字符串对象(用于表示数据的)

​ 如果加了@Responsebody注解,就代表返回的是数据,否则代表返回的视图。

实现步骤:

  1. 框架根据返回值String类型,依次调用框架中的HTTPMessageConverter接口的实现类对象的canWrite()方法,确定使用哪个类。
  2. 框架调用实现类的write()方法,把String类型按照"text/plain;charset=utf-8"编码方式处理。
  3. 根据@ResponseBody注解,把步骤2中转换的数据输出到浏览器中,相应ajax请求。

1.9、url-pattern为/时

tomcat配置文件:

<servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
<servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
 </servlet-mapping>

DefaultServlet作用:

1、处理静态资源,2、处理未映射的其他servlet请求。

当中央调度器url-pattern也为/时。

<servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--   在tomcat启动后,创建Servlet对象
               其中的数值(>=0)表示的是,创建对象的顺序,数值越小,创建的时间越早。
             -->
        <!--自定义spring配置文件的位置-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
      
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

​ 当中央调度器url-pattern也为/时,它会替代tomcat中的default,导致所有的静态资源都由中央调度器处理。默认情况下中央调度器是没有处理静态资源的控制器,所有像,.jp、.html、.css都会报404错误。

​ 动态资源是可以访问的,因为程序中有控制器对象。

处理静态资源访问不了问题:

  1. 在springmvc配置文件中加入mvc:default-servlet-handler/,框架会自动创建DefaultServletHttpRequestHandler对象,类似于我们自己创建的Controller对象。

  2. 处理方式二

        <!--  处理方式二  -->
        <!-- /img/**:表示处理img/123.jsp、img/test/23.jpg等访问地址
             /img/:表示根目录下img文件夹下面所有的文件
           -->
        <mvc:resources mapping="/static/**" location="/static/"/>
    

1.10、相对地址和绝对地址

1.10.1、绝对地址

绝对地址:带有协议名称的是绝对地址。例如:https://www.baidu.com。

1.10.2、相对地址

相对地址:没有协议开头,例如user/some.do、/user/some.do.

​ 相对地址不能独立使用,必须要一个参考地址。通过参考地址+相对地址才能指定到资源。

加"/":

<a href="/test/some.do">访问dosome链接</a>
<%--点击该地址后,实际访问的地址是http://localhost:8080/test/some.do
    加上"/"的作用是访问的是服务器的地址+点击的地址
--%>

不加"/"

<a href="test/some.do">访问dosome链接</a>
<%--点击该地址后,实际访问的地址是http://localhost:8080/springmvc01/test/some.do   不加上"/"的作用是访问的是资源访问路径地址+点击的地址--%>

解决访问地址问题:

<img src="${pageContext.request.contextPath}/img/123.jpeg" alt="静态资源(图片)">

1、在地址前面加上${pageContext.request.contextPath}

2、使用base标签。不过地址前面没有加"/",默认的加上的是这个地址

<head>
    <base href="http://localhost:8080/springmvc01/"/>
</head>
<a href="test/some.do">访问dosome链接</a>
<img src="img/123.jpeg" alt="静态资源(图片)">

1.11、Springmvc核心技术

1.11.1、请求重定向和转发

forward:请求转发

redirect:请求重定向

**注意:**请求转发可以访问WEB-INF目录里面的资源,但是请求重定向无法访问WEB-INF里面的资源。

   /**
     *语法:setViewName("forward:完整的视图名路径");
     * 请求转发不和视图解析器相关,需要完整的路径名
     * 请求重定向可以访问WEB-INF里面的文件
     */
    @RequestMapping("/forward")
    public ModelAndView forward(String name,Integer age){
        ModelAndView modelAndView = new ModelAndView();
        //在request的作用域下,相当于request.setAttribute();
        modelAndView.addObject("name",name);
        modelAndView.addObject("age",age);
        modelAndView.setViewName("forward:/WEB-INF/view/show.jsp");
        return modelAndView;
    }

    /**
     * 语法:setViewName("redirect:完整的视图名路径");
     * 请求转发不和视图解析器相关,需要完整的路径名
     * 框架对重定向的作用:
     *     1、框架会把简单的数据类型转换成String类型,作为redirect.jsp请求的参数
     *     目的在于两次请求之间传递参数
     *     2、在redirect.jsp中可以使用${param.name}来获取请求的参数
     *     3、请求重定向不能访问WEB-INF里面的文件
     */
    @RequestMapping("redirect")
    public ModelAndView redirect(String name, Integer age){
        ModelAndView modelAndView = new ModelAndView();
        //在request的作用域下,相当于request.setAttribute();
        modelAndView.addObject("name",name);
        modelAndView.addObject("age",age);
        modelAndView.setViewName("redirect:/redirect.jsp");
        return modelAndView;
    }

1.11.2、异常处理

​ spring框架采用统一的、全局的异常处理。

​ 把controller中的异常都集中到一个地方,采用的是aop的思想,把异常代码和业务代码分开,解耦合

​ 常用到的注解:@ExceptionHandle @ControllerAdvice

处理步骤:

  1. 创建maven项目

  2. 导入依赖

  3. 新建一个自定义异常类StudentException,再定义它的子类NameException,AgeException。

  4. 在controller中抛出NameException,AgeException异常。

  5. 创建一个普通类,作为全局异常处理类

    1. 在类的上面加上@ControllerAdvice
    2. 在类的方法上加上@ExceptionHandler
    //框架要扫描这个注解所在的包
    @ControllerAdvice
    public class MyExceptionHandler {
        /**
         * 方法的形式和controller方法一样
         * 当注解中有异常的类型,捕捉这个异常,
         * 参数:Exception,可以获取异常的信息。
         */
        @ExceptionHandler(NameException.class)
        public ModelAndView nameException(Exception e){
            ModelAndView modelAndView =new ModelAndView();
            modelAndView.addObject("exception",e);
            modelAndView.setViewName("exception");
            return modelAndView;
        }
    
        /**
         *  当注解后面没有加任何的异常类型,则表示除了上面的异常外,其他异常都走这边
         */
        @ExceptionHandler
        public ModelAndView otherException(Exception e){
            ModelAndView modelAndView =new ModelAndView();
            modelAndView.addObject("exception",e);
            modelAndView.setViewName("exception");
            return modelAndView;
        }
    

  6. 创建处理异常的视图页面

  7. 创建springmvc配置文件

    1. 组件扫描器,扫描@Controller注解
    2. 组件扫描器,扫描@ControllerAdvice注解
    3. 声明注解驱动
        <!--扫描异常处理类所在的包-->
        <context:component-scan base-package="com.jfs.exceptionHandler"/>
        <!--声明注解驱动-->
        <mvc:annotation-driven/>
    

1.11.3、拦截器

​ 1、拦截器是springmvc的一种,需要实现HandlerInterceptor接口。

​ 2、拦截器和过滤器相似,功能的侧重点不同。过滤器是用来过滤请求参数和设置字符集编码的,拦截器是用来拦截用户请求的

​ 3、拦截器是全局的,可以对多个controller拦截,一个项目中可以有0-n个拦截器,它们一起拦截用户的请求。拦截器常用在用户登录、权限检查、记录日志等方面。

1.11.3.1、使用步骤

1、定义类实现HandlerInterceptor接口。

public class MyInterceptor implements HandlerInterceptor {
    /**
     *  预处理方法
     *  特点:
     *      1、在控制器对象方法之前执行。
     *      2、在这个方法中可以获取请求信息,验证请求是否符合要求。
     *          可以验证用户是否登录,验证用户是否有权限访问该uri地址。
     *          如果验证失败,这拦截。验证成功可以访问控制器中的方法。
     * @param request
     * @param response
     * @param handler :被拦截的控制器对象
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("111拦截器preHandle方法");
        return true;
    }

    /**
     * 后处理方法。特点:
     *  1、在controller方法之后执行的
     *  2、能够获取modelAndView,故可以修改视图和数据
     *  3、主要对执行结果进行二次处理
     * @param request
     * @param response
     * @param handler :控制器对象
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("111拦截器postHandle方法");
    }

    /**
     * 最后执行的方法。特点:
     *  1、在请求执行完成后执行的,在框架中规定当你的视图处理完成后吗,对视图执行forward方法,认为请求完成。
     *  2、一般做资源回收工作。
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("111拦截器afterCompletion方法");
    }
}

2、在springmvc配置文件中声明拦截器,并指定要拦截的uri地址。

 <mvc:interceptors>
        <!--声明第一个拦截器-->
        <mvc:interceptor>
            <!--要拦截的uri地址
                **:表示任意字符,文件或者多级目录中的文件
            -->
            <mvc:mapping path="/student/**"/>
            <!--声明拦截器对象-->
            <bean class="com.jfs.interceptor.MyInterceptor"/>
        </mvc:interceptor>
        <!--声明第二个拦截器-->
        <mvc:interceptor>
            <!--要拦截的uri地址
                **:表示任意字符,文件或者多级目录中的文件
            -->
            <mvc:mapping path="/student/**"/>
            <!--声明拦截器对象-->
            <bean class="com.jfs.interceptor.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>
1.11.3.2、拦截器执行时间

1、在请求方法之前拦截,也就是在controller类方法执行前拦截

2、在控制器方法执行后也会执行拦截器

3、在请求处理完成后也会执行拦截器

1.11.3.3、多个拦截器执行顺序

两拦截器都是true的情况:

111拦截器preHandle方法
222拦截器preHandle方法
controller中的方法
222拦截器postHandle方法
111拦截器postHandle方法
222拦截器afterCompletion方法
111拦截器afterCompletion方法

111拦截器是true,222拦截器是false:

111拦截器preHandle方法
222拦截器preHandle方法

111拦截器afterCompletion方法

111拦截器是false,无论222是true还是false:

111拦截器preHandle方法

1.11.3.4、拦截器和过滤器的区别
  1. 过滤器是servlet中的对象,拦截器是框架中的对象

  2. 过滤器是实现Filter接口,拦截器实现HandlerInterceptor接口

  3. 过滤器是用来设置request、response参数、属性的,侧重数据的过滤。

    拦截器是用来验证登录等的,拦截请求的。

  4. 过滤器是在拦截器之前执行

  5. 过滤器是tomcat创建的对象,拦截器是springmvc容器创建的对象

  6. 过滤器有一个执行时间点,拦截器有三个执行时间点。

  7. 过滤器可以执行html,js,css等。拦截器侧重拦截controller对象,如果你的请求不能被DispatcherServlet接收,也不会执行拦截器。

1.12、Springmvc的执行流程

  1. 用户发起请求

  2. 中央调度器接收请求(DispatcherServlet),把请求转交给处理器映射器

    ​ 处理器映射器:springmvc框架中的一个对象,框架把实现了HandlerMapping接口的类叫做映射器(多个)。

    ​ 处理器映射器的作用:从springmvc容器中获取处理器对象。框架把找到的对象放到一个叫作处理器执行链类(HandlerExecutionChain)保存。

    HandlerExecutionChain类中保存着:1、处理器对象 2、项目中所有的拦截器

    中央调度器执行的方法:

    //获取处理器映射器
    mappedHandler = getHandler(processedRequest);
    

  3. 中央调度器把2中获得HandlerExecutionChain中的处理器对象交给处理器适配器(多个)

    ​ 处理器适配器:springmvc框架中的对象,实现HandlerAdapter接口

    ​ 处理器适配器的作用:执行处理器的方法,得到返回值ModelAndView。

    中央调度器执行的方法:

    //获取处理器适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    //执行处理器方法
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
  4. 中央调度器把在3中获取的ModelAndView交给视图解析器对象。

​ 视图解析器:springmvc中的对象,需要实现ViewResolver接口(可以有多个)

​ 视图解析器的作用:组成视图的完整路径,使用前缀后缀,并创建view对象。

​ view:是一个接口,表示视图的。在框架中jsp、html不是String表示,而是使用view和他的实现类表示视图。

​ InternalResourceView:视图类,表示jsp文件。视图会创建该类的对象。这个对象的里面有个/WEB-INF/view/show.jsp。

  1. 中央调度器获取到4步骤中view,调用View类中的方法。把Model数据放到request中。对视图对象执行forward。请求结束。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值