注册页面描述
注册页面主要内容如下
前端验证
在鼠标光标离开输入框,并且输入框内容有改变时进行验证。
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.put("account", "");// 让该字段不回显
request.put("hasAccount", "该账号已存在!!");
return "input";
} else if (flag == "Phone") {
request.put("phone", "");
request.put("hasPhone", "该手机号已被注册!!");
return "input";
} else if (flag == "Email") {
request.put("email", "");
request.put("hasEmail", "该邮箱已被注册!!");
return "input";
} else {
return "success";
}
} else {
request.put("checkImg", "验证码输入错误");
return "input";
}
}
public void prepareRegister() {
user = new User();
}
前端通过 OGNL 表达式获取错误提示信息、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="更换图片" οnclick="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