沉迷于超级机器人大战v二十多天后我终于想起来研究一下之前说的在hibernate validator中没有的密码一致性检测的问题,通过一个下午的研究终于将这个问题解决了,下面分享一下解决方案,包括后端和前段的检测。

要实现后端的密码一致性检测首先要定义一个Annotation用于标识,我定义了一个名为Compare的Annotation,代码如下:

package com.netease.JavaFinal.utils;import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;import javax.validation.Constraint;
import javax.validation.Payload;@Documented
@Retention(RUNTIME)
@Target(TYPE)
@Constraint(validatedBy = { CompareValidator.class })
public @interface Compare {String message() default "数据不一致";String field() default "";String verifyField() default "";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };}

Annotation的几个属性简单解释一下,message属性定义的是验证不通过时显示的错误信息,field定义的是模型中密码的属性名称,而verifyField则是模型中确认密码的属性名称,最后两个属性据说是hibernate validator中自定义验证Annotation中必须有的属性,具体有什么用我也不是非常清楚。另外需要注意这个Annotation的Target是TYPE,没有办法,因为如果想在验证的时候能够同时获取模型中的密码值和验证密码的值只能将这个Annotation放在模型类的定义上,否则无法同时获取两个属性值。还有ConStraint用于指定实现自定义验证的类,在这个类中具体实现密码校验的验证,具体代码如下:

package com.netease.JavaFinal.utils;import java.lang.reflect.Field;import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class CompareValidator implements ConstraintValidator<Compare, Object> {private String field;private String verifyField;public void initialize(Compare constraintAnnotation) {// TODO Auto-generated method stubthis.field = constraintAnnotation.field();this.verifyField = constraintAnnotation.verifyField();}public boolean isValid(Object value, ConstraintValidatorContext context) {// TODO Auto-generated method stubtry {Class<?> modelType = value.getClass();Field fieldValue = modelType.getDeclaredField(field);fieldValue.setAccessible(true);Field verifyFieldValue = modelType.getDeclaredField(verifyField);verifyFieldValue.setAccessible(true);if (fieldValue.get(value).equals(verifyFieldValue.get(value))) {return true;}//将错误信息绑定到verifyField上,否则错误信息是对应整个模型类的,无法在密码验证的位置显示String messageTemplate = context.getDefaultConstraintMessageTemplate();context.buildConstraintViolationWithTemplate(messageTemplate).addPropertyNode(verifyField).addConstraintViolation();context.disableDefaultConstraintViolation();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (NoSuchFieldException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}return false;}}

自定义的验证类需要继承ConstraintValidator接口,该接口的两个泛型参数指定了校验的Annotation类型和需要校验的数据的类型,因为需要校验的数据类型是自定义的模型类型因此通过Object结合反射来获取需要校验的数据。ConstraintValidator接口中需要实现两个方法分别是initialize和isValid。initialize是一个初始化方法可以在方法内对类中的属性值进行初始化,当然也可以什么都不做。isValid方法中实现具体的校验逻辑。最后修改模型类型,将Compare加入就完成了密码一致性的校验功能,具体代码如下:

package com.netease.JavaFinal.web.viewmodel;import javax.validation.constraints.Size;import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;import com.netease.JavaFinal.utils.Compare;@Compare(field = "password", verifyField = "confirmPassword", message = "两次输入密码不一致")
public class RegisterEditModel {@NotEmpty(message = "不能为空")@Size(min = 6, max = 15, message = "请输入长度在{min}到{max}之间的字符串")private String userName;@NotEmpty(message = "不能为空")@Length(min = 6, message = "不能少于{min}个字符")private String password;private String confirmPassword;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getConfirmPassword() {return confirmPassword;}public void setConfirmPassword(String confirmPassword) {this.confirmPassword = confirmPassword;}}

在页面上测试一下,结果显示校验成功,如下图所示。

完成了后端验证后我就想能否像上一篇博文中的将前端验证的js脚本通过解析模型中的校验Annotation自动生成出来,结论当然是可以的,但是因为这次定义的Compare是一个修饰type的Annotation,所以处理的方法和之前博文中介绍的并不相同,无法通过在ValidCreator中添加方法的形式来实现,只能作为一种特使的Annotation来特别处理。我为了省事直接修改的之前的ValidDirective类,代码如下:

package com.netease.JavaFinal.utils;import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;public class ValidDirective implements TemplateDirectiveModel {private ValidCreator validCreator;public ValidDirective(ValidCreator validCreator) {this.validCreator = validCreator;}public void execute(Environment env, Map params, TemplateModel[] model, TemplateDirectiveBody body)throws TemplateException, IOException {// TODO Auto-generated method stubString className = params.get("className").toString();String formName = params.get("formName").toString();String validateScript = "";String rules = "";String messages = "";try {Class<?> c = Class.forName(className);Field[] fields = c.getDeclaredFields();for (Field field : fields) {Map<String, String> result = GetValidationRule(field, c);if (result.containsKey("rule") && result.containsKey("message")) {String fieldRule = String.format("\n\t\t\t" + field.getName() + ": {%s\n\t\t\t},",result.get("rule"));String fieldMessage = String.format("\n\t\t\t" + field.getName() + ": {%s\n\t\t\t},",result.get("message"));rules += fieldRule;messages += fieldMessage;}}if (!rules.isEmpty() && !messages.isEmpty()) {validateScript = String.format("<script>\n$().ready(function() {\n\t$(\"#%s\").validate({\n\t\trules: {%s\n\t\t},\n\t\tmessages: {%s\n\t\t}\n\t});\n});\n</script>",formName, rules.substring(0, rules.length() - 1), messages.substring(0, messages.length() - 1));}Writer writer = env.getOut();writer.write(validateScript);body.render(writer);} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalArgumentException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (InvocationTargetException e) {// TODO Auto-generated catch blocke.printStackTrace();}}private Map<String, String> GetValidationRule(Field field, Class<?> c)throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {Map<String, String> result = new HashMap<String, String>();String rule = "";String message = "";Compare compare = c.getDeclaredAnnotation(Compare.class);if(compare != null && field.getName().equals(compare.verifyField())) {rule += String.format("\n\t\t\t\tequalTo:\"#%s\",", compare.field());message += ("\n\t\t\t\tequalTo:\"" + compare.message() + "\",");}Annotation[] annotations = field.getAnnotations();for (Annotation a : annotations) {Map<String, String> valid = validCreator.CreateValidation(a);if (valid != null) {rule += valid.get("rule");message += valid.get("message");}}if (!rule.isEmpty()) {result.put("rule", rule.substring(0, rule.length() - 1));}if (!message.isEmpty()) {result.put("message", message.substring(0, message.length() - 1));}return result;}
}

这里我直接对Compare进行了单独的判断,因为这里我只有一个修饰type的特殊的校验Annotation,如果有多个这种类型的Annotation可以定义一个专门处理这种Annotation类型的方法来统一处理,这里我因为没有这么多所以就简单实现了。最后执行程序,结果如下:

检测网页源码后结果如下,可以看到验证密码一致性的js脚本已经自动生成了。

这样对密码一致性的前后端的校验功能就完成了,下来应该会研究一下spring mvc中过滤器的使用,之前在.net中都是使用面向方面的标签类来进行过滤的,而spring mvc中原生的过滤器需要配置xml,这非常不方便,在我想来应该是可以用Annotation的方式来实现的,因为之前使用JFinal框架中就是这么实现的,所以在spring mvc中肯定也可以实现。

Java Web学习笔记(二)密码一致性检测的实现相关推荐

  1. java web学习笔记(持续更新)

    java web学习笔记 一.Java Web简介 二.认识Servlet 1.什么是Servlet? 2.请求路径 3.tomcat 4.Servlet的使用 三.Servlet简单应用 1.创建S ...

  2. 2019年Java Web学习笔记目录

    Java Web学习笔记目录 1.Java Web学习笔记01:动态网站初体验 2.Java Web学习笔记02:在Intellij里创建Web项目 3.Java Web学习笔记03:JSP元素 4. ...

  3. Java基础学习笔记(二)_Java核心技术(进阶)

    本篇文章的学习资源来自Java学习视频教程:Java核心技术(进阶)_华东师范大学_中国大学MOOC(慕课) 本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结 文章目录 Jav ...

  4. 1、JAVA web学习笔记

    以下内容是在学习某机构视频过程中记录的笔记,不准确的地方请大家评论指正. JavaWeb是使用Java语言开发基于互联网的项目. 资源分类有两类: 静态资源: 使用静态网页开发技术发布的资源. 特点: ...

  5. [原创]java WEB学习笔记02:javaWeb开发的目录结构

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  6. java web学习笔记-jsp篇

    转载自:http://www.cnblogs.com/happyfans/archive/2015/03/17/4343571.html 1.java web简介 1.1静态页面与动态页面   表现形 ...

  7. [原创]java WEB学习笔记48:其他的Servlet 监听器:域对象中属性的变更的事件监听器 (3 个),感知 Session 绑定的事件监听器(2个)...

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  8. [原创]java WEB学习笔记36:Java Bean 概述,及在JSP 中的使用,原理

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  9. [原创]java WEB学习笔记80:Hibernate学习之路--- hibernate配置文件:JDBC 连接属性,C3P0 数据库连接池属性等...

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

最新文章

  1. 一文盘点MWC 2019所有5G设备和研发进展
  2. 【ASP.NET】ASP.NET中权限验证使用OnAuthorization实现
  3. eclipse xml文件报错_Maven教程6: Maven与Eclipse整合
  4. 【Android进阶学习】设置透明效果的三种方法
  5. 供销大集有潜力吗_社区团购遭点名批评,互联网巨头真的只是惦记那几捆白菜吗?| 吴坚浙商频道...
  6. (1)算法设计与分析_算法设计思路
  7. 实现Ubuntu网络快速连接
  8. 你做过哪些事情让你女朋友感动到哭,这个100%可以做到!
  9. cesium three性能比较_初探希捷Exos银河18 TB盘,容量和性能双双提升
  10. 前端JavaScript DOM BOM 自学复盘 D1(DOM-获取DOM元素、修改HTML标签/表单/css样式属性、定时器-间歇函数)
  11. 【DBA】 Oracle 学习路线
  12. 事件冒泡、捕获?如何阻止
  13. Flutter实践之高仿有妖气漫画,移动客户端开发工程师专业
  14. Android设备硬件序列号(SN、串号)分析
  15. 《西法的刷题秘籍》电子书开放下载啦~
  16. TT浏览器 v4.7 简体中文版
  17. 团贷网面试php,团贷网的钱还能要回来吗?
  18. 手动编译完Exchangeis 的exchangis-service服务无法启动
  19. echarts K线图candlestick
  20. IBM Expands Watson Platform for Next Generation of Builders

热门文章

  1. 靠物管服务撑起半壁江山,华润万象生活还能笑多久
  2. CocosCreator 监听龙骨绑定的帧事件
  3. margin-right没效果,怎么解决
  4. 小米不只要做互联网公司,还要成为AI公司
  5. 第三次培训任务:心率传感器和烟雾传感器
  6. 白日依山尽 全诗是什么
  7. 浅谈surface go与ipad 2018
  8. C#--编写旅行社程序
  9. 为什么有人连操作系统的基本知识都不懂?
  10. iphone传输 android,还有这个功能?iPhone竟然可以传文件到安卓机?