您的位置:首页 > 编程语言 > Java开发

spring web应用的异常处理

2017-10-13 18:51 162 查看

针对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 ResponseEnt
4000
ityExceptionHandler {
// 捕获的异常类型,调用不同的方法处理
@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之后遇到的异常

@Component
public 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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息