验证短信登录或注册
Bo(business object)
封装业务对象的属性
- 只包含业务对象的属性;
- 只包含业务方法;
- 两者都包含。
service层和web层进行数据交换用BO
从业务模型角度看,见UML元件领域模型中的领域对象。
通过调用DAO方法,结合PO,VO进行业务操作。把业务逻辑封装为一个对象。这个对象可以包括一个或多个其它的对象。
因为验证登录注册需要手机号验证码 我们封装一个手机号验证码的BO
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
public class RegisterLoginBO {
@NotBlank(message = "手机号不能为空")
private String mobile;
@NotBlank(message = "验证码不能为空")
private String smsCode;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getSmsCode() {
return smsCode;
}
public void setSmsCode(String smsCode) {
this.smsCode = smsCode;
}
}
Vaild 注解以及BindingResult类
当对类中的字段进行校验我们一般有两种方法
方法一: 在业务代码中直接使用if语句判断字段是否为空 但是这种方法不好 会导致代码冗余度高
方法二: 使用vaild注解 交给spring处理即可
导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@Null
限制只能为null
@NotNull
限制必须不为null
@AssertFalse
限制必须为false
@AssertTrue
限制必须为true
@DecimalMax(value)
限制必须为一个不大于指定值的数字
@DecimalMin(value)
限制必须为一个不小于指定值的数字
@Digits(integer,fraction)
限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future
限制必须是一个将来的日期
@Max(value)
限制必须为一个不大于指定值的数字
@Min(value)
限制必须为一个不小于指定值的数字
@Past
限制必须是一个过去的日期
@Pattern(value)
限制必须符合指定的正则表达式
@Size(max,min)
限制字符长度必须在min到max之间
@Past
验证注解的元素值(日期类型)比当前时间早
@NotEmpty
验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank
验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email
验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
在类中添加即可
之后在controller方法中添加vaild注解即可
BindingResult 类中封装的valid注解中引发的错误
boolean hasErrors();中判断是否有错误
bindResult.getFieldErrors(); 获取所有字段
fieldError.getField() 获取字段
fieldError.getDefaultMessage()) 获取错误
因为别的controller可能会用到此方法 所以要封装到baseController中
/**
* 循环取出BO中的错误并返回
* @param bindResult
* @return
*/
protected Map<String, String> getBindResultErrors(BindingResult bindResult) {
Map<String, String> errorsMap = new HashMap<>();
List<FieldError> fieldErrors = bindResult.getFieldErrors();
fieldErrors.forEach((fieldError -> {
errorsMap.put(fieldError.getField(), fieldError.getDefaultMessage());
}));
return errorsMap;
}
验证思路
首先判断字段是否合法 也就是手机号和验证码是否为非空
其次redis中的字段是否匹配
@Override
public GraceJSONResult doLogin(RegisterLoginBO registerLoginBO, BindingResult bindResult) {
// 01 首先判断字段是否有错
if (bindResult.hasErrors()) {
Map<String, String> bindResultErrors = getBindResultErrors(bindResult);
return GraceJSONResult.errorMap(bindResultErrors);
}
// 02 判断手机号和验证码是否匹配
String mobile = registerLoginBO.getMobile();
String smsCode = registerLoginBO.getSmsCode();
String redisSMSCode = redisOperator.get(MOBILE_SMS_CODE + ":" + mobile);
if (StringUtils.isBlank(redisSMSCode) || !smsCode.equals(redisSMSCode)) {
return GraceJSONResult.errorCustom(ResponseStatusEnum.SMS_CODE_ERROR);
}
return GraceJSONResult.ok();
}
首先获取到手机号 验证码
在根据手机号获取到redis中的验证码
判断验证码是否为空 也就是在redis中查询不到
其次在判断前端传入的验证码是否和redis中的验证码匹配 若匹配直接返回ok
分组校验
根据不同的功能进行校验 如当进行删除操作时必须传入id 当进行插入操作时因为id时自增的 可以不用传入id
首先创建另个接口用于不同分组
public interface UpdateValid {
}
public interface AddValid {
}
使用group参数来进行分组
Null注解表示必须为空 当进行更新操作时 必须传入品牌id 当进行插入操作时 必须不指定id
然后在controller中定义所需操作即可
自定义校验注解
首先我们定义一个注解 注解上的注解可以看系统定义的注解 基本都一样 其中Constraint注解用于定义校验器
我们还在接口体中定义了一个values方法 用于记录传入的列表
message表示自定义的错误信息 校验失败默认会显示该信息 参数为包名
之后在resource中定义一个名为ValidationMessages.properties的文件 文件中配置之前写入message
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = { ValueListConstrain.class }
)
public @interface ValueList {
String message() default "{com.lyra.mail.common.valueList.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] values();
}
校验器
校验器范形方法1为自定义的注解 2为注解传入的类型
然后方法体 可以使用constraintAnnotation传入的values参数 这里传入的是1 0 然后使用isValid来进行校验 若set中不包含statusCode传入的参数 则表示校验失败
public class ValueListConstrain implements ConstraintValidator<ValueList, Integer> {
private final Set<Integer> set = new HashSet<>();
@Override
public void initialize(ValueList constraintAnnotation) {
for (int value : constraintAnnotation.values()) {
set.add(value);
}
}
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(integer);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律