zoukankan      html  css  js  c++  java
  • Java单体应用

    原文地址:http://www.work100.net/training/monolithic-project-iot-cloud-admin-manager-spring-validation.html
    更多教程:光束云 - 免费课程

    Spring Validation

    序号 文内章节 视频
    1 概述 -
    2 使用Spring-Validation验证 -
    3 实例源码 -

    请参照如上章节导航进行阅读

    1.概述

    1.1.JSR-303简介

    JSR-303 是 JavaEE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是 Hibernate Validator

    此实现与 Hibernate ORM 没有任何关系。JSR-303 用于对 Java Bean 中的字段的值进行验证。 Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中使用注解的方式对表单提交的数据方便地验证。

    Spring 4.0 开始支持 Bean Validation 功能。

    1.2.JSR-303 基本的校验规则

    空检查

    • @Null 验证对象是否为 null
    • @NotNull 验证对象是否不为 null, 无法查检长度为 0 的字符串
    • @NotBlank 检查约束字符串是不是 Null 还有被 Trim 的长度是否大于 0,只对字符串,且会去掉前后空格
    • @NotEmpty 检查约束元素是否为 NULL 或者是 EMPTY

    布尔检查

    • @AssertTrue 验证 Boolean 对象是否为 true
    • @AssertFalse 验证 Boolean 对象是否为 false

    长度检查

    • @Size(min=, max=) 验证对象(Array, Collection , Map, String)长度是否在给定的范围之内
    • @Length(min=, max=) 验证字符串长度介于 minmax 之间

    日期检查

    • @Past 验证 DateCalendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期
    • @Future 验证 DateCalendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期

    正则检查

    • @Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式
      • regexp:正则表达式
      • flags:指定 Pattern.Flag 的数组,表示正则表达式的相关选项

    数值检查

    注意: 建议使用在 String ,Integer 类型,不建议使用在 int 类型上,因为表单值为 “” 时无法转换为 int,但可以转换为 String“”Integernull

    • @Min 验证 NumberString 对象是否大等于指定的值
    • @Max 验证 NumberString 对象是否小等于指定的值
    • @DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过 BigDecimal 定义的最大值的字符串表示 .小数 存在精度
    • @DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过 BigDecimal 定义的最小值的字符串表示 .小数 存在精度
    • @Digits 验证 NumberString 的构成是否合法
    • @Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,integer 指定整数精度,fraction 指定小数精度
    • @Range(min=, max=) 被指定的元素必须在合适的范围内
    • @Range(min=10000,max=50000,message=”range.bean.wage”)
    • @Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个 map,则对其中的值部分进行校验.(是否进行递归验证)
    • @CreditCardNumber 信用卡验证
    • @Email 验证是否是邮件地址,如果为 null,不进行验证,算通过验证
    • @ScriptAssert(lang= ,script=, alias=)
    • @URL(protocol=,host=, port=,regexp=, flags=)

    2.使用Spring-Validation验证

    服务器端验证是确保输入数据安全的最终屏障,所以服务端的验证永远不能缺少,接下来修改为使用 BeanValidator 进行验证。

    2.1.引入依赖

    需要引入如下依赖:

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.17.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.0</version>
    </dependency>
    

    我们在 iot-cloud-dependenciesiot-cloud-commons 项目中添加上面的依赖。

    其中 org.glassfish:javax.el 依赖一定要引入,否则进行单元测试时会报错

    2.2.定义验证工具类

    iot-cloud-commons 项目中添加 BeanValidator 的工具类,代码如下:

    package net.work100.training.stage2.iot.cloud.commons.validator;
    
    import org.springframework.stereotype.Component;
    
    import javax.validation.ConstraintViolation;
    import javax.validation.ConstraintViolationException;
    import javax.validation.Validator;
    import java.util.*;
    
    /**
     * <p>Title: BeanValidator</p>
     * <p>Description: JSR303 Validator(Hibernate Validator)工具类.</p>
     *
     * @author liuxiaojun
     * @date 2020-03-17 16:17
     * ------------------- History -------------------
     * <date>      <author>       <desc>
     * 2020-03-17   liuxiaojun     初始创建
     * -----------------------------------------------
     */
    @Component
    public class BeanValidator {
    
        private Validator validator;
    
        public void setValidator(Validator validator) {
            this.validator = validator;
        }
    
        /**
         * 调用 JSR303 的 validate 方法, 验证失败时抛出 ConstraintViolationException.
         */
        private static void validateWithException(Validator validator, Object object, Class<?>... groups) throws ConstraintViolationException {
            Set constraintViolations = validator.validate(object, groups);
            if (!constraintViolations.isEmpty()) {
                throw new ConstraintViolationException(constraintViolations);
            }
        }
    
        /**
         * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 中为 List<message>.
         */
        private static List<String> extractMessage(ConstraintViolationException e) {
            return extractMessage(e.getConstraintViolations());
        }
    
        /**
         * 辅助方法, 转换 Set<ConstraintViolation> 为 List<message>
         */
        private static List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {
            List<String> errorMessages = new ArrayList<>();
            for (ConstraintViolation violation : constraintViolations) {
                errorMessages.add(violation.getMessage());
            }
            return errorMessages;
        }
    
        /**
         * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 Map<property, message>.
         */
        private static Map<String, String> extractPropertyAndMessage(ConstraintViolationException e) {
            return extractPropertyAndMessage(e.getConstraintViolations());
        }
    
        /**
         * 辅助方法, 转换 Set<ConstraintViolation> 为 Map<property, message>.
         */
        private static Map<String, String> extractPropertyAndMessage(Set<? extends ConstraintViolation> constraintViolations) {
            Map<String, String> errorMessages = new HashMap<>();
            for (ConstraintViolation violation : constraintViolations) {
                errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage());
            }
            return errorMessages;
        }
    
        /**
         * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 List<propertyPath message>.
         */
        private static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e) {
            return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");
        }
    
        /**
         * 辅助方法, 转换 Set<ConstraintViolations> 为 List<propertyPath message>.
         */
        private static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations) {
            return extractPropertyAndMessageAsList(constraintViolations, " ");
        }
    
        /**
         * 辅助方法, 转换 ConstraintViolationException 中的 Set<ConstraintViolations> 为 List<propertyPath + separator + message>.
         */
        private static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) {
            return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator);
        }
    
        /**
         * 辅助方法, 转换 Set<ConstraintViolation> 为 List<propertyPath + separator + message>.
         */
        private static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations, String separator) {
            List<String> errorMessages = new ArrayList<>();
            for (ConstraintViolation violation : constraintViolations) {
                errorMessages.add(violation.getPropertyPath() + separator + violation.getMessage());
            }
            return errorMessages;
        }
    
        /**
         * 服务端参数有效性验证
         *
         * @param object 验证的实体对象
         * @param groups 验证组
         * @return 验证成功:返回 null;验证失败:返回错误信息
         */
        public String validator(Object object, Class<?>... groups) {
            try {
                validateWithException(this.validator, object, groups);
            } catch (ConstraintViolationException ex) {
                List<String> list = extractMessage(ex);
                list.add(0, "数据验证失败:");
    
                // 封装错误消息为字符串
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < list.size(); i++) {
                    String exMsg = list.get(i);
                    if (i != 0) {
                        sb.append(String.format("%s. %s", i, exMsg)).append(list.size() > 1 ? "<br/>" : "");
                    } else {
                        sb.append(exMsg).append(list.size() > 1 ? "<br/>" : "");
                    }
                }
    
                return sb.toString();
            }
    
            return null;
        }
    }
    

    2.3.修改实体类

    修改 AuthManager 类,代码如下:

    package net.work100.training.stage2.iot.cloud.domain;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import lombok.Data;
    import net.work100.training.stage2.iot.cloud.commons.dto.AbstractBaseDomain;
    import org.hibernate.validator.constraints.Length;
    
    import javax.validation.constraints.NotEmpty;
    import java.util.Date;
    
    /**
     * <p>Title: AuthManager</p>
     * <p>Description: 管理员账户表</p>
     * <p>Url: http://www.work100.net/training/monolithic-project-iot-cloud-admin.html</p>
     *
     * @author liuxiaojun
     * @date 2020-02-23 22:42
     * ------------------- History -------------------
     * <date>      <author>       <desc>
     * 2020-02-23   liuxiaojun     初始创建
     * -----------------------------------------------
     */
    @Data
    public class AuthManager extends AbstractBaseDomain {
    
        private String userKey;
    
        @Length(min = 4, max = 20, message = "用户名必须介于 4~20 位之间")
        private String userName;
    
        @JsonIgnore
        @Length(min = 6, max = 20, message = "密码必须介于 6~20 位之间")
        private String password;
    
        /**
         * 状态:0=inactive, 1=active, 2=locked, 3=deleted
         */
        private int status;
    
        private boolean superuser;
    
        /**
         * 角色:admin, editor
         */
        @NotEmpty(message = "角色不能空")
        private String roles;
    
        private Date modifyPasswordTime;
    }
    

    2.4.修改ManagerController验证逻辑

    增加自动注入:

    @Autowired
    private BeanValidator beanValidator;
    

    add 方法为例演示,代码如下:

    @RequestMapping(value = "add", method = RequestMethod.POST)
    public String add(AuthManager authManager, Model model, RedirectAttributes redirectAttributes) {
        String validator = beanValidator.validator(authManager);
        if (validator != null) {
            model.addAttribute("baseResult", BaseResult.fail(validator));
            model.addAttribute("authManager", authManager);
            return "auth/manager_add";
        }
    
        // 新增处理
        BaseResult baseResult = authManagerService.insert(authManager);
        if (baseResult.getStatus() == HttpUtils.HTTP_STATUS_CODE_OK) {
            redirectAttributes.addFlashAttribute("baseResult", baseResult);
            return "redirect:/auth/manager/list";
        } else {
            model.addAttribute("baseResult", baseResult);
            return "auth/manager_add";
        }
    }
    

    2.5.注入工具类

    修改 spring-context.xml 文件,注入 Validator 工具类,配置如下:

    <!-- 配置 Bean Validator 定义 -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
    <bean id="beanValidator" class="net.work100.training.stage2.iot.cloud.commons.validator.BeanValidator">
        <property name="validator" ref="validator" />
    </bean>
    

    2.6.测试验证

    注释掉 manager_add.jsp 视图中的 JS 验证,运行效果如下:

    3.实例源码

    实例源码已经托管到如下地址:


    上一篇:使用Lombok

    下一篇:重构Dao层


    如果对课程内容感兴趣,可以扫码关注我们的 公众号QQ群,及时关注我们的课程更新

  • 相关阅读:
    MytBatis错题分析
    Spring核心概念
    延迟与缓存
    MyBatis的关联查询
    Mabatis注解
    [leetcode]226. Invert Binary Tree翻转二叉树
    [leetcode]633. Sum of Square Numbers平方数之和
    [leetcode]296. Best Meeting Point最佳见面地点
    [leetcode]412. Fizz Buzz报数
    [leetcode]142. Linked List Cycle II找出循环链表的入口
  • 原文地址:https://www.cnblogs.com/liuxiaojun/p/training-monolithic-project-iot-cloud-admin-manager-spring-validation.html
Copyright © 2011-2022 走看看