SpringBoot参数校验

一、pom文件

<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>2.0.2</version>
</dependency>
<!--SpringBoot 2.3中@Valid会失效-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、注解含义

注解含义
@Null值为null
@NotNull不能为null
@Pattern必须满足给定的正则表达式
@Email满足Email格式
@Max必须是数字,且值小于等于给定的值
@Min必须是数字,且值小于等于给定的值
@Range元素需在指定范围区间内

三、代码示例

1 代码目录

2自定义参数规则

2.1 注解,这里是对orderByValue的值的内容进行校验,必须为desc 或者asc,其它字符串则报错
package com.example.shiro.annotation;

import com.example.shiro.validator.MyValidator;

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

@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = MyValidator.class)
@Documented
public @interface MyValidate {
    String message() default  "orderByValue 的值不在可选范围内[desc,asc]";
    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
2.2 自定义validator,校验参数是否包含asc 或者 desc
package com.example.shiro.validator;

import com.example.shiro.annotation.MyValidate;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;

public class MyValidator implements ConstraintValidator<MyValidate, String> {
    /**
     * 验证参数是不是在指定值中
     * @param value
     * @param context
     * @return
     */
    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        HashSet<Object> typeName = new HashSet<>();
        typeName.add("desc");
        typeName.add("asc");
        return typeName.contains(value);
    }
}

3 自定义分组validator,创建lclass标识不通的分组

package com.example.shiro.validator;

public interface AreaCon {
}
package com.example.shiro.validator;

public interface TestCon {
}

4 实体类

1)校验参数值不可以为空

@NotNull(message = “num 值不允许为null”)
private Integer num;

2)分组参数校验,当控制层使用TestCon.class分组时 则校验page值不允许为空

@NotNull(groups = {TestCon.class},message = “当前页面不允许为空”)
private String page ; //当前页面

3)使用自定义注解参数校验,orderByValue必须是asc 或者 desc

@NotNull(message = “排序方式不允许为空”)
@MyValidate
private String orderByValue;

package com.example.shiro.entity;

import com.example.shiro.annotation.MyValidate;
import com.example.shiro.validator.AreaCon;
import com.example.shiro.validator.TestCon;
import lombok.Data;

import javax.validation.constraints.NotNull;

@Data
public class PageList {

    /**
     * 排序方式 desc or asc
     */
    @NotNull(message = "排序方式不允许为空")
    @MyValidate
    private String orderByValue;
    /**
     * 当前页
     */
    @NotNull(groups = {TestCon.class},message = "当前页面不允许为空")
    private String page ; //当前页面

    /**
     * 是否默认 0 否 1 是
     */
    @NotNull(groups = {AreaCon.class},message = "flag不允许为空")
    private String flag;

}

5 控制层代码

package com.example.shiro.controller;

import com.example.shiro.annotation.MyLogs;
import com.example.shiro.entity.MyResult;
import com.example.shiro.entity.PageList;
import com.example.shiro.validator.AreaCon;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.groups.Default;

@RestController
public class MyLogApi {


    @GetMapping("/hello")
    @MyLogs()
    public String getResHomeInformation(){
        return "hello api";
    }
    @PostMapping("/hello2")
    @MyLogs()
    public MyResult getResBuryListInfo(@Validated @RequestBody PageList pageList) {
        return new MyResult(true,"hello api 2");
    }

    @PostMapping("/hello3")
    @MyLogs()
    public MyResult getResBuryListInfoa(@Validated({AreaCon.class}) @RequestBody PageList pageList) {
        return new MyResult(true,"hello api 3");
    }

    @PostMapping("/hello4")
    @MyLogs()
    public MyResult getResBuryListInfoa4(@Validated({AreaCon.class,Default.class}) @RequestBody PageList pageList) {
        return new MyResult(true,"hello api 4");
    }
}

6 全局异常处理

6.1 全局异常捕获
package com.example.shiro.handler;

import com.example.shiro.entity.MyResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public MyResult expHandler(HttpServletRequest request, Exception e) {
        e.printStackTrace();
        return new MyResult(e);
    }
}
6.2 具体异常处理,code=1013为传递参数异常
package com.example.shiro.entity;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.shiro.constants.MyConstants;
import com.example.shiro.enums.MyCode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.yaml.snakeyaml.constructor.DuplicateKeyException;

import java.io.Serializable;
import java.net.ConnectException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyResult<T> implements Serializable {
    private static final long serialVersionUID = 1071681926787951549L;

    private Boolean success;

    /**
     *<p>状态码</p>
     */
    private Integer code;
    /**
     * <p>业务码</p>
     */
    private String operate;
    /**
     *<p> 状态说明</p>
     */
    private String message;
    /**
     * <p>返回数据</p>
     */
    private T data;


    public MyResult(boolean success) {
        this.success = success;
        this.code = success ? MyCode.SUCCESS.getCode() : MyCode.COMMON_FAIL.getCode();
        this.message = success ? MyCode.SUCCESS.getMessage() : MyCode.COMMON_FAIL.getMessage();
    }

    public MyResult(boolean success, MyCode resultEnum) {
        this.success = success;
        this.code = success ? MyCode.SUCCESS.getCode() : (resultEnum == null ? MyCode.COMMON_FAIL.getCode() : resultEnum.getCode());
        this.message = success ? MyCode.SUCCESS.getMessage() : (resultEnum == null ? MyCode.COMMON_FAIL.getMessage() : resultEnum.getMessage());
    }

    public MyResult(boolean success, String message) {
        this.success = success;
        this.code = success ? MyCode.SUCCESS.getCode() : MyCode.COMMON_FAIL.getCode();
        this.message = message;
    }

    public MyResult(boolean success, T data) {
        this.success = success;
        this.code = success ? MyCode.SUCCESS.getCode() : MyCode.COMMON_FAIL.getCode();
        this.message = success ? MyCode.SUCCESS.getMessage() : MyCode.COMMON_FAIL.getMessage();
        this.data = data;
    }

    public MyResult(boolean success, MyCode resultEnum, T data) {
        this.success = success;
        this.code = success ? MyCode.SUCCESS.getCode() : (resultEnum == null ? MyCode.COMMON_FAIL.getCode() : resultEnum.getCode());
        this.message = success ? MyCode.SUCCESS.getMessage() : (resultEnum == null ? MyCode.COMMON_FAIL.getMessage() : resultEnum.getMessage());
        this.data = data;
    }

    public MyResult(Throwable throwable) {
        this.operate = MyConstants.OPERATE_FAILED;
        if (throwable instanceof NullPointerException) {
            this.code = 1001;
            this.message = "空指针:" + throwable;
        } else if (throwable instanceof ClassCastException) {
            this.code = 1002;
            this.message = "类型强制转换异常:" + throwable;
        } else if (throwable instanceof ConnectException) {
            this.code = 1003;
            this.message = "链接失败:" + throwable;
        } else if (throwable instanceof IllegalArgumentException) {
            this.code = 1004;
            this.message = "传递非法参数异常:" + throwable;
        } else if (throwable instanceof NumberFormatException) {
            this.code = 1005;
            this.message = "数字格式异常:" + throwable;
        } else if (throwable instanceof IndexOutOfBoundsException) {
            this.code = 1006;
            this.message = "下标越界异常:" + throwable;
        } else if (throwable instanceof SecurityException) {
            this.code = 1007;
            this.message = "安全异常:" + throwable;
        } else if (throwable instanceof SQLException) {
            this.code = 1008;
            this.message = "数据库异常:" + throwable;
        } else if (throwable instanceof ArithmeticException) {
            this.code = 1009;
            this.message = "算术运算异常:" + throwable;
        } else if (throwable instanceof DuplicateKeyException) {
            this.code = 1011;
            this.message = "存在重复数据,标签名称: " + throwable.getMessage().substring(throwable.getMessage().indexOf("'") + 1, throwable.getMessage().indexOf("-"));
        } else if (throwable instanceof MissingServletRequestParameterException) {
            this.code = 1012;
            this.message = "参数缺失," + throwable.getMessage().substring(throwable.getMessage().indexOf("'"));
        } else if (throwable instanceof UnknownAccountException) {
            this.code = MyCode.USER_ACCOUNT_NOT_EXIST.getCode();
            this.message = MyCode.USER_ACCOUNT_NOT_EXIST.getMessage();
        } else if (throwable instanceof IncorrectCredentialsException) {
            this.code = MyCode.USER_CREDENTIALS_ERROR.getCode();
            this.message = MyCode.USER_CREDENTIALS_ERROR.getMessage();
        }  else if (throwable instanceof AuthenticationException) {
            this.code = MyCode.USER_ACCOUNT_EXPIRED.getCode();
            this.message = MyCode.USER_ACCOUNT_EXPIRED.getMessage();
        } else if (throwable instanceof RuntimeException) {
            this.code = 1010;
            this.message = "运行时异常:" + throwable;
        } else if (throwable instanceof MethodArgumentNotValidException) {
            this.code = 1013;
            List<ObjectError> allErrors = ((MethodArgumentNotValidException) throwable).getBindingResult().getAllErrors();
            List<Map> result = new ArrayList<>();
            for(int i=0;i<allErrors.size();i++){
                final String s = JSON.toJSONString(allErrors.get(i));
                JSONObject jsonObject = JSONObject.parseObject(s);
                String field = jsonObject.getString("field");
                if(field==null){
                    field = "";
                }
                String defaultMessage = allErrors.get(i).getDefaultMessage();
                Map<String,Object> map = new HashMap<>();
                map.put(field,defaultMessage);
                result.add(map);
            }
            this.message = "参数校验不通过";
            this.data = (T)result;
        } else if (throwable instanceof Exception) {
            this.code = 9999;
            this.message = "系统繁忙,请稍后重试:" + throwable.getMessage();
        }
    }
}

7 代码运行结果

接口参数结果
http://127.0.0.1:8000/hello2{ }{ “success”: null, “code”: 1013, “operate”: “failed”, “message”: “参数校验不通过”, “data”: [ { “orderByValue”: “排序方式不允许为空” }, { “num”: “num 值不允许为null” }, { “orderByValue”: “orderByValue 的值不在可选范围内[desc,asc]” } ]}
http://127.0.0.1:8000/hello3{ }{ “success”: null, “code”: 1013, “operate”: “failed”, “message”: “参数校验不通过”, “data”: [ { “flag”: “flag不允许为空” } ]}
http://127.0.0.1:8000/hello4{ }{ “success”: null, “code”: 1013, “operate”: “failed”, “message”: “参数校验不通过”, “data”: [ { “num”: “num 值不允许为null” }, { “orderByValue”: “orderByValue 的值不在可选范围内[desc,asc]” }, { “flag”: “flag不允许为空” }, { “orderByValue”: “排序方式不允许为空” } ]}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值