dubbo实现参数校验


Filter类

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.kuyu.framework.core.vo.ResultVO;
import com.kuyu.framework.enums.ReturnEnum;
import com.kuyu.framework.message.SpringContextUtil;
import org.apache.dubbo.common.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* 2021-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 com.example.common.ApiResult;
import com.example.common.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,由业务码去区分系统的异常情况。*/
@RestControllerAdvice
public 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 = Pattern.compile("^[0-9]*$");@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {//校验逻辑if (value != null) {Matcher matcher = PATTERN.matcher(value);return matcher.find();}return true;}
}

使用

@Data
public 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;
}

实现参数校验,统一异常处理,自定义参数校验器相关推荐

  1. 优雅书写Controller(参数验证+统一异常处理)

    优雅书写Controller(参数验证+统一异常处理) 文章目录 最近开发了比较多的接口,因为没有可参考的案例,所以一开始一直按照我的理解进行开发.开发多了发现自己每个结果都写了相同的代码:try() ...

  2. R语言使用caret包对GBM模型自定义参数调优:自定义参数优化网格

    R语言使用caret包对GBM模型自定义参数调优:自定义参数优化网格 目录 R语言使用caret包对GBM模型自定义参数调优:自定义优化参数网格

  3. e0312 不存在用户定义的_更加灵活的参数校验,Spring-boot自定义参数校验注解

    上文我们讨论了如何使用@Min.@Max等注解进行参数校验,主要是针对基本数据类型和级联对象进行参数校验的演示,但是在实际中我们往往需要更为复杂的校验规则,比如注册用户的密码和确认密码进行校验,这个时 ...

  4. validation 参数校验和统一异常处理

    文章目录 1. 引入依赖 2. 校验规则 3. 规则使用 4. 自定义异常类 5. 统一返回对象封装 6. 统一异常对象 7. 统一异常枚举 8. 前端form表单输入,自动触发校验 1. 引入依赖 ...

  5. Hive-CDH参数修改指南--增加自定义参数--命令行显示当前数据-查询结果显示表头(类似修改源生Hive的hive-site.xml文件)

    Hive-CDH参数修改指南(类似修改源生Hive的hive-site.xml文件) 问题描述 默认配置下,每次启动Hive都要手动输入配置选项,才能实现:在命令行显示当前数据库(set hive.c ...

  6. java xfire指定参数名_xfire中自定义参数名

    近期在做多个应用交互系统,其中数据交互采用了webservice的方式,说到webservice项目中不得不用到xfire这个框架,有了它我们几乎不用写代码,就可以很快速的创建自己的webservic ...

  7. SpringBoot:统一异常、数据校验处理

    本文转自:blog.lqdev.cn/2018/07/20/springboot/chapter-eight/ 前言 在web应用中,请求处理时,出现异常是非常常见的.所以当应用出现各类异常时,进行异 ...

  8. CAD制图初学入门教程:CAD机械软件中如何自定义参数栏?

    很多人CAD制图初学入门者不知道如何使用浩辰CAD机械软件来自定义参数栏,今天小编就来给大家分享一下在浩辰CAD机械软件中自定义参数栏的CAD制图初学入门教程吧! 在浩辰机械CAD软件中自定义参数栏首 ...

  9. 在js函数有默认参数情况下如何增加自定义参数而不覆盖原本的默认参数

    在用一些ui写项目的时候会遇到:函数有默认参数并且需要增加自定义参数而不覆盖原本的默认参数的情况(代码放在评论区了) 在vant Uploader 文件上传,自定义参数 list是传入进来的,方便赋值 ...

  10. 【Java】参数校验与统一异常处理

    Java参数校验与统一异常处理 [前言]参数校验是接口开发不可或缺的环节,校验参数在以前基本上依靠大量的if/else控制语句来实现,后来可以使用反射+自定义注解的形式进行校验,但是复用性不是很好.其 ...

最新文章

  1. [转]Asp.Net 上传大文件专题(3)--从请求流中获取数据并保存为文件[下]
  2. 转:a标签中如果有button, 那么在IE下就不能跳转到herf的链接
  3. jQuery常用的方法
  4. 在 SAP 电商云 Spartacus UI 里手动注入 module 的几种排列组合
  5. 教程:Hibernate,JPA和Spring MVC –第2部分
  6. java基础知识系列---垃圾收集
  7. php magento 开发,magento 2模块开发实例helloworld模块 hello world 程序 c语言hello world代码 c语言hello worl...
  8. MongoDB文档查询操作(三)
  9. Xamarin.Android AlertDialog中的EditText打上去字为什么不显示?也没有光标闪烁
  10. [独库骑行之我们路过高山]玉希莫勒盖达坂顶上的震撼
  11. 微信图片怎么添加竖排文字_微信拍照的照片怎样加文字?
  12. .net之实现文件上传与下载
  13. 显卡1060和1660测试对比
  14. Excel使用VBA动态设置打印区域
  15. 彩色图像高频与低频成分的分解
  16. GB9706.1-2007名词解释:电气间隙、爬电距离,绝缘、接地等
  17. iOS 非越狱下的代码注入
  18. 汇编指令 BCC/BLO
  19. fastboot烧录镜像--VTSGSI镜像替换
  20. 选调生推荐表计算机水平如何填写,2020广东选调生报考推荐表填写模板

热门文章

  1. android清理存储空间不足,安卓手机内存空间不足该如何清理
  2. 非因解读 | Multiplex immunofluorescnece-多重免疫荧光结合单细胞蛋白组技术探索肿瘤微环境
  3. 复习步骤7-获取权限数据CustomRealm提供subject桥梁,集成spring - 数据库获取用户权限角色等信息-shiro加密密码和盐存入数据库
  4. 链接脚本(Linker Script)用法解析(二) clear_table copy_table
  5. 资源集成视角解读项目管理-合同类型
  6. matplotlib论文图片配色
  7. 【例题】利用伴随矩阵求逆矩阵
  8. 30【源码】数据可视化大屏:基于 Echarts + Python Flask 实现的32-9超宽大屏 - 中国国际疫情实时追踪
  9. 电脑每次开机都出现check file system on:C 的解决办法
  10. 《SEM长尾搜索营销策略解密》一一2.1 起因:核心词成本过高