springboot对参数进行校验


在controller层接收前端传过来的数据时,我们需要对参数进行统一检验,比如登陆的时候检查手机号是否为空、格式是否正确,同时还需要返回校验信息,那么这一部分该怎么设计呢?

针对这个问题,Java开发者在Java API规范 (JSR303) 定义了Bean校验的标准validation-api,但没有提供实现。hibernate validation是对这个规范的实现,并增加了校验注解如@Email、@Length等。Spring Validation是对hibernate validation的二次封装,用于支持spring mvc参数自动校验。接下来,我们介绍Spring Validation的使用。

@Valid

  • 第一步:添加依赖
        <!-- hibernate 验证框架 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
  • 第二步:封装参数
    将前端传过来用户的参数封装到自定义实体RegistLoginBO中,对每个参数字段添加注解约束和message
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class RegistLoginBO {
    
    

    @NotBlank(message = "手机号不能为空")
    @Length(min = 11, max = 11, message = "手机长度不正确")
    private String mobile;
    @NotBlank(message = "验证码不能为空")
    private String verifyCode;

}
  • 第三步:Controller获取参数
    通过@Valid @RequestBody RegistLoginBO registLoginBO校验参数,如果参数不对抛出MethodArgumentNotValidException,由@ControllerAdvice + @ExceptionHandler(MethodArgumentNotValidException.class)统一捕获异常,参数校验的值放在BindingResult中,可通过e.getBindingResult()获得。
    @PostMapping("login")
    public GraceJSONResult login(@Valid @RequestBody RegistLoginBO registLoginBO) throws Exception {
    
    


        String mobile = registLoginBO.getMobile();
        String code = registLoginBO.getSmsCode();

        // 1. 从redis中获得验证码进行校验是否匹配
        String redisCode = redis.get(MOBILE_SMSCODE + ":" + mobile);
        if (StringUtils.isBlank(redisCode) || !redisCode.equalsIgnoreCase(code)) {
    
    
            return GraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);
        }

        // 2. 查询数据库,判断用户是否存在
        Users user = userService.queryMobileIsExist(mobile);
        if (user == null) {
    
    
            // 2.1 如果用户为空,表示没有注册过,则为null,需要注册信息入库
            user = userService.createUser(mobile);
        }

        // 3. 如果不为空,可以继续下方业务,可以保存用户会话信息
        String uToken = UUID.randomUUID().toString();
        redis.set(REDIS_USER_TOKEN + ":" + user.getId(), uToken);

        // 4. 用户登录注册成功以后,删除redis中的短信验证码
        redis.del(MOBILE_SMSCODE + ":" + mobile);

        // 5. 返回用户信息,包含token令牌
        UsersVO usersVO = new UsersVO();
        BeanUtils.copyProperties(user, usersVO);
        usersVO.setUserToken(uToken);

        return GraceJSONResult.ok(usersVO);
    }
  • 校验结果
    在这里插入图片描述

@Validated

如果对于某一个参数UserParam,它可以作为两个方法的参数,其中一个允许为null,另一个要求不为null,这时候就需要@Validated分组校验了。

@Validated提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制;可以用在类型、方法和方法参数上,但是不能用在成员属性上

@Valid作为标准JSR-303规范,还没有吸收分组的功能;可以用在方法、构造函数、方法参数和成员属性上。

  • 定义分组(无需实现接口)
public interface AddValidationGroup {
    
    
}
public interface EditValidationGroup {
    
    
}
  • 校验字段添加分组
@Data
@Builder
@ApiModel(value = "User", subTypes = {
    
    AddressParam.class})
public class UserParam implements Serializable {
    
    

    private static final long serialVersionUID = 1L;

    @NotEmpty(message = "{user.msg.userId.notEmpty}", groups = {
    
    EditValidationGroup.class}) // 这里
    private String userId;

}

  • controller中的接口使用校验时使用分组
@Slf4j
@Api(value = "User Interfaces", tags = "User Interfaces")
@RestController
@RequestMapping("/user")
public class UserController {
    
    

    /**
     * http://localhost:8080/user/add .
     *
     * @param userParam user param
     * @return user
     */
    @ApiOperation("Add User")
    @ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)
    @PostMapping("add")
    public ResponseEntity<UserParam> add(@Validated(AddValidationGroup.class) @RequestBody UserParam userParam) {
    
    
        return ResponseEntity.ok(userParam);
    }

    /**
     * http://localhost:8080/user/add .
     *
     * @param userParam user param
     * @return user
     */
    @ApiOperation("Edit User")
    @ApiImplicitParam(name = "userParam", type = "body", dataTypeClass = UserParam.class, required = true)
    @PostMapping("edit")
    public ResponseEntity<UserParam> edit(@Validated(EditValidationGroup.class) @RequestBody UserParam userParam) {
    
    
        return ResponseEntity.ok(userParam);
    }
}

自定义validation

如何按照自定的规则进行校验?

  • 自定义注解
package tech.pdai.springboot.validation.group.validation.custom;

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.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Target({
    
     METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {
    
    TelephoneNumberValidator.class}) // 指定校验器
public @interface TelephoneNumber {
    
    
    String message() default "Invalid telephone number";
    Class<?>[] groups() default {
    
     };
    Class<? extends Payload>[] payload() default {
    
     };
}
  • 定义校验器
public class TelephoneNumberValidator implements ConstraintValidator<TelephoneNumber, String> {
    
    
    private static final String REGEX_TEL = "0\\d{2,3}[-]?\\d{7,8}|0\\d{2,3}\\s?\\d{7,8}|13[0-9]\\d{8}|15[1089]\\d{8}";

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
    
    
        try {
    
    
            return Pattern.matches(REGEX_TEL, s);
        } catch (Exception e) {
    
    
            return false;
        }
    }

}

下面就可以正常使用添加校验约束了。

猜你喜欢

转载自blog.csdn.net/weixin_44153131/article/details/129011498