上幾篇文章,主要學習了 Extjs4 Grid 的使用方法,從本篇開始,我們開始其他元件的
學習,使用。在登入、注冊甚至是發表文章或文章的時候,都會用到驗證碼這個東西,那
麼在 EXTJS 中,可以使用驗證碼功能麼?答案是肯定的,在 EXTJS4 之前,也有很多驗證
碼的實作,在 Extjs4 中,驗證碼到底如何實作呢?
暫時,我們将驗證碼元件,命名為 CheckCode。此元件繼承自 Ext.form.field.Text,在
實作之前,我們需要寫兩個樣式,分别用來控制驗證碼的輸入框和驗證碼圖檔的大小。
CSS 樣式為:
Css代碼

- #CheckCode{ float:left;}
- .x-form-code{width:73px;height:20px;vertical-align:middle;cursor:pointer; float:left; margin-left:7px;}
#CheckCode{ float:left;}
.x-form-code{width:73px;height:20px;vertical-align:middle;cursor:pointer; float:left; margin-left:7px;}
記住這兩個樣式的定義,後面,我們會用到它。
驗證碼的 JS 代碼(CheckCode.js):
Js代碼

- Ext.define('SMS.view.CheckCode', {
- extend: 'Ext.form.field.Text',
- alias: 'widget.checkcode',
- inputType: 'codefield',
- codeUrl: Ext.BLANK_IMAGE_URL,
- isLoader: true,
- onRender: function(ct, position) {
- this.callParent(arguments);
- this.codeEl = ct.createChild({
- tag: 'img',
- src: Ext.BLANK_IMAGE_URL
- });
- this.codeEl.addCls('x-form-code');
- this.codeEl.on('click', this.loadCodeImg, this);
- if(this.isLoader) {
- this.loadCodeImg();
- }
- },
- aliasErrorIcon: function() {
- this.errorIcon.alignTo(this.codeEl, 'tl-tr', [2, 0]);
- },
- loadCodeImg: function() {
- //如果浏覽器發現url不變,就認為圖檔沒有改變,就會使用緩存中的圖檔,而不是重新向伺服器請求,是以需要加一個參數,改變url
- this.codeEl.set({
- src: this.codeUrl + '?id=' + Math.random()
- });
- }
- });
Ext.define('SMS.view.CheckCode', {
extend: 'Ext.form.field.Text',
alias: 'widget.checkcode',
inputType: 'codefield',
codeUrl: Ext.BLANK_IMAGE_URL,
isLoader: true,
onRender: function(ct, position) {
this.callParent(arguments);
this.codeEl = ct.createChild({
tag: 'img',
src: Ext.BLANK_IMAGE_URL
});
this.codeEl.addCls('x-form-code');
this.codeEl.on('click', this.loadCodeImg, this);
if(this.isLoader) {
this.loadCodeImg();
}
},
aliasErrorIcon: function() {
this.errorIcon.alignTo(this.codeEl, 'tl-tr', [2, 0]);
},
loadCodeImg: function() {
//如果浏覽器發現url不變,就認為圖檔沒有改變,就會使用緩存中的圖檔,而不是重新向伺服器請求,是以需要加一個參數,改變url
this.codeEl.set({
src: this.codeUrl + '?id=' + Math.random()
});
}
});
以上代碼中,定義了一個―類‖,名字是:SMS.view.CheckCode,其實這個名字,相當
于 extjs 3.x 之中的命名空間,以前也提到過。它繼承自 Ext.form.field.Text,在它的
onRender 中,我們寫了一些代碼。其中 this.callParent(arguments); 代替了
xxxx.superclass.onRender.call(this, ct, position);在 Ext.form.field.Text 的基礎上,使用
createChild 方法,建立了一個圖檔,并為其添加了一個名為 x-form-code,而後,給其建立
了一個 click 事件,這個事件實作的功能是,當我們點選驗證碼圖檔時,換另外一張圖檔,
也就是常說的:―看不清?換一張功能。‖,最後,如果 isLoader 為 True 時,調用
loadCodeImg 方法。至此,驗證碼功能全部完成了。下面,我們看看如何使用。
建立 Login.js 檔案,定義―類‖SMS.view.Login,其全部代碼為(Login.js):
Js代碼

- Ext.define('SMS.view.Login', {
- extend: 'Ext.window.Window',
- alias: 'widget.loginForm',
- requires: [
- 'Ext.form.*',
- 'SMS.view.CheckCode'
- ],
- initComponent: function() {
- var checkcode = Ext.create('SMS.view.CheckCode', {
- cls: 'key',
- fieldLabel: '驗證碼',
- name: 'checkcode',
- id: 'checkcode',
- allowBlank: false,
- isLoader: true,
- blankText: '驗證碼不能為空',
- codeUrl: 'rand.action',
- width: 160
- });
- var form = Ext.widget('form', {
- border: false,
- bodyPadding: 10,
- fieldDefaults: {
- labelAlign: 'left',
- labelWidth: 55,
- labelStyle: 'font-weight: bold'
- },
- defaults: {
- margins: '0 0 10 0'
- },
- items: [{
- xtype: 'textfield',
- id: 'username',
- name: 'username',
- fieldLabel: '使用者名',
- blankText: '使用者名不能為空',
- allowBlank: false,
- width: 240
- }, {
- xtype: 'textfield',
- id: 'password',
- name: 'password',
- fieldLabel: '密 碼',
- allowBlank: false,
- blankText: '密碼不能為空',
- width: 240,
- inputType: 'password'
- }, checkcode],
- buttons: [{
- text: '登入',
- handler: function() {
- //擷取目前的表單form
- var form = this.up('form').getForm();
- //判斷否通過了表單驗證,如果不能空的為空則不能送出
- if (form.isValid()) {
- //alert("可以送出");
- form.submit({
- clientValidation : true,
- waitMsg : '請稍候',
- waitTitle : '正在驗證登入',
- url : 'login.action',
- success : function(form, action) {
- //登入成功後的操作,這裡隻是提示一下
- Ext.MessageBox.show({
- width : 150,
- title : "登入成功",
- buttons : Ext.MessageBox.OK,
- msg : action.result.msg
- })
- },
- failure : function(form, action) {
- Ext.MessageBox.show({
- width : 150,
- title : "登入失敗",
- buttons : Ext.MessageBox.OK,
- msg : action.result.msg
- })
- }
- })
- }
- }
- }, {
- text: '取消',
- handler: function() {
- //點選取消,關閉登入視窗
- // var form = this.up('form');
- // form.close();
- }
- }]
- });
- Ext.apply(this, {
- height: 160,
- width: 280,
- title: '使用者登入',
- closeAction: 'hide',
- closable: false,
- iconCls: 'login',
- layout: 'fit',
- modal: true,
- plain: true,
- resizable: false,
- items: form
- });
- this.callParent(arguments);
- }
- });
Ext.define('SMS.view.Login', {
extend: 'Ext.window.Window',
alias: 'widget.loginForm',
requires: [
'Ext.form.*',
'SMS.view.CheckCode'
],
initComponent: function() {
var checkcode = Ext.create('SMS.view.CheckCode', {
cls: 'key',
fieldLabel: '驗證碼',
name: 'checkcode',
id: 'checkcode',
allowBlank: false,
isLoader: true,
blankText: '驗證碼不能為空',
codeUrl: 'rand.action',
width: 160
});
var form = Ext.widget('form', {
border: false,
bodyPadding: 10,
fieldDefaults: {
labelAlign: 'left',
labelWidth: 55,
labelStyle: 'font-weight: bold'
},
defaults: {
margins: '0 0 10 0'
},
items: [{
xtype: 'textfield',
id: 'username',
name: 'username',
fieldLabel: '使用者名',
blankText: '使用者名不能為空',
allowBlank: false,
width: 240
}, {
xtype: 'textfield',
id: 'password',
name: 'password',
fieldLabel: '密 碼',
allowBlank: false,
blankText: '密碼不能為空',
width: 240,
inputType: 'password'
}, checkcode],
buttons: [{
text: '登入',
handler: function() {
//擷取目前的表單form
var form = this.up('form').getForm();
//判斷否通過了表單驗證,如果不能空的為空則不能送出
if (form.isValid()) {
//alert("可以送出");
form.submit({
clientValidation : true,
waitMsg : '請稍候',
waitTitle : '正在驗證登入',
url : 'login.action',
success : function(form, action) {
//登入成功後的操作,這裡隻是提示一下
Ext.MessageBox.show({
width : 150,
title : "登入成功",
buttons : Ext.MessageBox.OK,
msg : action.result.msg
})
},
failure : function(form, action) {
Ext.MessageBox.show({
width : 150,
title : "登入失敗",
buttons : Ext.MessageBox.OK,
msg : action.result.msg
})
}
})
}
}
}, {
text: '取消',
handler: function() {
//點選取消,關閉登入視窗
// var form = this.up('form');
// form.close();
}
}]
});
Ext.apply(this, {
height: 160,
width: 280,
title: '使用者登入',
closeAction: 'hide',
closable: false,
iconCls: 'login',
layout: 'fit',
modal: true,
plain: true,
resizable: false,
items: form
});
this.callParent(arguments);
}
});
程式的入口(app.js):
Js代碼

- Ext.application({
- name: 'SMS',
- appFolder: 'app',
- launch: function() {
- requires: ['SMS.view.Login']
- var win;
- win = Ext.create('SMS.view.Login').show();
- }
- });
Ext.application({
name: 'SMS',
appFolder: 'app',
launch: function() {
requires: ['SMS.view.Login']
var win;
win = Ext.create('SMS.view.Login').show();
}
});
login.jsp:
Jsp代碼

- <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
- %>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <base href="<%=basePath%>">
- <title>使用者登入</title>
- <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css" />
- <script type="text/javascript" src="extjs/ext-all.js"></script>
- <script type="text/javascript" src="extjs/ext-lang-zh_CN.js"></script>
- <script type="text/javascript" src="app.js"></script>
- <style type="text/css">
- #checkcode {
- float: left;
- }
- .x-form-code {
- width: 73px;
- height: 20px;
- vertical-align: middle;
- cursor: pointer;
- float: left;
- margin-left: 7px;
- }
- </style>
- </head>
- <body>
- </body>
- </html>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>" target="_blank" rel="external nofollow" >
<title>使用者登入</title>
<link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css" target="_blank" rel="external nofollow" />
<script type="text/javascript" src="extjs/ext-all.js"></script>
<script type="text/javascript" src="extjs/ext-lang-zh_CN.js"></script>
<script type="text/javascript" src="app.js"></script>
<style type="text/css">
#checkcode {
float: left;
}
.x-form-code {
width: 73px;
height: 20px;
vertical-align: middle;
cursor: pointer;
float: left;
margin-left: 7px;
}
</style>
</head>
<body>
</body>
</html>
生成随機驗證碼的類( RandomNumUtil.java):
Java代碼

- package org.changkong.sms.utils;
- import java.awt.Color;
- import java.awt.Font;
- import java.awt.Graphics;
- import java.awt.image.BufferedImage;
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.util.Random;
- import javax.imageio.ImageIO;
- import javax.imageio.stream.ImageOutputStream;
- public class RandomNumUtil {
- private ByteArrayInputStream image; //圖像
- private String str; //驗證碼
- private RandomNumUtil() {
- init(); //初始化屬性
- }
- public static RandomNumUtil Instance() {
- return new RandomNumUtil();
- }
- public ByteArrayInputStream getImage() {
- return this.image;
- }
- public String getString() {
- return this.str;
- }
- private void init() {
- //在記憶體中建立圖象
- //圖像的高度和寬度
- int width = 55, height = 20;
- BufferedImage image = new BufferedImage(width, height,
- BufferedImage.TYPE_INT_RGB);
- //擷取圖形上下文
- Graphics g = image.getGraphics();
- //生成随機類
- Random random = new Random();
- //設定背景色
- g.setColor(getRandColor(200, 250));
- g.fillRect(0, 0, width, height);
- //設定字型
- g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
- //随機産生155條幹擾線,使圖象中的認證碼不易被其它程式探測到
- g.setColor(getRandColor(160, 200));
- for (int i = 0; i < 155; i++) {
- int x = random.nextInt(width);
- int y = random.nextInt(height);
- int xl = random.nextInt(12);
- int yl = random.nextInt(12);
- g.drawLine(x, y, x + xl, y + yl);
- }
- //取随機産生的認證碼(6位數字)
- String sRand = "";
- for (int i = 0; i < 4; i++) {
- String rand = String.valueOf(random.nextInt(10));
- sRand += rand;
- //将認證碼顯示到圖象中
- g.setColor(new Color(20 + random.nextInt(110), 20 + random
- .nextInt(110), 20 + random.nextInt(110)));
- //調用函數出來的顔色相同,可能是因為種子太接近,是以隻能直接生成
- g.drawString(rand, 13 * i + 6, 16);
- }
- //指派驗證碼
- this.str = sRand;
- //圖象生效
- g.dispose();
- ByteArrayInputStream input = null;
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- try {
- ImageOutputStream imageOut = ImageIO
- .createImageOutputStream(output);
- ImageIO.write(image, "JPEG", imageOut);
- imageOut.close();
- input = new ByteArrayInputStream(output.toByteArray());
- } catch (Exception e) {
- System.out.println("驗證碼圖檔産生出現錯誤:" + e.toString());
- }
- this.image = input;
- }
- 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);
- }
- }
package org.changkong.sms.utils;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
/**
* 生成驗證碼的類檔案
*
*/
public class RandomNumUtil {
private ByteArrayInputStream image; //圖像
private String str; //驗證碼
private RandomNumUtil() {
init(); //初始化屬性
}
/*
* 取得RandomNumUtil執行個體
*/
public static RandomNumUtil Instance() {
return new RandomNumUtil();
}
/*
* 取得驗證碼圖檔
*/
public ByteArrayInputStream getImage() {
return this.image;
}
/*
* 取得圖檔的驗證碼
*/
public String getString() {
return this.str;
}
private void init() {
//在記憶體中建立圖象
//圖像的高度和寬度
int width = 55, height = 20;
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
//擷取圖形上下文
Graphics g = image.getGraphics();
//生成随機類
Random random = new Random();
//設定背景色
g.setColor(getRandColor(200, 250));
g.fillRect(0, 0, width, height);
//設定字型
g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
//随機産生155條幹擾線,使圖象中的認證碼不易被其它程式探測到
g.setColor(getRandColor(160, 200));
for (int i = 0; i < 155; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x, y, x + xl, y + yl);
}
//取随機産生的認證碼(6位數字)
String sRand = "";
for (int i = 0; i < 4; i++) {
String rand = String.valueOf(random.nextInt(10));
sRand += rand;
//将認證碼顯示到圖象中
g.setColor(new Color(20 + random.nextInt(110), 20 + random
.nextInt(110), 20 + random.nextInt(110)));
//調用函數出來的顔色相同,可能是因為種子太接近,是以隻能直接生成
g.drawString(rand, 13 * i + 6, 16);
}
//指派驗證碼
this.str = sRand;
//圖象生效
g.dispose();
ByteArrayInputStream input = null;
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
ImageOutputStream imageOut = ImageIO
.createImageOutputStream(output);
ImageIO.write(image, "JPEG", imageOut);
imageOut.close();
input = new ByteArrayInputStream(output.toByteArray());
} catch (Exception e) {
System.out.println("驗證碼圖檔産生出現錯誤:" + e.toString());
}
this.image = input;/* 指派圖像 */
}
/*
* 給定範圍獲得随機顔色
*/
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);
}
}
驗證碼的Action(SecurityCodeAction.java):
Java代碼

- package org.changkong.sms.action;
- import java.io.ByteArrayInputStream;
- import org.changkong.sms.utils.RandomNumUtil;
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Controller;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
- @Controller("sercurityCodeAction")
- @Scope("prototype")
- public class SecurityCodeAction extends ActionSupport {
- private ByteArrayInputStream inputStream;
- public String execute() throws Exception {
- RandomNumUtil rdnu = RandomNumUtil.Instance();
- //取得帶有随機字元串的圖檔
- this.setInputStream(rdnu.getImage());
- //取得随機字元串放入HttpSession
- ActionContext.getContext().getSession().put("random", rdnu.getString());
- return SUCCESS;
- }
- public void setInputStream(ByteArrayInputStream inputStream) {
- this.inputStream = inputStream;
- }
- public ByteArrayInputStream getInputStream() {
- return inputStream;
- }
- }
package org.changkong.sms.action;
import java.io.ByteArrayInputStream;
import org.changkong.sms.utils.RandomNumUtil;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
/**
* 驗證碼的Action
* 使用SSH內建開發,Action由Spring管理
*/
@Controller("sercurityCodeAction")
@Scope("prototype")
public class SecurityCodeAction extends ActionSupport {
private ByteArrayInputStream inputStream;
public String execute() throws Exception {
RandomNumUtil rdnu = RandomNumUtil.Instance();
//取得帶有随機字元串的圖檔
this.setInputStream(rdnu.getImage());
//取得随機字元串放入HttpSession
ActionContext.getContext().getSession().put("random", rdnu.getString());
return SUCCESS;
}
public void setInputStream(ByteArrayInputStream inputStream) {
this.inputStream = inputStream;
}
public ByteArrayInputStream getInputStream() {
return inputStream;
}
}
登入Action(LoginAction.java):
Java代碼

- package org.changkong.sms.action;
- import org.apache.struts2.ServletActionContext;
- import org.springframework.context.annotation.Scope;
- import org.springframework.stereotype.Controller;
- import com.opensymphony.xwork2.ActionContext;
- @Controller("loginAction")
- @Scope("prototype")
- public class LoginAction {
- private String username;
- private String password;
- private String checkcode; // 表單中的rand
- //從session中取出RandomAction.java 中生成的驗證碼random
- String arandom = (String) (ActionContext.getContext().getSession().get("random"));
- public String execute() {
- if(!arandom.equals(checkcode)) {
- System.out.println("驗證碼不正确");
- } else if(!"admin".equals(username)) {
- System.out.println("使用者不存在");
- } else if("admin".equals(password)) {
- System.out.println("密碼錯誤");
- }
- return "success";
- }
- public String logout() {
- ServletActionContext.getRequest().getSession().invalidate();
- return "logout";
- }
- public String getCheckcode() {
- return checkcode;
- }
- public void setCheckcode(String checkcode) {
- this.checkcode = checkcode;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getPassword() {
- return password;
- }
- public void setPassword(String password) {
- this.password = password;
- }
- }
package org.changkong.sms.action;
import org.apache.struts2.ServletActionContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.opensymphony.xwork2.ActionContext;
/**
* 登入Action
*/
@Controller("loginAction")
@Scope("prototype")
public class LoginAction {
private String username;
private String password;
private String checkcode; // 表單中的rand
//從session中取出RandomAction.java 中生成的驗證碼random
String arandom = (String) (ActionContext.getContext().getSession().get("random"));
public String execute() {
if(!arandom.equals(checkcode)) {
System.out.println("驗證碼不正确");
} else if(!"admin".equals(username)) {
System.out.println("使用者不存在");
} else if("admin".equals(password)) {
System.out.println("密碼錯誤");
}
return "success";
}
public String logout() {
ServletActionContext.getRequest().getSession().invalidate();
return "logout";
}
public String getCheckcode() {
return checkcode;
}
public void setCheckcode(String checkcode) {
this.checkcode = checkcode;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Struts.xml:
Xml代碼

- <!-- 使用者登陸 -->
- <action name="login" class="loginAction">
- <!-- LoginAction無需經過LoginInterceptor -->
- <interceptor-ref name="defaultStack"></interceptor-ref>
- <result name="success" type="redirect">/main.jsp</result>
- <result name="fail">/login.jsp</result>
- <result name="logout">/login.jsp</result>
- </action>
- <!-- Random驗證碼 -->
- <action name="rand" class="sercurityCodeAction">
- <result type="stream">
- <param name="contentType">image/jpeg</param>
- <param name="inputName">inputStream</param>
- </result>
- </action>