亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

@validated注解異常返回JSON值方式

 更新時(shí)間:2021年10月20日 09:03:37   作者:youngerTree  
這篇文章主要介紹了@validated注解異常返回JSON值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

@validated注解異常返回JSON值

@ControllerAdvice
public class ValidParamExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Map<String, Object> allExceptionHandler(Exception e){
         Map<String, Object> map = new HashMap<>(2);
         if(e instanceof BindException) {
            BindException ex = (BindException)e;
            BindingResult bindingResult = ex.getBindingResult();
            StringBuilder errMsg = new StringBuilder(bindingResult.getFieldErrors().size() * 16);
            errMsg.append("Invalid request:");
            for (int i = 0 ; i < bindingResult.getFieldErrors().size() ; i++) {
                if(i > 0) {
                    errMsg.append(",");
                }
                FieldError error = bindingResult.getFieldErrors().get(i);
                errMsg.append(error.getField()+":"+error.getDefaultMessage());
            }
            map.put("errcode", 500);
            map.put("errmsg", errMsg.toString());
        
        }
        else {    
            map.put("errcode", 500);
            map.put("errmsg", e.getMessage());
        }
        return map;
    }

(1)這里@ControllerAdvice注解標(biāo)注,@ControllerAdvice是@Controller的增強(qiáng)版,一般與@ExceptionHandler搭配使用。

如果標(biāo)注@Controller,異常處理只會(huì)在當(dāng)前controller類中的方法起作用,但是使用@ControllerAdvice,則全局有效。

(2)@ExceptionHandler注解里面填寫(xiě)想要捕獲的異常類class對(duì)象

使用@Valid注解,對(duì)其參數(shù)錯(cuò)誤異常的統(tǒng)一處理

在我們使用springboot作為微服務(wù)框架進(jìn)行敏捷開(kāi)發(fā)的時(shí)候,為了保證傳遞數(shù)據(jù)的安全性,需要對(duì)傳遞的數(shù)據(jù)進(jìn)行校驗(yàn),但是在以往的開(kāi)發(fā)中,開(kāi)發(fā)人員花費(fèi)大量的時(shí)間在繁瑣的if else 等判斷語(yǔ)句來(lái)對(duì)參數(shù)進(jìn)行校驗(yàn),這種方式不但降低了我們的開(kāi)發(fā)速度,而且寫(xiě)出來(lái)的代碼中帶有很多冗余代碼,使得編寫(xiě)的代碼不夠優(yōu)雅,為了將參數(shù)的驗(yàn)證邏輯和代碼的業(yè)務(wù)邏輯進(jìn)行解耦,Java給我們提供了@Valid注解,用來(lái)幫助我們進(jìn)行參數(shù)的校驗(yàn),實(shí)現(xiàn)了將業(yè)務(wù)邏輯和參數(shù)校驗(yàn)邏輯在一定程度上的解耦,增加了代碼的簡(jiǎn)潔性和可讀性。

springboot中自帶了spring validation參數(shù)校驗(yàn)框架,其使用上和@valid差不多,在這里就不累述了,本文主要講解@valid的使用對(duì)其參數(shù)校驗(yàn)失敗后的錯(cuò)誤一樣的統(tǒng)一處理。

首先,簡(jiǎn)介對(duì)微服務(wù)開(kāi)發(fā)中異常的統(tǒng)一處理,spring中的@RestControllerAdvice注解可以獲取帶有@controller注解類的異常,通過(guò)@ExceptionHandler(MyException.class)注解來(lái)共同完成對(duì)異常進(jìn)行處理。示例如下:

/**
 * 通用異常攔截處理類(通過(guò)切面的方式默認(rèn)攔截所有的controller異常)
 */
@Slf4j
@RestControllerAdvice
public class CommonExceptionHandler {
 
    /**
     * 對(duì)運(yùn)行時(shí)異常進(jìn)行統(tǒng)一異常管理方法
     * @param e
     * @return
     */
    @ExceptionHandler(FlyException.class) // FlyException類繼承于RuntimeException
    public ResponseEntity<Map<String, Object>> handlerException(FlyException e) {
        Map<String, Object> result = new HashMap<>(1);
        result.put("message", e.getMessage());
        return ResponseEntity.status(e.getCode()).body(result);
    }

通過(guò)注解@RestControllerAdvice和注解@ExceptionHandler的聯(lián)合使用來(lái)實(shí)現(xiàn)對(duì)異常的統(tǒng)一處理,然后在前端以友好的方式顯示。

使用@Valid注解的示例如下:

  @PostMapping
    public ResponseEntity save(@Valid BrandCreateRequestDto dto, BindingResult bindingResult) {
        // 判斷是否含有校驗(yàn)不匹配的參數(shù)錯(cuò)誤
        if (bindingResult.hasErrors()) {
            // 獲取所有字段參數(shù)不匹配的參數(shù)集合
            List<FieldError> fieldErrorList = bindingResult.getFieldErrors();
            Map<String, Object> result = new HashMap<>(fieldErrorList.size());
            fieldErrorList.forEach(error -> {
                // 將錯(cuò)誤參數(shù)名稱和參數(shù)錯(cuò)誤原因存于map集合中
                result.put(error.getField(), error.getDefaultMessage());
            });
            return ResponseEntity.status(HttpStatus.BAD_REQUEST.value()).body(result);
        } 
        brandService.save(dto);
        return ResponseEntity.status(HttpStatus.CREATED.value()).build();
    }

@Valid注解確實(shí)將我們?cè)瓉?lái)的參數(shù)校驗(yàn)的問(wèn)題進(jìn)行了簡(jiǎn)化,但是,如果我們有多個(gè)handler需要處理,那我們豈不是每次都要寫(xiě)這樣的冗余代碼。通過(guò)查看@valid的實(shí)現(xiàn)機(jī)制(這里就不描述了),當(dāng)參數(shù)校驗(yàn)失敗的時(shí)候,會(huì)拋出MethodArgumentNotValidException異常(當(dāng)用{@code @Valid}注釋的參數(shù)在驗(yàn)證失敗時(shí),將引發(fā)該異常):

/**
 * Exception to be thrown when validation on an argument annotated with {@code @Valid} fails.
 *
 * @author Rossen Stoyanchev
 * @since 3.1
 */
@SuppressWarnings("serial")
public class MethodArgumentNotValidException extends Exception { 
 private final MethodParameter parameter; 
 private final BindingResult bindingResult; 
 
 /**
  * Constructor for {@link MethodArgumentNotValidException}.
  * @param parameter the parameter that failed validation
  * @param bindingResult the results of the validation
  */
 public MethodArgumentNotValidException(MethodParameter parameter, BindingResult bindingResult) {
  this.parameter = parameter;
  this.bindingResult = bindingResult;
 }

按照我們的預(yù)想,我們只需要在原來(lái)定義的統(tǒng)一異常處理類中,捕獲MethodArgumentNotValidException異常,然后對(duì)其錯(cuò)誤信息進(jìn)行分析和處理即可實(shí)現(xiàn)通用,代碼如下:

/**
 * 對(duì)方法參數(shù)校驗(yàn)異常處理方法
 */
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handlerNotValidException(MethodArgumentNotValidException exception) {
    log.debug("begin resolve argument exception");
    BindingResult result = exception.getBindingResult();
    Map<String, Object> maps;
 
    if (result.hasErrors()) {
        List<FieldError> fieldErrors = result.getFieldErrors();
        maps = new HashMap<>(fieldErrors.size());
        fieldErrors.forEach(error -> {
            maps.put(error.getField(), error.getDefaultMessage());
        });
    } else {
        maps = Collections.EMPTY_MAP;
    } 
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(maps);
}

但是經(jīng)過(guò)測(cè)試,會(huì)發(fā)現(xiàn)對(duì)該異常進(jìn)行捕獲然后處理是沒(méi)有效果的,這可能是我,也是大家遇到的問(wèn)題之一,經(jīng)過(guò)對(duì)@Valid的執(zhí)行過(guò)程的源碼進(jìn)行分析,數(shù)據(jù)傳遞到spring中的執(zhí)行過(guò)程大致為:前端通過(guò)http協(xié)議將數(shù)據(jù)傳遞到spring,spring通過(guò)HttpMessageConverter類將流數(shù)據(jù)轉(zhuǎn)換成Map類型,然后通過(guò)ModelAttributeMethodProcessor類對(duì)參數(shù)進(jìn)行綁定到方法對(duì)象中,并對(duì)帶有@Valid或@Validated注解的參數(shù)進(jìn)行參數(shù)校驗(yàn),對(duì)參數(shù)進(jìn)行處理和校驗(yàn)的方法為ModelAttributeMethodProcessor.resolveArgument(...),部分源代碼如下所示:

public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
 
...
 public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
   NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        ...
        Object attribute = null;
  BindingResult bindingResult = null;
 
  if (mavContainer.containsAttribute(name)) {
   attribute = mavContainer.getModel().get(name);
  }
  else {
   // Create attribute instance
   try {
    attribute = createAttribute(name, parameter, binderFactory, webRequest);
   }
   catch (BindException ex) {
    if (isBindExceptionRequired(parameter)) {
     // No BindingResult parameter -> fail with BindException
     throw ex;
    }
    // Otherwise, expose null/empty value and associated BindingResult
    if (parameter.getParameterType() == Optional.class) {
     attribute = Optional.empty();
    }
    bindingResult = ex.getBindingResult();
   }
  } 
        //進(jìn)行參數(shù)綁定和校驗(yàn)
  if (bindingResult == null) {
   // 對(duì)屬性對(duì)象的綁定和數(shù)據(jù)校驗(yàn);
   // 使用構(gòu)造器綁定屬性失敗時(shí)跳過(guò).
   WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
           
   if (binder.getTarget() != null) {
    if (!mavContainer.isBindingDisabled(name)) {
     bindRequestParameters(binder, webRequest);
    }
                // 對(duì)綁定參數(shù)進(jìn)行校驗(yàn),校驗(yàn)失敗,將其結(jié)果信息賦予bindingResult對(duì)象
    validateIfApplicable(binder, parameter);
                // 如果獲取參數(shù)綁定的結(jié)果中包含錯(cuò)誤的信息則拋出異常
    if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
     throw new BindException(binder.getBindingResult());
    }
   }
   // Value type adaptation, also covering java.util.Optional
   if (!parameter.getParameterType().isInstance(attribute)) {
    attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
   }
   bindingResult = binder.getBindingResult();
  }
 
  // Add resolved attribute and BindingResult at the end of the model
  Map<String, Object> bindingResultModel = bindingResult.getModel();
  mavContainer.removeAttributes(bindingResultModel);
  mavContainer.addAllAttributes(bindingResultModel); 
  return attribute;
}

通過(guò)查看源碼,當(dāng)BindingResult中存在錯(cuò)誤信息時(shí),會(huì)拋出BindException異常,查看BindException源代碼如下:

/**
 * Thrown when binding errors are considered fatal. Implements the
 * {@link BindingResult} interface (and its super-interface {@link Errors})
 * to allow for the direct analysis of binding errors.
 *
 * <p>As of Spring 2.0, this is a special-purpose class. Normally,
 * application code will work with the {@link BindingResult} interface,
 * or with a {@link DataBinder} that in turn exposes a BindingResult via
 * {@link org.springframework.validation.DataBinder#getBindingResult()}.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @see BindingResult
 * @see DataBinder#getBindingResult()
 * @see DataBinder#close()
 */
@SuppressWarnings("serial")
public class BindException extends Exception implements BindingResult { 
 private final BindingResult bindingResult; 
 
 /**
  * Create a new BindException instance for a BindingResult.
  * @param bindingResult the BindingResult instance to wrap
  */
 public BindException(BindingResult bindingResult) {
  Assert.notNull(bindingResult, "BindingResult must not be null");
  this.bindingResult = bindingResult;
 }

我們發(fā)現(xiàn)BindException實(shí)現(xiàn)了BindingResult接口(BindResult是綁定結(jié)果的通用接口, BindResult繼承于Errors接口),所以該異常類擁有BindingResult所有的相關(guān)信息,因此我們可以通過(guò)捕獲該異常類,對(duì)其錯(cuò)誤結(jié)果進(jìn)行分析和處理。代碼如下:

/**
 * 對(duì)方法參數(shù)校驗(yàn)異常處理方法
 */
@ExceptionHandler(BindException.class)
public ResponseEntity<Map<String, Object>> handlerNotValidException(BindException exception) {
    log.debug("begin resolve argument exception");
    BindingResult result = exception.getBindingResult();
    Map<String, Object> maps;
 
    if (result.hasErrors()) {
        List<FieldError> fieldErrors = result.getFieldErrors();
        maps = new HashMap<>(fieldErrors.size());
        fieldErrors.forEach(error -> {
            maps.put(error.getField(), error.getDefaultMessage());
        });
    } else {
        maps = Collections.EMPTY_MAP;
    } 
    return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(maps);
}

這樣,我們對(duì)是content-type類型為form(表單)類型的請(qǐng)求的參數(shù)校驗(yàn)的異常處理就解決了,對(duì)于MethodArgumentNotValidException異常不起作用的原因主要是因?yàn)楦?qǐng)求發(fā)起的數(shù)據(jù)格式(content-type)有關(guān)系,對(duì)于不同的傳輸數(shù)據(jù)的格式spring采用不同的HttpMessageConverter(http參數(shù)轉(zhuǎn)換器)來(lái)進(jìn)行處理.以下是對(duì)HttpMessageConverter進(jìn)行簡(jiǎn)介:

HTTP 請(qǐng)求和響應(yīng)的傳輸是字節(jié)流,意味著瀏覽器和服務(wù)器通過(guò)字節(jié)流進(jìn)行通信。但是,使用 Spring,controller 類中的方法返回純 String 類型或其他 Java 內(nèi)建對(duì)象。如何將對(duì)象轉(zhuǎn)換成字節(jié)流進(jìn)行傳輸?

在報(bào)文到達(dá)SpringMVC和從SpringMVC出去,都存在一個(gè)字節(jié)流到j(luò)ava對(duì)象的轉(zhuǎn)換問(wèn)題。在SpringMVC中,它是由HttpMessageConverter來(lái)處理的。

當(dāng)請(qǐng)求報(bào)文來(lái)到j(luò)ava中,它會(huì)被封裝成為一個(gè)ServletInputStream的輸入流,供我們讀取報(bào)文。響應(yīng)報(bào)文則是通過(guò)一個(gè)ServletOutputStream的輸出流,來(lái)輸出響應(yīng)報(bào)文。http請(qǐng)求與相應(yīng)的處理過(guò)程如下:

針對(duì)不同的數(shù)據(jù)格式,springmvc會(huì)采用不同的消息轉(zhuǎn)換器進(jìn)行處理,以下是springmvc的內(nèi)置消息轉(zhuǎn)換器:

由此我們可以看出,當(dāng)使用json作為傳輸格式時(shí),springmvc會(huì)采用MappingJacksonHttpMessageConverter消息轉(zhuǎn)換器, 而且底層在對(duì)參數(shù)進(jìn)行校驗(yàn)錯(cuò)誤時(shí),拋出的是MethodArgumentNotValidException異常,因此我們需要對(duì)BindException和MethodArgumentNotValidException進(jìn)行統(tǒng)一異常管理,最終代碼演示如下所示:

/**
     * 對(duì)方法參數(shù)校驗(yàn)異常處理方法(僅對(duì)于表單提交有效,對(duì)于以json格式提交將會(huì)失效)
     * 如果是表單類型的提交,則spring會(huì)采用表單數(shù)據(jù)的處理類進(jìn)行處理(進(jìn)行參數(shù)校驗(yàn)錯(cuò)誤時(shí)會(huì)拋出BindException異常)
     */
    @ExceptionHandler(BindException.class)
    public ResponseEntity<Map<String, Object>> handlerBindException(BindException exception) {
        return handlerNotValidException(exception);
    }
 
    /**
     * 對(duì)方法參數(shù)校驗(yàn)異常處理方法(前端提交的方式為json格式出現(xiàn)異常時(shí)會(huì)被該異常類處理)
     * json格式提交時(shí),spring會(huì)采用json數(shù)據(jù)的數(shù)據(jù)轉(zhuǎn)換器進(jìn)行處理(進(jìn)行參數(shù)校驗(yàn)時(shí)錯(cuò)誤是拋出MethodArgumentNotValidException異常)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, Object>> handlerArgumentNotValidException(MethodArgumentNotValidException exception) {
        return handlerNotValidException(exception);
    }
 
    public ResponseEntity<Map<String, Object>> handlerNotValidException(Exception e) {
        log.debug("begin resolve argument exception");
        BindingResult result;
        if (e instanceof BindException) {
            BindException exception = (BindException) e;
            result = exception.getBindingResult();
        } else {
            MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
            result = exception.getBindingResult();
        }
 
        Map<String, Object> maps;
        if (result.hasErrors()) {
            List<FieldError> fieldErrors = result.getFieldErrors();
            maps = new HashMap<>(fieldErrors.size());
            fieldErrors.forEach(error -> {
                maps.put(error.getField(), error.getDefaultMessage());
            });
        } else {
            maps = Collections.EMPTY_MAP;
        }
         return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(maps); 
    }

這樣就完美解決了我們對(duì)參數(shù)校驗(yàn)異常的統(tǒng)一處理。

在這里我僅僅是針對(duì)參數(shù)校驗(yàn)的異常進(jìn)行了統(tǒng)一處理,也就是返回給前端的響應(yīng)碼是400(參數(shù)格式錯(cuò)誤),對(duì)于自定義異?;蛘咂渌漠惓6伎梢圆捎眠@種方式來(lái)對(duì)異常進(jìn)行統(tǒng)一處理。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Lombok不生效,提示java:?找不到符號(hào)的解決方案

    Lombok不生效,提示java:?找不到符號(hào)的解決方案

    這篇文章主要介紹了Lombok不生效,提示java:?找不到符號(hào)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 淺析Java中Map與HashMap,Hashtable,HashSet的區(qū)別

    淺析Java中Map與HashMap,Hashtable,HashSet的區(qū)別

    HashMap和Hashtable兩個(gè)類都實(shí)現(xiàn)了Map接口,二者保存K-V對(duì)(key-value對(duì));HashSet則實(shí)現(xiàn)了Set接口,性質(zhì)類似于集合
    2013-09-09
  • ThreadLocal原理及內(nèi)存泄漏原因

    ThreadLocal原理及內(nèi)存泄漏原因

    這篇文章主要介紹了ThreadLocal原理及內(nèi)存泄漏原因,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-10-10
  • 利用Java實(shí)現(xiàn)復(fù)制Excel工作表功能

    利用Java實(shí)現(xiàn)復(fù)制Excel工作表功能

    這篇文章主要給大家介紹了關(guān)于如何利用Java實(shí)現(xiàn)復(fù)制Excel工作表功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 解決jhipster修改jdl生成的實(shí)體類報(bào)錯(cuò):liquibase.exception.ValidationFailedException: Validation Failed

    解決jhipster修改jdl生成的實(shí)體類報(bào)錯(cuò):liquibase.exception.ValidationFailed

    這篇文章主要介紹了解決jhipster修改jdl生成的實(shí)體類報(bào)錯(cuò):liquibase.exception.ValidationFailedException: Validation Failed問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 解決springboot與springcloud版本兼容問(wèn)題(附版本兼容表)

    解決springboot與springcloud版本兼容問(wèn)題(附版本兼容表)

    在基于spring boot搭建spring cloud時(shí),創(chuàng)建eureka后啟動(dòng)服務(wù)發(fā)生報(bào)錯(cuò),本文給大家介紹了解決springboot與springcloud版本兼容問(wèn)題的幾種方案,需要的朋友可以參考下
    2024-02-02
  • ActiveMQ消息隊(duì)列技術(shù)融合Spring過(guò)程解析

    ActiveMQ消息隊(duì)列技術(shù)融合Spring過(guò)程解析

    這篇文章主要介紹了ActiveMQ消息隊(duì)列技術(shù)融合Spring過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 關(guān)于@ApiImplicitParams、ApiImplicitParam的使用說(shuō)明

    關(guān)于@ApiImplicitParams、ApiImplicitParam的使用說(shuō)明

    這篇文章主要介紹了關(guān)于@ApiImplicitParams、ApiImplicitParam的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 使用filter實(shí)現(xiàn)url級(jí)別內(nèi)存緩存示例

    使用filter實(shí)現(xiàn)url級(jí)別內(nèi)存緩存示例

    這篇文章主要介紹了使用filter實(shí)現(xiàn)url級(jí)別內(nèi)存緩存示例,只需要一個(gè)靜態(tài)類,在filter中調(diào)用,也可以全部寫(xiě)到filt里面。可以根據(jù)查詢參數(shù)分別緩存,需要的朋友可以參考下
    2014-03-03
  • Java設(shè)計(jì)模式之迭代器模式

    Java設(shè)計(jì)模式之迭代器模式

    這篇文章介紹了Java設(shè)計(jì)模式之迭代器模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10

最新評(píng)論