900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 实现参数校验 统一异常处理 自定义参数校验器

实现参数校验 统一异常处理 自定义参数校验器

时间:2023-07-31 17:01:39

相关推荐

实现参数校验 统一异常处理 自定义参数校验器

dubbo实现参数校验

Filter类

import com.alibaba.fastjson.JSON;import mon.collect.Maps;import com.kuyu.framework.core.vo.ResultVO;import com.kuyu.framework.enums.ReturnEnum;import com.kuyu.framework.message.SpringContextUtil;import org.mon.extension.Activate;import org.apache.dubbo.rpc.AsyncRpcResult;import org.apache.dubbo.rpc.Filter;import org.apache.dubbo.rpc.Invocation;import org.apache.dubbo.rpc.Invoker;import org.apache.dubbo.rpc.Result;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.ApplicationContext;import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.executable.ExecutableValidator;import java.lang.reflect.Method;import java.util.Map;import java.util.Objects;import java.util.Set;/*** dubbo参数校验过滤器** @author zx* -10-27*/@Activate(order = 2)public class DubboServiceParameterFilter implements Filter {/*** 日志*/private static final Logger LOGGER = LoggerFactory.getLogger(DubboServiceParameterFilter.class);/*** 校验器线程池*/private static ExecutableValidator executableValidator = Validation.buildDefaultValidatorFactory().getValidator().forExecutables();@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) {// 获取方法Method method = getMethod(invoker, invocation);// 记录下请求参数,用于打印参数Object[] arguments = invocation.getArguments();if (Objects.nonNull(method)) {// 获取返回值对象,只有返回值包装成了ResultVO的对象才做处理Class returnType = method.getReturnType();String returnClassName = returnType.getName();if ("com.kuyu.framework.core.vo.ResultVO".equals(returnClassName)) {// 日志信息StringBuilder logInfo = new StringBuilder();// 获取接口类Class interfaceName = invoker.getInterface();logInfo.append("|className:").append(interfaceName.getName()).append(".").append(method.getName()).append("|requestParam:").append(JSON.toJSONString(arguments)).append("|context:").append(JSON.toJSONString(invocation.getAttachments()));ApplicationContext applicationContext = SpringContextUtil.getApplicationContext();Object object = applicationContext.getBean(interfaceName);Object[] paramList = invocation.getArguments();//用校验器,校验此object的method方法的paramList是否合法,返回校验结果Set<ConstraintViolation<Object>> constraintViolations = executableValidator.validateParameters(object, method, paramList);ResultVO response = getValidationResult(constraintViolations);if (response != null && ReturnEnum.ERROR_KY00001.getCode().equals(response.getCode())) {AsyncRpcResult asyncRpcResult = new AsyncRpcResult(invocation);asyncRpcResult.setValue(response);logInfo.append("|response:").append(JSON.toJSONString(response));LOGGER.info("commonAccessLog:" + logInfo.toString());return asyncRpcResult;}}}return invoker.invoke(invocation);}/*** 获取校验方法*/private static Method getMethod(Invoker<?> invoker, Invocation invocation) {Method[] methods = invoker.getInterface().getDeclaredMethods();for (Method m : methods) {// 即获取此次dubbo invocation对应的method对象boolean needCheck = m.getName().equals(invocation.getMethodName())&& invocation.getArguments().length == m.getParameterCount();if (needCheck) {if (matchMethod(invocation.getParameterTypes(), m.getParameterTypes())) {return m;}}}return null;}/*** 获取匹配的方法** @param invokerMethodParamClassList 方法列表* @param matchMethodParamClassList 匹配的方法列表* @return boolean*/private static boolean matchMethod(Class[] invokerMethodParamClassList, Class[] matchMethodParamClassList) {for (int i = 0; i < invokerMethodParamClassList.length; i++) {if (!invokerMethodParamClassList[i].equals(matchMethodParamClassList[i])) {return false;}}return true;}/*** 校验结果转换返回对象*/private static <T> ResultVO getValidationResult(Set<ConstraintViolation<T>> set) {if (set != null && !set.isEmpty()) {Map<String, String> errorMsg = Maps.newHashMap();for (ConstraintViolation<T> violation : set) {errorMsg.put(violation.getPropertyPath().toString(), violation.getMessage());}return ResultVO.error(ReturnEnum.ERROR_KY00001.getCode(), ReturnEnum.ERROR_KY00001.getMsg(), errorMsg);}return ResultVO.success();}}

springboot 参数校验统一异常处理

导入依赖

<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId><version>6.0.1.Final</version></dependency>

统一异常处理类

import mon.ApiResult;import mon.enums.ApiCode;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.validation.BindException;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.web.HttpMediaTypeNotSupportedException;import org.springframework.web.HttpRequestMethodNotSupportedException;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;import javax.validation.ConstraintViolationException;/*** 统一异常处理* 前面说过,如果校验失败,会抛出MethodArgumentNotValidException或者ConstraintViolationException异常。* 在实际项目开发中,通常会用统一异常处理来返回一个更友好的提示。比如我们系统要求无论发送什么异常,* http的状态码必须返回200,由业务码去区分系统的异常情况。*/@RestControllerAdvicepublic class CommonExceptionHandler {private static final Logger log = LoggerFactory.getLogger(CommonExceptionHandler.class);/*** 参数校验错误错误,如果校验失败,* 会抛出MethodArgumentNotValidException或者ConstraintViolationException异常** @param ex* @return*/@ExceptionHandler({MethodArgumentNotValidException.class})public ApiResult handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {BindingResult bindingResult = ex.getBindingResult();StringBuilder sb = new StringBuilder("校验失败:");for (FieldError fieldError : bindingResult.getFieldErrors()) {sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");}String msg = sb.toString();return ApiResult.fail(ApiCode.PARAMETER_ERROR, msg);}@ExceptionHandler({BindException.class})public ApiResult handleMethodArgumentNotValidException(BindException ex) {FieldError fieldError = ((BindException) ex).getBindingResult().getFieldError();return ApiResult.fail(ApiCode.PARAMETER_ERROR, fieldError.getField() + fieldError.getDefaultMessage());}@ExceptionHandler({ConstraintViolationException.class})public ApiResult handleConstraintViolationException(ConstraintViolationException ex) {return ApiResult.fail(ApiCode.PARAMETER_ERROR, ex.getMessage());}/*** 400** @param e* @return*/@ExceptionHandler(HttpMessageNotReadableException.class)public ApiResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {log.error("参数解析失败", e);return ApiResult.fail(ApiCode.ERROR_400004);}/*** 405** @param e* @return*/@ExceptionHandler(HttpRequestMethodNotSupportedException.class)public ApiResult handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {log.error("不支持的请求方式", e);return ApiResult.fail(ApiCode.ERROR_400005);}/*** 不支持的媒体格式** @param e* @return*/@ExceptionHandler(HttpMediaTypeNotSupportedException.class)public ApiResult handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {log.error("不支持的媒体类型", e);return ApiResult.fail(ApiCode.ERROR_400006);}/*** 其它未知异常** @param e* @return*/@ExceptionHandler(Exception.class)public ApiResult handlerException(Exception e) {log.error("未知异常", e);return ApiResult.fail(ApiCode.ERROR);}}

自定义参数校验器:

import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.Documented;import java.lang.annotation.Retention;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.ANNOTATION_TYPE;import static java.lang.annotation.ElementType.CONSTRUCTOR;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.ElementType.PARAMETER;import static java.lang.annotation.RetentionPolicy.RUNTIME;@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})@Retention(RUNTIME)@Documented@Constraint(validatedBy = {EncryptIdValidator.class})public @interface EncryptId {String message() default "加密id格式错误";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};}

/*** 自定义一个参数校验器*/public class EncryptIdValidator implements ConstraintValidator<EncryptId, String> {private static final Pattern PATTERN = pile("^[0-9]*$");@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {//校验逻辑if (value != null) {Matcher matcher = PATTERN.matcher(value);return matcher.find();}return true;}}

使用

@Datapublic class UserDto implements Serializable {private static final long serialVersionUID = 8612985472141018146L;@EncryptId(message = "必须是0-9的数字格式")private String userId;@NotBlank(message = "用户名不能为空")@Length(min = 2, max = 10)private String userName;@NotBlank(message = "account不能为空")@Length(min = 6, max = 20)private String account;@NotBlank(message = "password不能为空")@Length(min = 6, max = 20)private String password;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。