首页 > 其他分享 >基础设施建设——全局请求参数校验

基础设施建设——全局请求参数校验

时间:2024-06-07 21:10:49浏览次数:23  
标签:基础设施 message 校验 private public 全局 Validated class

基础设施建设——全局请求参数校验

Bean Validation 漫谈 一文中已经对Bean Validation进行了详细的介绍,以及Spring Validator与Jakarta Bean Validation 规范的关系,本文讨论在微服务架构中,如何做全局的请求参数校验。

1.基于SpringMVC的http接口如何校验

在Spring Framework中有自己的Validator接口,但是其API 设计的比较简陋,而且需要编写大量 Validator 实现类,与javax bean validation的注解式校验相形见绌,于是在Spring 3.0版本开始,Spring Validator将其所有校验请求转发至Jakarta Bean Validation接口的实现中。下面举例介绍在Spring Web框架下如何做请求参数校验。

实体类:

@Data
public class Entity {
  
    @NotBlank(message = "名称不能为空")
    private String name;

    @NotBlank(message = "描述不能为空")
    private String description;

    @NotNull(message = "类型不能为null")
    private Byte type;
}

controller层:

@RestController
@RequestMapping("/demo")
@Validated
public class DemoController {

    @PostMapping("create")
    public String create(@Valid @RequestBody Entity entity) {
        return "ok";
    }
}

上述代码涉及到两个注解@Validated和@Valid,其中@Valid是JSR-303规范中的注解,@Validated是由Spring提供的注解,具体区别为:

  1. 注解使用的位置:@Validated可以用在类型、方法和方法参数上,但是不能用在成员属性上;而@Valid可以用在方法、构造函数、方法参数和成员属性上;
  2. 分组校验:@Validated提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制;
  3. 嵌套校验:二者均无法单独提供嵌套校验的功能,但是可以通过在引用属性上加@Valid注解实现对引用属性中的字段校验;

其中分组校验:

// 分组
public interface Group1{
}
public interface Group2{
}

// 实体类
public class Entity {
	@NotNull(message = "id不能为null", groups = { Group1.class })
	private int id;
 
	@NotBlank(message = "用户名不能为空", groups = { Group2.class })
	private String username;
}

// controller层
public String create(@Validated( { Group1.class }) Entity entity, BindingResult result) {
	if (result.hasErrors()) {
		return "validate error";
	}
	return "redirect:/success";
}

其中嵌套校验:

// Controller层
@RestController
public class DemoController {

    @RequestMapping("/create")
    public void create(@Validated Outer outer, BindingResult bindingResult) {
        doSomething();
    }
}

// 实体类
public class Outer {

    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;

    @Valid
    @NotNull(message = "inner不能为空")
    private Inner inner;
}

// 引用属性
public class Inner {

    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;

    @NotBlank(message = "name不能为空")
    private String name;
}

2.Dubbo接口如何校验

利用dubbo的拦截器扩展点,判断请求参数是否为自定义的Request类型,如果是的话调用validator.validate方法校验参数,并将结果映射出一个属性路径拼接错误信息的list,最终将校验异常信息封装为失败响应返回。下面结合我司的请求规范举例说明:

@Activate(group = Constants.PROVIDER, before = {"DubboExceptionFilter"}, order = -20)
public class ValidatorDubboProviderFilter implements Filter {

    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        Object[] arguments = invocation.getArguments();
        if (arguments != null && arguments.length > 0 && arguments[0] instanceof Request<?> request) {
            Object requestParams = request.getRequestParams();
            Set<ConstraintViolation<Object>> errors = validator.validate(requestParams);
            List<String> collect = errors.stream().map(error -> error.getPropertyPath() + "," + error.getMessage()).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(collect)) {
                OpenApiResponse openApiResponse = new OpenApiResponse();
                openApiResponse.setSuccess(false);
                openApiResponse.setCode(DddCons.ValidateError);
                openApiResponse.setMessage(String.join("||", collect));
                if (request.getRequestId() != null) {
                    openApiResponse.setRequestId(request.getRequestId());
                }
                return  AsyncRpcResult.newDefaultAsyncResult(openApiResponse ,invocation);
            }
        }
        return invoker.invoke(invocation);
    }
}

最后别忘了添加META-INF/dubbo/org.apache.dubbo.rpc.Filter

ValidatorDubboProviderFilter=com.xxx.infrastructure.tech.validator.dubbo.ValidatorDubboProviderFilter

3.OpenFeign接口如何校验

OpenFeign接口的校验与SpringMVC的接口校验类似,下面举例说明:

@FeignClient(value = "user", fallback = UserHystrix.class)
@Validated
public interface UserService {

    @PostMapping(value = "/user/hello")
    UserDto hello(@RequestParam("name") @NotEmpty String name);
    
    @PostMapping("/user/add")
    UserDto add(@RequestBody @Validated UserDto userDTO);
    
    @PostMapping("/user/list")
    void testParamList(@RequestBody @Valid List<UserDto> userList);
}

本博客内容仅供个人学习使用,禁止用于商业用途。转载需注明出处并链接至原文。

标签:基础设施,message,校验,private,public,全局,Validated,class
From: https://www.cnblogs.com/zhaobo1997/p/18237871

相关文章

  • vue3多个表单一起校验
    当定义了多个表单但是保存时需要同时校验的时候可以这样做<template><el-form:model="userForm1"label-width="auto"ref="userFormRef1"></el-form><el-form:model="userForm2"label-width="auto......
  • dubbo~全局异常拦截器的使用与设计缺陷
    异常拦截器ExceptionMapper在JAX-RS(JavaAPIforRESTfulWebServices)中,ExceptionMapper接口用于将Java异常映射到HTTP响应。通过实现ExceptionMapper接口,你可以自定义如何处理特定类型的异常,并生成相应的HTTP响应。优先级和选择当有多个ExceptionMapper可用于处理同一类型的......
  • TCP的校验和与编号
    TCP的校验和与编号TCP校验和特点:端到端校验:校验和覆盖TCP首部和TCP数据,确保从发送端到接收端的数据完整性。检错能力:TCP校验和具有较强的检错能力,可以检测出在传输过程中发生的位错误。伪首部:在计算TCP校验和时,会加上一个12字节的伪首部,包含源IP地址、目的IP地址、保留字节(......
  • 全局 type 类型的寻找 typescript 类型 - fabric.Canvas
    全局type类型的寻找typescript类型-fabric.CanvasdeclaretypeExtCanvas=fabric.Canvas&{isDragging:boolean;lastPosX:number;lastPosY:number;};这个代码没有定义fabric.Canvas,然后看看提示说在namespace定义了。这个是子项目,没有type定义,上父项......
  • 校验和与编号
    校验和与编号校验和(Checksum)和编号(Numbering)是两种不同的概念,它们在数据处理和通信中扮演着不同的角色。在实际应用中,校验和和编号可以结合使用,以提高数据的完整性和可靠性。例如,在TCP/IP协议中,数据包不仅包含序列号以确保顺序,还包含校验和以检测数据损坏。校验和(Checksum)校验......
  • 【PB案例学习笔记】-03用户名密码校验
    写在前面这是PB案例学习笔记系列文章的第3篇,该系列文章适合具有一定PB基础的读者。通过一个个由浅入深的编程实战案例学习,提高编程技巧,以保证小伙伴们能应付公司的各种开发需求。文章中设计到的源码,小凡都上传到了gitee代码仓库https://gitee.com/xiezhr/pb-project-example.gi......
  • validate方法进行表单异步校验时,回调函数内部避免使用全局变量
    对整个表单进行校验的方法,参数为一个回调函数。该回调函数会在校验结束后被调用,并传入两个参数:是否校验成功和未通过校验的字段。若不传入回调函数,则会返回一个promise问题代码:save(){console.log(that.pos.indexName)console.log(that.pos.indexCode)......
  • 哈希校验
    哈希校验的工具包有两个系列,一个是GNU系的md5sum、shaXXXsum,另一个是BSD/macOS系的md5、shasum。GNU系计算md5sum<file>sha1sum<file>sha256sum<file>sha512sum<file>例:sha256sum*>SHA256SUMS#将目录中所有文件的SHA-256校验和写到SHA256SUMS文件中......
  • 【DRF-10】rest-framework之序列化(数据校验)
    1.自定义classTitleValidator(object):def__init__(self,start):self.start=startdef__call__(self,value):ifnotvalue.startswith(self.start):message='标题必须以%s为开头。'%self.startraiseseria......
  • java使用百度地图接口校验收货地址是否超出配送范围
    1.地理编码API服务地址:https://api.map.baidu.com/geocoding/v3/?address=北京市海淀区上地十街10号&output=json&ak=您的ak&callback=showLocationMapmap=newHashMap();map.put("address",shopAddress);map.put("output","......