SpringMVC-异常处理

SpringMVC提供了HandlerExceptionResolver接口来处理异常,并在web容器初始化时被dispatcherServlet自动加载。
这篇文章说一下ExceptionHandlerExceptionResolverResponseStatusExceptionResolverDefaultHandlerExceptionResolverSimpleMappingExceptionResolver等四种实现类处理异常的方式。

1.ExceptionHandlerExceptionResolver

ExceptionHandlerExceptionResolverHandlerExceptionResolver接口的一个实现类,该类提供了@ExceptionHandler注解用来捕获指定类型的异常。我们下面通过一个示例来了解一下ExceptionHandlerExceptionResolver处理异常的基本流程:

请求处理类(产生一个异常):ExceptionHandlerExceptionResolverDemo.java

@Controller
@RequestMapping("ExceptionHandlerExceptionResolverDemo")
public class ExceptionHandlerExceptionResolverDemo {

	@RequestMapping("testExceptionHandlerExceptionResolver")
	public String testExceptionHandlerExceptionResolver() {
		//产生一个ArithmeticException异常
		int num = 1/0;
		return "success";
	}
	
	 //捕获本类中所有方法抛出的ArithmeticException异常
	@ExceptionHandler({ArithmeticException.class})
	public String handleArithmeticException(Exception ex) {
		System.out.println("异常:"+ex);
		return "error";
	}
}

index.jsp

<a href="ExceptionHandlerExceptionResolverDemo/testExceptionHandlerExceptionResolver">test</a>

执行index.jsp中的超链接,可以发现控制台输出了handleArithmeticException()方法中的异常提示,并且页面跳转到了error.jsp,如图。
在这里插入图片描述
可以发现,@ExceptionHandler({ArithmeticException.class})标识的方法会捕获当前类中抛出的ArithmeticException类型的异常。也就是说,在某一个类中产生的异常,可以通过在该类中定义一个被@ExceptionHandler({异常类型.class})标识的方法来捕获此异常。并且,异常对象会被保存在Exception类型的参数中。

我们知道ArithmeticExceptionRuntimeException的子类,如果在一个类中抛出一个ArithmeticException类型的异常,而该类中既存在@ExceptionHandler({ArithmeticException.class})修饰的方法,又存在@ExceptionHandler({RuntimeException.class})修饰的方法,那么异常只会被@ExceptionHandler({ArithmeticException.class})修饰的方法所捕获。只有当本类中不存在@ExceptionHandler({ArithmeticException.class})修饰的方法时,此异常才会被@ExceptionHandler({RuntimeException.class})修饰的方法所捕获。也就是说,如果有多个@ExceptionHandler修饰的方法可以捕获同一个异常时,异常只会被最精确的处理方法所捕获。

还需要注意的是,使用@ExceptionHandler修饰的方法的参数,只能是Throwable或其子类类型,并且不能再有其他参数存在

例如可以写成以下几种形式:

@ExceptionHandler({ArithmeticException.class})
public String handleArithmeticException(Throwable ex)
{…}
@ExceptionHandler({ArithmeticException.class})
public String handleException(Exception ex)
{…}
@ExceptionHandler({ArithmeticException.class})
public String handleArithmeticException(ArithmeticException aEx)
{…}

而不能写成:

@ExceptionHandler({ArithmeticException.class})
public String handleArithmeticException(Exception ex,Map<String,Object> map)
{…}
@ExceptionHandler({ArithmeticException.class})
public String handleArithmeticException(String message)
{…}

已经知道,使用@ExceptionHandler修饰的方法可以捕获同一个类中的异常。但如果@ExceptionHandler修饰的方法与产生异常的方法不在同一个类之中,那么产生的异常就不会被捕获。为此,我们可以这样解决:
新建一个类,并且使用@ControllerAdvice注解修饰此类,如下:

MyExceptionHandler.java

@ControllerAdvice
public class MyExceptionHandler{
 @ExceptionHandler({ArithmeticException.class})
 public ModelAndView MyException(Exception e){
  System.out.println("(异常处理类)异常信息:"+e);
  ModelAndView mv = new ModelAndView("exception");
  mv.addObject("ex", e);
  return mv;
 }
}

@ControllerAdvice修饰的类可以理解为“异常处理类”,此异常处理类就可以捕获项目中所有类中方法产生的ArithmeticException异常。
如果同一个异常既可以被同一个类中@ExceptionHandler修饰的方法所捕获,又可以被异常处理类中@ExceptionHandler修饰的方法所捕获,那么根据“就近原则”只会被同一个类中@ExceptionHandler修饰的方法所捕获。

2.ResponseStatusExceptionResolver

在开发中,我们经常会看到类似的异常页面,
在这里插入图片描述
页面中的异常信息都是服务器预先设置好的,除此之外,我们还可以自己定制这些页面中的异常信息:
通过ResponseStatusExceptionResolver类提供的@ResponseStatus注解来实现
通过@ResponseStatus注解的value属性指定异常的状态码(如404等)、reason属性指定具体的异常信息,如下

其中HttpStatus.FORBIDDEN的值是403。

ResponseStatusDemo.java

@Controller
@RequestMapping("ResponseStatusDemo")
public class ResponseStatusDemo {

	@RequestMapping("testResponseStatus")
	public String testResponseStatus(@RequestParam Integer i) {
		if(i==10) {
			throw new MyArrayOutOfBounderException();
		}
		return "success";
	}
}

index.jsp

<a href="ResponseStatusDemo/testResponseStatus?i=10">testResponseStatus</a>

执行index.jsp中的超链接,运行结果:
在这里插入图片描述
@ResponseStatus注解除了能标识在异常类上以外,还可以标识在方法上。@ResponseStatus标识在方法上时,就会使访问此方法的请求直接显示@ResponseStatus指定的异常信息,如下:

ResponseStatusDemo.java

@Controller
@RequestMapping(value = "/SecondSpringDemo")
public class ResponseStatusDemo{

 @ResponseStatus(value=HttpStatus.FORBIDDEN, reason="我在测试forbidden")
 @RequestMapping("/testResponseStatusWithMethod")
 public String testResponseStatusWithMethod(){
  return "sucess";
 }
}

index.jsp

<a href="ResponseStatusDemo/testResponseStatusWithMethod">testResponseStatusWithMethod</a>

执行index.jsp中的超链接,去访问被@ResponseStatus注解标识的方法,就能直接得到异常页面。

3.DefaultHandlerExceptionResolver

Springmvc默认装配了DefaultHandlerExceptionResolver异常解析器 ,会对一些特殊的异常,如NoSuchRequestHandlingMethodException、HttpRequestMethodNotSupportedException、HttpMediaTypeNotSupportedException、HttpMediaTypeNotAcceptableException等进行处理。以下,我们以NoSuchRequestHandlingMethodException为例进行测试:

如果某一个请求的请求方式,与请求处理方法所指定的请求方式不一致,就会抛出NoSuchRequestHandlingMethodException异常。例如,请求的是GET方式,而请求处理方法指定的是POST方式,如下:

NoSuchRequestHandlingMethodExceptionDemo.java

@Controller
@RequestMapping(value = "/NoSuchRequestHandlingMethodExceptionDemo")
public class NoSuchRequestHandlingMethodExceptionDemo{
  
 @RequestMapping(value="/testNoSuchRequestHandlingMethodException",method=RequestMethod.POST)
 public String testNoSuchRequestHandlingMethodException(){
  return "success";
 }
}

index.jsp

<a href="NoSuchRequestHandlingMethodExceptionDemo/testNoSuchRequestHandlingMethodException">
testNoSuchRequestHandlingMethodException
</a>

执行index.jsp中的超链接,所产生的NoSuchRequestHandlingMethodException异常就会被DefaultHandlerExceptionResolver所捕获并处理。

4.SimpleMappingExceptionResolver

SpringMVC还提供了SimpleMappingExceptionResolver,来让我们通过配置的方式处理异常。例如,先通过以下代码产生一个NumberFormatException异常

@Controller
@RequestMapping(value = "/SecondSpringDemo")
public class SecondSpringDemo{
   
 @RequestMapping("/testSimpleMappingExceptionResolver")
 public String testSimpleMappingExceptionResolver()  
{
  //java.lang.NumberFormatException
  int  num = Integer.parseInt("abc");
  return "success" ;
 }
}

index.jsp

<a href="SecondSpringDemo/testSimpleMappingExceptionResolver">
testSimpleMappingExceptionResolver
</a>

之后就可以通过在springmvc.xml配置SimpleMappingExceptionResolver,来使得程序在发生NumberFormatException异常后,能跳转到一个指定的错误页面,如下:
springmvc.xml

 <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
	<property name="exceptionAttribute" value="ex"></property>
   		 <property name="exceptionMappings">
   			 <props>
				<prop key="java.lang.NumberFormatException">
					error
				</prop>
   			 </props>
    </property>
 </bean>

以上,通过exceptionMappings属性指定捕获的异常类型是NumberFormatException,并且指定发生此类型的异常后,页面立即跳转到/views/error.jsp页面。并通过exceptionAttribute属性指定将异常对象保存在request作用域中的ex变量之中。

说明:
exceptionAttribute属性的默认值是exception。即如果不设置exceptionAttribute的值,SpringMVC就会自动的将异常对象保存在request作用域中的exception变量之中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值