基於SSH的預約掛號系統之註冊驗證
註冊頁面描述
註冊頁面主要內容如下
前端驗證
在滑鼠游標離開輸入框,並且輸入框內容有改變時進行驗證。
1、暱稱:判斷是否為空-->正則表示式判斷是否合法
/*判斷使用者名稱是否為空 是否合法(2-6個漢字)*/ $(":input[name=username]").change(function() { var val = $(this).val().trim(); if(val != "") { var pattern = /^[\u4e00-\u9fa5]{2,6}$/;if(!pattern.test(val)) { $("#_username_msg").html("暱稱不合法").css("color", "red"); }else { $("#_username_msg").html("該暱稱可用").css("color", "#7CFC00"); } }else { $("#_username_msg").html("使用者名稱不能為空").css("color", "red"); } });
2、登入賬號:判斷是否為空-->正則表示式判斷是否合法-->AJAX判斷是否已存在
/* 判斷賬號是否為空 是否合法(英文字母或數字組成的4-16個字元) 傳送 AJAX 請求校驗賬號是否可用*/ $(":input[name=account]").change(function() { var val = $(this).val(); val = $.trim(val); if(val != "") { var pattern = /^\w{4,16}$/ if(!pattern.test(val)) { $("#_account_msg").html("賬號不合法").css("color", "red"); }else { var url = "user-validateAccount.action"; var args = {"account": val, "time": new Date()}; $.post(url, args, function(data) { if(data.hasAccount === true) { $("#_account_msg").html("該賬號已存在").css("color", "red"); }else { $("#_account_msg").html("該賬號可用").css("color", "#7CFC00"); } }); } }else{ $("#_account_msg").html("登入賬號不能為空").css("color", "red"); } });
對於AJAX請求,後端驗證需要注意的點
①由於我希望後端返回的是 JSON 格式,需要匯入 struts2 相應的 json 包:struts2-json-plugin-2.3.35.jar
②struts 配置檔案中ajax請求所在的包繼承自 json-default:extends="json-default"
③對應的 result 為(其中 dataMap 用於返回資料):
<result name="ajax-success" type="json"> <param name="root">dataMap</param> </result>
④action 中對應的程式碼:
// 用於返回 ajax 請求的資訊 使用 Map, struts2會將資料轉為 json 格式 private Map<String, Object> dataMap = new HashMap<>(); public Map<String, Object> getDataMap() { return dataMap; } public void setDataMap(Map<String, Object> dataMap) { this.dataMap = dataMap; }
/** * 檢驗登入賬號是否可用 */ private String account; public void setAccount(String account) { this.account = account; } public String validateAccount() { boolean flag = UserService.validateAccount(account); if(flag) { dataMap.put("hasAccount", false);//賬號可用 }else { dataMap.put("hasAccount", true);//賬號已存在 } return "ajax-success"; }
3、密碼:判斷是否為空-->正則表示式判斷是否合法
$(":input[name=password]").change(function() { var val = $(this).val().trim(); if(val == "") { $("#_password_msg").html("密碼不能為空").css("color", "red"); }else { if(val.length < 6) { $("#_password_msg").html("密碼長度不能少於6位").css("color", "red"); } /*密碼輸入框已經限制了輸入字元數*/ /*else if(val.length > 16) { $("#_password_msg").html("密碼長度不能多於16位").css("color", "red"); }*/ else { $("#_password_msg").html(""); } } });
4、確認密碼:判斷是否和密碼一致
$(":input[name=repassword]").blur(function() { var val = $(this).val().trim(); if(val != "") { var val2 = $(":input[name=password]").val().trim(); if(val != val2) { $("#_repassword_msg").html("兩次密碼不相同").css("color", "red"); }else { $("#_repassword_msg").html(""); } } });
5、手機號碼:判斷是否為空-->正則表示式判斷是否合法-->AJAX判斷是否已被註冊
/*手機號碼*/ $(":input[name=phone]").change(function() { var val = $(this).val().trim(); if(val != "") { /*判斷手機號碼格式是否正確*/ var pattern = /^1[34578]\d{9}$/ if(!pattern.test(val)) { $("#_phone_msg").html("手機號碼有誤").css("color", "red"); }else { /* AJAX 請求檢驗該手機號是否註冊過 */ var url = "user-validatePhone.action"; var args = {"phone": val, "time": new Date()}; $.post(url, args, function(data) { if(data.hasPhone === true) { $("#_phone_msg").html("該手機號已被註冊").css("color", "red"); }else { $("#_phone_msg").html(""); } }); } }else { $("#_phone_msg").html("手機號不能為空").css("color", "red"); } });
AJAX請求與賬號類似
6、郵箱:判斷是否為空-->正則表示式判斷是否合法-->AJAX判斷是否已被註冊
/*郵箱 */ $(":input[name=email]").change(function() { var val = $(this).val().trim(); if(val != "") { /*判斷郵箱格式是否正確*/ var pattern = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/ if(!pattern.test(val)) { $("#_email_msg").html("郵箱格式有誤").css("color", "red"); }else { /*AJAX 請求驗證郵箱是否被註冊過*/ var url = "user-validateEmail.action"; var args = {"email": val, "time": new Date()}; $.post(url, args, function(data) { if(data.hasEmail === true) { $("#_email_msg").html("該郵箱已被註冊").css("color", "red"); }else { $("#_email_msg").html(""); } }); } }else { $("#_email_msg").html("郵箱不能為空").css("color", "red"); } });
AJAX請求與賬號類似
完成日期:2018/11/28
後端驗證
由於前端驗證只是一個提示作用,我並沒有在點選註冊按鈕生效前再次進行驗證,需要struts的驗證器對這些欄位進行驗證
1、在 Action 所在的包新建一個 xml 檔案:UserAction-user-register-validation.xml
UserAction 對應 ActionClassName,user-register 對應 action 請求,validation.xml固定寫法
UserAction-user-register-validation.xml 內容如下:
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.2//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.2.dtd"> <validators> <!-- 暱稱驗證 --> <field name="username"> <!-- 開啟短路驗證 驗證是否為空--> <field-validator type="requiredstring" short-circuit="true"> <!-- 驗證前去掉前後空格 --> <param name="trim">true</param> <message key="error.username.isnull" /> </field-validator> <!-- 驗證是否合法 --> <field-validator type="regex"> <param name="regexExpression"><![CDATA[([\u4e00-\u9fa5]{2,6})]]></param> <message key="error.username.regex" /> </field-validator> </field> <!-- 賬號驗證 --> <field name="account"> <field-validator type="requiredstring" short-circuit="true"> <param name="trim">true</param> <message key="error.account.isnull"></message> </field-validator> <field-validator type="regex"> <param name="regexExpression"><![CDATA[(\w{4,16})]]></param> <message key="error.account.regex" /> </field-validator> </field> <!-- 密碼驗證 --> <field name="password"> <field-validator type="requiredstring" short-circuit="true"> <message key="error.password.isnull"></message> </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param> <message key="error.password.length"></message> </field-validator> </field> <!-- 欄位驗證 兩次密碼輸入是否一致 --> <field name="repassword"> <field-validator type="fieldexpression"> <param name="expression"><![CDATA[repassword==password]]></param> <message key="error.password.unequal"></message> </field-validator> </field> <!-- 非欄位驗證 兩次密碼輸入是否一致 --> <!-- <validator type="expression"> <param name="expression"><![CDATA[repassword==password]]></param> <message key="error.password.unequal"></message> </validator> --> <!-- 手機號碼驗證 --> <field name="phone"> <field-validator type="requiredstring" short-circuit="true"> <param name="trim">true</param> <message key="error.phone.isnull"></message> </field-validator> <field-validator type="regex"> <param name="regexExpression"><![CDATA[(1[34578]\d{9})]]></param> <message key="error.phone.regex" /> </field-validator> </field> <!-- 郵箱驗證 --> <field name="email"> <field-validator type="requiredstring" short-circuit="true"> <param name="trim">true</param> <message key="error.email.isnull"></message> </field-validator> <field-validator type="regex"> <param name="regexExpression"><![CDATA[(\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2})]]></param> <message key="error.email.regex" /> </field-validator> </field> </validators>
錯誤提示資訊檔案 i18n.properties(方便後面做國際化)
error.username.isnull=\u6635\u79F0\u4E0D\u80FD\u4E3A\u7A7A error.username.regex=\u8BE5\u6635\u79F0\u4E0D\u5408\u6CD5 error.account.isnull=\u8D26\u53F7\u4E0D\u80FD\u4E3A\u7A7A error.account.regex=\u8BE5\u8D26\u53F7\u4E0D\u53EF\u7528 error.password.isnull=\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A error.password.length=\u5BC6\u7801\u957F\u5EA6\u4E0D\u80FD\u5C11\u4E8E${minLength}\u4F4D error.password.unequal=\u4E24\u6B21\u5BC6\u7801\u8F93\u5165\u4E0D\u4E00\u81F4 error.phone.isnull=\u624B\u673A\u53F7\u7801\u4E0D\u80FD\u4E3A\u7A7A error.phone.regex=\u624B\u673A\u53F7\u7801\u6709\u8BEF error.email.isnull=\u90AE\u7BB1\u4E0D\u80FD\u4E3A\u7A7A error.email.regex=\u90AE\u7BB1\u683C\u5F0F\u6709\u8BEF
需要在 struts 配置檔案中新增:<constant name="struts.custom.i18n.resources" value="i18n"></constant>
前端頁面通過 OGNL 表示式獲取錯誤資訊:${fieldErrors.xxx[0] }
2、當通過 struts 的驗證器後,進入 UserAction 中的註冊方法
①、實現 ModelDriven, Preparable 介面
實現 ModelDriven 可將各個欄位封裝在 javaBean 中
實現 Preparable 介面可在呼叫目標方法前對該方法的 Model 進行處理
Preparable 介面有一個 prepare() 方法,預設是執行的,由於我希望每個 action 方法對應一個自己的 prepare 方法,在配置檔案中將 prepare() 方法改為不執行
在所在的 package 中定義,
<!-- 定義新的攔截器棧, 配置 prepare 攔截器棧的 alwaysInvokePrepare 引數值為 false --> <interceptors> <interceptor-stack name="appointmentStack"> <interceptor-ref name="paramsPrepareParamsStack"> <param name="prepare.alwaysInvokePrepare">false</param> </interceptor-ref> </interceptor-stack> </interceptors> <!-- 使用新的攔截器棧 --> <default-interceptor-ref name="appointmentStack"></default-interceptor-ref>
②、由於我的 User 沒有“確認密碼”對應的欄位,需要準備一個 String 型別的字串來儲存它,當時由於這個原因導致我的密碼和確認密碼的驗證一直無法通過
private String repassword;// 獲取確認密碼 public void setRepassword(String repassword) { this.repassword = repassword; } public String getRepassword() { return repassword; }
核心方法
public String register() { // 註冊失敗時可用於回顯 request.put("username", user.getUsername()); request.put("account", user.getAccount()); request.put("phone", user.getPhone()); request.put("email", user.getEmail()); // 先判斷驗證碼 if (checkCode != null && checkCode.equals(session.get("check"))) { user.setRegisterTime(new Date());// 設定註冊時間 String flag = UserService.register(user); if (flag == "Account") { request.remove("account");// 讓該欄位不回顯 request.put("hasAccount", "該賬號已存在!!"); return "input"; } else if (flag == "Phone") { request.remove("phone"); request.put("hasPhone", "該手機號已被註冊!!"); return "input"; } else if (flag == "Email") { request.remove("email"); request.put("hasEmail", "該郵箱已被註冊!!"); return "input"; } else { return "success"; } } else { request.put("checkImg", "驗證碼輸入錯誤"); return "input"; } } public void prepareRegister() { user = new User(); }
前端通過 EL 表示式獲取錯誤提示資訊
驗證碼
①、新建一個驗證碼 action:CheckImgAction.java
package com.zhc.actions; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.util.Map; import java.util.Random; import javax.imageio.ImageIO; import org.apache.struts2.ServletActionContext; import org.apache.struts2.interceptor.SessionAware; import com.opensymphony.xwork2.ActionSupport; public class CheckImgAction extends ActionSupport implements SessionAware { /** * */ private static final long serialVersionUID = -4133833024670509406L; @Override public String execute() throws Exception { int width = 120; int height = 30; // 1、準備一張圖片 BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 2、圖片背景顏色 Graphics graphics = bufferedImage.getGraphics(); // 指定顏色 graphics.setColor(getRandColor(200, 250)); graphics.fillRect(0, 0, width, height); // 3、繪製邊框 graphics.setColor(Color.WHITE); graphics.drawRect(0, 0, width - 1, height - 1); // 4、四個隨機數字 Graphics2D graphics2d = (Graphics2D) graphics; // 輸出字型 graphics2d.setFont(new Font("宋體", Font.BOLD, 18)); String words = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; //生成隨機數 Random random = new Random(); StringBuffer sb = new StringBuffer(); int x = 10; for(int i = 0; i < 4; i++) { graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110))); //角度旋轉 -30 - 30 int angle = random.nextInt(60) - 30; //換算弧度 double theta = angle * Math.PI / 180; //生成一個隨機數字 int index = random.nextInt(words.length()); //獲得字母或數字 char c = words.charAt(index); sb.append(c); //輸出到圖片 graphics2d.rotate(theta, x, 20); graphics2d.drawString(String.valueOf(c), x, 20); graphics2d.rotate(-theta, x, 20); x += 30; } //將字串放入 session 用於Action,不能忘了toString方法 session.put("check", sb.toString()); //5、繪製干擾線 graphics.setColor(getRandColor(160, 200)); int x1; int x2; int y1; int y2; for(int i =0; i < 30; i++) { x1 = random.nextInt(width); x2 = random.nextInt(12); y1 = random.nextInt(height); y2 = random.nextInt(12); graphics.drawLine(x1, y1, x1 + x2, y1 + y2); } //釋放資源 graphics.dispose(); //將圖片輸出到瀏覽器 ImageIO.write(bufferedImage, "jpg", ServletActionContext.getResponse().getOutputStream()); return NONE; } private Color getRandColor(int fc, int bc) { Random random = new Random(); if (fc > 255) { fc = 255; } if (bc > 255) { bc = 255; } int r = fc + random.nextInt(bc - fc); int g = fc + random.nextInt(bc - fc); int b = fc + random.nextInt(bc - fc); return new Color(r, g, b); } private Map<String, Object> session; @Override public void setSession(Map<String, Object> session) { this.session = session; } }
②、Spring 配置檔案中配置 bean:applicationContext-beans.xml
<!-- 驗證碼Action --> <bean id="checkImgAction" class="com.zhc.actions.CheckImgAction" scope="prototype"></bean>
③、struts 配置檔案中配置 Action
<!-- 驗證碼Action --> <action name="checkImg" class="checkImgAction"></action>
④、前端頁面
<li class="layout"> <span class="register_label">驗證碼:</span> <div class="register_input"> <input class="inp_lon" type="text" name="checkCode" autocomplete="off"/> <img id="checkImg" src="${pageContext.request.contextPath}/checkImg.action" alt="更換圖片" onclick="ChangeCodeImg()" title="點選更換圖片" /> <span id="_checkImg_msg" >${requestScope.checkImg }</span> </div> </li>
⑤、jquery 切換檔案
/*更換驗證碼圖片*/ $("#checkImg").click(function() { $("#checkImg").attr('src', "${pageContext.request.contextPath}/checkImg.action?"+new Date().getTime()); });
完成日期:2018/11/29