1、前端校验
el-form的表单校验
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="密码" prop="pass">
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="确认密码" prop="checkPass">
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model.number="ruleForm.age"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
<el-button @click="resetForm('ruleForm')">重置</el-button>
</el-form-item>
</el-form>
<script>
export default {
data() {
var checkAge = (rule, value, callback) => {
if (!value) {
return callback(new Error('年龄不能为空'));
}
setTimeout(() => {
if (!Number.isInteger(value)) {
callback(new Error('请输入数字值'));
} else {
if (value < 18) {
callback(new Error('必须年满18岁'));
} else {
callback();
}
}
}, 1000);
};
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
if (this.ruleForm.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass');
}
callback();
}
};
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请再次输入密码'));
} else if (value !== this.ruleForm.pass) {
callback(new Error('两次输入密码不一致!'));
} else {
callback();
}
};
return {
ruleForm: {
pass: '',
checkPass: '',
age: ''
},
rules: {
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
],
age: [
{ validator: checkAge, trigger: 'blur' }
]
}
};
},
methods: {
}
}
</script>
自定义校验器
<el-form
:model="dataForm"
:rules="dataRule"
ref="dataForm"
@keyup.enter.native="dataFormSubmit()"
label-width="140px"
>
</el-form>
data() {
return {
visible: false,
dataForm: {
brandId: 0,
name: "",
logo: "",
descript: "",
showStatus: "",
firstLetter: "",
sort: "",
},
dataRule: {
name: [{required: true, message: "品牌名不能为空", trigger: "blur"}],
logo: [
{required: true, message: "品牌logo地址不能为空", trigger: "blur"},
],
descript: [
{required: true, message: "介绍不能为空", trigger: "blur"},
],
showStatus: [
{
required: true,
message: "显示状态[0-不显示;1-显示]不能为空",
trigger: "blur",
},
],
firstLetter: [
{
validator: (rule, value, callback) => {
if (value == "") {
callback(new Error("请输入首字母"));
} else if (!(/^[a-zA-Z]$/).test(value)) {
callback(new Error("请输入英文字母"));
} else {
callback();
}
}, trigger: "blur"
},
],
sort: [{
validator: (rule, value, callback) => {
if (value == '') {
callback(new Error("请输入排序字段"));
} else if (!Number.isInteger(value) || value < 0) {
callback(new Error('排序字段必须是一个整数并且大于0'))
} else {
callback();
}
}, trigger: "blur"
}],
},
};
},
2、JSR303后端校验
后端的校验注解:
代码:
package com.atguigu.gulimall.product.entity;
import com.atguigu.common.valid.AddGroup;
import com.atguigu.common.valid.ListValue;
import com.atguigu.common.valid.UpdateGroup;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
//import com.sun.istack.internal.NotNull;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
/**
* 品牌
*
* @author pansd
* @email [email protected]
* @date 2022-02-23 16:02:02
*/
@Data
@TableName("pms_brand")
public class PmsBrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
@Null(message = "新增时不能填写品牌id",groups = {AddGroup.class}) //实现分组检验;
@NotNull(message = "修改时必须填写品牌id",groups = {UpdateGroup.class})
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空",groups = {AddGroup.class,UpdateGroup.class}) //不能是一个空格,至少是一个非空字符;如果仅仅在此处标准,默认是不起作用的。得在controller@Valid//响应状态码为400,是校验不通过的。
private String name;
/**
* 品牌logo地址
*/
@URL //如果没有增加分组的校验,那么它的注解是不起作用的。@Validated({AddGroup.class})
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@ListValue(vals = {0,1})
private Integer showStatus;
/**
* 检索首字母
*/
@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母")
private String firstLetter;
/**
* 排序
*/
@Min(value = 0)
@NotNull //sort字段是一个Integer字段,不能使用notEmpty来标注
private Integer sort;
}
注意:此时在实体类中增加的校验是不起作用的。需要在controller中配置@Valid才能使用
代码如下:
@RequestMapping("/save2")
public R save2(@Valid @RequestBody PmsBrandEntity brandEntity){
pmsBrandService.save(brandEntity);
return R.ok();
}
此时,返回的错误信息较为杂乱,为了方便处理,需要返回统一的异常处理。
3、校验的统一异常处理
针对于某个接口进行特定的处理方式:
@RequestMapping("/save")
public R save(@Valid @RequestBody PmsBrandEntity pmsBrand, BindingResult bindingResult){ //获取校验结果的信息,从而对错误信息进行封装
//在json后边,紧跟着一个校验的结果。BindingResult bindingResult,拿到校验的结果,就可以封装。
boolean b = bindingResult.hasErrors(); //是否有错误
if(b){
Map<String,Object> map = new HashMap<>();
//获取校验数据的结果
bindingResult.getFieldErrors().forEach((item)->{
//获取校验字段的名字
String field = item.getField();
//获取校验信息
String defaultMessage = item.getDefaultMessage();
map.put(field,defaultMessage);
});
return R.error(400,"提交的数据不合法!").put("data",map);
}
pmsBrandService.save(pmsBrand);
return R.ok();
}
全局进行处理,代码如下:
@RequestMapping("/save2")
public R save2(@Valid @RequestBody PmsBrandEntity brandEntity){
pmsBrandService.save(brandEntity);
return R.ok();
}
package com.atguigu.gulimall.product.exception;
import com.atguigu.common.exception.BizCodeEnum;
import com.atguigu.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
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.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
/**
* @author pshdhx
* @date 2022-03-04 11:12
* @Des 统一标准来处理异常的
*/
@Slf4j
//@ControllerAdvice
//@ResponseBody
@RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
public class PshdhxGuliControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e){
BindingResult bindingResult = e.getBindingResult();
Map<String,Object> map = new HashMap<>();
bindingResult.getFieldErrors().forEach(item->{
//...
//获取校验字段的名字
String field = item.getField();
//获取校验信息
String defaultMessage = item.getDefaultMessage();
map.put(field,defaultMessage);
});
log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());
return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",map);
//return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",map);
}
@ExceptionHandler(value = Throwable.class)
public R handleException(Throwable throwable){
log.error("错误:",throwable);
return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(),BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
}
}
为了统一自定义异常编码,指定了枚举类型。
package com.atguigu.common.exception;
/**
* @author pshdhx
* @date 2022-03-04 11:25
*/
public enum BizCodeEnum {
UNKNOW_EXCEPTION(10000,"系统未知异常"),
VAILD_EXCEPTION(10001,"参数格式校验失败");
private int code;
private String msg;
BizCodeEnum(int code,String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
结果如下:
4、JSR303后端分组检验
比如说id这个字段,在新增时,不需要它;在修改时,必须要它,那么就需要对其进行分组处理
@Data
@TableName("pms_brand")
public class PmsBrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
@Null(message = "新增时不能填写品牌id",groups = {AddGroup.class}) //实现分组检验;
@NotNull(message = "修改时必须填写品牌id",groups = {UpdateGroup.class})
private Long brandId;
package com.atguigu.common.valid;
public interface AddGroup {
}
package com.atguigu.common.valid;
public interface UpdateGroup {
}
定义俩空接口即可。但是,要想使其生效,则必须在控制器中使用注解@Validated
//实现分组校验,这是添加是要校验的内容
@RequestMapping("/save4")
public R save4(@Validated({AddGroup.class}) @RequestBody PmsBrandEntity brandEntity){
pmsBrandService.save(brandEntity);
return R.ok();
}
但是,如果其他字段没有增加上相关的分组,则字段上的注释会失效。
5、JSR303自定义校验规则
我想让某个字段只输入0和1,需要自定义注解
@ListValue(vals = {0,1})
private Integer showStatus;
1、自定义校验规则
package com.atguigu.common.valid;
/*
自定义校验规则
*/
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.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class }) //关联
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "{com.atguigu.common.valid.ListValue.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals() default { };
}
2、自定义校验器
package com.atguigu.common.valid;
/**
* 自定义校验器
*/
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
//初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
//判断是否校验成功
/**
*
* @param value 需要校验的值
* @param context
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
return set.contains(value);
}
}
3、关联校验规则和校验器
@Documented
@Constraint(validatedBy = { ListValueConstraintValidator.class }) //关联
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
4、校验信息定义
ValidationMessages.properties
com.atguigu.common.valid.ListValue.message=必须提交指定的值
标签:vue,springboot,校验,value,element,callback,import,com,public From: https://blog.51cto.com/u_15890333/5884001