SpringMVC

SpringMVC:


SpringMVC简介:

  • SpringMVC是基于Spring的一个框架 , 实际上就是spring的一个模块 , 专门是做web开发的 , 是servlet的升级版
  • web开发底层就是Servlet , 框架是在servlet基础之上加入一些功能 , 让你做web开发方便 ,
  • springMVC就是一个Spring , spring就是一个容器 , ioc能够管理对象 , 使用 , @Component , @Repository , @Service , @Controller
  • SpringMVC能够创建对象 , 放入到容器中(SpringMVC容器) , Springmvc容器中放的是控制器对象 ,

我们要做的就是 : 使用@Controller创建对象 , 把对象放入到Springmvc容器中 , 把创建的对象作为控制器使用 , 这个控制器对象能够接收用户的请求 , 显示处理结果 , 就当做是一个servlet使用

使用**@Controller 注解创建的是一个普通类的对象** , 不是servlet , SpringMVC赋予了控制器对象一些额外的功能

web开发底层是servlet , springmvc中有一个对象是servlet : DispatherServlet(中央调度器)

DispatcherServlet : 负责接收用户的所有请求 , 用户把请求给了DispatcherServlet, 之后 , DispatcherServlet把请求转发给我们的Controller对象 , 最后是Controller对象处理请求


SpringMVC优点 :

  • 1.基于MVC架构 ,
    • 功能分工明确 , 解耦合
  • 2.容易理解 , 上手快 , 解耦合
    • 就可以开发一个注解的SpringMVC项目 , SpringMVC也是轻量级的 , jar很小 , 不依赖特定的接口和类
  • 3.作为Spring框架的一部分 , 能够使用Spring的 IOC , 和AOP , 方便整合Strtus , MyBatis , Hibernate , JPA等其他框架
  • 4.SpringMVC强化注解的使用 , 在控制器 , Service , Dao都可以使用注解 , 方便灵活 ,
    • 使用@Controller创建处理器对象 , @Service创建业务对象 , @Autowired 或者 @Resource在控制器类中注入Service , Service类中注入Dao

SpringMVC快速入门:

image-20220318155236323

image-20220318171258549

重要面试重点

image-20220318191747411


SpringMVC快速入门

  • 配置SpringMVC核心控制器DispatcherServlet , 在web.xml文件中配置
<!--配置spring-mvc的前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--设置服务器启动的时候就去加载控制器-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!--设置/ 表示所有的请求都会通过这个控制器-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  • 创建Controller类和视图页面 , 并且配置业务方法的映射地址
@Controller
public class UserController {
    //请求映射
    @RequestMapping("/save")
    public String save(){
        System.out.println("Controller save Running...");
        //return 直接就是对应的资源文件
        return "success.html";
        //这里默认的就是转发的方式 , 如果想要使用重定向 , 就要在访问路径前边加上一个 , redirect:
    }
}
  • 配置Spring-MVC的核心配置文件 spring-mvc.xml
    • 使用的是spring的主配置文件模板
<!--Controller的组件扫描-->
<context:component-scan base-package="controller"/>
  • 在上边的xml文件中的前端控制器中 , 配置初始化参数 : 将spring-mvc.xml文件加载进去
<!--配置spring-mvc的前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--设置初始化参数 , 在创建前端控制器的时候 , 加载spring-mvc的主配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <!--设置服务器启动的时候就去加载控制器-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!--设置/ 表示所有的请求都会通过这个控制器-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

SpringMVC注解解析:

@Controller :


@RequestMapping : 请求映射

用于建立请求URL与处理请求方法之间的对应关系
位置 :
类上 : 请求URL的第一级访问目录 , 此处不写的话 , 就相当于应用的根路径
方法上 : 请求URL的第二级访问目录 , 与类上使用@RequestMapping标注的一级目录一起组成访问虚拟路径

属性 :
value : 用于指定请求的URL , 它和path属性的作用是一样的
method : 用于指定请求的方式
params : 用于指定限制请求参数的条件 , 它支持简单的表达式 , 要求请求参数的key和value必须和配置的一模一样

  • 例如 : params = {“accountName”} , 表示请求参数必须有accountName
  • params = {“money!100”} 表示请求参数中money不能是100
@Controller
@RequestMapping("/user")//一级访问
public class UserController {
    //请求映射 , 如果类上边没写这个注解 , 那么访问路径就是直接使用/save 即可 ,
    // 如果类上边也有这个注解 , 那么访问路径就是 , /user/save
    @RequestMapping(value = "/save",method = RequestMethod.POST) //二级访问
    public String save(){
        System.out.println("Controller save Running...");
        //return 直接就是对应的资源文件
        return "success.jsp";
        //前边什么都不写,就是相对位置,
        //在使用请求路径,/user/save时,进行跳转,会寻找/user/success.jsp
        //所以这里要加一个 / , 表示从项目的根路径下找资源
        //    "/success.jsp";
    }
}

spring-mvc组件扫描器的其他用法 :

spring-mvc.xml文件

<!--Controller的组件扫描-->
    <context:component-scan base-package="com.sichen">
        <!--二者不能重复使用-->
        <!--exclude : 表示排除这个之外的内容-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!--include : 表示扫描指定的这个内容-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

spring-mvc配置文件的其他配置 :(了解)

spring-mvc配置文件除了可以配置组件扫描之外 , 还可以配置其他组件

  • 这些组件在spring-mvc的jar下的DispatcherServlet.properties文件中可以看到 , 可以指定其中的一些属性 , (比较深层次 , 了解即可)
  • 使用的是 和 这些标签完成的功能

可以修改那些带有set方法的参数内容:

image-20220318203500901


各个组件的名称 , 以及功能 :

  • DispatcherServlet : 前端控制器
    • 需要我们手动配置的 , 帮助我们调用其他的一些功能组件
  • HandlerMapping : 处理器映射器
    • 帮我们解析请求 , 返回一个处理器执行链
  • HandlerAdapter : 处理器配适器
    • 被前端处理器调用 , 帮我们去执行对应的处理器
  • Handler : 处理器
    • 相当于就是 Controller
  • View Resolver : 视图解析器
    • 帮我们将view解析出来
  • View : 视图
    • 封装了视图的一些信息

在Spring-MVC的各大组件中 , 处理器映射器 , 处理器配适器 , 视图解析器 , 称为Spring-MVC的三大组件


SpringMVC的数据响应:

你想使用那些对象 , 都可以在方法的参数中 , 添加这个对象 , Spring-MVC内部都可以进行创建 , 并且将其放在域中 , 你在方法中直接使用就可以了

(1)页面跳转

  • 直接返回字符串

    • 此种方式会将返回的字符串与视图解析器的前后缀进行拼接后跳转
    • image-20220320162319740
  • 通过ModelAndView对象返回

    • @RequestMapping(value = "/save2")
      public ModelAndView save2(){
          /*
          * Model: 模型 , 作用封装数据
          * View : 视图 , 作用展示数据
          * */
         ModelAndView modelAndView = new ModelAndView();
         //设置模型数据 , 在页面中配合el表达式 , 来获取数据
         modelAndView.addObject("username","sichen");
         //设置视图 :
         modelAndView.setViewName("/success.jsp");
         return modelAndView;
      }
      
    • 或者直接在参数中添加 , Spring-MVC会根据你的参数 ,自动给你创建一个ModelAndView对象存储到容器中

    • @RequestMapping(value = "/save3")
          public ModelAndView save3(ModelAndView modelAndView){
              //设置模型数据 , 在页面中配合el表达式 , 来获取数据
              modelAndView.addObject("username","sichen");
              //设置视图 :
              modelAndView.setViewName("/success.jsp");
              return modelAndView;
          }
      

(2)写回数据

  • 直接返回字符串

    • (1)通过Spring-MVC框架注入的response对象 , 使用response.getWriter().print(“hello world”)回写数据, 此时不需要视图跳转 , 业务方法返回值为 void

      • @RequestMapping(value = "/save4")
        public void save4(HttpServletResponse response) throws IOException {
                response.getWriter().print("思尘");
            }
        
    • (2)如果你想直接返回字符串 , 而不是使用response对象 , 那么就需要使用@ResponseBody注解 , 告诉SpringMVC框架 , 方法返回的字符串不是跳转 , 而是直接在http响应体中返回

      • //使用@ResponseBody 
        //告诉SpringMVC 不进行跳转 , 返回的字符串是直接响应的
            @ResponseBody
            @RequestMapping(value = "/save5")
            public String save5() throws IOException {
                return "hello sichen";
            }
        
  • 返回对象或集合

    • //使用json返回数据 , 将数据的转换工作交给springmvc完成
          @ResponseBody
          @RequestMapping("/save7")
          //期望SpringMVC自动将User转换为json格式的字符串
          public User save7() throws JsonProcessingException {
              User user = new User();
              user.setName("思尘");
              user.setAge(21);
              return user;
          }
      

      这个工作需要你在springmvc.xml文件中配置处理器映射器

      <!--配置处理器映射器-->
      <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
          <property name="messageConverters">
              <list>
                  <!--注入jackson转换的转换器-->
      			<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
              </list>
          </property>
      </bean>
      

简便方式配置处理器映射器 , 是返回数据自动转换为json类型数据

上边配置配置处理器映射器 , 的时候配置是比较繁琐的 , 这里springmvc提供了一个注解驱动代替上边的配置 ,

<mvc:annotation-driven/>

在SpringMVC的各大组件中 , 处理器映射器 , 处理器配适器 , 视图解析器 , 称为SpringMVC的三大组件 ,
使用 <mvc:annotation-driven > 自动加载处理器映射器 ,
处理器适配器 , 可用在Spring-MVC的配置文件中使用 , <mvc:annotation-driven >替代注解处理器和配适器的配置

同时 , 使用mvc:annotation-driven 默认底层就会集成jackson进行对象或集合的json格式字符串的转换


SpringMVC获得请求数据:

(1)获得请求参数 :

客户端请求参数的格式是 : name=value&age=value…

服务器端获得请求的参数 , 有时还需要进行数据的封装 , SpringMVC可以接收如下类型的参数 :

  • 基本类型参数
  • POJO类型参数 (bean)
  • 数组类型的参数
  • 集合类型的参数

获得基本类型的参数 :

Controller中的业务方法的参数名称要与请求参数的name一致 , 参数值会自动映射匹配 , 会自动获取请求参数的值

请求 : http://localhost:8080/request/save1?name=思尘&age=21

 @RequestMapping("/save1")
    @ResponseBody
    //请求中的参数名称和方法参数中的name一致时 , springMVC会自动进行赋值
    // http://localhost:8080/request/save1?name=思尘&age=21
    public User save1(User user,String name,int age){
        user.setName(name);
        user.setAge(age);
        return user;
        // {"name":"思尘","age":21}
    }

获得POJO类型参数 :

Controller中的业务方法的POJO参数的属性与请求参数的name一致 , 参数值会自动映射匹配 , springMVC会自动对请求参数进行封装

//请求参数中的name名和一个bean对象中的参数一致时 , springMVC会自动进行封装
    // http://localhost:8080/request/save2?name=思尘&age=21
    @RequestMapping("/save2")
    @ResponseBody
    public User save2(User user){
        return user;
        // {"name":"思尘","age":21}
    }

获取数组类型的参数:

Controller中的业务方法数组名称与请求参数中的name一致 , 参数值会自动映射匹配

//获取请求参数中重复的值 , 比如说爱好..
    // http://localhost:8080/request/save3?strs=思尘&strs=闻熙灏
    @RequestMapping("/save3")
    @ResponseBody
    public List<String> save3(String[] strs){
        return Arrays.asList(strs);
        // ["思尘","闻熙灏"]
    }

获取集合类型参数:

获取集合参数的时候 , 要将集合的参数包装到一个POJO中才可以

//domain : VO
private List<User> userList;


@RequestMapping("/save4")
@ResponseBody
public void save4(VO vo){
    System.out.println(vo);
}

from表单 : 使用js :

<from action="${pageContext.request.contextPath}/request/save4" method="post">
<%--表示是第几个User对象的username--%> 
<!--这里的name要是domain中的参数名一致 , 那是一个数组 , 所以要增加一个下标 , 表示是第几个User对象 , 并且是什么内容-->
<input type="text" name="userList[0].name"/><br>
<input type="text" name="userList[0].age"/><br>
<input type="text" name="userList[1].name"/><br>
<input type="text" name="userList[1].age"/><br>
<input type="submit" value="提交"/>
</from>

使用ajax请求的方式请求数据 :

 <script src="${pageContext.request.contextPath}/js/jquery-3.3.1.js"/>
    <script>
        var userList = new Array();
        userList.push({name: "sichen", age: 18});
        userList.push({name:"wenxihao",age:21});
        $.ajax({
            type:"POST",
url:"${pageContext.request.contextPath}/request/save5",
            data:JSON.stringify(userList),
            contentType:"application/json;charset=UTF-8",
        });
    </script>
 @RequestMapping("/save5")
    @ResponseBody
    //这里需要在参数前添加一个注解 @RequestBody
    public void save5(@RequestBody List<User> userList){
        System.out.println(userList);
    }

找不到js文件的解决方式 :

这里是应为在web.xml中注册spring-mvc的前端控制器的时候 , 使用的是缺省的路径格式 , 这会导致在请求数据的时候 , 会将js的文件的名称也当做一个请求路径来请求 , 这样就导致 , 请求不到对应的资源

在springmvc.xml文件中添加 :

 <!--开放资源的访问权限-->
<!--
mapping表示映射地址 , 也就是要开放的资源 , 
location表示的是资源所在的位置-->
<mvc:resources mapping="/js/**" location="/js/"/>


<!--或者使用-->
<mvc:default-servlet-handler/>
<!--这个是表示 , 如果请求的资源找不到的话 , 就使用原始的tomcat的内部机制去找这个资源-->

解决请求数据乱码的问题 :

当post请求时 , 数据会出现乱码 , 我们可以设置一个过滤器来进行编码的过滤

web.xml文件中配置

<!--配置全局过滤的filter-->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
</filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

参数绑定注解 @RequestParam 参数名称不一致时

当你请求参数名称与Controller的业务方法的参数名称不一致时 , 就需要通过@RequestParam注解显示的绑定

//使用@RequestParam注解来进行 , 请求参数的赋值
@RequestMapping("/save6")
@ResponseBody
//参数值就是请求时使用的参数名称
public void save6(@RequestParam(value = "name") String username){
    System.out.println(username);
}

注解中有三个参数可以使用 :

  • value : 与请求参数名称一致
  • required : 此在指定的请求参数是否必须包括 , 默认是true , 提交时如果没有此参数则报错 ,
  • defaultValue : 当没有指定的请求参数时 , 则使用指定的默认值赋值

获取Restful风格的参数 :

Restful : 是一种软件的架构风格 , 设计风格 , 而不是标准 , 只是提供了一组设计原则和约束条件 , 主要用于客户端和服务器交互类的软件, 基于这个设计风格设计的软件可以更简洁 , 更有层次 , 更易于实现缓存机制等 …

Restful风格的请求是使用 “url+请求方式” , 表示一次请求目的的 , HTTP协议里面四个表示操作方式的动词如下 :

  • GET : 用于获取资源
  • POST : 用于新建资源
  • PUT : 用于更新资源
  • DELETE : 用于删除资源

例如 :

  • /user/1 GET : 表示得到id=1 的user
  • /user/1 DELETE : 表示删除id =1 的user
  • /user/1 PUT : 表示更新id = 1的user
  • /user POST : 表示新增user

image-20220321183952793

使用注解 : @PathVariable : 注意这里边的值 , 必须要和参数名称一致

//使用@PathVariable
    @RequestMapping("/save7/{username}")
    @ResponseBody
    public void save7(@PathVariable(value = "username") String username){
        System.out.println(username);
    }

自定义类型转换器 :

  • SpringMVC默认已经提供了一些常用的类型转换器 , 例如客户端提交的字符串转换成int类型进行参数设置
  • 但是不是所有的数据类型都提供了转换器 , 没有提供的就需要自定义转换器 , 例如 : 日期类型的数据就需要自定义转换器

实现步骤 :

(1)定义转换器类实现Converter接口 (springMVC提供的转换器接口)

import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements Converter<String,Date> {
    public Date convert(String dateStr){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = format.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }
}

(2)在配置文件中声明转换器

 <!--声明自定义转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="com.sichen.converter.DateConverter"/>
        </list>
    </property>
</bean>

(3)在 中引用转换器

 <!--mvc的注解驱动-->
<mvc:annotation-driven conversion-service="conversionService"/>

获取Servlet相关的API:

常见的对象有

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession

直接在业务方法的参数的位置写入即可 , SpringMVC会自动帮你创建这个对象


获取请求头的数据 :

(1)使用注解 @RequestHeader获取请求头信息

可以获取请求头信息 , 相当于web阶段学习的Request.getHeader(name)

@RequestHeader注解的属性如下

  • value : 请求头的名称
  • required : 是否必须携带此请求头
//使用@RequestHeader注解获取请求头
@RequestMapping("/save9")
@ResponseBody
public void save9(@RequestHeader(value = "User-Agent" ,required = false) String user_agent){
	System.out.println(user_agent);
}

常用来对Cookie来进行操作


(2)直接获取Cookie的值 :

使用@CookieValue注解 : 可以直接获取指定Cookie的值

  • value : 指定cookie的名称
  • required : 是否必须携带次cookie

文件上传 :

文件上传客户端三要素:

  • 表单项type = “file”
  • 表单的提交方式是post
  • 表单的enctype属性是多部分的表单形式 ,
    • 即enctype=“multipart/form-data”
<form action="${pageContext.request.contextPath}/request/save10" method="post" enctype="multipart/form-data">
        名称 : <input type="text" name="username"><br>
        文件 : <input type="file" name="upload"><br>
        <input type="submit" value="提交">
    </form>
  • 当form表单修改为多部分表单的时候 , request.getParameter()将失效
  • enctype = "application/x-www-form-urlencoded"是 , form表单的正文内容格式是 : key=value&key=value&key=value
  • 当form表单的enctype取值为Mutilpart/from-data时 , 请求正文内容就变成多部分格式

image-20220321195710932


单文件上传实现

(1)导入fileupload和io坐标

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.3</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
</dependency>

(2)配置文件上传解析器

<!--指定文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--上传文件总大小-->
    <property name="maxUploadSize" value="5242800"/>
    <!--上传单个文件的大小-->
    <property name="maxUploadSizePerFile" value="5242800"/>
    <!--上传文件的编码格式-->
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

(3)编写文件上传代码

@RequestMapping("/save10")
@ResponseBody
//这里的MultipartFile upload 参数名要和表单对应文件选项的name值一致
public void save10(String username, MultipartFile upload) throws IOException {
    System.out.println(username);
    System.out.println(upload);
    //获得上传文件的名称 :
    String filename = upload.getOriginalFilename();
    //使用自带的方法将文件保存在指定的目录中
    upload.transferTo(new File("D:\\riji\\wenjian\\"+filename));
}

多文件上传实现 :

  • (1)将上边的表单项重复多个 , 修改每个对应的name值 , 在文件上传代码的时候 , 设置对应个数的MultipartFile upload 参数 , 注意参数的名字一一对应 , 即可
  • (2)也可以将name的值设置一样 , 在java代码中使用数组的形式 , 接收数据 , 然后使用for循环来遍历数组 , 完成文件的保存
@RequestMapping("/save12")
@ResponseBody
//使用数组的形式 , 来获取保存文件
public void save12(MultipartFile[] upload1) throws IOException {
    for (MultipartFile multipartFile : upload1) {
    String filename = multipartFile.getOriginalFilename();
	multipartFile.transferTo(new File("D:\\riji\\wenjian\\"+filename));
    }
}

SpringMVC拦截器 (interceptor):


概述:

SpringMVC的拦截器类似于Servlet开发中的过滤器Filter , 用于对处理器进行预处理后处理

将拦截器按一定的顺序联结成一条链 , 这条链称为拦截器链(interceptor Chain) ,

在访问被拦截的方法或字段时 , 拦截器链中的拦截器就会按照之前定义的顺序被调用 , 拦截器也是AOP思想的具体实现

拦截器和过滤器的区别

Spring-MVC拦截器可以设置标签排除不需要拦截的资源

拦截器方法说明


快速入门:

自定义拦截器很简单 , 只有如下两步 :

(1)创建拦截器类 , 实现HandlerInterceptor接口

public class MyInterceptor implements HandlerInterceptor {
    @Override
    //在目标方法执行之前执行的
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        //这里输出的是false , 就会阻止继续访问
        //输出true的话 , 放行
        return true;
    }
    @Override
    //在目标方法执行之后  , 视图返回之前执行的
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }
    @Override
    //在整个流程都执行完毕后 , 执行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

(2)配置拦截器 : 在spring-mvc中进行配置 :

<!--配置拦截器-->
<mvc:interceptors><!--这里可以创建多个拦截器-->
    <mvc:interceptor>
        <!--mvc:mapping是指定对那些资源进行拦截 ,
        /** 代表对所有资源都进行拦截-->
        <mvc:mapping path="/**"/>
        <bean class="com.sichen.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

实现用户登录权限的检测 :

@Override
//在目标方法执行之前执行的
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        //这里输出的是false , 就会阻止继续访问
        //输出true的话 , 不会阻拦
        String name = request.getParameter("name");
        if ("yes".equals(name)){
            return true;
        }else{
            request.getRequestDispatcher("/error.jsp").forward(request,response);
            return false;
        }
}

interceptor拦截器链的执行顺序 :

//和filter的执行顺序是一样的 , 在配置文件中 , 写在前边的先执行下边的方法 , 
@Override
    //在目标方法执行之前执行的
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    return false;
}

//但是后两个方法 , 的顺序是反过来的 , 类似于进栈的操作 , 在第一个方法的时候 , 这些拦截器先存入堆栈中  , 在后续方法的执行过程中 , 会优先执行堆栈上边

SpringMVC的异常处理机制:

过去我们直接是在业务层 (也就是Service层进行的异常抛出处理 ,)但是 , 这样会导致代码过度的耦合 , 可读性差 , 代码不容易维护 , 等等缺点


异常处理的思路:

系统中的异常包括两类 , 预期异常运行时异常 RuntimeException
前者通过捕获异常从而获取异常信息 ,
后者主要通过规范代码的开发 , 测试等手段 , 减少运行时异常的发生

系统的Dao , Service , Controller 出现都通过throws Exception向上抛出 , 最后由SpringMVC前端控制器交由异常处理器进行异常处理 ,

HandlerExceptionResolver : 异常处理器


异常处理的两种方式 :

(1)使用SpringMVC提供的简单异常处理器 : SimpleMappingExceptionResolver

SpringMVC已经定义好了该类型转换器 , 在使用时可以根据项目情况进行响应异常与视图的映射配置

<!--配置简单的异常处理器-->
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <!--这个是指定默认的异常 , 及跳转路径-->
        <property name="defaultErrorView" value="error"/>
        <property name="exceptionMappings">
            <map>
                <!--这里的key值是异常的全限定名称 , value的值就是发生异常时的跳转路径-->
                <entry key="java.lang.ClassCastException" value="error"/>
                <!--可以指定多个异常-->
                <entry key="java.io.FileNotFoundException" value="error1"/>
            </map>
        </property>
    </bean>

(2)使用Spring的异常处理接口 : HandlerExceptionResolver

① : 创建异常处理器类实现 HandlerExceptionResolver

/**
     * @param o Object
     * @param e Exception : 参数Exception : 异常对象
     * @return 返回值 , ModelAndView , 跳转到错误视图信息
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        ModelAndView modelAndView = new ModelAndView();
        if (e instanceof MyException){
            //判断e , 是不是MyException的实例
            modelAndView.addObject("info","自定义异常");
        }else if (e instanceof ClassCastException){
            modelAndView.addObject("info","类转换异常");
        }
        modelAndView.setViewName("error");
        return modelAndView;
    }

② : 配置异常处理器

<!--这里就比较简单了 , 只需要将类加载进内存即可-->
<!--自定义异常处理器-->
<bean class="com.itheima.resolver.MyExceptionResolver"/>

③ : 编写异常页面

④ : 测试异常跳转


在配置了这些之后 , 再有异常就直接往上层抛即可 , 我们配置了一个异常的处理类 , 会帮助我们处理这些异常

 * @param o Object
 * @param e Exception : 参数Exception : 异常对象
 * @return 返回值 , ModelAndView , 跳转到错误视图信息
 */
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
    ModelAndView modelAndView = new ModelAndView();
    if (e instanceof MyException){
        //判断e , 是不是MyException的实例
        modelAndView.addObject("info","自定义异常");
    }else if (e instanceof ClassCastException){
        modelAndView.addObject("info","类转换异常");
    }
    modelAndView.setViewName("error");
    return modelAndView;
}

② : 配置异常处理器

```xml
<!--这里就比较简单了 , 只需要将类加载进内存即可-->
<!--自定义异常处理器-->
<bean class="com.itheima.resolver.MyExceptionResolver"/>

③ : 编写异常页面

④ : 测试异常跳转


在配置了这些之后 , 再有异常就直接往上层抛即可 , 我们配置了一个异常的处理类 , 会帮助我们处理这些异常

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值