hibernate-validator優雅地校驗參數,全局異常處理封裝校驗異常


hibernate-validator 是一個參數校驗框架,可以對於入參進行優雅的進行數據校驗,可以減少入參校驗重復的代碼。

對於hibernate-validator 對於校驗異常的數據,會拋出MethodArgumentNotValidException,我們可以通過全局異常處理,進行異常封裝,優雅地返回異常信息。

 

1.集成hibernate-validator需要進行依賴,我這邊用的版本是

<hibernate-validator.version>6.0.13.Final</hibernate-validator.version>
  <dependency>
                <groupId>org.hibernate.validator</groupId>
                <artifactId>hibernate-validator</artifactId>
                <version>${hibernate-validator.version}</version>
  </dependency>

  

2.對於controller層中,方法需要標記 @Valid

  @RequestMapping(value = "/test",method = RequestMethod.POST)
    @ApiOperation(value = "問卷轉換",tags={"問卷轉換核保規則"}, notes = "問卷與核保規則轉換",httpMethod = "POST")
    public Result<ConvertQuestionResponseMO> convertQuestion(@RequestBody @Valid ConvertQuestionRequestMO request)
    {
        
    }

  

3.MO上我們可以使用注解進行數據校驗

public class ConvertQuestionRequestMO implements Serializable {
    /**請求流水號*/
    @NotBlank(message = "messageId不能為空")
    private String messageId;
    /**渠道代碼*/
    @NotNull(message = "testId不能為空")
    private String testId;
  @Pattern(regexp="^(\\s*|[0-9]+([.]{1}[0-9]+){0,1})$",message="scores格式不正確")
  private String score;

  @NotEmpty(message = "qtnList不能為空")  
  @Valid
  private List<Test2Req> qtnList;


  //注:Test2Req中的字段如果想要校驗參數,必須也加上@Valid的注解,否則驗證器不生效

 

4.對於驗證器驗證不通過拋出的異常,我們需要處理下,避免往外拋異常,返回友好的mo信息

package com.uwe.handler;


import com.common.base.enums.ResponseCode;
import com.common.base.excepiton.BusinessException;
import com.common.base.mo.Result;
import com.common.base.utils.JsonUtil;
import com.uwe.eo.UwInterfaceLog;
import com.uwe.service.UwInterfaceLogService;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;

/**
 * 全局異常處理 code 200/500
 * @Auther: tony_t_peng
 * @Date: 2020-07-31 16:22
 * @Description: 
 */
@RestControllerAdvice
public class GlobalExceptionHandler  {

    @Autowired
    private UwInterfaceLogService interfaceLogService;

    public static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 全局異常統一處理
     * @throws Exception
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        String requestBody = "";
        if (req != null && req instanceof ContentCachingRequestWrapper) {
            ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) req;
            requestBody = new String(wrapper.getContentAsByteArray());
        }
        logger.info("接口請求參數:{}",requestBody);
        logger.error("接口調用數據異常 ",e);
        Result response = new Result();
        String errorMesssage = "";
        if (e instanceof BusinessException) {
            errorMesssage=e.getMessage();
        }else if(e instanceof MethodArgumentNotValidException){//參數校驗異常
           BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
           if(bindingResult!=null&& CollectionUtils.isNotEmpty(bindingResult.getFieldErrors())){
               for (FieldError fieldError : bindingResult.getFieldErrors()) {
                   errorMesssage += fieldError.getDefaultMessage() + ",";
               }
               errorMesssage="參數校驗異常:"+errorMesssage.substring(0,errorMesssage.length()-1);
           }else{
               errorMesssage="參數校驗異常";
           }
        }else{//其他異常
            errorMesssage="接口調用數據異常";
        }
        ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) req;
        response.setTraceId(gettraceId(req));
        response.setMessage(errorMesssage);
        response.setCode(ResponseCode.FAIL.getCode());
        saveInterfaceLog(requestBody,errorMesssage,response);
        return response;
    }

    private void saveInterfaceLog(String  requestBody,String errorMesssage,Result result){
        UwInterfaceLog uwInterfaceLog = new UwInterfaceLog();
        uwInterfaceLog.setTrxnId(result.getTraceId());
        uwInterfaceLog.setException(errorMesssage);
        uwInterfaceLog.setRequestTime(new Date());
        uwInterfaceLog.setResponseTime(new Date());
        uwInterfaceLog.setRequestBody(requestBody);
        uwInterfaceLog.setResponseBody(JsonUtil.toJSONString(result));
        uwInterfaceLog.setInterfaceType("convert_question");
        interfaceLogService.saveInterfaceLog(uwInterfaceLog);
    }

    private String gettraceId(HttpServletRequest req){
        if (req != null && req instanceof ContentCachingRequestWrapper) {ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) req;
            String body = new String(wrapper.getContentAsByteArray());
            HashMap map = JsonUtil.parseObject(body, HashMap.class);
            Object traceId = map.get("traceId");
            if(traceId!=null&&traceId instanceof String){
                return (String) traceId;
            }
        }
        return null;
    }
}

  

定義的返回Result

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.common.base.mo;

import com.common.base.enums.ResponseCode;
import java.io.Serializable;

public class Result<T> implements Serializable {
    private String traceId;
    private String code;
    private String message;
    private T data;

    public Result() {
        this.code = ResponseCode.SUCCESS.getCode();
        this.message = ResponseCode.SUCCESS.name();
    }

    public String getCode() {
        return this.code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMessage() {
        return this.message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return this.data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getTraceId() {
        return this.traceId;
    }

    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }
}

  

 

5. 測試下,hibernate-validator的異常信息,我們捕獲之后,就可以優雅的返回給調用者

{
	"traceId": "20200819174018044",
	"code": "1",
	"message": "參數校驗異常:scores格式不正確,lifeRisk格式不正確", 
     "data": null
}

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM