最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring MVC Controller返回值及異常的統(tǒng)一處理方法

 更新時(shí)間:2019年11月02日 11:17:28   作者:donespeak  
這篇文章主要給大家介紹了關(guān)于Spring MVC Controller返回值及異常的統(tǒng)一處理方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Spring MVC具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

舊的設(shè)計(jì)方案

開(kāi)發(fā)api的時(shí)候,需要先定義好接口的數(shù)據(jù)響應(yīng)結(jié)果.如下是一個(gè)很簡(jiǎn)單直接的Controller實(shí)現(xiàn)方法及響應(yīng)結(jié)果定義.

@RestController
@RequestMapping("/users")
public class UserController {

 @Inject
 private UserService userService;

 @GetRequest("/{userId:\\d+}")
 public ResponseBean signin(@PathVariable long userId) {
  try {
   User user = userService.getUserBaseInfo(userId);
   return ResponseBean.success(user);
  } catch (ServiceException e) {
   return new ReponseBean(e.getCode(), e.getMsg());
  } catch (Exception e) {
   return ResponseBean.systemError();
  }
 }
}
{
 code: "",
 data: {}, // 可以是對(duì)象或者數(shù)組
 msg: ""
}

從上面的代碼,我們可以看到對(duì)于每個(gè) Controller 方法,都會(huì)有很多重復(fù)的代碼出現(xiàn),我們應(yīng)該設(shè)法去避免重復(fù)的代碼。將重復(fù)的代碼移除之后,可以得到如下的代碼,簡(jiǎn)單易懂。

@RestController
@RequestMapping("/users")
public class UserController {
  
 @Inject
 private UserService userService;

 @GetRequest("/{userId:\\d+}")
 public User signin(@PathVariable long userId) {
  return userService.getUserBaseInfo(userId);
 }
}

在以上的實(shí)現(xiàn)中,還做了一個(gè)必要的要求,就是 ServiceException 需要定義為 RuntimeException的子類(lèi),而不是 Exception的子類(lèi)。由于 ServiceException 表示服務(wù)異常,一般發(fā)生這種異常是應(yīng)該直接提示前端,而無(wú)需進(jìn)行其他特殊處理的。在定義為 RuntimeException 的子類(lèi)之后,會(huì)減少大量的異常拋出聲明,而且不再需要在事務(wù)@Transactional 中進(jìn)行特殊聲明。

統(tǒng)一 Controller 返回值格式

在開(kāi)發(fā)的過(guò)程中,我發(fā)現(xiàn)上面的結(jié)構(gòu)

@ControllerAdvice
public class ControllerResponseHandler implements ResponseBodyAdvice<Object> {
 
 private Logger logger = LogManager.getLogger(getClass());

 @Override
 public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
  // 支持所有的返回值類(lèi)型
  return true;
 }

 @Override
 public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
   Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
   ServerHttpResponse response) {
  if(body instanceof ResponseBean) {
   return body;
  } else {
   // 所有沒(méi)有返回 ResponseBean 結(jié)構(gòu)的結(jié)果均認(rèn)為是成功的
   return ResponseBean.success(body);
  }
 }
}

統(tǒng)一異常處理

如下的代碼中,ServiceException ServiceMessageException ValidatorErrorType FieldValidatorError 均為自定義類(lèi)。

@ControllerAdvice
public class ControllerExceptionHandler {

 private Logger logger = LogManager.getLogger(getClass());

 private static final String logExceptionFormat = "[EXIGENCE] Some thing wrong with the system: %s";

 /**
  * 自定義異常
  */
 @ExceptionHandler(ServiceMessageException.class)
 public ResponseBean handleServiceMessageException(HttpServletRequest request, ServiceMessageException ex) {
  logger.debug(ex);
  return new ResponseBean(ex.getMsgCode(), ex.getMessage());
 }

 /**
  * 自定義異常
  */
 @ExceptionHandler(ServiceException.class)
 public ResponseBean handleServiceException(HttpServletRequest request, ServiceException ex) {
  logger.debug(ex);
  String message = codeToMessage(ex.getMsgCode());
  return new ResponseBean(ex.getMsgCode(), message);
 }

 /**
  * MethodArgumentNotValidException: 實(shí)體類(lèi)屬性校驗(yàn)不通過(guò)
  * 如: listUsersValid(@RequestBody @Valid UserFilterOption option)
  */
 @ExceptionHandler(MethodArgumentNotValidException.class)
 public ResponseBean handleMethodArgumentNotValid(HttpServletRequest request, MethodArgumentNotValidException ex) {
  logger.debug(ex);
  return validatorErrors(ex.getBindingResult());
 }

 private ResponseBean validatorErrors(BindingResult result) {
  List<FieldValidatorError> errors = new ArrayList<FieldValidatorError>();
  for (FieldError error : result.getFieldErrors()) {
   errors.add(toFieldValidatorError(error));
  }
  return ResponseBean.validatorError(errors);
 }

 /**
  * ConstraintViolationException: 直接對(duì)方法參數(shù)進(jìn)行校驗(yàn),校驗(yàn)不通過(guò)。
  * 如: pageUsers(@RequestParam @Min(1)int pageIndex, @RequestParam @Max(100)int pageSize)
  */
 @ExceptionHandler(ConstraintViolationException.class)
 public ResponseBean handleConstraintViolationException(HttpServletRequest request,
   ConstraintViolationException ex) {
  logger.debug(ex);
  // 
  List<FieldValidatorError> errors = new ArrayList<FieldValidatorError>();

  for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
   errors.add(toFieldValidatorError(violation));
  }
  return ResponseBean.validatorError(errors);
 }

 private FieldValidatorError toFieldValidatorError(ConstraintViolation<?> violation) {
  Path.Node lastNode = null;
  for (Path.Node node : violation.getPropertyPath()) {
   lastNode = node;
  }

  FieldValidatorError fieldNotValidError = new FieldValidatorError();
  // fieldNotValidError.setType(ValidatorTypeMapping.toType(violation.getConstraintDescriptor().getAnnotation().annotationType()));
  fieldNotValidError.setType(ValidatorErrorType.INVALID.value());
  fieldNotValidError.setField(lastNode.getName());
  fieldNotValidError.setMessage(violation.getMessage());
  return fieldNotValidError;
 }

 private FieldValidatorError toFieldValidatorError(FieldError error) {
  FieldValidatorError fieldNotValidError = new FieldValidatorError();
  fieldNotValidError.setType(ValidatorErrorType.INVALID.value());
  fieldNotValidError.setField(error.getField());
  fieldNotValidError.setMessage(error.getDefaultMessage());
  return fieldNotValidError;
 }

 /**
  * BindException: 數(shù)據(jù)綁定異常,效果與MethodArgumentNotValidException類(lèi)似,為MethodArgumentNotValidException的父類(lèi)
  */
 @ExceptionHandler(BindException.class)
 public ResponseBean handleBindException(HttpServletRequest request, BindException ex) {
  logger.debug(ex);
  return validatorErrors(ex.getBindingResult());
 }

 /**
  * 返回值類(lèi)型轉(zhuǎn)化錯(cuò)誤
  */
 @ExceptionHandler(HttpMessageConversionException.class)
 public ResponseBean exceptionHandle(HttpServletRequest request,
   HttpMessageConversionException ex) {
  return internalServiceError(ex);
 }
 
 /**
  * 對(duì)應(yīng) Http 請(qǐng)求頭的 accept
  * 客戶(hù)器端希望接受的類(lèi)型和服務(wù)器端返回類(lèi)型不一致。
  * 這里雖然設(shè)置了攔截,但是并沒(méi)有起到作用。需要通過(guò)http請(qǐng)求的流程來(lái)進(jìn)一步確定原因。
  */
 @ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
 public ResponseBean handleHttpMediaTypeNotAcceptableException(HttpServletRequest request,
   HttpMediaTypeNotAcceptableException ex) {
  logger.debug(ex);
  StringBuilder messageBuilder = new StringBuilder().append("The media type is not acceptable.")
    .append(" Acceptable media types are ");
  ex.getSupportedMediaTypes().forEach(t -> messageBuilder.append(t + ", "));
  String message = messageBuilder.substring(0, messageBuilder.length() - 2);

  return new ResponseBean(HttpStatus.NOT_ACCEPTABLE.value(), message);
 }

 /**
  * 對(duì)應(yīng)請(qǐng)求頭的 content-type
  * 客戶(hù)端發(fā)送的數(shù)據(jù)類(lèi)型和服務(wù)器端希望接收到的數(shù)據(jù)不一致
  */
 @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
 public ResponseBean handleHttpMediaTypeNotSupportedException(HttpServletRequest request,
   HttpMediaTypeNotSupportedException ex) {
   logger.debug(ex);
  StringBuilder messageBuilder = new StringBuilder().append(ex.getContentType())
    .append(" media type is not supported.").append(" Supported media types are ");
  ex.getSupportedMediaTypes().forEach(t -> messageBuilder.append(t + ", "));
  String message = messageBuilder.substring(0, messageBuilder.length() - 2);
  System.out.println(message);
  return new ResponseBean(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), message);
 }

 /**
  * 前端發(fā)送過(guò)來(lái)的數(shù)據(jù)無(wú)法被正常處理
  * 比如后天希望收到的是一個(gè)json的數(shù)據(jù),但是前端發(fā)送過(guò)來(lái)的卻是xml格式的數(shù)據(jù)或者是一個(gè)錯(cuò)誤的json格式數(shù)據(jù)
  */
 @ExceptionHandler(HttpMessageNotReadableException.class)
 public ResponseBean handlerHttpMessageNotReadableException(HttpServletRequest request,
   HttpMessageNotReadableException ex) {
  logger.debug(ex);
  String message = "Problems parsing JSON";
  return new ResponseBean(HttpStatus.BAD_REQUEST.value(), message);
 }

 /**
  * 將返回的結(jié)果轉(zhuǎn)化到響應(yīng)的數(shù)據(jù)時(shí)候?qū)е碌膯?wèn)題。
  * 當(dāng)使用json作為結(jié)果格式時(shí),可能導(dǎo)致的原因?yàn)樾蛄谢e(cuò)誤。
  * 目前知道,如果返回一個(gè)沒(méi)有屬性的對(duì)象作為結(jié)果時(shí),會(huì)導(dǎo)致該異常。
  */
 @ExceptionHandler(HttpMessageNotWritableException.class)
 public ResponseBean handlerHttpMessageNotWritableException(HttpServletRequest request,
   HttpMessageNotWritableException ex) {
  return internalServiceError(ex);
 }

 /**
  * 請(qǐng)求方法不支持
  */
 @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
 public ResponseBean exceptionHandle(HttpServletRequest request, HttpRequestMethodNotSupportedException ex) {
  logger.debug(ex);
  StringBuilder messageBuilder = new StringBuilder().append(ex.getMethod())
    .append(" method is not supported for this request.").append(" Supported methods are ");

  ex.getSupportedHttpMethods().forEach(m -> messageBuilder.append(m + ","));
  String message = messageBuilder.substring(0, messageBuilder.length() - 2);
  return new ResponseBean(HttpStatus.METHOD_NOT_ALLOWED.value(), message);
 }

 /**
  * 參數(shù)類(lèi)型不匹配
  */
 @ExceptionHandler(MethodArgumentTypeMismatchException.class)
 public ResponseBean methodArgumentTypeMismatchExceptionHandler(HttpServletRequest request,
   MethodArgumentTypeMismatchException ex) {
  logger.debug(ex);
  String message = "The parameter '" + ex.getName() + "' should of type '"
    + ex.getRequiredType().getSimpleName().toLowerCase() + "'";

  FieldValidatorError fieldNotValidError = new FieldValidatorError();
  fieldNotValidError.setType(ValidatorErrorType.TYPE_MISMATCH.value());
  fieldNotValidError.setField(ex.getName());
  fieldNotValidError.setMessage(message);

  return ResponseBean.validatorError(Arrays.asList(fieldNotValidError));
 }

 /**
  * 缺少必填字段
  */
 @ExceptionHandler(MissingServletRequestParameterException.class)
 public ResponseBean exceptionHandle(HttpServletRequest request,
   MissingServletRequestParameterException ex) {
  logger.debug(ex);
  String message = "Required parameter '" + ex.getParameterName() + "' is not present";

  FieldValidatorError fieldNotValidError = new FieldValidatorError();
  fieldNotValidError.setType(ValidatorErrorType.MISSING_FIELD.value());
  fieldNotValidError.setField(ex.getParameterName());
  fieldNotValidError.setMessage(message);

  return ResponseBean.validatorError(Arrays.asList(fieldNotValidError));
 }

 /**
  * 文件上傳時(shí),缺少 file 字段
  */
 @ExceptionHandler(MissingServletRequestPartException.class)
 public ResponseBean exceptionHandle(HttpServletRequest request, MissingServletRequestPartException ex) {
  logger.debug(ex);
  return new ResponseBean(HttpStatus.BAD_REQUEST.value(), ex.getMessage());
 }

 /**
  * 請(qǐng)求路徑不存在
  */
 @ExceptionHandler(NoHandlerFoundException.class)
 public ResponseBean exceptionHandle(HttpServletRequest request, NoHandlerFoundException ex) {
  logger.debug(ex);
  String message = "No resource found for " + ex.getHttpMethod() + " " + ex.getRequestURL();
  return new ResponseBean(HttpStatus.NOT_FOUND.value(), message);
 }

 /**
  * 缺少路徑參數(shù)
  * Controller方法中定義了 @PathVariable(required=true) 的參數(shù),但是卻沒(méi)有在url中提供
  */
 @ExceptionHandler(MissingPathVariableException.class)
 public ResponseBean exceptionHandle(HttpServletRequest request, MissingPathVariableException ex) {
  return internalServiceError(ex);
 }

 /**
  * 其他所有的異常
  */
 @ExceptionHandler()
 public ResponseBean handleAll(HttpServletRequest request, Exception ex) {
  return internalServiceError(ex);
 }

 private String codeToMessage(int code) {
  //TODO 這個(gè)需要進(jìn)行自定,每個(gè) code 會(huì)匹配到一個(gè)相應(yīng)的 msg
  return "The code is " + code;
 }

 private ResponseBean internalServiceError(Exception ex) {
  logException(ex);
  // do something else
  return ResponseBean.systemError();
 }

 private <T extends Throwable> void logException(T e) {
  logger.error(String.format(logExceptionFormat, e.getMessage()), e);
 }
}

通過(guò)上面的配置,可以有效地將異常進(jìn)行統(tǒng)一的處理,同時(shí)對(duì)返回的結(jié)果進(jìn)行統(tǒng)一的封裝。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Spring基礎(chǔ)篇之初識(shí)DI和AOP

    Spring基礎(chǔ)篇之初識(shí)DI和AOP

    這篇文章主要為大家詳細(xì)介紹了Spring基礎(chǔ)篇之初識(shí)DI和AOP,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • 關(guān)于Java集合框架Collection接口詳解

    關(guān)于Java集合框架Collection接口詳解

    這篇文章主要介紹了關(guān)于Java集合框架Collection接口詳解,Collection接口是Java集合框架中的基礎(chǔ)接口,定義了一些基本的集合操作,包括添加元素、刪除元素、遍歷集合等,需要的朋友可以參考下
    2023-05-05
  • Spring boot啟動(dòng)流程之解決循環(huán)依賴(lài)的方法

    Spring boot啟動(dòng)流程之解決循環(huán)依賴(lài)的方法

    循環(huán)依賴(lài),指的是兩個(gè)bean之間相互依賴(lài),形成了一個(gè)循環(huán),spring解決循環(huán)依賴(lài)的方式是在bean的實(shí)例化完成之后,所以不要在構(gòu)造方法中引入循環(huán)依賴(lài),因?yàn)檫@時(shí)對(duì)象還沒(méi)有實(shí)例化,spring也無(wú)法解決,本文給大家介紹Spring boot循環(huán)依賴(lài)的解決方法,一起看看吧
    2024-02-02
  • Java List的remove()方法踩坑

    Java List的remove()方法踩坑

    Java的List在刪除元素時(shí),一般會(huì)用list.remove(o)/remove(i)方法。在使用時(shí),容易觸碰陷阱,本文就來(lái)介紹一下容易踩的坑,感興趣的可以了解一下
    2021-10-10
  • 使用c3p0連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查

    使用c3p0連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查

    這篇文章主要為大家詳細(xì)介紹了使用c3p0連接數(shù)據(jù)庫(kù)實(shí)現(xiàn)增刪改查,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • java Callable接口和Future接口創(chuàng)建線(xiàn)程示例詳解

    java Callable接口和Future接口創(chuàng)建線(xiàn)程示例詳解

    這篇文章主要為大家介紹了java Callable接口和Future接口創(chuàng)建線(xiàn)程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java常量池知識(shí)點(diǎn)總結(jié)

    Java常量池知識(shí)點(diǎn)總結(jié)

    本篇文章給大家通過(guò)理論原理等方便徹底分析了Java常量池的相關(guān)知識(shí),有興趣的朋友閱讀學(xué)習(xí)下吧。
    2017-12-12
  • java操作mongodb示例分享

    java操作mongodb示例分享

    這篇文章主要介紹了java操作mongodb示例,實(shí)現(xiàn)了簡(jiǎn)單的條件查詢(xún)和復(fù)雜的條件查詢(xún),需要的朋友可以參考下
    2014-02-02
  • java?ThreadPoolExecutor線(xiàn)程池內(nèi)部處理流程解析

    java?ThreadPoolExecutor線(xiàn)程池內(nèi)部處理流程解析

    這篇文章主要為大家介紹了java?ThreadPoolExecutor線(xiàn)程池內(nèi)部處理流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Java中l(wèi)ist集合為空或?yàn)閚ull的區(qū)別說(shuō)明

    Java中l(wèi)ist集合為空或?yàn)閚ull的區(qū)別說(shuō)明

    這篇文章主要介紹了Java中l(wèi)ist集合為空或?yàn)閚ull的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評(píng)論

长垣县| 利津县| 磐石市| 灵璧县| 雅安市| 蒙城县| 百色市| 永寿县| 彭泽县| 八宿县| 轮台县| 太康县| 中方县| 泸西县| 高雄市| 桑植县| 三台县| 乡宁县| 兴城市| 连江县| 静安区| 长宁区| 藁城市| 唐海县| 保德县| 尼勒克县| 衡阳市| 巩义市| 扶沟县| 兖州市| 沐川县| 虹口区| 东乡族自治县| 高陵县| 西乡县| 石柱| 青浦区| 融水| 安仁县| 商都县| 佛教|