JavaWeb框架 -SpringMVC04

异常处理器和拦截器

  1. 异常处理的思路:

    • 系统中异常包括两类:预期异常运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生
    • 系统的 dao、service、controller 出现都通过 throws Exception 向上抛出,最后由 springmvc 前端
      控制器交由异常处理器进行异常处理
  2. 异常处理器的编写:

    • 当程序发生错误时(异常会层层外抛),错误最终会传递给DispatcherServlet,由DispatcherServlet进行异常处理
    • SpringMVC的异常处理机制处理异常的步骤:
      • 创建自定义异常类
        public class SysException extends Exception {
        
            // 存储提示信息的
            private String message;
        
            // 构造方法
            public SysException(String message) {this.message = message; }
        
            // get,set方法
            public String getMessage() {return message; }
            public void setMessage(String message) {this.message = message; }
        }			
        
      • 创建异常处理器,异常处理器必须实现HandlerExceptionResolver接口,其resolveException()方法执行异常处理
        // 自定义异常处理器
        public class MyExceptionResolver implements HandlerExceptionResolver {
        
            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
                SysException e = null;
                if (ex instanceof SysException) {
                    e = (SysException) ex;
                } else {
                    e = new SysException("其他错误");
                }        
                ModelAndView mv = new ModelAndView();
                // 封装错误信息
                mv.addObject("errorMsg", e.getMessage());  
                // 跳转页面
                mv.setViewName("error");                    
                return mv;
            }
        }
        
      • Spring容器中注入异常处理器
        <!--配置异常处理器-->
        <bean id="myExceptionResolver" class="cn.maoritian.exception.MyExceptionResolver"/>			
        
  3. SpringMVC中处理异常的三种方式:

    • 第一种方式:使用 @ ExceptionHandler 注解 使用该注解有一个不好的地方就是:进行异常处理的方法必须与出错的方法在同一个Controller里面不能全局的控制异常

      @ExceptionHandler({MyException.class})   
      public String exception(MyException e) {   
           System.out.println(e.getMessage());   
           e.printStackTrace();   
           return "exception";   
      }   
      
    • 第二种方式:使用 @ControllerAdvice 注解+@ExceptionHandler @ ExceptionHandler 需要进行异常处理的方法必须与出错的方法在同一个Controller里面。那么当代码加入了 @ControllerAdvice,则不需要必须在同一个 controller 中了。这也是 Spring 3.2 带来的新特性上可以看出大体意思是控制器增强 可以实现全局的异常捕捉:

      @ExceptionHandler(value={java.lang.ArithmeticException.class})
          public ModelAndView arithmeticExceptionHandler(Exception e){
              ModelAndView mv = new ModelAndView(); 
              mv.addObject("error", e.toString()+" -- advice"); 
              mv.setViewName("error1");
              return mv;
          }
      

      通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置:注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上:

      • @ExceptionHandler:用于全局处理控制器里的异常。
      • @InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
      • @ModelAttribute:本来作用是绑定键值对到Model中,此处让全局的@RequestMapping都能获得在此处设置的键值对
    • 如果 @ExceptionHandler 注解中未声明要处理的异常类型,则默认为参数列表中的异常类型。所以还可以写成这样:

      @ControllerAdvice
      public class GlobalExceptionHandler {
      
          @ExceptionHandler()
          @ResponseBody
          String handleException(Exception e){
              return "Exception Deal! " + e.getMessage();
          }
      }
      
    • 第三种方式:实现 HandlerExceptionResolver 接口 项目中的异常需要统一处理,正常情况下,需要提前准备好一个错误页面,当项目出错了,将该页面展示给用户这个类必须声明到 Spring 配置文件中,或者使用 @Component 标签 或者是SimpleMappingExceptionResolver 这是HandlerExceptionResolver 接口实现类 使用时只需要使用注入到 Spring 配置文件进行声明即可

      	// 自定义异常处理器
      	public class MyExceptionResolver implements HandlerExceptionResolver {
      	
      	    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
      	        SysException e = null;
      	        if (ex instanceof SysException) {
      	            e = (SysException) ex;
      	        } else {
      	            e = new SysException("其他错误");
      	        }        
      	        ModelAndView mv = new ModelAndView();
      	        // 封装错误信息
      	        mv.addObject("errorMsg", e.getMessage());  
      	        // 跳转页面
      	        mv.setViewName("error");                    
      	        return mv;
      	    }
      	}
      

      SimpleMappingExceptionResolver实现类使用方式:但是一般的都是使用第一种方式

      <!-- 自定义的实现类 -->
      <bean id="exceptionHandler" class="com.edu.CustomExceptionHandler"/>
      <!-- 默认的实现类注入 -->
      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
          <!-- 为所有的异常定义默认的异常处理页面,exceptionMappings未定义的异常使用本默认配置 -->  
          <property name="defaultErrorView" value="error"></property>  
          <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为exception -->  
          <property name="exceptionAttribute" value="ex"></property>  
          <!-- 
          定义需要特殊处理的异常,用类名或完全路径名作为key,异常页文件名作为值,
          将不同的异常映射到不同的页面上。
         -->  
          <property name="exceptionMappings">  
              <props>  
                  <prop key="IOException">error/ioexp</prop>  
                  <prop key="java.sql.SQLException">error/sqlexp</prop>  
              </props>  
          </property>  
      </bean>
      
    • 第四种方式:配置errorpage

      <!--通过状态码进行设置-->
      <error-page>
      	<error-code>404</error-code>
          <location>/error/404.html</location>
      </error-page>
      <!--通过异常的类型进行配置-->
      <error-page>
      	<exception-type>java.lang.Exception</exception-type>
          <location>/error/500.html</location>
      </error-page>
      
  4. 拦截器:

    • 拦截器的配置:
      • 自定义拦截器需要继承HandlerInterceptor接口,该接口中定义了三个方法,都已有其默认实现:
        • preHandle(...): 该方法在处理器方法实际执行之前执行
          • preHandle(..)方法返回一个boolean值可以通过这个方法来决定是否继续执行处理链中的部件。当方法返回 true时,处理器链会继续执行;若方法返回 false, DispatcherServlet即认为拦截器自身已经完成了对请求的处理(比如说,已经渲染了一个合适的视图),那么其余的拦截器以及执行链中的其他处理器就不会再被执行了
        • postHandle(...): 该方法在处理器方法实际执行完毕以后执行
        • afterCompletion(...): 该方法在整个请求处理完成后执行
    • 具体的步骤:
      • 拦截器的编写:
        public class TimeBasedAccessInterceptor extends HandlerInterceptor {
        
            private int openingTime;
            private int closingTime;
            
            public void setOpeningTime(int openingTime) {this.openingTime = openingTime; }
            public void setClosingTime(int closingTime) {this.closingTime = closingTime; }
        
            public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                Calendar cal = Calendar.getInstance();
                int hour = cal.get(HOUR_OF_DAY);
                if (openingTime <= hour && hour < closingTime) {
                    return true;
                }
                response.sendRedirect("http://host.com/outsideOfficeHours.html");
                return false;
            }
        }
        
      • Spring容器中注入拦截器 使用的标签是<mvc:interceptors>
        <mvc:interceptors>
            <mvc:interceptor>
                <!-- 拦截的方法 -->
                <mvc:mapping path="/**" />
                <!-- 具体的拦截器 -->
                <bean id="officeHoursInterceptor" class="com.itheiam.interceptor.TimeBasedAccessInterceptor">
                    <property name="openingTime" value="9"/>
                    <property name="closingTime" value="18"/>
                </bean>
            </mvc:interceptor>
        </mvc:interceptors>
        
    • 多个拦截器的执行顺序
      • 多个拦截器的执行顺序是由外向内分层执行(在XML文件中先进行配置的先执行)
  5. 自定义类型转换器:(将字符串转成)

    **
     * 将字符串转换成日期类型 在springmvc配置文件中 进行配置自定义类型转换器 自定义的类型转换器同样的是一个对象 使用的是bean标签
     */
    public class StringToDateConverter implements Converter<String, Date> {
    
        /**
         * source 就是传入的值就是传入的值
         * @param source
         * @return
         */
        @Override
        public Date convert(String source) {
            if (source == null){
                throw new RuntimeException("没有传值!");
            }else{
                // 使用DateFormat 接口来进行类型的转换
                DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                Date parse = null;
                try {
                   parse = df.parse(source);
                } catch (Exception e) {
                    throw new RuntimeException("数据类型转换出现错误!");
                }
                return parse;
            }
        }
    }
    

    进行自定义类型转换器的配置:

    <!--配置自定义类型转换器 使用的标签是bean标签 属性是id 和 class属性-->
    <bean id="dateConverter" class="org.springframework.context.support.ConversionServiceFactoryBean">
       <property name="converters">
           <set>
               <!--将自定义的类型转换器注册到set中 第三步将转换器生效-->
               <bean class="com.itheima.utils.StringToDateConverter"></bean>
           </set>
       </property>
    </bean>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上山打卤面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值