在上一篇中已经实现了基本的数据库写入操作,但是实际项目中,是不允许如此不设防注册的,比如说用户名要唯一,身份证号码要合法,各种字段必须要填,两次密码要一致等等,那么有哪些方式可以进行这种验证呢,客户端验证和服务端验证相关答案有很多,这里就不一一列举了,这里只写我认为比较好用的方式,有的项目同时需要客户端验证和服务端验证,那就由项目具体的需求决定。
还用上一篇的jsp进行检验,使用技术就是jQuery框架的validate插件,所需要的文件可以在/Files/DyEnigma/验证.rar下载
在webroot下面建立一个文件夹js,然后把这4个文件放进去,在index.jsp页面引用这4个js文件
1 <head>
2 <title>简单的注册页面</title>
3 <script type="text/javascript"src="js/jquery-1.6.1.js"></script>
4 <script type="text/javascript"src="js/jquery.validate.js"></script>
5 <script type="text/javascript"src="js/jquery.metadata.js"></script>
6 <script type="text/javascript"src="js/validate_ex.js"></script>
7 </head>
这里需要说明的是,jquery-1.6.1.js必须放在第一位,原因详见【待填】,另外还有个问题,有时候为了安全起见,我们把jsp文件都放在了WEB-INF文件夹里面,如果使用相对路径,它会找不到放在外面的文件,比如说css、js、图片之类,这时候的解决办法就是使用绝对路径,如:/DyEngima/js/jquery-1.6.1.js。如果觉得判断很麻烦,全部使用绝对路径就对了。
然后建立自己的js文件,在js文件夹中新建js,命名为main.js,并在index.jsp文件中导入此js,并对各字段写入框架验证编码,index.jsp最终代码如下
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
2 <%@ taglib uri="/struts-tags" prefix="s"%>
3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5 <head>
6 <title>简单的注册页面</title>
7 <script type="text/javascript" src="js/jquery-1.6.1.js"></script>
8 <script type="text/javascript" src="js/jquery.validate.js"></script>
9 <script type="text/javascript" src="js/jquery.metadata.js"></script>
10 <script type="text/javascript" src="js/validate_ex.js"></script>
11 <script type="text/javascript" src="js/main.js"></script>
12 </head>
13 <body>
14 <s:form action="op_insert" namespace="/user" method="post"
15 id="regForm">
16 <table class="mytable">
17 <tr>
18 <td>
19 <label for="name">
20 *帐号:
21 </label>
22 </td>
23 <td>
24 <s:textfield id="name" name="user.userName" value=""
25 cssClass="required" />
26 <p>
27 用户名为3-16个字符,可以为数字、字母、下划线
28 </p>
29 </td>
30 </tr>
31 <tr>
32 <td>
33 <label for="password">
34 *密码:
35 </label>
36 </td>
37 <td>
38 <s:password id="password" name="user.userPassword" value=""
39 cssClass="{required:true,rangelength:[6,16]}" />
40 <p>
41 最小长度:6 最大长度:16
42 </p>
43 </td>
44 </tr>
45 <tr>
46 <td>
47 <label for="repassword">
48 *确认密码:
49 </label>
50 </td>
51 <td>
52 <s:password id="repassword" value="" name="repassword"
53 cssClass="{required:true,rangelength:[6,16],equalTo:'#password',messages:{equalTo:'两次密码输入不一致.'}}" />
54 </td>
55 </tr>
56 <tr>
57 <td>
58 <label for="true">
59 *真实姓名:
60 </label>
61 </td>
62 <td>
63 <s:textfield id="true" name="user.trueName" value=""
64 cssClass="required" />
65 </td>
66 </tr>
67 <tr>
68 <td>
69 <label for="peopleId">
70 *身份证号:
71 </label>
72 </td>
73 <td>
74 <s:textfield id="peopleId" name="user.peopleId" value=""
75 cssClass="{required:true,isIdCardNo:true}" />
76 <p>
77 请输入18位的身份证号码
78 </p>
79 </td>
80 </tr>
81 <tr>
82 <td>
83
84 </td>
85 <td>
86 <s:submit value="添加" />
87 <s:reset value="重置" />
88 </td>
89 </tr>
90 </table>
91 </s:form>
92 </body>
93 </html>
94
注意各字段中cssClass部分,这些就是根据jQuery-validate验证插件完成的配置,详细请见【待填】;这里简单说明一下,required标记该输入框不能为空,rangelength标记该输入框的长度范围限制,equalTo:'#password'检验这个输入框数值和id为password的输入框数值是否一致,message是如果equalTo检验结果为否的情况下,给用户的提示信息,isIdCardNo:true检验该输入框输入的数值是否是个身份证号码,这些都是jsp页面的检验,另外还有用户名唯一,身份证号码唯一检验,请看main.js。
1 $(function() {
2
3 // 表单验证,用户名、身份证
4 $("#regForm").validate({
5 focusCleanup : true,
6 rules : {
7 'user.userName' : {
8 maxlength : 16,
9 minlength : 3,
10 userName : true,
11 remote : {
12 url : "/DyEngima/user/ck_checkUser.do",
13 type : "post",
14 data : {
15 'user.userName' : function() {
16 return encodeURIComponent($("#name").val());
17 }
18 }
19 }
20 },
21 'user.peopleId' : {
22 remote : {
23 url : "/DyEngima/user/ck_checkPeopleId.do",
24 type : "post",
25 data : {
26 'user.peopleId' : function() {
27 return encodeURIComponent($("#peopleId").val());
28 }
29 }
30 }
31 }
32 },
33 messages : {
34 'user.userName' : {
35 remote : "该用户名已存在,请使用其他的用户名."
36 },
37 'user.peopleId' : {
38 remote : "身份证号码已经存在."
39 },
40 low : ""
41 },
42 errorPlacement : function(error, element) {
43 if (element.is(":radio"))
44 error.appendTo(element.parent());
45 else if (element.is(":checkbox"))
46 error.appendTo(element.parent());
47 else if (element.is("input[name=captcha]"))
48 error.appendTo(element.parent());
49 else
50 error.insertAfter(element);
51 },
52 success : function(label) {
53 label.html(" ").addClass("right");
54 }
55 });
56
57 // 表单重置
58 $("input:reset").click(function() {
59 validate.resetForm();
60 });
61 });
新建一个action,命名为CheckAction.java。在cn.dy.dao包内的UserDao.java接口添加 public List<User> check(String username, String peopleId); 。
在cn.dy.dao.impl包内UserDaoBean.java类实现这个方法,这里要说明的是,不要使用“+”来连接查询字符串,第一不好维护,容易出错;第二,有被sql注入风险;而用"?"连接又会照成序号对应不上,而且当一个字段反复出现的话,就会一个一个都要列举出来,这里采用占位别名的方式处理。如果对SQL不熟练,可以使用别的方法:【待填】
1 @SuppressWarnings("unchecked")
2 @Override
3 @Transactional(propagation = Propagation.NOT_SUPPORTED)
4 public List<User> check(String username, String peopleId) {
5 String hql = "from User where username=:name or peopleId=:PID";
6 Query q = factory.getCurrentSession().createQuery(hql);
7 q.setString("name", username);
8 q.setString("PID", peopleId);
9 List list = q.list();
10 return list;
11 }
在cn.dy.service包内UserService.java接口添加 public boolean check(String username, String peopleId); 这里的返回值,就和dao中的那个接口不一样。
在cn.dy.service.impl包内的UserServiceBean.java类中实现这个方法(注意比较代码,这就是业务层和数据层的区别),注意import相关包,错误地方按F2可以出现提示。
1 @Override
2 public boolean check(String username,String peopleId) {
3 // 业务判断,看将要注册的帐号名或者身份证号码,是否已经存在
4 if (userDao.check(username,peopleId).isEmpty()) {
5 return true;
6 } else {
7 return false;
8 }
9 }
相关方法已经实现,CheckAction.java里面直接调用,代码如下
1 package cn.dy.action;
2
3 import java.io.InputStream;
4 import java.io.StringBufferInputStream;
5 import java.io.UnsupportedEncodingException;
6 import javax.annotation.Resource;
7 import org.springframework.stereotype.Controller;
8 import cn.dy.bean.User;
9 import cn.dy.service.UserService;
10 import com.opensymphony.xwork2.ActionSupport;
11
12 @SuppressWarnings("deprecation")
13 @Controller
14 public class CheckAction extends ActionSupport {
15
16 private static final long serialVersionUID = -859896811239454253L;
17 @Resource
18 UserService userService;
19
20 private InputStream inputStream;
21 private User user;
22
23 public User getUser() {
24 return user;
25 }
26
27 public void setUser(User user) {
28 this.user = user;
29 }
30
31 public InputStream getInputStream() {
32 return inputStream;
33 }
34
35 public String checkUser() {
36 String name = user.getUserName();
37 try {
38 name = java.net.URLDecoder.decode(name, "utf-8");
39 } catch (UnsupportedEncodingException e) {
40 e.printStackTrace();
41 }
42 String pass = "false";
43 if (userService.check(name, "")) {
44 pass = "true";
45 }
46 inputStream = new StringBufferInputStream(pass);
47 return "check";
48 }
49
50 public String checkPeopleId() {
51 String peopleId = user.getPeopleId();
52 String pass = "false";
53 if (userService.check("", peopleId)) {
54 pass = "true";
55 }
56 inputStream = new StringBufferInputStream(pass);
57 return "check";
58 }
59 }
60
struts.xml文件里面新添加的配置
1 <action name="ck_*" class="checkAction" method="{1}">
2 <result name="input">/index.jsp</result>
3 <result name="check" type="stream">
4 <param name="contentType">text/html</param>
5 <param name="inputName">inputStream</param>
6 </result>
7 </action>
注意第二个result的格式,必须这样声明才能在前台页面获取返回值。
好了,让我们检验一下。噢,出现一个问题,可以进行长度、是否为空、是否是身份证校验,但是,不能判断用户名、身份证是否存在,原来是js文件中的跳转路径的问题,在这里是.do结尾的,而struts2中默认是.action结尾,我们在struts.xml文件中加上这个一句:<constant name="struts.action.extension" value="do" />;设置默认为.do结尾就好了,现在再看看吧,成功。如果出现乱码问题,请检查页面、js文件的编码是否为UTF-8。