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
}

  

 

posted @ 2020-08-20 16:58  火羽  阅读(1399)  评论(0编辑  收藏  举报