springboot 请求参数解析与规范化

请求规范化

一个接口一般对参数(请求数据)都会进行安全校验,参数校验的重要性自然不必多说,那么如何对参数进行校验就有讲究了。

以前的业务层校验

首先我们来看一下最常见的做法,就是在业务层进行参数校验:

public String addUser(User user) {
     if (user == null || user.getId() == null || user.getAccount() == null || user.getPassword() == null || user.getEmail() == null) {
         return "对象或者对象字段不能为空";
     }
     if (StringUtils.isEmpty(user.getAccount()) || StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getEmail())) {
         return "不能输入空字符串";
     }
     if (user.getAccount().length() < 6 || user.getAccount().length() > 11) {
         return "账号长度必须是6-11个字符";
     }
     if (user.getPassword().length() < 6 || user.getPassword().length() > 16) {
         return "密码长度必须是6-16个字符";
     }
     if (!Pattern.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", user.getEmail())) {
         return "邮箱格式不正确";
     }
     // 参数校验完毕后这里就写上业务逻辑
     return "success";
 }

这样做当然是没有什么错的,而且格式排版整齐也一目了然,不过这样太繁琐了,这还没有进行业务操作呢光是一个参数校验就已经这么多行代码,实在不够优雅。

现在参数校验的几种情况
PathVariable 校验

在定义 Restful 风格的接口时,通常会采用 @PathVariable 指定关键业务参数,如下:

@GetMapping("/path/{group:[a-zA-Z0-9_]+}/{userid}")
@RestController
public String path(@PathVariable("group") String group, @PathVariable("userid") Integer userid) {
    return group + ":" + userid;
}

{group:[a-zA-Z0-9_]+} 这样的表达式指定了 group 必须是以大小写字母、数字或下划线组成的字符串。 类似这样可以使用正则去匹配

这种情况如果未匹配上就会返回404错误

方法参数校验

大多数情况下,我们都会直接将HTTP请求参数映射到方法参数上。

@GetMapping("/param")
@RestController
public String param(@RequestParam("group")@Email String group, 
                    @RequestParam("userid") Integer userid) {
   return group + ":" + userid;
}

@RequestParam 声明了映射,此外我们还为 group 定义了一个规则(Email格式)

@Email 这些注解哪里来的呢 ?

JSR-303

JSR-303是Java为Bean数据合法性校验提供的标准框架,它定义了一套可标注在成员变量,属性方法上的校验注解。注解是JSR-303 定义的 而他的实现就是通过 Hibernate Validator 来提供的,且已经包含在spring boot web stater 场景下了,若不是spring boot 框架则需引入

<!-- Hibernate Validator -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>6.0.7.Final</version>
</dependency> 

下面是常用的注解

在这里插入图片描述

JSR-303定义的注解

@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

Hibernate Validator提供的校验注解

@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内

使用方法参数校验

将注解标在controller参数上

@GetMapping("/param")
public String param(@RequestParam("model")@Size(min=4, max=4,message = "请检查型号的长度是否有问题") String model) {
   return model;
}

开启方法参数的校验

将其注入到ioc

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
     return new MethodValidationPostProcessor();
}

并将**@Validated ** 标注在controller类上

@RestController
@RequestMapping("/validate")
@Validated
public class ValidateController { // ....
}
表单对象校验

页面的表单通常比较复杂,此时可以将请求参数封装到表单对象中,

当使用方法参数校验对表单进行校验时,要在方法参数部分写好多 , 这时就需要对象校验了

这时仍然适用JSR-303 的校验规则

将JSR-303注解标在对象上 使用**@Validated **标注在参数上 进行校验

public class Laptop {
    @NotNull
    @Size(min=4, max=4,message = "请检查型号的长度是否有问题")
    @JsonProperty("型号")
    private String model;

    @NotNull
    @JsonProperty("速度G")
    private Double speed;
    //........
}
分组校验

将这些注解注释在实体类上在controller层需要使用@Validated/@Valid 对注解的校验

@Validated注解表示使用Spring的校验机制,支持分组校验,声明在入参上.

Validated 可以分组校验:意思是有些情况我们不需要对某些参数进行检验,这个时候就可以使用分组校验 ,下面是步骤

  • 定义分组接口做标识(仅仅是标识)

    public interface GroupA {
    
    }
    
    public interface GroupB {
    
    }
    
  • 使用校验注解标注在属性上并进行分组 不标识默认会全匹配

    public class Laptop {
        @NotNull
        @Size(max=4,message = "请检查型号的长度是否有问题",groups={GroupA.class})
        @JsonProperty("型号")
        private String model;
        //........
    }
    
  • @Validated 注解校验时指定组

    @Validated(value= {GroupB.class}) Laptop laptop
    

@Valid注解表示使用Hibernate的校验机制,不支持分组校验,声明在入参上.

在controller参数后面要紧跟BindingResult对象,该对象用于获取当校验失败时的异常信息.

根据BindingResult 的异常信息处理

    @PostMapping("/addUser")
    public String addUser(@RequestBody @Validated User user, BindingResult bindingResult) {
        // 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里
        for (ObjectError error : bindingResult.getAllErrors()) {
            String error =  error.getDefaultMessage();
            //处理异常结果
        }
        return "";
    }
自定义校验注解

有时候,第三方库中并没有我们想要的校验类型,好在系统提供了很好的扩展能力,我们可以自定义检验。

比如检验手机号

步骤
  1. 编写校验注解

    // 我们可以直接拷贝系统内的注解如@Min,复制到我们新的注解中,然后根据需要修改。
    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
    @Retention(RUNTIME)
    @Documented
    //注解的实现类。
    @Constraint(validatedBy = {IsMobileValidator.class 实现类})
    public @interface IsMobile {
        //校验错误的默认信息
        String message() default "手机号码格式有问题";
    
        //是否强制校验
        boolean isRequired() default false;
        
        //组校验
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    
  2. 编写实现类

    // 自定义注解一定要实现ConstraintValidator接口,里面的两个参数
    // 第一个为 具体要校验的注解
    // 第二个为 校验的参数类型
    public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {
    
        private boolean required = false;
    
        private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");
        //工具方法,判断是否是手机号
        public static boolean isMobile(String src) {
            if (StringUtils.isEmpty(src)) {
                return false;
            }
            Matcher m = mobile_pattern.matcher(src);
            return m.matches();
        }
    
        @Override
        public void initialize(IsMobile constraintAnnotation) {
            required = constraintAnnotation.isRequired();
        }
    
        @Override
        public boolean isValid(String phone, ConstraintValidatorContext constraintValidatorContext) {
            //是否为手机号的实现
            if (required) {
                return isMobile(phone);
            } else {
                if (StringUtils.isEmpty(phone)) {
                    return true;
                } else {
                    return isMobile(phone);
                }
            }
        }
        
    }
    
  3. 测试

    标注在属性上测试即可

参数校验异常处理

参数异常处理可以在controller参数后面要紧跟BindingResult对象,该对象用于获取当校验失败时的异常信息.

BindingResult 处理异常

根据BindingResult 的异常信息处理

    @PostMapping("/addUser")
    public String addUser(@RequestBody @Validated User user, BindingResult bindingResult) {
        // 如果有参数校验失败,会将错误信息封装成对象组装在BindingResult里
        for (ObjectError error : bindingResult.getAllErrors()) {
            String error =  error.getDefaultMessage();
            //处理异常结果
        }
        return "";
    }

但是这样就会重复写很多异常处理,尽管可以做成统一接口 ,但还是麻烦.

全局异常处理

参数校验失败会自动引发异常,那正好使用SpringBoot全局异常处理来达到一劳永逸的效果

在包 solveexception中新建类,在这个类上加上@ControllerAdvice或@RestControllerAdvice注解,这个类就配置成全局处理类了。(这个根据你的Controller层用的是@Controller还是@RestController来决定,返回页面还是数据)

再类中新增方法 加上@ExceptionHandler 添加要处理的类 ,编写对应逻辑就完成了相关异常处理

例如

@RestControllerAdvice
public class ExceptionControllerAdvice {
    
@ExceptionHandler(MethodArgumentNotValidException.class)
public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        // 从异常对象中拿到ObjectError对象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 然后提取错误提示信息进行返回
    	//推荐使用统一返回类型
        return objectError.getDefaultMessage();
}
}

这个时候我们就可以编写自定义异常然后再全局进行处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Boot 是一个开发框架,用于构建基于Spring框架的Java应用程序。在使用Spring Boot时,我们可以使用多种方法对请求参数进行加密。 一种常见的方法是使用HTTPS来保护传输中的数据。HTTPS使用了SSL(Secure Sockets Layer)和TLS(Transport Layer Security)协议来加密HTTP请求和响应中的数据。我们可以在Spring Boot应用程序中配置HTTPS,使用自签名证书或者购买可信任的证书来建立安全的通信通道。 另一种方法是使用加密算法对请求参数进行加密。我们可以使用对称加密算法,如AES(Advanced Encryption Standard)或DES(Data Encryption Standard),将请求参数加密后再发送到服务器。服务器端接收到加密后的请求参数后,使用相同的密钥和算法进行解密,获取原始数据。 还有一种方法是使用数字签名来验证请求参数的完整性和真实性。我们可以使用非对称加密算法,如RSA(Rivest-Shamir-Adleman)算法,将请求参数进行签名。服务器端使用相应的公钥验证签名,确保请求参数未被篡改。 除此之外,还可以使用其他加密技术,如哈希函数或消息摘要算法对请求参数进行加密。哈希函数将请求参数转换成固定长度的摘要,服务器端接收到请求参数后,将其进行相同的哈希运算,并与接收到的摘要进行比较,以验证参数的完整性。 在Spring Boot中,我们可以使用相应的加密算法和工具类来实现以上加密方法,保护请求参数的安全性。需要根据具体的需求和场景选择适合的加密方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值