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
}