舒適提示:本文使用的spring boot版本爲2.1.8.RELEASE。html
全局異常處理你們應該都接觸過,也不是什麼難事,網上一搜一大堆,可是寫的對不對只能本身測試了,運氣好的話找了一個能用的,運氣很差的可能會煩到你懷疑人生。java
我就是那個運氣很差的人,也是由於碰到了一些問題,因此纔會有這篇文章吧。web
全局異常處理主要的好處:spring
通常的方案都是基於@ControllerAdvice
和@ExceptionHandler
作的。apache
@ControllerAdvice
至關於controller的切面,主要用於@ExceptionHandler
, @InitBinder
和@ModelAttribute
,使註解標註的方法對每個controller都起做用。默認對全部controller都起做用,固然也能夠經過@ControllerAdvice
註解中的一些屬性選定符合條件的controller。@ExceptionHandler
用於異常處理的註解,能夠經過value指定處理哪一種類型的異常還能夠與@ResponseStatus
搭配使用,處理特定的http錯誤。標記的方法入參與返回值都有很大的靈活性,具體能夠看註釋也能夠後邊的深度探究。其實有上面兩個已經夠了,還能夠繼承ResponseEntityExceptionHandler
json
讀一下這個類的註釋就知道它是幹啥的了微信
大概意思就是這個類是爲了方便統一異常處理的基類,可是要注意返回的是ResponseEntity
,若是不須要往響應體中寫內容或者返回一個視圖,可使用DefaultHandlerExceptionResolver
。session
能夠看一下這個類的實現mvc
/** * Provides handling for standard Spring MVC exceptions. * @param ex the target exception * @param request the current request */ @ExceptionHandler({ HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class, HttpMediaTypeNotAcceptableException.class, MissingPathVariableException.class, MissingServletRequestParameterException.class, ServletRequestBindingException.class, ConversionNotSupportedException.class, TypeMismatchException.class, HttpMessageNotReadableException.class, HttpMessageNotWritableException.class, MethodArgumentNotValidException.class, MissingServletRequestPartException.class, BindException.class, NoHandlerFoundException.class, AsyncRequestTimeoutException.class }) @Nullable public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) throws Exception { HttpHeaders headers = new HttpHeaders(); if (ex instanceof HttpRequestMethodNotSupportedException) { HttpStatus status = HttpStatus.METHOD_NOT_ALLOWED; return handleHttpRequestMethodNotSupported((HttpRequestMethodNotSupportedException) ex, headers, status, request); } else if (ex instanceof HttpMediaTypeNotSupportedException) { HttpStatus status = HttpStatus.UNSUPPORTED_MEDIA_TYPE; return handleHttpMediaTypeNotSupported((HttpMediaTypeNotSupportedException) ex, headers, status, request); } else if (ex instanceof HttpMediaTypeNotAcceptableException) { HttpStatus status = HttpStatus.NOT_ACCEPTABLE; return handleHttpMediaTypeNotAcceptable((HttpMediaTypeNotAcceptableException) ex, headers, status, request); } else if (ex instanceof MissingPathVariableException) { HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; return handleMissingPathVariable((MissingPathVariableException) ex, headers, status, request); } else if (ex instanceof MissingServletRequestParameterException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleMissingServletRequestParameter((MissingServletRequestParameterException) ex, headers, status, request); } else if (ex instanceof ServletRequestBindingException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleServletRequestBindingException((ServletRequestBindingException) ex, headers, status, request); } else if (ex instanceof ConversionNotSupportedException) { HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; return handleConversionNotSupported((ConversionNotSupportedException) ex, headers, status, request); } else if (ex instanceof TypeMismatchException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleTypeMismatch((TypeMismatchException) ex, headers, status, request); } else if (ex instanceof HttpMessageNotReadableException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleHttpMessageNotReadable((HttpMessageNotReadableException) ex, headers, status, request); } else if (ex instanceof HttpMessageNotWritableException) { HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; return handleHttpMessageNotWritable((HttpMessageNotWritableException) ex, headers, status, request); } else if (ex instanceof MethodArgumentNotValidException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleMethodArgumentNotValid((MethodArgumentNotValidException) ex, headers, status, request); } else if (ex instanceof MissingServletRequestPartException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleMissingServletRequestPart((MissingServletRequestPartException) ex, headers, status, request); } else if (ex instanceof BindException) { HttpStatus status = HttpStatus.BAD_REQUEST; return handleBindException((BindException) ex, headers, status, request); } else if (ex instanceof NoHandlerFoundException) { HttpStatus status = HttpStatus.NOT_FOUND; return handleNoHandlerFoundException((NoHandlerFoundException) ex, headers, status, request); } else if (ex instanceof AsyncRequestTimeoutException) { HttpStatus status = HttpStatus.SERVICE_UNAVAILABLE; return handleAsyncRequestTimeoutException((AsyncRequestTimeoutException) ex, headers, status, request); } else { // Unknown exception, typically a wrapper with a common MVC exception as cause // (since @ExceptionHandler type declarations also match first-level causes): // We only deal with top-level MVC exceptions here, so let's rethrow the given // exception for further processing through the HandlerExceptionResolver chain. throw ex; } }
對於每一種異常,能夠重寫相應的方法。同時每一個異常的具體處理方法最後又調用了同一個方法app
/** * A single place to customize the response body of all exception types. * <p>The default implementation sets the {@link WebUtils#ERROR_EXCEPTION_ATTRIBUTE} * request attribute and creates a {@link ResponseEntity} from the given * body, headers, and status. * @param ex the exception * @param body the body for the response * @param headers the headers for the response * @param status the response status * @param request the current request */ protected ResponseEntity<Object> handleExceptionInternal( Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST); } return new ResponseEntity<>(body, headers, status); }
通用的處理能夠在這個方法中實現,返回結果中能夠自定義body、header、以及http status。好比對於一些異常,可能並不但願http status code爲500,而是返回200,用body裏的code再去判斷是成功仍是失敗,用這種方法就很是容易實現。
使用這種方案,咱們本身寫的類就應該相似這種
package com.zworks.aircraft.web.advice; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @ControllerAdvice public class AirCraftExceptionHandler extends ResponseEntityExceptionHandler { }
能夠去Spring Initializr去初始化工程
依賴只須要web就能夠了,爲了方即可以添加lombok
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.8.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zworks</groupId> <artifactId>aircraft</artifactId> <version>0.0.1-SNAPSHOT</version> <name>aircraft</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
定義一個通用返回結果
package com.zworks.aircraft.model; import lombok.Data; @Data public class RespMsg<T> { private int code = 200; private String msg; private T data; public RespMsg() { } public RespMsg(int code, String msg) { this.code = code; this.msg = msg; } public RespMsg(T data) { this.data = data; } public static <T> RespMsg<T> success() { return new RespMsg(); } public static <T> RespMsg<T> success(T data) { return new RespMsg(data); } public static RespMsg failed(int code, String msg) { return new RespMsg(code, msg); } }
定義用戶實體類,在字段上加上校驗,方便演示錯誤的請求
package com.zworks.aircraft.model; import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @Data public class User { @NotNull(message = "id不能爲空") private Long id; @NotBlank(message = "名稱不能爲空") private String name; }
定義一個Controller,什麼都不用幹,只須要驗證參數的合法性,而後返回正確便可。
package com.zworks.aircraft.web.controller; import com.zworks.aircraft.model.RespMsg; import com.zworks.aircraft.model.User; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; @RestController public class UserController { @PostMapping(value = "user") public RespMsg user(@Valid @RequestBody User user) { return RespMsg.success(); } }
若是參數正確,返回以下
{ "code": 200, "msg": null, "data": null }
但若是參數錯誤,好比不傳入name,則會返回
{ "timestamp": "2019-09-07T14:04:54.440+0000", "status": 400, "error": "Bad Request", "errors": [ { "codes": [ "NotBlank.user.name", "NotBlank.name", "NotBlank.java.lang.String", "NotBlank" ], "arguments": [ { "codes": [ "user.name", "name" ], "arguments": null, "defaultMessage": "name", "code": "name" } ], "defaultMessage": "名稱不能爲空", "objectName": "user", "field": "name", "rejectedValue": null, "bindingFailure": false, "code": "NotBlank" } ], "message": "Validation failed for object='user'. Error count: 1", "path": "/user" }
這確定不是咱們想要的結果。
按照剛纔的方案,實現一個全局異常處理。
package com.zworks.aircraft.web.advice; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; @ControllerAdvice public class AirCraftExceptionHandler extends ResponseEntityExceptionHandler { }
這個時候其實已經生效了,只是默認的什麼數據都沒有返回,能夠重寫handleExceptionInternal
方法
package com.zworks.aircraft.web.advice; import com.zworks.aircraft.model.RespMsg; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.util.WebUtils; @ControllerAdvice public class AirCraftExceptionHandler extends ResponseEntityExceptionHandler { protected ResponseEntity<Object> handleExceptionInternal( Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST); } logger.error(ex.getMessage(), ex);//打印異常信息 RespMsg respMsg = RespMsg.failed(status.value(), ex.getMessage());//使用http狀態碼做爲返回體的code,同時把異常信息返回 return new ResponseEntity<>(respMsg, headers, status); } }
這時返回的信息以下
{ "code": 400, "msg": "Validation failed for argument [0] in public com.zworks.aircraft.model.RespMsg com.zworks.aircraft.web.controller.UserController.user(com.zworks.aircraft.model.User): [Field error in object 'user' on field 'name': rejected value [null]; codes [NotBlank.user.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.name,name]; arguments []; default message [name]]; default message [不能爲空]] ", "data": null }
雖然已是咱們想要的格式了,可是返回的內容不太已讀。
剛纔打印了日誌,能夠看到報錯爲MethodArgumentNotValidException
,能夠經過重寫handleMethodArgumentNotValid
方法改變異常信息
package com.zworks.aircraft.web.advice; import com.zworks.aircraft.model.RespMsg; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.lang.Nullable; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import org.springframework.web.util.WebUtils; @ControllerAdvice public class AirCraftExceptionHandler extends ResponseEntityExceptionHandler { protected ResponseEntity<Object> handleExceptionInternal( Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) { if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) { request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST); } logger.error(ex.getMessage(), ex);//打印異常信息 RespMsg respMsg = RespMsg.failed(status.value(), ex.getMessage());//使用http狀態碼做爲返回體的code,同時把異常信息返回 return new ResponseEntity<>(respMsg, headers, status); } protected ResponseEntity<Object> handleMethodArgumentNotValid( MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { StringBuffer sb = new StringBuffer(); ex.getBindingResult().getAllErrors().forEach(error -> { sb.append(error.getDefaultMessage()).append(";"); }); RespMsg respMsg = RespMsg.failed(status.value(), sb.toString()); return new ResponseEntity<>(respMsg, headers, HttpStatus.OK);//這裏能夠根據具體狀況改變狀態碼 } }
返回以下
{ "code": 400, "msg": "名稱不能爲空;", "data": null }
同時須要注意的是,因爲我修改了返回碼,此次請求返回的是http status code是200而不是以前的400。
在最開始沒有自定義全局異常處理的時候,也返回了錯誤信息,那這個是誰處理的呢。
默認spring boot 會提供一個/error映射處理全部的異常。並且會根據請求的不一樣返回一個頁面或是json。
在ErrorMvcAutoConfiguration
類中能夠看到
@Bean @ConditionalOnMissingBean(value = ErrorAttributes.class, search = SearchStrategy.CURRENT) public DefaultErrorAttributes errorAttributes() { return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException()); } @Bean @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT) public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) { return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers); }
均可以經過本身定義相應的類進行定製化。
以前因爲被網上文章誤導,使用前面那種方式沒成功,爲了記錄異常,我還寫了個切面。
package com.zworks.aircraft.config; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Aspect @Component @Slf4j public class ErrorControllerAspect { @Before("execution(public * org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.*(..))") public void before(JoinPoint joinPoint) { Object arg = joinPoint.getArgs()[0]; if (arg instanceof HttpServletRequest) { HttpServletRequest request = (HttpServletRequest) arg; log.error((String) request.getAttribute("javax.servlet.error.message"), (Throwable) request.getAttribute("javax.servlet.error.exception")); } } }
我被坑主要是由於看了一篇文章,Validation in Spring Boot,我不能說必定是文章的問題,至少我按他的沒作對。
異常處理是這麼寫的
package com.zworks.aircraft.web.advice; import org.springframework.http.HttpStatus; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class AirCraftExceptionHandler { @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach((error) -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return errors; } }
注意這裏返回的是Map類型
返回和沒加是同樣的
{ "timestamp": "2019-09-07T14:30:21.688+0000", "status": 500, "error": "Internal Server Error", "errors": [ { "codes": [ "NotBlank.user.name", "NotBlank.name", "NotBlank.java.lang.String", "NotBlank" ], "arguments": [ { "codes": [ "user.name", "name" ], "arguments": null, "defaultMessage": "name", "code": "name" } ], "defaultMessage": "名稱不能爲空", "objectName": "user", "field": "name", "rejectedValue": null, "bindingFailure": false, "code": "NotBlank" } ], "message": "Validation failed for object='user'. Error count: 1", "path": "/user" }
而後我在那個方法上打了斷點,發現代碼竟然執行了
而後我就跟代碼,也對比了兩種實現的執行狀況,發如今HandlerMethodReturnValueHandlerComposite
的selectHandler
方法中會根據返回的類型決定使用那個handler進行處理
@Nullable private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } if (handler.supportsReturnType(returnType)) { return handler; } } return null; }
如今的handler是MapMethodProcessor
而若是咱們將返回值格式改一下
package com.zworks.aircraft.web.advice; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import java.util.HashMap; import java.util.Map; @ControllerAdvice public class AirCraftExceptionHandler { @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity handleValidationExceptions(MethodArgumentNotValidException ex) { Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach((error) -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return new ResponseEntity<>(errors, new HttpHeaders(), HttpStatus.OK);//這裏能夠根據具體狀況改變狀態碼 } }
會發現handler變成了HttpEntityMethodProcessor
返回值也沒問題了
{ "name": "名稱不能爲空" }
大部分人從網上查到了信息,都不會考慮請求參數該傳那些,順序有沒有影響吧,受前面返回類型的影響,我也看了下請求參數相關的。
能夠在本身的方法中打個斷點,而後不斷找上層調用。
在InvocableHandlerMethod
的invokeForRequest
方法中能夠看到
@Nullable public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); }
會獲取參數,而後調用咱們的方法
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
在findProvidedArgument
中會根據類型找參數
@Nullable protected static Object findProvidedArgument(MethodParameter parameter, @Nullable Object... providedArgs) { if (!ObjectUtils.isEmpty(providedArgs)) { for (Object providedArg : providedArgs) { if (parameter.getParameterType().isInstance(providedArg)) { return providedArg; } } } return null; }
providedArgs
中有兩個類型,一個是org.springframework.web.bind.MethodArgumentNotValidException
類型,也就是異常,另外一個是org.springframework.web.method.HandlerMethod
。因此若是單寫一個異常是沒問題的。
若是經過providedArgs
沒取到,會從resolvers
裏去取。
只要這些resolvers
能支持的參數,均可以取到。
好比看到了上面有ServletRequestMethodArgumentResolver
類,能夠看到支持HttpSession
@Override public boolean supportsParameter(MethodParameter parameter) { Class<?> paramType = parameter.getParameterType(); return (WebRequest.class.isAssignableFrom(paramType) || ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType) || HttpSession.class.isAssignableFrom(paramType) || (pushBuilder != null && pushBuilder.isAssignableFrom(paramType)) || Principal.class.isAssignableFrom(paramType) || InputStream.class.isAssignableFrom(paramType) || Reader.class.isAssignableFrom(paramType) || HttpMethod.class == paramType || Locale.class == paramType || TimeZone.class == paramType || ZoneId.class == paramType); }
咱們測試下,在參數裏添加一個HttpSession
package com.zworks.aircraft.web.advice; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.context.request.WebRequest; import javax.servlet.http.HttpSession; import java.util.HashMap; import java.util.Map; @Slf4j @ControllerAdvice public class AirCraftExceptionHandler { @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity handleValidationExceptions(WebRequest request, MethodArgumentNotValidException ex, HttpSession httpSession) { log.info("sessionId:{}", httpSession.getId()); Map<String, String> errors = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach((error) -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errors.put(fieldName, errorMessage); }); return new ResponseEntity<>(errors, new HttpHeaders(), HttpStatus.OK);//這裏能夠根據具體狀況改變狀態碼 } }
能夠看到已經輸出了sessionId
2019-09-07 23:15:43.257 INFO 25692 --- [nio-8080-exec-1] c.z.a.w.advice.AirCraftExceptionHandler : sessionId:B9C6E5BA4156BBBC5931FFE9B259E5ED
請求參數的處理方式和返回類型的處理方式是否很類似呢
全局異常處理我也處理過不少次了,大部分也都是網上找一篇,雖然每次不會花不少時間,可是作了這麼多遍也只是有個大概印象,並無很深刻的去探究過。整理一下,知識才會變成本身的。
看到了這裏必定是真愛了,關注微信公衆號【憨憨的春天】第一時間獲取更新