java mvc异常捕获_Spring MVC异常处理详解 ExceptionHandler good

@ControllerAdvice(basePackageClasses = AcmeController.class)public class AcmeControllerAdvice extendsResponseEntityExceptionHandler {

@ExceptionHandler(YourException.class)

@ResponseBody

ResponseEntity>handleControllerException(HttpServletRequest request, Throwable ex) {

HttpStatus status=getStatus(request);return new ResponseEntity<>(newCustomErrorType(status.value(), ex.getMessage()), status);

}privateHttpStatus getStatus(HttpServletRequest request) {

Integer statusCode= (Integer) request.getAttribute("javax.servlet.error.status_code");if (statusCode == null) {returnHttpStatus.INTERNAL_SERVER_ERROR;

}returnHttpStatus.valueOf(statusCode);

}

}

https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/

下图中,我画出了Spring MVC中,跟异常处理相关的主要类和接口。

bc14c6efd12a094a8905b89e5d32abc1.png

1.包含文件

spring.xml

messages_zh_CN.properties

messages_en_US.properties

ExceptionHandle.java

XXController.java

2.文件内容

spring.xml

class="org.springframework.http.converter.StringHttpMessageConverter">

text/plain;charset=UTF-8

text/html;charset=UTF-8

classpath:messagesclasspath:org/hibernate/validator/ValidationMessages

messages_zh_CN.properties

#注意了,如果你的启动jvm是local是US他会去读取messages_en_US.properties文件

#如果不存在,就不会解析{uname.null}

uname.null=用户名不能为空

ExceptionHandle.java

import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

import org.springframework.validation.BindException;

import org.springframework.validation.ObjectError;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

import

org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import com.xx.customquery.exception.BusinessException;

import com.xx.customquery.exception.CommonMessageCode.SystemMessageCode;

import com.xx.customquery.util.Result;

@ControllerAdvice

@Slf4j

public class ExceptionHandle {

@ExceptionHandler(BindException.class)

@ResponseBody

public String processValidationError(BindException ex) {

log.error(ex.getMessage(), ex);

String result = ex

.getBindingResult()

.getAllErrors()

.stream()

.map(ObjectError::getDefaultMessage)

.collect(Collectors.joining(","));

return Result.returnParamFailResult(result);

}

@ExceptionHandler(MethodArgumentTypeMismatchException.class)

@ResponseBody

public String processArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {

log.error(ex.getMessage(), ex);

return Result.returnParamFailResult(ex.getMessage());

}

@ExceptionHandler(BusinessException.class)

@ResponseBody

public String processBusinessException(BusinessException ex) {

log.error(ex.getMessage(), ex);

return Result.returnFailResult(ex);

}

@ExceptionHandler(Throwable.class)

@ResponseBody

public String processException(Throwable ex) {

log.error(ex.getMessage(), ex);

return Result.returnFailResult(new BusinessException(SystemMessageCode.ERROR_SYSTEM));

}

}

Result.java

import com.google.gson.Gson;

import com.xx.customquery.exception.BusinessException;

public class Result {

public final static int SUCCESS = 0;

public final static int FAIL = 999;

public final static int PARAM_FAIL = -1;

private final static Gson GSON = new GsonBuilder().disableHtmlEscaping().create();

public static String returnSuccResult(){

return GSON.toJson(new Result(SUCCESS, "", ""));

}

public static String returnFailResult(String message){

return GSON.toJson(new Result(FAIL, message, ""));

}

public static String returnParamFailResult(String message){

return GSON.toJson(new Result(PARAM_FAIL, message, ""));

}

public static String returnFailResult(BusinessException exception){

return GSON.toJson(new Result(exception.getCode(), exception.getMessage(), ""));

}

public static String returnDataResult(T data){

return GSON.toJson(new Result(SUCCESS, "", data));

}

private int code;

private String message;

private E data;

public Result(){}

public Result(int code,String message, E data){

this.code = code;

this.message = message;

this.data = data;

}

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

public E getData() {

return data;

}

public void setData(E data) {

this.data = data;

}

}

XXController.java

@ResponseBody

@RequestMapping(value = "save", method = RequestMethod.POST)

public String saveQuery(@Valid Query querys) {

}

Query

import lombok.Data;

import org.hibernate.validator.constraints.NotBlank;

@Data

public class Queries {

private long id;

@NotBlank(message="{uname.null}")

private String user;

}

http://www.jianshu.com/p/1390dc477d92

@ControllerAdvice源码

package org.springframework.web.bind.annotation;

import java.lang.annotation.Annotation;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;

import org.springframework.stereotype.Component;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Component

public @interface ControllerAdvice {

@AliasFor("basePackages")

String[] value() default {};

@AliasFor("value")

String[] basePackages() default {};

Class>[] basePackageClasses() default {};

Class>[] assignableTypes() default {};

Class extends Annotation>[] annotations() default {};

}

源码分析

@ ControllerAdvice是一个@ Component,

用于定义@ ExceptionHandler的,@InitBinder和@ModelAttribute方法,适用于所有使用@ RequestMapping方法,并处理所有@ RequestMapping标注方法出现异常的统一处理。

项目图片

597bdc63e8d2ccc4b2e48fe08288aece.png

这里写图片描述

pom.xml

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

com.jege.spring.boot

spring-boot-controller-advice

0.0.1-SNAPSHOT

jar

spring-boot-controller-advice

http://maven.apache.org

org.springframework.boot

spring-boot-starter-parent

1.4.1.RELEASE

UTF-8

1.8

org.springframework.boot

spring-boot-starter-web

org.springframework.boot

spring-boot-starter-data-jpa

com.h2database

h2

runtime

org.springframework.boot

spring-boot-starter-test

test

spring-boot-controller-advice

org.apache.maven.plugins

maven-compiler-plugin

${java.version}

${java.version}

全局异常处理类CommonExceptionAdvice

package com.jege.spring.boot.exception;

import java.util.Set;

import javax.validation.ConstraintViolation;

import javax.validation.ConstraintViolationException;

import javax.validation.ValidationException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.dao.DataIntegrityViolationException;

import org.springframework.http.HttpStatus;

import org.springframework.http.converter.HttpMessageNotReadableException;

import org.springframework.validation.BindException;

import org.springframework.validation.BindingResult;

import org.springframework.validation.FieldError;

import org.springframework.web.HttpMediaTypeNotSupportedException;

import org.springframework.web.HttpRequestMethodNotSupportedException;

import org.springframework.web.bind.MethodArgumentNotValidException;

import org.springframework.web.bind.MissingServletRequestParameterException;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.ResponseStatus;

import com.jege.spring.boot.json.AjaxResult;

/**

* @author JE哥

* @email 1272434821@qq.com

* @description:全局异常处理

*/

@ControllerAdvice

@ResponseBody

public class CommonExceptionAdvice {

private static Logger logger = LoggerFactory.getLogger(CommonExceptionAdvice.class);

/**

* 400 - Bad Request

*/

@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler(MissingServletRequestParameterException.class)

public AjaxResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {

logger.error("缺少请求参数", e);

return new AjaxResult().failure("required_parameter_is_not_present");

}

/**

* 400 - Bad Request

*/

@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler(HttpMessageNotReadableException.class)

public AjaxResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {

logger.error("参数解析失败", e);

return new AjaxResult().failure("could_not_read_json");

}

/**

* 400 - Bad Request

*/

@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler(MethodArgumentNotValidException.class)

public AjaxResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {

logger.error("参数验证失败", e);

BindingResult result = e.getBindingResult();

FieldError error = result.getFieldError();

String field = error.getField();

String code = error.getDefaultMessage();

String message = String.format("%s:%s", field, code);

return new AjaxResult().failure(message);

}

/**

* 400 - Bad Request

*/

@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler(BindException.class)

public AjaxResult handleBindException(BindException e) {

logger.error("参数绑定失败", e);

BindingResult result = e.getBindingResult();

FieldError error = result.getFieldError();

String field = error.getField();

String code = error.getDefaultMessage();

String message = String.format("%s:%s", field, code);

return new AjaxResult().failure(message);

}

/**

* 400 - Bad Request

*/

@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler(ConstraintViolationException.class)

public AjaxResult handleServiceException(ConstraintViolationException e) {

logger.error("参数验证失败", e);

Set> violations = e.getConstraintViolations();

ConstraintViolation> violation = violations.iterator().next();

String message = violation.getMessage();

return new AjaxResult().failure("parameter:" + message);

}

/**

* 400 - Bad Request

*/

@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler(ValidationException.class)

public AjaxResult handleValidationException(ValidationException e) {

logger.error("参数验证失败", e);

return new AjaxResult().failure("validation_exception");

}

/**

* 405 - Method Not Allowed

*/

@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)

@ExceptionHandler(HttpRequestMethodNotSupportedException.class)

public AjaxResult handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {

logger.error("不支持当前请求方法", e);

return new AjaxResult().failure("request_method_not_supported");

}

/**

* 415 - Unsupported Media Type

*/

@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)

@ExceptionHandler(HttpMediaTypeNotSupportedException.class)

public AjaxResult handleHttpMediaTypeNotSupportedException(Exception e) {

logger.error("不支持当前媒体类型", e);

return new AjaxResult().failure("content_type_not_supported");

}

/**

* 500 - Internal Server Error

*/

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

@ExceptionHandler(ServiceException.class)

public AjaxResult handleServiceException(ServiceException e) {

logger.error("业务逻辑异常", e);

return new AjaxResult().failure("业务逻辑异常:" + e.getMessage());

}

/**

* 500 - Internal Server Error

*/

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

@ExceptionHandler(Exception.class)

public AjaxResult handleException(Exception e) {

logger.error("通用异常", e);

return new AjaxResult().failure("通用异常:" + e.getMessage());

}

/**

* 操作数据库出现异常:名称重复,外键关联

*/

@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)

@ExceptionHandler(DataIntegrityViolationException.class)

public AjaxResult handleException(DataIntegrityViolationException e) {

logger.error("操作数据库出现异常:", e);

return new AjaxResult().failure("操作数据库出现异常:字段重复、有外键关联等");

}

}

自定义异常ServiceException

package com.jege.spring.boot.exception;

/**

* @author JE哥

* @email 1272434821@qq.com

* @description:自定义异常类

*/

public class ServiceException extends RuntimeException {

public ServiceException(String msg) {

super(msg);

}

}

不需要application.properties

控制器AdviceController

package com.jege.spring.boot.controller;

import java.util.List;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import com.jege.spring.boot.exception.ServiceException;

/**

* @author JE哥

* @email 1272434821@qq.com

* @description:全局异常处理演示入口

*/

@RestController

public class AdviceController {

@RequestMapping("/hello1")

public String hello1() {

int i = 1 / 0;

return "hello";

}

@RequestMapping("/hello2")

public String hello2(Long id) {

String string = null;

string.length();

return "hello";

}

@RequestMapping("/hello3")

public List hello3() {

throw new ServiceException("test");

}

}

访问

http://localhost:8080/hello1

{"meta":{"success":false,"message":"通用异常:/ by zero"},"data":null}

http://localhost:8080/hello2

{"meta":{"success":false,"message":"通用异常:null"},"data":null}

http://localhost:8080/hello3

{"meta":{"success":false,"message":"业务逻辑异常:test"},"data":null}

源码地址

http://www.jianshu.com/p/5c5601789626

在Spring MVC中,所有用于处理在请求映射和请求处理过程中抛出的异常的类,都要实现HandlerExceptionResolver接口。AbstractHandlerExceptionResolver实现该接口和Orderd接口,是HandlerExceptionResolver类的实现的基类。ResponseStatusExceptionResolver等具体的异常处理类均在AbstractHandlerExceptionResolver之上,实现了具体的异常处理方式。一个基于Spring MVC的Web应用程序中,可以存在多个实现了HandlerExceptionResolver的异常处理类,他们的执行顺序,由其order属性决定, order值越小,越是优先执行, 在执行到第一个返回不是null的ModelAndView的Resolver时,不再执行后续的尚未执行的Resolver的异常处理方法。。

下面我逐个介绍一下SpringMVC提供的这些异常处理类的功能。

DefaultHandlerExceptionResolver

HandlerExceptionResolver接口的默认实现,基本上是Spring MVC内部使用,用来处理Spring定义的各种标准异常,将其转化为相对应的HTTP Status Code。其处理的异常类型有:

handleNoSuchRequestHandlingMethod

handleHttpRequestMethodNotSupported

handleHttpMediaTypeNotSupported

handleMissingServletRequestParameter

handleServletRequestBindingException

handleTypeMismatch

handleHttpMessageNotReadable

handleHttpMessageNotWritable

handleMethodArgumentNotValidException

handleMissingServletRequestParameter

handleMissingServletRequestPartException

handleBindException

ResponseStatusExceptionResolver

用来支持ResponseStatus的使用,处理使用了ResponseStatus注解的异常,根据注解的内容,返回相应的HTTP Status Code和内容给客户端。如果Web应用程序中配置了ResponseStatusExceptionResolver,那么我们就可以使用ResponseStatus注解来注解我们自己编写的异常类,并在Controller中抛出该异常类,之后ResponseStatusExceptionResolver就会自动帮我们处理剩下的工作。

这是一个自己编写的异常,用来表示订单不存在:

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Order") // 404

public class OrderNotFoundException extends RuntimeException {

// ...

}

这是一个使用该异常的Controller方法:

@RequestMapping(value="/orders/{id}", method=GET)

public String showOrder(@PathVariable("id") long id, Model model) {

Order order = orderRepository.findOrderById(id);

if (order == null) throw new OrderNotFoundException(id);

model.addAttribute(order);

return "orderDetail";

}

这样,当OrderNotFoundException被抛出时,ResponseStatusExceptionResolver会返回给客户端一个HTTP Status Code为404的响应。

AnnotationMethodHandlerExceptionResolver和ExceptionHandlerExceptionResolver

用来支持ExceptionHandler注解,使用被ExceptionHandler注解所标记的方法来处理异常。其中AnnotationMethodHandlerExceptionResolver在3.0版本中开始提供,ExceptionHandlerExceptionResolver在3.1版本中开始提供,从3.2版本开始,Spring推荐使用ExceptionHandlerExceptionResolver。

如果配置了AnnotationMethodHandlerExceptionResolver和ExceptionHandlerExceptionResolver这两个异常处理bean之一,那么我们就可以使用ExceptionHandler注解来处理异常。

下面是几个ExceptionHandler注解的使用例子:

@Controller

public class ExceptionHandlingController {

// @RequestHandler methods

...

// 以下是异常处理方法

// 将DataIntegrityViolationException转化为Http Status Code为409的响应

@ResponseStatus(value=HttpStatus.CONFLICT, reason="Data integrity violation") // 409

@ExceptionHandler(DataIntegrityViolationException.class)

public void conflict() {

// Nothing to do

}

// 针对SQLException和DataAccessException返回视图databaseError

@ExceptionHandler({SQLException.class,DataAccessException.class})

public String databaseError() {

// Nothing to do. Returns the logical view name of an error page, passed to

// the view-resolver(s) in usual way.

// Note that the exception is _not_ available to this view (it is not added to

// the model) but see "Extending ExceptionHandlerExceptionResolver" below.

return "databaseError";

}

// 创建ModleAndView,将异常和请求的信息放入到Model中,指定视图名字,并返回该ModleAndView

@ExceptionHandler(Exception.class)

public ModelAndView handleError(HttpServletRequest req, Exception exception) {

logger.error("Request: " + req.getRequestURL() + " raised " + exception);

ModelAndView mav = new ModelAndView();

mav.addObject("exception", exception);

mav.addObject("url", req.getRequestURL());

mav.setViewName("error");

return mav;

}

}

需要注意的是,上面例子中的ExceptionHandler方法的作用域,只是在本Controller类中。如果需要使用ExceptionHandler来处理全局的Exception,则需要使用ControllerAdvice注解。

@ControllerAdvice

class GlobalDefaultExceptionHandler {

public static final String DEFAULT_ERROR_VIEW = "error";

@ExceptionHandler(value = Exception.class)

public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {

// 如果异常使用了ResponseStatus注解,那么重新抛出该异常,Spring框架会处理该异常。

if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null)

throw e;

// 否则创建ModleAndView,处理该异常。

ModelAndView mav = new ModelAndView();

mav.addObject("exception", e);

mav.addObject("url", req.getRequestURL());

mav.setViewName(DEFAULT_ERROR_VIEW);

return mav;

}

}

SimpleMappingExceptionResolver

提供了将异常映射为视图的能力,高度可定制化。其提供的能力有:

根据异常的类型,将异常映射到视图;

可以为不符合处理条件没有被处理的异常,指定一个默认的错误返回;

处理异常时,记录log信息;

指定需要添加到Modle中的Exception属性,从而在视图中展示该属性。

@Configuration

@EnableWebMvc

public class MvcConfiguration extends WebMvcConfigurerAdapter {

@Bean(name="simpleMappingExceptionResolver")

public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {

SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();

Properties mappings = new Properties();

mappings.setProperty("DatabaseException", "databaseError");

mappings.setProperty("InvalidCreditCardException", "creditCardError");

r.setExceptionMappings(mappings); // 默认为空

r.setDefaultErrorView("error"); // 默认没有

r.setExceptionAttribute("ex");

r.setWarnLogCategory("example.MvcLogger");

return r;

}

...

}

自定义ExceptionResolver

Spring MVC的异常处理非常的灵活,如果提供的ExceptionResolver类不能满足使用,我们可以实现自己的异常处理类。可以通过继承SimpleMappingExceptionResolver来定制Mapping的方式和能力,也可以直接继承AbstractHandlerExceptionResolver来实现其它类型的异常处理类。

Spring MVC是如何创建和使用这些Resolver的?

首先看Spring MVC是怎么加载异常处理bean的。

Spring MVC有两种加载异常处理类的方式,一种是根据类型,这种情况下,会加载ApplicationContext下所有实现了ExceptionResolver接口的bean,并根据其order属性排序,依次调用;一种是根据名字,这种情况下会加载ApplicationContext下,名字为handlerExceptionResolver的bean。

不管使用那种加载方式,如果在ApplicationContext中没有找到异常处理bean,那么Spring MVC会加载默认的异常处理bean。

默认的异常处理bean定义在DispatcherServlet.properties中。

org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\

org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\

org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

以下代码摘自ispatcherServlet,描述了异常处理类的加载过程:

/**

* Initialize the HandlerMappings used by this class.

*

If no HandlerMapping beans are defined in the BeanFactory for this namespace,

* we default to BeanNameUrlHandlerMapping.

*/

private void initHandlerMappings(ApplicationContext context) {

this.handlerMappings = null;

if (this.detectAllHandlerMappings) {

// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.

Map matchingBeans =

BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);

if (!matchingBeans.isEmpty()) {

this.handlerMappings = new ArrayList(matchingBeans.values());

// We keep HandlerMappings in sorted order.

OrderComparator.sort(this.handlerMappings);

}

}

else {

try {

HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);

this.handlerMappings = Collections.singletonList(hm);

}

catch (NoSuchBeanDefinitionException ex) {

// Ignore, we'll add a default HandlerMapping later.

}

}

// Ensure we have at least one HandlerMapping, by registering

// a default HandlerMapping if no other mappings are found.

if (this.handlerMappings == null) {

this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);

if (logger.isDebugEnabled()) {

logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");

}

}

}

然后看Spring MVC是怎么使用异常处理bean的。

Spring MVC把请求映射和处理过程放到try catch中,捕获到异常后,使用异常处理bean进行处理。

所有异常处理bean按照order属性排序,在处理过程中,遇到第一个成功处理异常的异常处理bean之后,不再调用后续的异常处理bean。

以下代码摘自DispatcherServlet,描述了处理异常的过程。

/**

* Process the actual dispatching to the handler.

*

The handler will be obtained by applying the servlet's HandlerMappings in order.

* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters

* to find the first that supports the handler class.

*

All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers

* themselves to decide which methods are acceptable.

*@param request current HTTP request

*@param response current HTTP response

*@throws Exception in case of any kind of processing failure

*/

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

HttpServletRequest processedRequest = request;

HandlerExecutionChain mappedHandler = null;

boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {

ModelAndView mv = null;

Exception dispatchException = null;

try {

processedRequest = checkMultipart(request);

multipartRequestParsed = (processedRequest != request);

// Determine handler for the current request.

mappedHandler = getHandler(processedRequest);

if (mappedHandler == null || mappedHandler.getHandler() == null) {

noHandlerFound(processedRequest, response);

return;

}

// Determine handler adapter for the current request.

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler.

String method = request.getMethod();

boolean isGet = "GET".equals(method);

if (isGet || "HEAD".equals(method)) {

long lastModified = ha.getLastModified(request, mappedHandler.getHandler());

if (logger.isDebugEnabled()) {

logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);

}

if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {

return;

}

}

if (!mappedHandler.applyPreHandle(processedRequest, response)) {

return;

}

// Actually invoke the handler.

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {

return;

}

applyDefaultViewName(request, mv);

mappedHandler.applyPostHandle(processedRequest, response, mv);

}

catch (Exception ex) {

dispatchException = ex;

}

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

}

catch (Exception ex) {

triggerAfterCompletion(processedRequest, response, mappedHandler, ex);

}

catch (Error err) {

triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);

}

finally {

if (asyncManager.isConcurrentHandlingStarted()) {

// Instead of postHandle and afterCompletion

if (mappedHandler != null) {

mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);

}

}

else {

// Clean up any resources used by a multipart request.

if (multipartRequestParsed) {

cleanupMultipart(processedRequest);

}

}

}

}

/**

* Determine an error ModelAndView via the registered HandlerExceptionResolvers.

*@param request current HTTP request

*@param response current HTTP response

*@param handler the executed handler, or {@code null} if none chosen at the time of the exception

* (for example, if multipart resolution failed)

*@param ex the exception that got thrown during handler execution

*@return a corresponding ModelAndView to forward to

*@throws Exception if no error ModelAndView found

*/

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,

Object handler, Exception ex) throws Exception {

// Check registered HandlerExceptionResolvers...

ModelAndView exMv = null;

for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {

exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);

if (exMv != null) {

break;

}

}

if (exMv != null) {

if (exMv.isEmpty()) {

request.setAttribute(EXCEPTION_ATTRIBUTE, ex);

return null;

}

// We might still need view name translation for a plain error model...

if (!exMv.hasView()) {

exMv.setViewName(getDefaultViewName(request));

}

if (logger.isDebugEnabled()) {

logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);

}

WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());

return exMv;

}

throw ex;

}

何时该使用何种ExceptionResolver?

Spring提供了很多选择和非常灵活的使用方式,下面是一些使用建议:

如果自定义异常类,考虑加上ResponseStatus注解;

对于没有ResponseStatus注解的异常,可以通过使用ExceptionHandler+ControllerAdvice注解,或者通过配置SimpleMappingExceptionResolver,来为整个Web应用提供统一的异常处理。

如果应用中有些异常处理方式,只针对特定的Controller使用,那么在这个Controller中使用ExceptionHandler注解。

不要使用过多的异常处理方式,不然的话,维护起来会很苦恼,因为异常的处理分散在很多不同的地方。

http://www.cnblogs.com/xinzhao/p/4902295.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值