exception handling
Exceptions are thrown from the bottom layer to the Controller for processing. The client's request first goes to the controller and then to the dao. The exception encountered at the time of the request, the exception encountered by the lower layer such as the dao will be thrown in the return result of the controller, so the exception is handled uniformly. All in the controller layer
1. @ExceptionHandler does not need to be written on the target method, but on the notification processing method
2. @ExceptionHandler automatically intercepts the set exception. The scope of this control class---in this case, a parent class is generally defined, and then each controller can inherit
refer to:
http://yuhuiblog6338999322098842.iteye.com/blog/2312438
3. @ExceptionHandler combined with @ControllerAdvice will automatically intercept exceptions in all controller classes.
1. When an exception occurs in any method in this Controller, it will be intercepted by this method. Then, output the log. Encapsulate Map and return (Json), the status is false on the page.
code show as below:
1 @Controller 2 public class AccessController { 3 4 /** 5 * Exception page control 6 * 7 * @param runtimeException 8 * @return 9 */ 10 @ExceptionHandler(RuntimeException.class) 11 public @ResponseBody 12 Map<String,Object> runtimeExceptionHandler(RuntimeException runtimeException) { 13 logger.error(runtimeException.getLocalizedMessage()); 14 15 Map model = new TreeMap(); 16 model.put("status", false); 17 return model; 18 } 19 20 }
2. Return to the error interface
code show as below:
1 @Controller 2 public class AccessController { 3 /** 4 * Exception page control 5 * 6 * @param runtimeException 7 * @return 8 */ 9 @ExceptionHandler(RuntimeException.class) 10 public String runtimeExceptionHandler(RuntimeException runtimeException, 11 ModelMap modelMap) { 12 logger.error(runtimeException.getLocalizedMessage()); 13 14 modelMap.put("status", IntegralConstant.FAIL_STATUS); 15 return "exception"; 16 } 17 }
3.使用 @ControllerAdvice,不用任何的配置,只要把这个类放在项目中,Spring能扫描到的地方。就可以实现全局异常的回调。
代码如下:
@ControllerAdvice public class SpringExceptionHandler{ /** * 全局处理Exception * 错误的情况下返回500 * @param ex * @param req * @return */ @ExceptionHandler(value = {Exception.class}) public ResponseEntity<Object> handleOtherExceptions(final Exception ex, final WebRequest req) { TResult tResult = new TResult(); tResult.setStatus(CodeType.V_500); tResult.setErrorMessage(ex.getMessage()); return new ResponseEntity<Object>(tResult,HttpStatus.OK); } }
二、@ExceptionHandler注解
直接在Controller里面加上用@ExceptionHandler标注一个处理异常的方法像下面这样子
@ExceptionHandler(MissingServletRequestParameterException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void processMethod(MissingServletRequestParameterException ex,HttpServletRequest request ,HttpServletResponse response) throws IOException {
System.out.println("抛异常了!"+ex.getLocalizedMessage());
logger.error("抛异常了!"+ex.getLocalizedMessage());
response.getWriter().printf(ex.getMessage());
response.flushBuffer();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
这样,Controller里面的方法抛出了MissingServletRequestParameterException异常就会执行上面的这个方法来进行异常处理。
如下面的代码:
@RequestMapping("/index")
public String index(@MyUser User user,@RequestParam String id,ModelMap modelMap){
return "login";
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
如果我没有传入id值,那么就会抛出MissingServletRequestParameterException的异常,就会被上面的异常处理方法处理。
上面的@ExceptionHandler(MissingServletRequestParameterException.class)这个注解的value的值是一个Class[]类型的,这里的ExceptionClass是你自己指定的,你也可以指定多个需要处理的异常类型,比如这样@ExceptionHandler(value = {MissingServletRequestParameterException.class,BindException.class}),这样就会处理多个异常了。
但这个只会是在当前的Controller里面起作用,如果想在所有的Controller里面统一处理异常的话,可以用@ControllerAdvice来创建一个专门处理的类。如一中的3所述。
三、@ControllerAdvice注解
@ControllerAdvice,是Spring3.2提供的新注解,从名字上可以看出大体意思是控制器增强。让我们先看看@ControllerAdvice的实现:
没什么特别之处,该注解使用@Component注解,这样的话当我们使用<context:component-scan>
扫描时也能扫描到。
再一起看看官方提供的comment。
大致意思是:
-
@ControllerAdvice是一个@Component,用于定义@ExceptionHandler,@InitBinder和@ModelAttribute方法,适用于所有使用@RequestMapping方法。
-
Spring4之前,@ControllerAdvice在同一调度的Servlet中协助所有控制器。Spring4已经改变:@ControllerAdvice支持配置控制器的子集,而默认的行为仍然可以利用。
-
在Spring4中, @ControllerAdvice通过annotations(), basePackageClasses(), basePackages() 方法定制用于选择控制器子集。
不过据经验之谈,只有配合@ExceptionHandler最有用,其它两个不常用。
在SpringMVC重要注解(一)@ExceptionHandler和@ResponseStatus我们提到,如果单使用@ExceptionHandler,只能在当前Controller中处理异常。但当配合@ControllerAdvice一起使用的时候,就可以摆脱那个限制了。
@Controller
@RequestMapping(value = "exception")
public class ExceptionHandlerController {
@RequestMapping(value = "e2/{id}", method = { RequestMethod.GET })
@ResponseBody
public String testExceptionHandle2(@PathVariable(value = "id") Integer id) {
List<String> list = Arrays.asList(new String[]{"a","b","c","d"});
return list.get(id-1);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
当我们访问http://localhost:8080/SpringMVC/exception/e2/5的时候会抛出ArrayIndexOutOfBoundsException异常,这时候定义在@ControllerAdvice中的@ExceptionHandler就开始发挥作用了。
如果我们想定义一个处理全局的异常
At first glance, there is no problem, but there is a flaw here. Since Exception is the parent class of exceptions, if you use @ResponseStatus in custom exceptions in your project, your original intention is to encounter that custom exception. Response to the corresponding status code, and this controller enhanced processing class will enter first and return directly, there will be no more @ResponseStatus thing, here in order to solve this flaw, I provide a solution.
If you encounter a custom exception with @ResponseStatus added, continue to throw it, so that the custom exception will not lose the original intention of adding @ResponseStatus.