• springboot+vue+element-ui实现前后端的全部校验


    1、前端校验

    el-form的表单校验

    1. <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
    2. <el-form-item label="密码" prop="pass">
    3. <el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input>
    4. </el-form-item>
    5. <el-form-item label="确认密码" prop="checkPass">
    6. <el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input>
    7. </el-form-item>
    8. <el-form-item label="年龄" prop="age">
    9. <el-input v-model.number="ruleForm.age"></el-input>
    10. </el-form-item>
    11. <el-form-item>
    12. <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
    13. <el-button @click="resetForm('ruleForm')">重置</el-button>
    14. </el-form-item>
    15. </el-form>
    16. <script>
    17. export default {
    18. data() {
    19. var checkAge = (rule, value, callback) => {
    20. if (!value) {
    21. return callback(new Error('年龄不能为空'));
    22. }
    23. setTimeout(() => {
    24. if (!Number.isInteger(value)) {
    25. callback(new Error('请输入数字值'));
    26. } else {
    27. if (value < 18) {
    28. callback(new Error('必须年满18岁'));
    29. } else {
    30. callback();
    31. }
    32. }
    33. }, 1000);
    34. };
    35. var validatePass = (rule, value, callback) => {
    36. if (value === '') {
    37. callback(new Error('请输入密码'));
    38. } else {
    39. if (this.ruleForm.checkPass !== '') {
    40. this.$refs.ruleForm.validateField('checkPass');
    41. }
    42. callback();
    43. }
    44. };
    45. var validatePass2 = (rule, value, callback) => {
    46. if (value === '') {
    47. callback(new Error('请再次输入密码'));
    48. } else if (value !== this.ruleForm.pass) {
    49. callback(new Error('两次输入密码不一致!'));
    50. } else {
    51. callback();
    52. }
    53. };
    54. return {
    55. ruleForm: {
    56. pass: '',
    57. checkPass: '',
    58. age: ''
    59. },
    60. rules: {
    61. pass: [
    62. { validator: validatePass, trigger: 'blur' }
    63. ],
    64. checkPass: [
    65. { validator: validatePass2, trigger: 'blur' }
    66. ],
    67. age: [
    68. { validator: checkAge, trigger: 'blur' }
    69. ]
    70. }
    71. };
    72. },
    73. methods: {
    74. }
    75. }
    76. </script>

    自定义校验器

    1. <el-form
    2. :model="dataForm"
    3. :rules="dataRule"
    4. ref="dataForm"
    5. @keyup.enter.native="dataFormSubmit()"
    6. label-width="140px"
    7. >
    8. </el-form>
    9. data() {
    10. return {
    11. visible: false,
    12. dataForm: {
    13. brandId: 0,
    14. name: "",
    15. logo: "",
    16. descript: "",
    17. showStatus: "",
    18. firstLetter: "",
    19. sort: "",
    20. },
    21. dataRule: {
    22. name: [{required: true, message: "品牌名不能为空", trigger: "blur"}],
    23. logo: [
    24. {required: true, message: "品牌logo地址不能为空", trigger: "blur"},
    25. ],
    26. descript: [
    27. {required: true, message: "介绍不能为空", trigger: "blur"},
    28. ],
    29. showStatus: [
    30. {
    31. required: true,
    32. message: "显示状态[0-不显示;1-显示]不能为空",
    33. trigger: "blur",
    34. },
    35. ],
    36. firstLetter: [
    37. {
    38. validator: (rule, value, callback) => {
    39. if (value == "") {
    40. callback(new Error("请输入首字母"));
    41. } else if (!(/^[a-zA-Z]$/).test(value)) {
    42. callback(new Error("请输入英文字母"));
    43. } else {
    44. callback();
    45. }
    46. }, trigger: "blur"
    47. },
    48. ],
    49. sort: [{
    50. validator: (rule, value, callback) => {
    51. if (value == '') {
    52. callback(new Error("请输入排序字段"));
    53. } else if (!Number.isInteger(value) || value < 0) {
    54. callback(new Error('排序字段必须是一个整数并且大于0'))
    55. } else {
    56. callback();
    57. }
    58. }, trigger: "blur"
    59. }],
    60. },
    61. };
    62. },

     

    2、JSR303后端校验

    后端的校验注解:

    代码:

    1. package com.atguigu.gulimall.product.entity;
    2. import com.atguigu.common.valid.AddGroup;
    3. import com.atguigu.common.valid.ListValue;
    4. import com.atguigu.common.valid.UpdateGroup;
    5. import com.baomidou.mybatisplus.annotation.TableId;
    6. import com.baomidou.mybatisplus.annotation.TableName;
    7. import java.io.Serializable;
    8. import java.util.Date;
    9. //import com.sun.istack.internal.NotNull;
    10. import lombok.Data;
    11. import org.hibernate.validator.constraints.URL;
    12. import javax.validation.constraints.*;
    13. /**
    14. * 品牌
    15. *
    16. * @author pansd
    17. * @email 1152777670@qq.com
    18. * @date 2022-02-23 16:02:02
    19. */
    20. @Data
    21. @TableName("pms_brand")
    22. public class PmsBrandEntity implements Serializable {
    23. private static final long serialVersionUID = 1L;
    24. /**
    25. * 品牌id
    26. */
    27. @TableId
    28. @Null(message = "新增时不能填写品牌id",groups = {AddGroup.class}) //实现分组检验;
    29. @NotNull(message = "修改时必须填写品牌id",groups = {UpdateGroup.class})
    30. private Long brandId;
    31. /**
    32. * 品牌名
    33. */
    34. @NotBlank(message = "品牌名不能为空",groups = {AddGroup.class,UpdateGroup.class}) //不能是一个空格,至少是一个非空字符;如果仅仅在此处标准,默认是不起作用的。得在controller@Valid//响应状态码为400,是校验不通过的。
    35. private String name;
    36. /**
    37. * 品牌logo地址
    38. */
    39. @URL //如果没有增加分组的校验,那么它的注解是不起作用的。@Validated({AddGroup.class})
    40. private String logo;
    41. /**
    42. * 介绍
    43. */
    44. private String descript;
    45. /**
    46. * 显示状态[0-不显示;1-显示]
    47. */
    48. @ListValue(vals = {0,1})
    49. private Integer showStatus;
    50. /**
    51. * 检索首字母
    52. */
    53. @Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须是一个字母")
    54. private String firstLetter;
    55. /**
    56. * 排序
    57. */
    58. @Min(value = 0)
    59. @NotNull //sort字段是一个Integer字段,不能使用notEmpty来标注
    60. private Integer sort;
    61. }

     注意:此时在实体类中增加的校验是不起作用的。需要在controller中配置@Valid才能使用

    代码如下:

    1. @RequestMapping("/save2")
    2. public R save2(@Valid @RequestBody PmsBrandEntity brandEntity){
    3. pmsBrandService.save(brandEntity);
    4. return R.ok();
    5. }

     此时,返回的错误信息较为杂乱,为了方便处理,需要返回统一的异常处理。

    3、校验的统一异常处理

    针对于某个接口进行特定的处理方式:

    1. @RequestMapping("/save")
    2. public R save(@Valid @RequestBody PmsBrandEntity pmsBrand, BindingResult bindingResult){ //获取校验结果的信息,从而对错误信息进行封装
    3. //在json后边,紧跟着一个校验的结果。BindingResult bindingResult,拿到校验的结果,就可以封装。
    4. boolean b = bindingResult.hasErrors(); //是否有错误
    5. if(b){
    6. Map<String,Object> map = new HashMap<>();
    7. //获取校验数据的结果
    8. bindingResult.getFieldErrors().forEach((item)->{
    9. //获取校验字段的名字
    10. String field = item.getField();
    11. //获取校验信息
    12. String defaultMessage = item.getDefaultMessage();
    13. map.put(field,defaultMessage);
    14. });
    15. return R.error(400,"提交的数据不合法!").put("data",map);
    16. }
    17. pmsBrandService.save(pmsBrand);
    18. return R.ok();
    19. }

    全局进行处理,代码如下:

    1. @RequestMapping("/save2")
    2. public R save2(@Valid @RequestBody PmsBrandEntity brandEntity){
    3. pmsBrandService.save(brandEntity);
    4. return R.ok();
    5. }
    6. package com.atguigu.gulimall.product.exception;
    7. import com.atguigu.common.exception.BizCodeEnum;
    8. import com.atguigu.common.utils.R;
    9. import lombok.extern.slf4j.Slf4j;
    10. import org.springframework.validation.BindingResult;
    11. import org.springframework.web.bind.MethodArgumentNotValidException;
    12. import org.springframework.web.bind.annotation.ControllerAdvice;
    13. import org.springframework.web.bind.annotation.ExceptionHandler;
    14. import org.springframework.web.bind.annotation.ResponseBody;
    15. import org.springframework.web.bind.annotation.RestControllerAdvice;
    16. import java.util.HashMap;
    17. import java.util.Map;
    18. /**
    19. * @author pshdhx
    20. * @date 2022-03-04 11:12
    21. * @Des 统一标准来处理异常的
    22. */
    23. @Slf4j
    24. //@ControllerAdvice
    25. //@ResponseBody
    26. @RestControllerAdvice(basePackages = "com.atguigu.gulimall.product.controller")
    27. public class PshdhxGuliControllerAdvice {
    28. @ExceptionHandler(value = MethodArgumentNotValidException.class)
    29. public R handleValidException(MethodArgumentNotValidException e){
    30. BindingResult bindingResult = e.getBindingResult();
    31. Map<String,Object> map = new HashMap<>();
    32. bindingResult.getFieldErrors().forEach(item->{
    33. //...
    34. //获取校验字段的名字
    35. String field = item.getField();
    36. //获取校验信息
    37. String defaultMessage = item.getDefaultMessage();
    38. map.put(field,defaultMessage);
    39. });
    40. log.error("数据校验出现问题{},异常类型{}",e.getMessage(),e.getClass());
    41. return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",map);
    42. //return R.error(BizCodeEnum.VAILD_EXCEPTION.getCode(),BizCodeEnum.VAILD_EXCEPTION.getMsg()).put("data",map);
    43. }
    44. @ExceptionHandler(value = Throwable.class)
    45. public R handleException(Throwable throwable){
    46. log.error("错误:",throwable);
    47. return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(),BizCodeEnum.UNKNOW_EXCEPTION.getMsg());
    48. }
    49. }

    为了统一自定义异常编码,指定了枚举类型。

    1. package com.atguigu.common.exception;
    2. /**
    3. * @author pshdhx
    4. * @date 2022-03-04 11:25
    5. */
    6. public enum BizCodeEnum {
    7. UNKNOW_EXCEPTION(10000,"系统未知异常"),
    8. VAILD_EXCEPTION(10001,"参数格式校验失败");
    9. private int code;
    10. private String msg;
    11. BizCodeEnum(int code,String msg){
    12. this.code = code;
    13. this.msg = msg;
    14. }
    15. public int getCode() {
    16. return code;
    17. }
    18. public String getMsg() {
    19. return msg;
    20. }
    21. }

     

    结果如下: 

     

    4、JSR303后端分组检验

    比如说id这个字段,在新增时,不需要它;在修改时,必须要它,那么就需要对其进行分组处理

    1. @Data
    2. @TableName("pms_brand")
    3. public class PmsBrandEntity implements Serializable {
    4. private static final long serialVersionUID = 1L;
    5. /**
    6. * 品牌id
    7. */
    8. @TableId
    9. @Null(message = "新增时不能填写品牌id",groups = {AddGroup.class}) //实现分组检验;
    10. @NotNull(message = "修改时必须填写品牌id",groups = {UpdateGroup.class})
    11. private Long brandId;
    1. package com.atguigu.common.valid;
    2. public interface AddGroup {
    3. }

     

    1. package com.atguigu.common.valid;
    2. public interface UpdateGroup {
    3. }

    定义俩空接口即可。但是,要想使其生效,则必须在控制器中使用注解@Validated

    1. //实现分组校验,这是添加是要校验的内容
    2. @RequestMapping("/save4")
    3. public R save4(@Validated({AddGroup.class}) @RequestBody PmsBrandEntity brandEntity){
    4. pmsBrandService.save(brandEntity);
    5. return R.ok();
    6. }

     但是,如果其他字段没有增加上相关的分组,则字段上的注释会失效。

    5、JSR303自定义校验规则

    我想让某个字段只输入0和1,需要自定义注解

    1. @ListValue(vals = {0,1})
    2. private Integer showStatus;

    1、自定义校验规则 

    1. package com.atguigu.common.valid;
    2. /*
    3. 自定义校验规则
    4. */
    5. import javax.validation.Constraint;
    6. import javax.validation.Payload;
    7. import java.lang.annotation.Documented;
    8. import java.lang.annotation.Retention;
    9. import java.lang.annotation.Target;
    10. import static java.lang.annotation.ElementType.*;
    11. import static java.lang.annotation.ElementType.TYPE_USE;
    12. import static java.lang.annotation.RetentionPolicy.RUNTIME;
    13. @Documented
    14. @Constraint(validatedBy = { ListValueConstraintValidator.class }) //关联
    15. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    16. @Retention(RUNTIME)
    17. public @interface ListValue {
    18. String message() default "{com.atguigu.common.valid.ListValue.message}";
    19. Class<?>[] groups() default { };
    20. Class<? extends Payload>[] payload() default { };
    21. int[] vals() default { };
    22. }

    2、自定义校验器

    1. package com.atguigu.common.valid;
    2. /**
    3. * 自定义校验器
    4. */
    5. import javax.validation.ConstraintValidator;
    6. import javax.validation.ConstraintValidatorContext;
    7. import java.util.HashSet;
    8. import java.util.Set;
    9. public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    10. private Set<Integer> set = new HashSet<>();
    11. //初始化方法
    12. @Override
    13. public void initialize(ListValue constraintAnnotation) {
    14. int[] vals = constraintAnnotation.vals();
    15. for (int val : vals) {
    16. set.add(val);
    17. }
    18. }
    19. //判断是否校验成功
    20. /**
    21. *
    22. * @param value 需要校验的值
    23. * @param context
    24. * @return
    25. */
    26. @Override
    27. public boolean isValid(Integer value, ConstraintValidatorContext context) {
    28. return set.contains(value);
    29. }
    30. }

    3、关联校验规则和校验器

    1. @Documented
    2. @Constraint(validatedBy = { ListValueConstraintValidator.class }) //关联
    3. @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    4. @Retention(RUNTIME)
    5. public @interface ListValue {

    4、校验信息定义

    ValidationMessages.properties

    com.atguigu.common.valid.ListValue.message=必须提交指定的值
  • 相关阅读:
    【HarmonyOS】鸿蒙开发之Stage模型-应用配置文件——第4.2章
    debugger调试监听webpack配置文件的代码
    安达发|印刷包装行业利用APS自动排产系统迎来绿色革命
    系列二、Shiro的核心组件
    ‘std::thread‘ has not been declared
    藏在 Java 数组的背后,你可能忽略的知识点
    【软件工程】【23.04】p1
    【云原生之K8s】 K8s之持久化存储PV、PVC
    分库分表实践
    基于kubenetes的kubespere安装
  • 原文地址:https://blog.csdn.net/pshdhx/article/details/125511077