富浏览器程序设计实例 -页面控制 - 登录与验证码

10年前


这篇介绍是作为富浏览器程序设计实例前面博客的补充。
页面效果如下:



登录与验证涉及8个文件,罗列如下:
login.js
checkCode.css
LoginAction.java
LoginService.java
LoginServiceImpl.java
LoginDao.java
LoginDaoImpl.java
User.java

        在登录的模块中首先应当验证验证码的正确性,然后在查阅数据库内容。如果仅仅是简单的登录验证,实际上和Session并没有关系,但是如果你要控制页面,不让他随便跳转,这就和Session有关了。举例来说:登录页是login.jsp,登录完成,借助struts你会跳转到对应的页面。但是如果你直接在地址栏输入你要去的页面,你可以直接进入。这在很多系统中是不允许的。为了达到这个目的,我们需要对页面进行拦截和过滤,Servlet中提供了一个类是Filter类,专门做这件事。在这里先介绍登录与验证的实现方法,过滤的功能 将在《页面Filter拦截与过滤》介绍,因为有些可写的。这篇文章是对《SSH2+ExtJS4.2.1+MySql示例程序》系列博客的完善,在这篇博客中提供的源代码也将更新,但源地址连接会保留。新的源代码中将会增加对登录、验证和页面拦截与过滤的功能。
       针对源代码在CSDN中的积分设置仍然是20分,分成两个压缩包,每个10分。这样设置的原因是:1.CSDN初始20分,如果你只是个伸手党,没有开源精神,不做贡献,你的CSDN积分肯定不够20分,那么资源不会分享给你;2.下载资源,评论下,系统会返还你的积分,也就是说对你并没有损失;3.作者耗费精力从无到有,算是另一种收获吧。


在login()方法中
ajaxJson()方法是向服务器发送消息的

  1.     /** 
  2.      * trim()方法用于去除空格 
  3.      * 1. 判断验证码正确性 
  4.      * 2. 判断用户名在数据库中是否存在 
  5.      * 3. 判断密码是否正确 
  6.      */  
  7.     public void login()  
  8.     {  
  9.         String msg = "";  
  10.   
  11.         // 判断验证码正确性  
  12.         String actionCheckCode = (String) ActionContext.getContext().getSession().get("getRandomNum");  
  13.         if ( !pageCheckCode.equals(actionCheckCode) )  
  14.         {  
  15.             msg = "{success:false,failMessage:'验证码有误'}";  
  16.         }  
  17.         else  
  18.         {  
  19.             try  
  20.             {  
  21.                 // 判断用户名在数据库中是否存在  
  22.                 user = loginService.get(User.class"username", username.trim());  
  23.                 if (user != null)  
  24.                 {  
  25. //                    if ( passwordMd5.trim().equals(user.getPassword().trim()) )     // TODO 2013-11-18  
  26.                     if ( password.trim().equals(user.getPassword().trim()) )  
  27.                     {  
  28.                         msg = "{success:true}";  
  29.   
  30.                         this.userSession();  
  31.                     }  
  32.                     else{  
  33.                         msg = "{success:false,failMessage:'密码不正确'}";  
  34.                     }  
  35.                 }  
  36.                 else {  
  37.                     msg = "{success:false,failMessage:'系统无此用户'}";  
  38.                 }  
  39.             }  
  40.             catch (Exception e)  
  41.             {  
  42.                 msg = "{success:false, failMessage:'登录失败,请确认网络或数据库是否正常!'}";  
  43.             }  
  44.         }  
  45.         ajaxJson(msg);  
  46.     }  


         验证码生成方法,作为LoginAction.java中的一个独立方法,当你在浏览器地址栏中输入如下连接的时候,页面中会出现一个图片,图片中包含验证码
http://localhost:8099/system/login!sendCheckCode.action
  1.     /** 
  2.      * 生 成随机验证码 这是一个独立的 Action 方法  
  3.      */  
  4.     public void sendCheckCode() throws IOException  
  5.     {  
  6.         //设置页面不缓存  
  7.         HttpServletResponse response = getUTFResponse();     //ServletActionContext.getResponse();  
  8.         response.setHeader("Pragma""No-cache");  
  9.         response.setHeader("Cache-Control""no-cache");  
  10.         response.setHeader("Content-Type""image/jpeg");  
  11.         response.setDateHeader("Expires"0);  
  12.   
  13.         // 在内存中创建图象  
  14.         int width = 60, height = 20;  
  15.         BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);  
  16.         // 获取图形上下文  
  17.         Graphics g = image.getGraphics();  
  18.         //生成随机类  
  19.         Random random = new Random();  
  20.         // 设定背景色  
  21.         g.setColor(getRandColor(200250));  
  22.         g.fillRect(00, width, height);  
  23.         //设定字体  
  24.         g.setFont(new Font("Times New Roman", Font.PLAIN, 18));  
  25.   
  26.         // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到  
  27.         g.setColor(getRandColor(160200));  
  28.         for (int i = 0; i < 155; i++)  
  29.         {  
  30.             int x = random.nextInt(width);  
  31.             int y = random.nextInt(height);  
  32.             int xl = random.nextInt(12);  
  33.             int yl = random.nextInt(12);  
  34.             g.drawLine(x, y, x + xl, y + yl);  
  35.         }  
  36.   
  37.         // 取随机产生的认证码(4位数字)  
  38.         String randomNum = "";  
  39.         for (int i = 0; i < 4; i++)  
  40.         {  
  41.             String getRandomNum = String.valueOf(random.nextInt(10));  
  42.             randomNum += getRandomNum;  
  43.             // 将认证码显示到图象中  
  44.             g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));  
  45.                     // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成  
  46.   
  47.             g.drawString(getRandomNum, 13 * i + 616);  
  48.         }  
  49.   
  50.         System.out.println("randomNum = " + randomNum);  
  51.   
  52.         // 将认证码存入SESSION  
  53.         ActionContext.getContext().getSession().put("getRandomNum", randomNum);  
  54.         // 图象生效  
  55.         g.dispose();  
  56.         OutputStream output = response.getOutputStream();  
  57.         try  
  58.         {  
  59.             // 输出图象到页面  
  60.             ImageIO.write(image, "JPEG", output);  
  61.         }  
  62.         finally {  
  63.             output.flush();  
  64.             output.close();  
  65.         }  
  66.     }  
  67.   
  68.     //获得随机颜色 给定范围获得随机颜色  
  69.     // java.awt.Color  
  70.     private Color getRandColor(int fc, int bc)  
  71.     {  
  72.         Random random = new Random();  
  73.         if (fc > 255)  
  74.             fc = 255;  
  75.   
  76.         if (bc > 255)  
  77.             bc = 255;  
  78.   
  79.         int r = fc + random.nextInt(bc - fc);  
  80.         int g = fc + random.nextInt(bc - fc);  
  81.         int b = fc + random.nextInt(bc - fc);  
  82.         return new Color(r, g, b);  
  83.     } 

         后台查询用户调用的方法:
  1.     /** 
  2.      * 根据属性名和属性值获取实体对象. 
  3.      * 
  4.      * @param clazz        实体对象类型 
  5.      * @param propertyName 属性名称 
  6.      * @param value        属性值 
  7.      * @return 实体对象 
  8.      */  
  9.     @SuppressWarnings("unchecked")  
  10.     public <T> T get(Class<T> clazz, String propertyName, Object value)  
  11.     {  
  12.         Assert.hasText(propertyName, "propertyName must not be empty");  
  13.         Assert.notNull(value, "value is required");  
  14.   
  15.         String hql = "from " + clazz.getName() + " as model where model." + propertyName + " = ?";  
  16.   
  17.         return (T) getSession().createQuery(hql).setParameter(0, value).uniqueResult();  
  18.     }  
  19.   
  20. }

        对前台脚本的处理
  1.         var loginForm = Ext.create('Ext.FormPanel',  
  2.         {  
  3.             height:100,  
  4.             width:300,  
  5.             frame:true,  
  6.             baseCls:'x-plain',  
  7.             items:  
  8.             [  
  9.                 {  
  10.                     xtype:'textfield',  
  11.   
  12.                     value:'a',  
  13.   
  14.                     name:'username',    // 要对应LoginAction里的username  
  15.                     fieldLabel:'用户名',  
  16.                     labelWidth:60,  
  17.                     width:250,  
  18.                     padding:'5 20 5 20',  
  19.                     allowBlank:false,  
  20.                     blankText:'用户名不能为空',  
  21.                     msgTarget:'side'  
  22.                 },  
  23.                 {  
  24.                     xtype:'textfield',  
  25.   
  26.                     value:'a',  
  27.   
  28.                     name:'password',  
  29.                     itemId:'password',  
  30.                     inputType:'password',  
  31.                     fieldLabel:'密   码',  
  32.                     labelWidth:60,  
  33.                     width:250,  
  34.                     padding:'10 20 5 20',  
  35.                     allowBlank:false,  
  36.                     blankText:'密码不能为空',  
  37.                     msgTarget:'side'  
  38.                 },  
  39.                 {  
  40.                     xtype:'textfield',         // 隐藏字段 用于将密码铭文加密  
  41.                     itemId:'passwordMd5',  
  42.                     name:'passwordMd5',  
  43.                     width:0,  
  44.                     hidden:true  
  45.                 },  
  46.                 checkcode  
  47.             ]  
  48.         }); 

        关于Struts2的属性映射原理,页面中定义的属性只要和对应要访问的Action中的属性相同即可,这里相同指大小写也要一致。在ExtJS中 定义的
name:'username',属性,在Action中也要有对应的字段。从请求的页面将要发送的值传送到Action中是通过Struts2来做的,Struts2就像一个信息传递的使者。知道该这么用就好,没必要深究太多。

          相关资源将会在12月2日之前更新,在
SSH2+ExtJS4.2.1+MySql示例程序下面会给出新的资源链接。针对用户登录与页面控制是一组完整的逻辑,这篇文章先介绍登录与验证,今天晚上在更新《页面Filter拦截与过滤》的内容,如果对您有帮助,帮忙点个赞~