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
}
