1. 程式人生 > >基於SSH的預約掛號系統之註冊驗證

基於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