现在的位置: 首页 > 综合 > 正文

Extjs+Struts+simpleCaptcha+jsp:搭建你的验证码平台

2013年08月04日 ⁄ 综合 ⁄ 共 10501字 ⁄ 字号 评论关闭

步骤一:

在servlet容器中部署一个SimpleCaptchaServlet

1、编写一个名为SimpleCaptchaServlet的HttpServlet子类:

import java.io.IOException;
//from kaiwii's blog

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import nl.captcha.Captcha;
import nl.captcha.servlet.CaptchaServletUtil;

public class SimpleCaptchaServlet extends HttpServlet
{
  private static final long serialVersionUID = 1L;
  private static final String PARAM_HEIGHT = "height";
  private static final String PARAM_WIDTH = "width";
  protected int _width = 200;
  protected int _height = 50;
//from kaiwii's blog

/**
 * 方法通过取默认值或者读取初始化值的方式获取验证码图形的大小
 */

  public void init()
    throws ServletException
  {
    if (getInitParameter("height") != null)
      this._height = Integer.valueOf(getInitParameter("height")).intValue();
    if (getInitParameter("width") != null)
      this._width = Integer.valueOf(getInitParameter("width")).intValue();
  }

  public void doGet(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse)
    throws ServletException, IOException
  {
//from kaiwii's blog

//根据设置的大小初始化验证码对象localCaptcha
    Captcha localCaptcha = new Captcha.Builder(this._width, this._height).addText().addBackground().addNoise().build();
//将验证码的图片写到response中
    CaptchaServletUtil.writeImage(paramHttpServletResponse, localCaptcha.getImage());
//将验证码对象localCaptcha放到Session中,待会会在LoginAction类中取出
    paramHttpServletRequest.getSession().setAttribute("simpleCaptcha", localCaptcha);
  }
}

2、在web.xml中注册SimpleCaptchaServlet

<!-- 验证码(form kaiwii’s blog) -->
<servlet>
        <servlet-name>SimpleCaptcha</servlet-name>
        <servlet-class>com.htsoft.core.web.servlet.SimpleCaptchaServlet</servlet-class>
</servlet>

步骤一总结:

请求路径/CaptchaImg,实际上是请求调用SimpleCaptchaServlet的doGet()方法。每次调用doGet()方法先生成一个SimpleCaptcha对象,(而一个SimpleCaptcha对象又对应一组图片,验证码对),然后将图片作为结果,回应请求,并且将这个SimpleCaptcha对象保存到session中,以便后续步骤:LoginAction类对照验证。

步骤二:

编写LoginAction类作为验证码等信息的校验

1、关于LoginAction类,下面我们只谈谈关于验证码的部分(LoginAction类的login()方法):

//从session中获取Captcha类对象localCaptcha;localCaptcha中包含了原来的一组图片,验证码对
//from kaiwii's blog

    Captcha localCaptcha = (Captcha)getSession().getAttribute("simpleCaptcha");
              if (localCaptcha == null)
                localStringBuffer.append("请刷新验证码再登录.'");
              else if (localCaptcha.isCorrect(this.checkCode))//检验验证码对是否正确
               

2、在struts.xml中注册LoginAction类和LoginAction类里面的方法login():

<action name="login" class="LoginAction" method="login">
    <result>${successResultValue}</result>
</action>

步骤二总结:

Struts负责转发请求,就是访问login.do也就是调用LoginAction类里面的方法login()

步骤三:

编写页面部分,主要是extjs的js文件

//from kaiwii's blog
Ext.ns("App");
App.LoginWin = function(b, g) {//b,g的值通过login.jsp传递过来
    this.isCodeEnabled = b;
    this.isDyPwdEnabled = g;
    //输入框群组的布局
    var a = new Ext.form.FormPanel({
        id : "LoginFormPanel",
        bodyStyle : "padding-top:6px",
        defaultType : "textfield",
        columnWidth : 0.75,
        labelAlign : "right",
        labelWidth : 55,
        labelPad : 0,
        border : false,
        layout : "form",
        defaults : {
            style : "margin:0 0 0 0",
            anchor : "90%,120%",
            selectOnFocus : true
        },
        items : [ {
            name : "username",
            fieldLabel : "账      号",
            cls : "text-user",
            allowBlank : false,
            blankText : "账号不能为空"
        }, {
            name : "password",
            fieldLabel : "密      码",
            allowBlank : false,
            blankText : "密码不能为空",
            cls : "text-lock",
            inputType : "password"
        }, {
            name : "checkCode",
            id : "checkCode",
            fieldLabel : "验证码",
            allowBlank : false,
            hidden : true,
            cls : "text-code",
            blankText : "验证码不能为空"
        }, {
            name : "curDynamicPwd",
            hidden : true,
            id : "curDynamicPwd",
            fieldLabel : "令     牌",
            cls : "text-dynamic",
            blankText : "令牌不能为空"
        }, {//只是一个容器,里面到底是什么,需要另外指定
            //在下面指定
            /**
             * var f = Ext.getCmp("codeContainer");
             *  f.add(d);
             */

            xtype : "container",
            id : "codeContainer",
            layout : "table",
            defaultType : "textfield",
            hideLabel : false,
            layoutConfig : {
                columns : 3
            }
        }, {
            xtype : "container",
            style : "padding-left:57px",
            layout : "column",
            items : [ {
                xtype : "checkbox",
                name : "_spring_security_remember_me",
                boxLabel : "让系统记住我 "
            }, {
                xtype : "panel",
                border : false,
                bodyStyle : "font-size:12px;padding-left:80px;",
                html : '<a href="javascript:toSuggestBox()">意见箱</a>'
            } ]
        } ]
    });
    if (this.isCodeEnabled != "undefined" && this.isCodeEnabled != ""
            && this.isCodeEnabled != "1" || this.isCodeEnabled == "close") {
        a.remove(Ext.getCmp("checkCode"));
    } else {
        Ext.getCmp("checkCode").show();
        var d = [
                {
                    width : 55,
                    xtype : "label",
                    text : "    "
                },
                {
                    width : 150,
                    id : "loginCode",
                    xtype : "panel",
                    border : false,
                    //这句是验证码框架simplecaptcha的一个关键语句
                    //通过以下的url请求资源,servlet容器将其请求的资源解释
                    //为请求SimpleCaptchaServlet,而最终调用里面的doGet()方法
                    //doGet()方法会生成一个simpleVaptcha对象,这个simplecaptcha对象
                    //将会回应一个图片
                    html : '<img border="0" height="30" width="150" src="'
                            + __ctxPath + '/CaptchaImg"/>'
                }, {
                    width : 55,
                    xtype : "panel",
                    border : false,
                    bodyStyle : "font-size:12px;padding-left:12px",
                    //作为一个链接,请求刷新验证码的方法:refeshCode()
                    html : '<a href="javascript:refeshCode()">看不清</a>'
                } ];
        var f = Ext.getCmp("codeContainer");
        //codeContainer原来只是一个空的容器,现在将d的内容赋进去
        f.add(d);
        f.doLayout();
    }
    if (this.isDyPwdEnabled != "undefined" && this.isDyPwdEnabled != ""
            && this.isDyPwdEnabled != "1" || this.isDyPwdEnabled == "close") {
        a.remove(Ext.getCmp("curDynamicPwd"));
    } else {
        Ext.getCmp("curDynamicPwd").show();
    }
    var e = function() {
        if (a.form.isValid()) {
            a.form.submit({
                waitTitle : "请稍候",
                waitMsg : "正在登录......",
                //请求url:/login.do,struts框架会将其输入框里面的值都
                //转发到loginaction类里面,并且调用loginaction类里面
                //login()方法
                url : __ctxPath + "/login.do",
                success : function(h, i) {
                    handleLoginResult(i.result);
                },
                failure : function(h, i) {
                    handleLoginResult(i.result);
                    h.findField("password").setRawValue("");
                    h.findField("username").focus(true);
                }
            });
        }
    };
    //这个是整个登录页面的布局
    var c = new Ext.Window({
        id : "LoginWin",
        title : "用户登录",
        iconCls : "login-icon",
        bodyStyle : "background-color: white",
        border : true,
        closable : false,
        resizable : false,
        buttonAlign : "center",
        height : 275,
        width : 460,
        layout : {
            type : "vbox",
            align : "stretch"
        },
        keys : {
            key : Ext.EventObject.ENTER,
            fn : e,
            scope : this
        },
        items : [ {
            xtype : "panel",
            border : false,
            bodyStyle : "padding-left:60px",
            html : '<img src="' + __loginImage + '" />',
            height : 50
        }, {
            xtype : "panel",
            border : false,
            layout : "column",
            items : [ a, {
                xtype : "panel",
                border : false,
                columnWidth : 0.25,
                html : '<img src="' + __ctxPath + '/images/login-user.jpg"/>'
            } ]
        } ],
        buttons : [ {
            text : "登录",
            iconCls : "btn-login",
            handler : e.createDelegate(this)
        }, {
            text : "重置",
            iconCls : "btn-login-reset",
            handler : function() {
                a.getForm().reset();
            }
        } ]
    });
    return c;
};
function handleLoginResult(a) {
    if (a.success) {
        Ext.getCmp("LoginWin").hide();
        var b = new Ext.ProgressBar({
            text : "正在登录..."
        });
        b.show();
        window.location.href = __ctxPath + "/index.jsp";
    } else {
        Ext.MessageBox.show({
            title : "操作信息",
            msg : a.msg,
            buttons : Ext.MessageBox.OK,
            icon : Ext.MessageBox.ERROR
        });
    }
}
//刷新验证码对象,并且更新验证码容器里面的内容
//from kaiwii's blog
//关键:
function refeshCode() {
    var a = Ext.getCmp("loginCode");
    a.body.update('<img border="0" height="30" width="150" src="' + __ctxPath
            + "/CaptchaImg?rand=" + Math.random() + '"/>');
}
function toSuggestBox() {
    window.open(__ctxPath + "/info/suggest.do", "_blank");

代码中已经含有详细分析,所以关于步骤三的总结就不再累赘了!

机制分析:

servlet容器启动伊始,读取web.xml文件,发现web.xml中已经注册了SimpleCaptchaServlet,所以调用SimpleCaptchaServlet的init()方法,初始化SimpleCaptcha的大小。

用户打开login页面,在初始化页面的过程中,会读取js文件中的内容。其中,为了初始化验证码图片的时候,会请求得到一个图片资源。请求发送到服务器端的时候,servlet

容器会根据web.xml中的url pattern将这个请求理解成请求SimpleCaptchaServlet,并且调用了SimpleCaptchaServlet里面的doGet()方法。每次调用doGet()方法,都会生成一个SimpleCaptcha对象,而一个SimpleCaptcha对象里面就含有一组图片和验证码信息(在SimpleCaptcha的机制中,用户是根据图片的信息与验证码的信息作匹配来达到验证的目的的)。所以,SimpleCaptchaServlet会将SimpleCaptcha对象中的那个图片作为结果回应这个url请求,并且将这个SimpleCaptcha对象保存到session对象中,以便后续步骤中的其他类使用。这个时候,用户的客户端页面就可以获得了一个图片资源,并且使用这个图片资源来初始化验证码页面。

当用户填写完验证码和用户名、密码之后,点击按钮,触发页面的js方法。这个页面的js方法,会请求login.do资源。当这个请求发送到服务器端的时候,struts框架会根据struts.xml文件,将这个请求转发到LoginAction类中,并且将页面中由验证码和用户名、密码组成的表单(form)作为参数调用LoginAction类的login()方法。login()方法会从session对象中取出前面步骤中生成的SimpleCaptcha对象。并且使用这个SimpleCaptcha对象验证用户发送过来的验证码是否正确。

结束语:

本文只是谈了一下,基于extjs+servlet+struts+SimpleCaptcha框架下,如何实现验证码校验的基本设计和实施。至于如何配置SimpleCaptcha,extjs,struts等,请参考本博客中的其他文章:http://blog.csdn.net/Kaiwii

另外,关于SimpleCaptcha的配置,建议你可以阅读官网中的文章:

http://simplecaptcha.sourceforge.net/samples.html


                                                 作者:kaiwii

抱歉!评论已关闭.