Java参数合法性校验(Hibernate Validator)及全局异常处理

作者:不染心

时间:2022/6/5

🍃源码地址:https://download.csdn.net/download/qq_38234785/85557796

简介

在程序开发中,经常要对数据进行校验后再进行业务处理。如果在业务代码中进行Bean的字段校验,会使得代码变的十分繁琐。JSR303 - Bean Validation 为JavaBean的验证定义了相关的元数据模型和API。

This JSR will define a meta-data model and API for JavaBeanTM validation based on annotations, with overrides and extended meta-data through the use of XML validation descriptors.

在 java 8 之后,又推出了JSR380 - Bean Validation 2.0

This JSR aims at evolving the Bean Validation specification by leveraging Java 8 language constructs for the purposes of validation.

Hibernate Validator 是 Bean Validation 的实现,Hibernate Validator 内置了 JSR303/JSR380 中所有的 constraint 的实现,还额外提供了很多自定义的 constraint。

项目目录结果如下:
    |--- controller
        |--- UserController
    |--- entity
        |--- CodeMsgException
        |--- GlobalException
        |--- User
    |--- interceptor
        |--- GlobalExceptionHandler
    |--- Utils
        |--- PatternContents

导入本项目依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>


    <!--    validator参数校验    -->
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.7.Final</version>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>3.0.0</version>
    </dependency>
    <!--    validator参数校验    -->

Java参数合法性校验(Hibernate Validator)

🍀 UserController.java

package com.example.valitedpro.controller;


import com.example.valitedpro.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * @author dyl
 * @description:
 * @date 2022/6/3 0003 下午 22:03
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/api")
public class UserController {

    @PostMapping("/add")
    public String addSysUser(@Validated User user) throws Exception {
        log.info("开始测试参数校验功能");
        return "validator参数校验";
    }
}

🍀 User.java

package com.example.valitedpro.entity;


import com.example.valitedpro.Utils.PatternContents;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import javax.validation.constraints.*;


/**
 * @author dyl
 * @description:
 * @date 2022/6/3 0003 下午 20:57
 */
@Data
@ToString
@AllArgsConstructor
public class User {
    /**
     * 将正则表达式与异常描述存储在PatternContents类中
     */    
    @Pattern(regexp = PatternContents.SYSUSER_NAME_TYPE, message = PatternContents.SYSUSER_NAME_DES)
    private String user_name;


    @Size(min = 5, max = 20, message = "pass太短了")
    private String user_pass;
}

🍀 PatternContents.java

package com.example.valitedpro.Utils;

/**
 * @Author: dyl
 * @Data: 2021/7/17
 * @Description: 参数校验正则表达式
 *
 */
public class PatternContents {
    /**
     * 整数
     */
    private static final String V_INTEGER = "^-?[1-9]\\d*$";

    /**
     * 正整数
     */
    private static final String V_POSITIVE_INTEGER = "^[1-9]\\d*$";

    /**
     * 负整数
     */
    private static final String V_NEGATIVE_INTEGER = "^-[1-9]\\d*$";

    /**
     * 数字
     */
    private static final String V_NUMBER = "^([+-]?)\\d*\\.?\\d+$";

    /**
     * 正数
     */
    private static final String V_POSITIVE_NUMBER = "^[1-9]\\d*|0$";

    /**
     * 负数
     */
    private static final String V_NEGATINE_NUMBER = "^-[1-9]\\d*|0$";

    /**
     * 浮点数
     */
    private static final String V_FLOAT = "^([+-]?)\\d*\\.\\d+$";

    /**
     * 正浮点数
     */
    private static final String V_POSTTIVE_FLOAT = "^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*$";

    /**
     * 负浮点数
     */
    private static final String V_NEGATIVE_FLOAT = "^-([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*)$";

    /**
     * 非负浮点数(正浮点数 + 0)
     */
    private static final String V_UNPOSITIVE_FLOAT = "^[1-9]\\d*.\\d*|0.\\d*[1-9]\\d*|0?.0+|0$";

    /**
     * 非正浮点数(负浮点数 + 0)
     */
    private static final String V_UNNEGATIVE_FLOAT = "^(-([1-9]\\d*.\\d*|0.\\d*[1-9]\\d*))|0?.0+|0$";

    /**
     * 邮件
     */
    private static final String V_EMAIL = "^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$";

    /**
     * 颜色
     */
    private static final String V_COLOR = "^[a-fA-F0-9]{6}$";

    /**
     * url
     */
    private static final String V_URL = "^http[s]?:\\/\\/([\\w-]+\\.)+[\\w-]+([\\w-./?%&=]*)?$";

    /**
     * 仅中文
     */
    private static final String V_CHINESE = "^[\\u4E00-\\u9FA5\\uF900-\\uFA2D]+$";

    /**
     * 仅ACSII字符
     */
    private static final String V_ASCII = "^[\\x00-\\xFF]+$";

    /**
     * 邮编
     */
    private static final String V_ZIPCODE = "^\\d{6}$";

    /**
     * 手机
     */
    public static final String V_MOBILE = "^(1)[0-9]{10}$";

    /**
     * ip地址
     */
    private static final String V_IP4 = "^(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)$";

    /**
     * 非空
     */
    private static final String V_NOTEMPTY = "^\\S+$";

    /**
     * 图片
     */
    private static final String V_PICTURE = "(.*)\\.(jpg|bmp|gif|ico|pcx|jpeg|tif|png|raw|tga)$";

    /**
     * 压缩文件
     */
    private static final String V_RAR = "(.*)\\.(rar|zip|7zip|tgz)$";

    /**
     * 日期
     */
    private static final String V_DATE = "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-)) (20|21|22|23|[0-1]?\\d):[0-5]?\\d:[0-5]?\\d$";

    /**
     * QQ号码
     */
    private static final String V_QQ_NUMBER = "^[1-9]*[1-9][0-9]*$";

    /**
     * 电话号码的函数(包括验证国内区号,国际区号,分机号)
     */
    private static final String V_TEL = "^(([0\\+]\\d{2,3}-)?(0\\d{2,3})-)?(\\d{7,8})(-(\\d{3,}))?$";

    /**
     * 用来用户注册。匹配由数字、26个英文字母或者下划线组成的字符串
     */
    private static final String V_USERNAME = "^\\w+$";

    /**
     * 字母
     */
    private static final String V_LETTER = "^[A-Za-z]+$";

    /**
     * 大写字母
     */
    private static final String V_LETTER_UPPER = "^[A-Z]+$";

    /**
     * 小写字母
     */
    private static final String V_LETTER_LOWER = "^[a-z]+$";

    /**
     * 身份证
     */
    private static final String V_IDCARD = "^(\\d{15}$|^\\d{18}$|^\\d{17}(\\d|X|x))$";

    /**
     * 验证密码(数字和英文同时存在)
     */
    private static final String V_PASSWORD_REG = "[A-Za-z]+[0-9]";

    /**
     * 验证密码长度(6-18位)
     */
    private static final String V_PASSWORD_LENGTH = "^\\d{6,18}$";

    /**
     * 验证两位数
     */
    private static final String V_TWO_POINT = "^[0-9]+(.[0-9]{2})?$";

    /**
     * 验证一个月的31天
     */
    private static final String V_31DAYS = "^((0?[1-9])|((1|2)[0-9])|30|31)$";


    /**
     * 公共参数校验
     */
    // 手机号
    public static final String PHONE_TYPE = "^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$";
    public static final String PHONE_DES = "电话号码不合法";

    // email
    public static final String EMAIL_TYPE = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$";
    public static final String EMAIL_DES = "Email不合法";

    // 身份证号码
    public static final String IDCARD_TYPE = "^\\d{15}|\\d{18}$";
    public static final String IDCARD_DES = "身份证不合法";

    // 中文名字
    public static final String CHINESE_NAME_TPYE = "^[\\u4e00-\\u9fa5]{2,}$";
    public static final String CHINESE_NAME_DES = "长度大于2的中文名字";

    /**
     * ========= Sysuser ===============
     */
    // 账户名称
    public static final String SYSUSER_NAME_TYPE = "^.{8,}$";
    public static final String SYSUSER_NAME_DES = "用户名称长度应大于8";

    // 账户密码
    public static final String SYSUSER_PASS_TYPE = "^(\\w){6,20}$";
    public static final String SYSUSER_PASS_DES = "用户密码长度应大于6";


    /**
     * ========= role ===============
     */
    public static final String ROLE_CODE = "^[A-Za-z]{2,}$";
    public static final String ROLE_DESCRIPTION = "^.{2,}$";

}

Java全局异常处理

在项目中异常处理是与用户交互,提升系统友好性的重要手段,尤为重要。代码中每次出现异常的地方都需要try catch则会出现大量的冗余代码,不方便代码的统一管理。所以,我们在项目中配置一个异常拦截器,在其中对异常进行统一处理,不需要写那么多try catch

🍀 CodeMsgException.java

package com.example.valitedpro.entity;

import java.io.Serializable;

/**
 * @Author: dyl
 * @Data: 2021/7/17
 * @Description: 异常返回信息
 *
 */

public class CodeMsgException implements Serializable {
    private int code;
    private String msg;

    //通用异常
    public static CodeMsgException SUCCESS = new CodeMsgException(0, "success");
    public static CodeMsgException SERVER_ERROR = new CodeMsgException(500100, "服务端异常");
    //注意  %s ,格式化字符串
    public static CodeMsgException SERVER_BIND_ERROR = new CodeMsgException(500101, "服务端绑定异常:%s");
    //登录模块 5002XX
    public static CodeMsgException MSG_NAME_IS_EMPTY = new CodeMsgException(500200, "用户名不能为空!");
    public static CodeMsgException MSG_PASSWORD_IS_EMPTY = new CodeMsgException(500201, "密码不能为空!");
    public static CodeMsgException MSG_MOBILE_ERROR = new CodeMsgException(500202, "手机号格式不正确!");
    public static CodeMsgException MSG_MOBILE_IS_EMPTY = new CodeMsgException(500203, "手机号不能为空!");
    public static CodeMsgException MSG_MOBILE_NOT_EXIST = new CodeMsgException(500204, "手机号不存在!");
    public static CodeMsgException MSG_PASSWORD_ERROR = new CodeMsgException(500205, "密码错误!");

    //权限模块 5003XX
    public static CodeMsgException MSG_PERMISSION_NEED_ADMIN = new CodeMsgException(500301, "需要管理员权限!");


    private CodeMsgException(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public CodeMsgException fillArgs(Object ... args){
        int code=this.code;
        String message=String.format(msg,args);
        return new CodeMsgException(code,message);
    }
    public int getCode() {
        return code;
    }
    public String getMsg() {
        return msg;
    }
}

🍀 GlobalException.java

package com.example.valitedpro.entity;

import java.io.Serializable;

/**
 * @Author: dyl
 * @Data: 2021/7/17
 * @Description: 全局异常类
 *
 */
public class GlobalException extends RuntimeException implements Serializable {
    private CodeMsgException codeMsgException;
    public GlobalException(CodeMsgException codeMsgException){
        super(codeMsgException.toString());
        this.codeMsgException = codeMsgException;

    }

    public CodeMsgException getCodeMsg() {
        return codeMsgException;
    }
}

🍀 GlobalExceptionHandler.java

package com.example.valitedpro.interceptor;




import com.example.valitedpro.entity.CodeMsgException;
import com.example.valitedpro.entity.GlobalException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @Author: dyl
 * @Data: 2021/7/17
 * @Description: 异常拦截器,处理系统中出现的异常,或者是自定义异常
 *
 */

@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
public class GlobalExceptionHandler {
    @ExceptionHandler({Exception.class, BindException.class})
    public CodeMsgException exceptionHandler(HttpServletRequest request, Exception e) {
        System.out.println(e);
        // 本地自定义异常处理
        if(e instanceof GlobalException){
            return ((GlobalException) e).getCodeMsg();
        }
        //绑定异常是需要明确提示给用户的
        else if (e instanceof BindException) {
            BindException exception = (BindException) e;
            List<ObjectError> errors = exception.getAllErrors();
            //获取自错误信息
            String msg = errors.get(0).getDefaultMessage();
            //将具体错误信息设置到CodeMsg中返回
            return CodeMsgException.SERVER_BIND_ERROR.fillArgs(msg);
        }
        // 系统异常处理
        return CodeMsgException.SERVER_BIND_ERROR.fillArgs(e.getCause() + e.getMessage());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不染心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值