SpringMVC学习总结(六).异常处理解析器

HandlerExceptionResolver

    • Spring MVC通过HandlerExceptionResolver处理程序的异常,包括Handler 映射、数据绑定以及目标方法执行时发生的异常。

    • SpringMVC提供的HandlerExceptionResolver的实现类






 • DispatcherServlet默认装配的HandlerExceptionResolver

        – 没有使用<mvc:annotation-driven/> 配置:


      – 使用了<mvc:annotation-driven/> 配置:



ExceptionHandlerExceptionResolver

  • 主要处理Handler 中用@ExceptionHandler注解定义的方法。
  • @ExceptionHandler注解定义的方法优先级问题:例如发生的是NullPointerException,但是声明的异常有RuntimeExceptionException,此时会根据异常的最近继承关系找到继承深度最浅的那个@ExceptionHandler注解方法,即标记了RuntimeException的方法
  • ExceptionHandlerMethodResolver内部若找不到@ExceptionHandler注解的话,会找@ControllerAdvice中的@ExceptionHandler注解方法

    @ExceptionHandler({ RuntimeException.class })
    public ModelAndView handleArithmeticException2(Exception ex) {
        System.out.println("[出异常了]: " + ex);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", ex);
        return mv;
    }

    /**
     * 1. 在 @ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象 
     * 2. @ExceptionHandler方法的入参中不能传入 Map. 若希望把异常信息传导页面上, 需要使用 ModelAndView 作为返回值 
     * 3. @ExceptionHandler 方法标记的异常有优先级的问题.
     * 4. @ControllerAdvice: 如果在当前 Handler 中找不到 @ExceptionHandler 方法来出来当前方法出现的异常, 则将去 @ControllerAdvice
     * 标记的类中查找 @ExceptionHandler 标记的方法来处理异常.
     */
    @ExceptionHandler({ ArithmeticException.class })
    public ModelAndView handleArithmeticException(Exception ex) {
        System.out.println("出异常了: " + ex);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", ex);
        return mv;
    }

    @RequestMapping("/testExceptionHandlerExceptionResolver")
    public String testExceptionHandlerExceptionResolver(@RequestParam("i") int i) {
        System.out.println("result: " + (10 / i));
        return "success";
    }

若找不到 @ExceptionHandler 注解的话,会找 @ControllerAdvice 中的 @ExceptionHandler 注解方法

@ControllerAdvice
public class HandlerException {

    @ExceptionHandler({ ArithmeticException.class })
    public ModelAndView handleArithmeticException(Exception ex) {
        System.out.println("出异常了: " + ex);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception", ex);
        return mv;
    }
}


ResponseStatusExceptionResolver

    • 在异常及异常父类中找到@ResponseStatus注解,然后使用这个注解的属性进行处理。

    • 定义一个@ResponseStatus注解修饰的异常类


  • 若在处理器方法中抛出了上述异常:

        ExceptionHandlerExceptionResolver不解析述异常。由于触发的异常UserNameNotMatchPasswordException带有@ResponseStatus注解。因此会被ResponseStatusExceptionResolver解析到。最后响应HttpStatus.UNAUTHORIZED代码给客户端。HttpStatus.UNAUTHORIZED代表响应码401,无权限。关于其他的响应码请参考HttpStatus枚举类型源码。

目标方法:

@RequestMapping("/testResponseStatusExceptionResolver")
public String testResponseStatusExceptionResolver(@RequestParam("i") int i) {
    if (i == 13) {
        throw new UserNameNotMatchPasswordException();
    }
    System.out.println("testResponseStatusExceptionResolver...");

    return "success";
}
若请求参数为13,则抛出自定义异常UserNameNotMatchPasswordException

@ResponseStatus(value=HttpStatus.UNAUTHORIZED, reason="用户名和密码不匹配!")
public class UserNameNotMatchPasswordException extends RuntimeException {

    /**   
     * @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)   
     */   
    private static final long serialVersionUID = 1L;

}

请求http://localhost:8081/testResponseStatusExceptionResolver?i=13    测试结果:


如果@ResponseStatus 标注在目标方法上,参数为13则抛出UserNameNotMatchPasswordException,正常情况不为13的话 结果如下:

DefaultHandlerExceptionResolver


SpringMVC内部对一些特 殊的异常进行处理,比NoSuchRequestHandlingMethodException、                                                          HttpRequestMethodNotSupportedException HttpMediaTypeNotSupportedException HttpMediaTypeNotAcceptableException等。

部分核心源代码如下:

@Override
@SuppressWarnings("deprecation")
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
		Object handler, Exception ex) {

	try {
		// 处理 404 (Not Found) 异常
		if (ex instanceof org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) {
			return handleNoSuchRequestHandlingMethod((org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException) ex,
					request, response, handler);
		}
		// 处理请求方式不支持 异常
		else if (ex instanceof HttpRequestMethodNotSupportedException) {
			return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, request,
					response, handler);
		}
		//这个网上说  如果发送的ajax请求类型为'application/x-www-form-urlencoded;charset=UTF-8',但是Spring MVC使用的是‘application/json’,所以需要在ajax请求中改成'Content-Type' : 'application/json;charset=utf-8',
		else if (ex instanceof HttpMediaTypeNotSupportedException) {
			return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, request, response,
					handler);
		}
		else if (ex instanceof HttpMediaTypeNotAcceptableException) {
			return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, request, response,
					handler);
		}
		else if (ex instanceof MissingPathVariableException) {
			return handleMissingPathVariable((MissingPathVariableException) ex, request,
					response, handler);
		}
		else if (ex instanceof MissingServletRequestParameterException) {
			return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, request,
					response, handler);
		}
		else if (ex instanceof ServletRequestBindingException) {
			return handleServletRequestBindingException((ServletRequestBindingException) ex, request, response,
					handler);
		}
		else if (ex instanceof ConversionNotSupportedException) {
			return handleConversionNotSupported((ConversionNotSupportedException) ex, request, response, handler);
		}
		else if (ex instanceof TypeMismatchException) {
			return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
		}
		else if (ex instanceof HttpMessageNotReadableException) {
			return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, request, response, handler);
		}
		else if (ex instanceof HttpMessageNotWritableException) {
			return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, request, response, handler);
		}
		else if (ex instanceof MethodArgumentNotValidException) {
			return handleMethodArgumentNotValidException((MethodArgumentNotValidException) ex, request, response,
					handler);
		}
		else if (ex instanceof MissingServletRequestPartException) {
			return handleMissingServletRequestPartException((MissingServletRequestPartException) ex, request,
					response, handler);
		}
		else if (ex instanceof BindException) {
			return handleBindException((BindException) ex, request, response, handler);
		}
		else if (ex instanceof NoHandlerFoundException) {
			return handleNoHandlerFoundException((NoHandlerFoundException) ex, request, response, handler);
		}
		else if (ex instanceof AsyncRequestTimeoutException) {
			return handleAsyncRequestTimeoutException(
					(AsyncRequestTimeoutException) ex, request, response, handler);
		}
	}
	catch (Exception handlerException) {
		if (logger.isWarnEnabled()) {
			logger.warn("Handling of [" + ex.getClass().getName() + "] resulted in Exception", handlerException);
		}
	}
	return null;
}


测试方法:
/**
 * 
 * @Title: testDefaultHandlerExceptionResolver   
 * @Description: 测试  DefaultHandlerExceptionResolver 异常
 * 如果请求方式为 GET 方式,则抛出DefaultHandlerExceptionResolver 异常
 * @param: @return      
 * @return: String      
 * @throws
 */
@RequestMapping(value="/testDefaultHandlerExceptionResolver",method=RequestMethod.POST)
public String testDefaultHandlerExceptionResolver(){
        System.out.println("testDefaultHandlerExceptionResolver...");
        return "success";
}


SimpleMappingExceptionResolver


•  如果希望对所有异常进行统一处理,可以使用 SimpleMappingExceptionResolver ,它将异常类名映射为视图名,即发生异常时使用对应的视图报告异常

/**
 * 
 * @Title: testSimpleMappingExceptionResolver   
 * @Description: 测试SimpleMappingExceptionResolver 异常
 * 如果数组下标越界,则抛出异常
 * @param: @param i
 * @param: @return      
 * @return: String      
 * @throws
 */
@RequestMapping("/testSimpleMappingExceptionResolver")
public String testSimpleMappingExceptionResolver(@RequestParam("i") int i){
        String [] vals = new String[10];
        System.out.println(vals[i]);
        return "success";
}

需在xml中配置异常处理
<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
		</props>
	</property>
</bean>

出现异常跳转到error.jsp页面
<h4>error Page</h4>
	
${exception }

发送请求http://localhost:8081/testSimpleMappingExceptionResolver?i=14      此时触发异常


可以看到 并没有往请求域中存放exception 属性及对应的值,但是却可以从请求域中获取该属性对应的value,查看源代码发现:



这个exceptionAttribute属性的值为exception


既然默认值为exception ,那么就可以在xml 中手动改变其值
<!-- 配置使用 SimpleMappingExceptionResolver 来映射异常 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionAttribute" value="ex"></property>
	<property name="exceptionMappings">
		<props>
			<prop key="java.lang.ArrayIndexOutOfBoundsException">error</prop>
		</props>
	</property>
</bean>	

同时页面上,也需要从请求域中获取ex属性对应的value.




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值