版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
告别if-else校验代码,参数校验这么写才足够优雅很痛苦遇到大量的参数进行校验,在业务中还要抛出异常或者不断的返回异常时的校验信息,在代码中相当冗长,充满了if-else这种校验代码,今天我们就来学习spring的javax.validation注解式参数校验.为什么要用validatorjavax.validation的一系列注解可以帮我们完成参数校验,免去繁琐的串行校验不然我们的代码就像下面这样:
//
http://localhost:8080/api/user/save/serial
/**
*
走串行校验
*
*
@param
userVO
*
@return
*/
@PostMapping("/save/serial")
public
Object
save(@RequestBody
UserVO
userVO)
{
String
mobile
=
userVO.getMobile();
//手动逐个
参数校验~
写法
if
(StringUtils.isBlank(mobile))
{
return
RspDTO.paramFail("mobile:手机号码不能为空");
}
else
if
(!Pattern.matches("^[1][3,4,5,6,7,8,9][0-9]{9}$",
mobile))
{
return
RspDTO.paramFail("mobile:手机号码格式不对");
}
//抛出自定义异常等~写法
if
(StringUtils.isBlank(userVO.getUsername()))
{
throw
new
BizException(Constant.PARAM_FAIL_CODE,
"用户名不能为空");
}
//
比如写一个map返回
if
(StringUtils.isBlank(userVO.getSex()))
{
Map
result
=
new
HashMap<>(5);
result.put("code",
Constant.PARAM_FAIL_CODE);
result.put("msg",
"性别不能为空");
return
result;
}
//.........各种写法
...
userService.save(userVO);
return
RspDTO.success();
}
这被大佬看见,一定说,都9102了还这么写,然后被劝退了.....什么是javax.validationJSR303是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面(面向注解编程的时代),就可以在需要校验的时候进行校验了,在SpringBoot中已经包含在starter-web中,再其他项目中可以引用依赖,并自行调整版本:
javax.validation
validation-api
1.1.0.Final
org.hibernate
hibernate-validator
5.2.0.Final
注解说明
1.@NotNull:不能为null,但可以为empty("","
","
")
2.@NotEmpty:不能为null,而且长度必须大于0
("
","
")
3.@NotBlank:只能作用在String上,不能为null,而且调用trim()后,长度必须大于0("test")
即:必须有实际字符
验证注解验证的数据类型说明@AssertFalseBoolean,boolean验证注解的元素值是false@AssertTrueBoolean,boolean验证注解的元素值是true@NotNull任意类型验证注解的元素值不是null@Null任意类型验证注解的元素值是null@Min(value=值)BigDecimal,BigInteger,byte,short,int,long,等任何Number或CharSequence(存储的是数字)子类型验证注解的元素值大于等于@Min指定的value值@Max(value=值)和@Min要求一样验证注解的元素值小于等于@Max指定的value值@DecimalMin(value=值)和@Min要求一样验证注解的元素值大于等于@DecimalMin指定的value值@DecimalMax(value=值)和@Min要求一样验证注解的元素值小于等于@DecimalMax指定的value值@Digits(integer=整数位数,fraction=小数位数)和@Min要求一样验证注解的元素值的整数位数和小数位数上限@Size(min=下限,max=上限)字符串、Collection、Map、数组等验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小@Pastjava.util.Date,java.util.Calendar;JodaTime类库的日期类型验证注解的元素值(日期类型)比当前时间早@Future与@Past要求一样验证注解的元素值(日期类型)比当前时间晚@NotBlankCharSequence子类型验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的首位空格@Length(min=下限,max=上限)CharSequence子类型验证注解的元素值长度在min和max区间内@NotEmptyCharSequence子类型、Collection、Map、数组验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)@Range(min=最小值,max=最大值)BigDecimal,BigInteger,CharSequence,byte,short,int,long等原子类型和包装类型验证注解的元素值在最小值和最大值之间@Email(regexp=正则表达式,flag=标志的模式)CharSequence子类型(如String)验证注解的元素值是Email,也可以通过regexp和flag指定自定义的email格式@Pattern(regexp=正则表达式,flag=标志的模式)String,任何CharSequence的子类型验证注解的元素值与指定的正则表达式匹配@Valid任何非原子类型指定递归验证关联的对象如用户对象中有个地址对象属性,如果想在验证用户对象时一起验证地址对象的话,在地址对象上加@Valid注解即可级联验证此处只列出HibernateValidator提供的大部分验证约束注解,请参考hibernatevalidator官方文档了解其他验证约束注解和进行自定义的验证约束注解定义。实战演练话不多说,直接走实践路线,同样使用的是SpringBoot的快速框架,详细代码见:/leaJone/myb…在公众号后端架构师后台回复“架构整洁”,获取一份惊喜礼包。1.@Validated声明要检查的参数这里我们在控制器层进行注解声明
/**
*
走参数校验注解
*
*
@param
userDTO
*
@return
*/
@PostMapping("/save/valid")
public
RspDTO
save(@RequestBody
@Validated
UserDTO
userDTO)
{
userService.save(userDTO);
return
RspDTO.success();
}
2.对参数的字段进行注解标注import
lombok.Data;
import
org.hibernate.validator.constraints.Length;
import
javax.validation.constraints.*;
import
java.io.Serializable;
import
java.util.Date;
/**
*
@author
LiJing
*
@ClassName:
UserDTO
*
@Description:
用户传输对象
*
@date
2019/7/30
13:55
*/
@Data
public
class
UserDTO
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L;
/***
用户ID*/
@NotNull(message
=
"用户id不能为空")
private
Long
userId;
/**
用户名*/
@NotBlank(message
=
"用户名不能为空")
@Length(max
=
20,
message
=
"用户名不能超过20个字符")
@Pattern(regexp
=
"^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$",
message
=
"用户昵称限制:最多20字符,包含文字、字母和数字")
private
String
username;
/**
手机号*/
@NotBlank(message
=
"手机号不能为空")
@Pattern(regexp
=
"^[1][3,4,5,6,7,8,9][0-9]{9}$",
message
=
"手机号格式有误")
private
String
mobile;
/**性别*/
private
String
sex;
/**
邮箱*/
@NotBlank(message
=
"联系邮箱不能为空")
@Email(message
=
"邮箱格式不对")
private
String
email;
/**
密码*/
private
String
password;
/***
创建时间
*/
@Future(message
=
"时间必须是将来时间")
private
Date
createTime;
}
3.在全局校验中增加校验异常MethodArgumentNotValidException是springBoot中进行绑定参数校验时的异常,需要在springBoot中处理,其他需要处理ConstraintViolationException异常进行处理.为了优雅一点,我们将参数异常,业务异常,统一做了一个全局异常,将控制层的异常包装到我们自定义的异常中为了优雅一点,我们还做了一个统一的结构体,将请求的code,和msg,data一起统一封装到结构体中,增加了代码的复用性import
com.boot.lea.mybot.dto.RspDTO;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
org.springframework.dao.DuplicateKeyException;
import
org.springframework.web.bind.MethodArgumentNotValidException;
import
org.springframework.web.bind.annotation.ExceptionHandler;
import
org.springframework.web.bind.annotation.RestControllerAdvice;
import
org.springframework.web.servlet.NoHandlerFoundException;
import
javax.validation.ConstraintViolationException;
import
javax.validation.ValidationException;
/**
*
@author
LiJing
*
@ClassName:
GlobalExceptionHandler
*
@Description:
全局异常处理器
*
@date
2019/7/30
13:57
*/
@RestControllerAdvice
public
class
GlobalExceptionHandler
{
private
Logger
logger
=
LoggerFactory.getLogger(getClass());
private
static
int
DUPLICATE_KEY_CODE
=
1001;
private
static
int
PARAM_FAIL_CODE
=
1002;
private
static
int
VALIDATION_CODE
=
1003;
/**
*
处理自定义异常
*/
@ExceptionHandler(BizException.class)
public
RspDTO
handleRRException(BizException
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(e.getCode(),
e.getMessage());
}
/**
*
方法参数校验
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public
RspDTO
handleMethodArgumentNotValidException(MethodArgumentNotValidException
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(PARAM_FAIL_CODE,
e.getBindingResult().getFieldError().getDefaultMessage());
}
/**
*
ValidationException
*/
@ExceptionHandler(ValidationException.class)
public
RspDTO
handleValidationException(ValidationException
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(VALIDATION_CODE,
e.getCause().getMessage());
}
/**
*
ConstraintViolationException
*/
@ExceptionHandler(ConstraintViolationException.class)
public
RspDTO
handleConstraintViolationException(ConstraintViolationException
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(PARAM_FAIL_CODE,
e.getMessage());
}
@ExceptionHandler(NoHandlerFoundException.class)
public
RspDTO
handlerNoFoundException(Exception
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(404,
"路径不存在,请检查路径是否正确");
}
@ExceptionHandler(DuplicateKeyException.class)
public
RspDTO
handleDuplicateKeyException(DuplicateKeyException
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(DUPLICATE_KEY_CODE,
"数据重复,请检查后提交");
}
@ExceptionHandler(Exception.class)
public
RspDTO
handleException(Exception
e)
{
logger.error(e.getMessage(),
e);
return
new
RspDTO(500,
"系统繁忙,请稍后再试");
}
}
4.测试如下确实做到了参数校验时返回异常信息和对应的code,方便了我们不再繁琐的处理参数校验在ValidationMperties就是校验的message,有着已经写好的默认的message,且是支持i18n的,大家可以阅读源码赏析自定义参数注解1.比如我们来个自定义身份证校验注解@Documented
@Target({ElementType.PARAMETER,
ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy
=
IdentityCardNumberValidator.class)
public
@interface
IdentityCardNumber
{
String
message()
default
"身份证号码不合法";
Class[]
groups()
default
{};
Class[]
payload()
default
{};
}
这个注解是作用在Field字段上,运行时生效,触发的是IdentityCardNumber这个验证类。message定制化的提示信息,主要是从ValidationMperties里提取,也可以依据实际情况进行定制groups这里主要进行将validator进行分类,不同的类group中会执行不同的validator操作payload主要是针对bean的,使用不多。2.然后自定义Validator这个是真正进行验证的逻辑代码:public
class
IdentityCardNumberValidator
implements
ConstraintValidator<IdentityCardNumber,
Object>
{
@Override
public
void
initialize(IdentityCardNumber
identityCardNumber)
{
}
@Override
public
boolean
isValid(Object
o,
ConstraintValidatorContext
constraintValidatorContext)
{
return
IdCardValidatorUtils.isValidate18Idcard(o.toString());
}
}
IdCardValidatorUtils在项目源码中,可自行查看3.使用自定义的注解
@NotBlank(message
=
"身份证号不能为空")
@IdentityCardNumber(message
=
"身份证信息有误,请核对后提交")
private
String
clientCardNo;
4.使用groups的校验有的宝宝说同一个对象要复用,比如UserDTO在更新时候要校验userId,在保存的时候不需要校验userId,在两种情况下都要校验username,那就用上groups了:在公众号顶级架构师后台回复“架构”,获取一份惊喜礼包。先定义groups的分组接口Create和Updateimport
javax.validation.groups.Default;
public
interface
Create
extends
Default
{
}
import
javax.validation.groups.Default;
public
interface
Update
extends
Default{
}
再在需要校验的地方@Validated声明校验组
/**
*
走参数校验注解的
groups
组合校验
*
*
@param
userDTO
*
@return
*/
@PostMapping("/update/groups")
public
RspDTO
update(@RequestBody
@Validated(Update.class)
UserDTO
userDTO)
{
userService.updateById(userDTO);
return
RspDTO.success();
}
在DTO中的字段上定义好groups={}的分组类型@Data
public
class
UserDTO
implements
Serializable
{
private
static
final
long
serialVersionUID
=
1L;
/***
用户ID*/
@NotNull(message
=
"用户id不能为空",
groups
=
Update.class)
private
Long
userId;
/**
*
用户名
*/
@NotBlank(message
=
"用户名不能为空")
@Length(max
=
20,
message
=
"用户名不能超过20个字符",
groups
=
{Create.class,
Update.class})
@Pattern(regexp
=
"^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$",
message
=
"用户昵称限制:最多20字符,包含文字、字母和数字")
private
String
username;
/**
*
手机号
*/
@NotBlank(message
=
"手机号不能为空")
@Pattern(regexp
=
"^[1][3,4,5,6,7,8,9][0-9]{9}$",
message
=
"手机号格式有误",
groups
=
{Create.class,
Update.class})
private
String
mobile;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 陇南家庭固化地坪施工方案
- 普通话测试说话范文50篇
- 三年级信息技术上册 画线条和填色说课稿 人教新课标版
- 电商运营案例教学与启发
- 人教版地理八年级下册第六章第三节《世界最大的黄土堆积区黄土高原》听课评课记录1
- 粤人版地理七年级上册《第三节 世界的主要气候类型》听课评课记录2
- 2025年度股权转让承债尽职调查报告合同
- 环保技术对人类生活方式的影响
- 电商平台的数据分析与运用
- 烟台企业绿色发展路径及政策支持研究
- 三年级上册数学脱式计算大全600题及答案
- 计算机控制系统 课件 第10章 网络化控制系统的分析与设计
- 鲁教版(五四制)七年级数学上册期末考试卷-附带答案
- 南京大学仪器分析习题集
- 空调维保应急预案
- 小学六年级数学上册解决问题专项必考题西师大版
- 2023年高考语文全国乙卷作文范文及导写(解读+素材+范文)课件版
- 模块建房施工方案
- 多域联合作战
- 定向钻出入土点平面布置图(可编辑)
- 美容美发场所卫生规范
评论
0/150
提交评论