前面我们已经学习过了在服务器端进行验证,这次学习 JQuery Validator 客户端验证。客户端验证虽然可以被用户绕过,但是可以作为辅助手段,对于一般用户可以减少一定的服务器通讯。

以注册页面为例,实现一般化的验证,并且加上二次输入密码、用户名字段唯一性验证。

首先添加 jquery.min.js, jquery.validate.js。

register.jsp,jquery, bootstrap 在之前的 sitemesh 基础模板内。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>

<html>
<head>
    <title>Register</title>
</head>
<body>
<h1>Register</h1>
<sf:form commandName="user" cssClass="form-horizontal registrationForm">
    <c:if test="${param.success eq true }">
        <div class="alert alert-success">Registration successful!</div>
    </c:if>

    <div class="form-group">
        <label for="userName" class="col-sm-2 control-label">Name:</label>
        <div class="col-sm-10">
            <sf:input path="userName" id="userName" cssClass="form-control"/>
            <sf:errors path="userName" />
        </div>
    </div>

    <div class="form-group">
        <label for="fullname" class="col-sm-2 control-label">Nickname:</label>
        <div class="col-sm-10">
            <sf:input path="fullname" id="fullname" cssClass="form-control"/>
            <sf:errors path="fullname" />
        </div>
    </div>

    <div class="form-group">
        <label for="email" class="col-sm-2 control-label">Email:</label>
        <div class="col-sm-10">
            <sf:input path="email" id="email" cssClass="form-control"/>
            <sf:errors path="email" />
        </div>
    </div>
    <div class="form-group">
        <label for="password" class="col-sm-2 control-label">Password:</label>
        <div class="col-sm-10">
            <sf:input type="password" path="password" id="password" cssClass="form-control"/>
            <sf:errors path="password" />
        </div>
    </div>
    <div class="form-group">
        <label for="password" class="col-sm-2 control-label">Password again:</label>
        <div class="col-sm-10">
            <input type="password" name="password_again" id="password_again" class="form-control"/>
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-2">
            <input type="submit" value="Submit" class="btn btn-lg btn-primay" />
        </div>
    </div>
</sf:form>

<script>
    $(document).ready(function(){
        $('ul.navbar-nav li').removeClass("active");
        $('ul.navbar-nav li:nth-child(4)').addClass("active");
        $(".registrationForm").validate(
            {
                rules: {
                    userName: {
                        required : true,
                        minlength : 3,
                        remote : {
                            url: "<spring:url value='/register/available' />",
                            type: "get",
                            data: {
                                username: function() {
                                    return $("#userName").val();
                                }
                            }
                        }
                    },
                    email: {
                        required : true,
                        email : email
                    },
                    password: {
                        required : true,
                        minlength : 5
                    },
                    password_again: {
                        required : true,
                        minlength : 5,
                        equalTo: '#password'
                    }
                },
                highlight: function(element) {
                    $(element).closest('.form-group').removeClass('has-success').addClass('has-error');
                },
                unhighlight: function(element) {
                    $(element).closest('.form-group').removeClass('has-error').addClass('has-success');
                },
                messages: {
                    userName: {
                        remote: "Such username already exists!"
                    }
                }
            }
        );
    });
</script>
</body>
</html>

重点在 remote

UniqueUsername 注解类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Target({ FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = {UniqueUsernameValidator.class })
public @interface UniqueUsername {
    String message();

    Class<?>[] groups() default { };

    Class<? extends Payload>[] payload() default { };
}

public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {

    @Autowired
    private HibUserService hibUserService;

    @Override
    public void initialize(UniqueUsername constraintAnnotation) {

    }

    @Override
    public boolean isValid(String username, ConstraintValidatorContext context) {
        if (hibUserService == null)
            return true;
        return hibUserService.findUserByName(username) == null;
    }
}

User 类 userName 字段加上注解。

RegisterController.java

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Controller
@RequestMapping(value="register")
public class RegisterController {
    @Autowired
    private HibUserService hibUserService;

    @ModelAttribute("user")
    public User constructUser() {
        return new User();
    }

    @RequestMapping(method = RequestMethod.GET)
    public String showRegister() {
        return "register";
    }

    @RequestMapping(method= RequestMethod.POST)
    public String register(@ModelAttribute("user") @Valid User user,
                           BindingResult result,
                           HttpServletRequest request) {

        if (result.hasErrors()) {
            return "register";
        }

        user.setLastIp(request.getRemoteAddr());
        user.setLastVisit(new Date());
        hibUserService.save(user);

        return "redirect:register?success=true";
    }

    @RequestMapping("/available")
    @ResponseBody
    public String available(@RequestParam String username) {
        Boolean available = (hibUserService.findUserByName(username) == null);
        return available.toString();
    }
}