spring web应用的异常处理

来源:互联网 发布:大话西游手游藕丝数据 编辑:程序博客网 时间:2024/05/22 16:20

针对RESTful返回json的异常处理

@ControllerAdvice和@ExceptionHandler
字面理解
ControllerAdvice:控制增强
ExceptionHandler:异常处理程序
spring有一个类专门处理异常的基类,已经写好了一些默认的异常处理方法,如果需要可以直接继承这个类:ResponseEntityExceptionHandler,如果不能满足需求可以自己重写某些方法(例:方法3)或者直接自己捕获异常(例:方法1/方法2)

@ControllerAdvicej avadoc定义是:

/*** Indicates the annotated class assists a "Controller".** <p>Serves as a specialization of {@link Component @Component}, allowing for* implementation classes to be autodetected through classpath scanning.** <p>It is typically used to define {@link ExceptionHandler @ExceptionHandler},* {@link InitBinder @InitBinder}, and {@link ModelAttribute @ModelAttribute}* methods that apply to all {@link RequestMapping @RequestMapping} methods.** @author Rossen Stoyanchev* @since 3.2*/

即把@ControllerAdvice注解内部使用@ExceptionHandler、@InitBinder、@ModelAttribute注解的方法应用到所有的 @RequestMapping注解的方法。
理解:
1. @ControllerAdvice:是必须加的
2. @ExceptionHandler:是指定捕获的异常类型的(可以不指定类型)
3. 这是开始执行@RequestMapping方法时发生的异常,执行方法之前的异常是无法捕捉的(例:404)
例1:

@ControllerAdvice  public class ControllerAdviceTest {      @ModelAttribute      public User newUser() {          System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前把返回值放入Model");          return new User();      }      @InitBinder      public void initBinder(WebDataBinder binder) {          System.out.println("============应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器");      }      @ExceptionHandler(UnauthenticatedException.class)      @ResponseStatus(HttpStatus.UNAUTHORIZED)      public String processUnauthenticatedException(NativeWebRequest request, UnauthenticatedException e) {          System.out.println("===========应用到所有@RequestMapping注解的方法,在其抛出UnauthenticatedException异常时执行");          return "viewName"; //返回一个逻辑视图名      }  }  

例2:

// 可以指定类型,本例就是加了RestController注解的类@ControllerAdvice(annotations = RestController.class)public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {    private final Logger logger = LoggerFactory.getLogger(this.getClass());   // 方法1:value是能够被捕获的异常类型,不同的异常调用不同的处理方法    @ExceptionHandler(value = {            FatalException.class,            NonFatalException.class    })    protected ResponseEntity<Object> handleExceptions(Exception ex) {        logger.error("Rest Exception!", ex);        if (ex instanceof FatalException) {            return handleFatalException((FatalException) ex);        } else if (ex instanceof NonFatalException) {            return handleNonFatalException((NonFatalException) ex);        } else {            return new ResponseEntity<Object>(ReturnJson.systemError(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);        }    }    // 处理非致命异常的方法    private ResponseEntity<Object> handleNonFatalException(NonFatalException ex) {        return new ResponseEntity<Object>(ReturnJson.json(ex.getCode(), ex.getMessage(), null), new HttpHeaders(), HttpStatus.OK);    }    // 处理致命异常的方法    private ResponseEntity<Object> handleFatalException(FatalException ex) {        return new ResponseEntity<Object>(ReturnJson.json(ex.getCode(), ex.getMessage(), null), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);    }    // 方法2:其他异常处理方法    @ExceptionHandler    protected ResponseEntity<Object> handleOtherExceptions(Exception ex) {        logger.error("Rest Exception!", ex);        return new ResponseEntity<Object>(ReturnJson.systemError(), new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);    }    // 方法3:父类的方法无法满足我们的需要,就要重写父类的方法    @Override    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {        logger.error("请求参数错误", ex);        return new ResponseEntity<Object>(ReturnJson.fail(), new HttpHeaders(), HttpStatus.OK);    }}

ResponseEntityExceptionHandler代码片段

public abstract class ResponseEntityExceptionHandler {    // 捕获的异常类型,调用不同的方法处理    @ExceptionHandler(value = {            NoSuchRequestHandlingMethodException.class,            HttpRequestMethodNotSupportedException.class,            HttpMediaTypeNotSupportedException.class,            HttpMediaTypeNotAcceptableException.class,            MissingServletRequestParameterException.class,            ServletRequestBindingException.class,            ConversionNotSupportedException.class,            TypeMismatchException.class,            HttpMessageNotReadableException.class,            HttpMessageNotWritableException.class,            MethodArgumentNotValidException.class,            MissingServletRequestPartException.class,            BindException.class,            NoHandlerFoundException.class    })    public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) {        HttpHeaders headers = new HttpHeaders();        if (ex instanceof NoSuchRequestHandlingMethodException) {            HttpStatus status = HttpStatus.NOT_FOUND;            return handleNoSuchRequestHandlingMethod((NoSuchRequestHandlingMethodException) ex, headers, status, request);        }        。        。        。        else {            logger.warn("Unknown exception type: " + ex.getClass().getName());            HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;            return handleExceptionInternal(ex, null, headers, status, request);        }    }    // 异常处理的方法    protected ResponseEntity<Object> handleNoSuchRequestHandlingMethod(NoSuchRequestHandlingMethodException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {        pageNotFoundLogger.warn(ex.getMessage());        return handleExceptionInternal(ex, null, headers, status, request);    }    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {        if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {            request.setAttribute("javax.servlet.error.exception", ex, WebRequest.SCOPE_REQUEST);        }        return new ResponseEntity<Object>(body, headers, status);    }}

对于使用模板渲染HTML的应用

1.在执行@RequestMapping之后遇到的异常

@Componentpublic class ExceptionHandler implements HandlerExceptionResolver {    private static Logger log = LoggerFactory.getLogger(ExceptionHandler.class);    @Override    public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse resp, Object handler, Exception ex) {    // 异常处理逻辑 goes here        log.info("got exception: {}", ex.getClass());        return new ModelAndView("pc/500");    }}

异常的处理逻辑:
DispatcherServlet中如果产生了异常,则接下来会在processDispatchResult()方法中查询当前容器中是否有HandlerExceptionResolver接口的实现类,如果有则调用它的resolveException()方法,得到返回的View,如果没有则使用框架默认的异常处理类。

2.在执行@RequestMapping之前遇到的异常

这个是spring-boot才有的
我们要写一个@Controller,并实现ErrorController接口:

@Controller  public class MainsiteErrorController implements ErrorController { private static final String ERROR_PATH = "/error";  @RequestMapping(value=ERROR_PATH)      public String handleError(){          return "pages/404";      }   @Override   public String getErrorPath() {  return ERROR_PATH;   }}  
原创粉丝点击