【电信计费系统项目实战】基础篇---登录界面实现

来源:互联网 发布:中国产业数据网 编辑:程序博客网 时间:2024/04/29 19:03

这一篇很简单,登录界面无非就是账号密码框再加上一个验证码,这里我们主要了解生成验证码及验证的基本原理,可以参考我之前写的一篇ajax注册页面异步验证。
这里写图片描述
登录界面代码:

<%@page pageEncoding="utf-8"%><%@taglib uri="/struts-tags" prefix="s" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml">    <head>        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />        <title>达内-NetCTOSS</title>        <link type="text/css" rel="stylesheet" media="all" href="../styles/global.css" />        <link type="text/css" rel="stylesheet" media="all" href="../styles/global_color.css" />          <script type="text/javascript" language="javascript">             function change(imgObj) {                 imgObj.src = "createImage?date=" + new Date().getTime();             }         </script>    </head>    <body class="index">        <div class="login_box">            <!-- method="post",保证中文不乱码 -->            <form action="login" method="post">                <table>                    <tr>                        <td class="login_info">账号:</td>                        <td colspan="2"><input name="adminCode" type="text" value="<s:property value="adminCode"/>" class="width150" /></td>                        <td class="login_error_info"><span class="required">30长度的字母、数字和下划线</span></td>                    </tr>                    <tr>                        <td class="login_info">密码:</td>                        <td colspan="2"><input name="password" type="password" value="<s:property value="password"/>" class="width150" /></td>                        <td><span class="required">30长度的字母、数字和下划线</span></td>                    </tr>                    <tr>                        <td class="login_info">验证码:</td>                        <td class="width70"><input name="imageCode" type="text" class="width70" /></td>                        <td><img src="createImage" onclick="change(this)" alt="验证码" title="点击更换" /></td>                          <td><span class="required"></span></td>                                  </tr>                                <tr>                        <td></td>                        <td class="login_button" colspan="2">                            <a href="javascript:document.forms[0].submit();"><img src="../images/login_btn.png" /></a>                        </td>                            <td><span class="required"><s:property value="errorMsg"/></span></td>                                    </tr>                </table>            </form>        </div>    </body></html>

代码解释:验证码图片那一行代码,通过点击超链接的方式来变换验证码图片上的验证码:

function change(imgObj) {                 imgObj.src = "createImage?date=" + new Date().getTime();             }

显而易见,通过createImage请求来变换验证码的,接着看到底是哪个Action用来生成验证码的:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"    "http://struts.apache.org/dtds/struts-2.1.7.dtd"><struts>    <!-- 登录模块 -->    <package name="login" namespace="/login"        extends="struts-default">        <!--             跳转到登录页面Action。            该Action不需要写业务代码,class可以省略。            当class省略时,Struts2会自动调用ActionSupport,            这个类中有默认的方法execute,返回success。        -->        <action name="toLogin">            <result name="success">                /WEB-INF/main/login.jsp            </result>        </action>        <!-- 登录校验Action -->        <action name="login"             class="com.tarena.action.login.LoginAction">            <!-- 成功时跳转到首页 -->            <result name="success">                /WEB-INF/main/index.jsp            </result>            <!-- 失败时回登录页 -->            <result name="fail">                /WEB-INF/main/login.jsp            </result>        </action>        <!-- 生成验证码Action -->        <action name="createImage"            class="com.tarena.action.login.CreateImageAction">            <result name="success" type="stream">                <!--                     param是参数注入的标签,用于                    给组件的属性注入值。这里相当于是给                    stream类型的Result的inputName属性                    设置值,其值为"imageStream".                 -->                <param name="inputName">                    imageStream                </param>            </result>        </action>    </package></struts>

以上是登录模块的struts配置,我们可以看到CreateImageAction类生成验证码操作

<!-- 生成验证码Action -->        <action name="createImage"            class="com.tarena.action.login.CreateImageAction">            <result name="success" type="stream">                <!--                     param是参数注入的标签,用于                    给组件的属性注入值。这里相当于是给                    stream类型的Result的inputName属性                    设置值,其值为"imageStream".                 -->                <param name="inputName">                    imageStream                </param>            </result>        </action>

CreateImageAction完成的功能步骤:

  1. 生成图片
  2. 读取出验证码,并放入session
  3. 3.读取出图片
package com.tarena.action.login;import java.awt.image.BufferedImage;import java.io.IOException;import java.io.InputStream;import java.util.Map;import com.tarena.action.BaseAction;import com.tarena.util.ImageUtil;public class CreateImageAction extends BaseAction {    //output    private InputStream imageStream;    public String execute() {        //1.生成图片        Map<String, BufferedImage> map =             ImageUtil.createImage();        //2.读取出验证码,并放入session        String code = map.keySet().iterator().next();        session.put("imageCode", code);        //3.读取出图片        BufferedImage image = map.get(code);        try {            imageStream = ImageUtil.getInputStream(image);        } catch (IOException e) {            e.printStackTrace();            return "error";        }        return "success";    }    public InputStream getImageStream() {        return imageStream;    }    public void setImageStream(InputStream imageStream) {        this.imageStream = imageStream;    }}(map的keySet()方法返回值是Map中key值的集合)由此可以看出,具体完成验证码的是工具类ImageUtil,只不过CreateImageAction 调用它而已,它完成的功能有: 1. 用于生成一个图片,图片中带有验证码。 2. Map的key存的是验证码字符串 3. Map的value存的是图片此处灵活的运用map这个容器,非常方便的存取值。ImageUtil里都是java里最基本的知识,没什么好讲的,看看就行了:
package com.tarena.util;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.io.IOException;import java.io.InputStream;import java.util.HashMap;import java.util.Map;import java.util.Random;import com.sun.image.codec.jpeg.JPEGCodec;import com.sun.image.codec.jpeg.JPEGImageEncoder;public final class ImageUtil {    private static final char[] chars = { '0', '1', '2', '3', '4', '5', '6',            '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' };    private static final int SIZE = 4;    private static final int LINES = 5;    private static final int WIDTH = 80;    private static final int HEIGHT = 35;    private static final int FONT_SIZE = 30;    /**     * 用于生成一个图片,图片中带有验证码。     * Map的key存的是验证码字符串,     * Map的value存的是图片。     */    public static Map<String, BufferedImage> createImage() {        StringBuffer sb = new StringBuffer();        BufferedImage image = new BufferedImage(WIDTH, HEIGHT,                BufferedImage.TYPE_INT_RGB);        Graphics graphic = image.getGraphics();        graphic.setColor(Color.LIGHT_GRAY);        graphic.fillRect(0, 0, WIDTH, HEIGHT);        Random ran = new Random();        // 画随机字符        for (int i = 1; i <= SIZE; i++) {            int r = ran.nextInt(chars.length);            graphic.setColor(getRandomColor());            graphic.setFont(new Font(null, Font.BOLD + Font.ITALIC, FONT_SIZE));            graphic.drawString(chars[r] + "", (i - 1) * WIDTH / SIZE,                    2*HEIGHT/3);            sb.append(chars[r]);// 将字符保存,存入Session        }        // 画干扰线        for (int i = 1; i <= LINES; i++) {            graphic.setColor(getRandomColor());            graphic.drawLine(ran.nextInt(WIDTH), ran.nextInt(HEIGHT),                    ran.nextInt(WIDTH), ran.nextInt(HEIGHT));        }        Map<String, BufferedImage> map = new HashMap<String, BufferedImage>();        map.put(sb.toString(), image);        return map;    }    public static Color getRandomColor() {        Random ran = new Random();        Color color = new Color(ran.nextInt(256), ran.nextInt(256),                ran.nextInt(256));        return color;    }    public static InputStream getInputStream(BufferedImage image)            throws IOException {        ByteArrayOutputStream bos = new ByteArrayOutputStream();        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos);        encoder.encode(image);        byte[] imageBts = bos.toByteArray();        InputStream in = new ByteArrayInputStream(imageBts);        return in;    }}

然后就是登陆验证了,也没什么好讲的(代码如下),其他内容后面的章节会讲到。

package com.tarena.action.login;import org.omg.CORBA.Request;import com.tarena.action.BaseAction;import com.tarena.dao.DAOException;import com.tarena.dao.DAOFactory;import com.tarena.dao.login.ILoginDAO;import com.tarena.entity.Admin;public class LoginAction extends BaseAction {    //input    private String adminCode;    private String password;    private String imageCode;    //output    private String errorMsg;    public String execute() {        //1.校验验证码        String code = (String) session.get("imageCode");        if(code == null ||                !code.equalsIgnoreCase(imageCode)) {            //验证码不匹配,校验失败            errorMsg = "验证码错误!";            return "fail";        }        //2.根据账号查询管理员        ILoginDAO dao = DAOFactory.getLoginDAO();        Admin admin = null;        try {            admin = dao.findByCode(adminCode);        } catch (DAOException e) {            e.printStackTrace();            errorMsg = "查询管理员报错,请联系系统管理员!";            return "fail"; //异常,返回登录页面        }        if(admin == null) {            //3.如果没有对应的管理员,登录失败,账号不存在            errorMsg = "账号不存在!";            return "fail"; //验证失败,回登录页面        } else {            //4.如果有对应管理员,看密码,若密码错误,登录失败            String pwd = admin.getPassword();            if(!pwd.equals(password)) {                errorMsg = "密码错误!";                return "fail"; //验证失败,回登录页面            }        }        //4.登录成功后,将登录信息记录到Session        session.put("admin", adminCode);        return "success"; //成功,去index.jsp    }    public String getAdminCode() {        return adminCode;    }    public void setAdminCode(String adminCode) {        this.adminCode = adminCode;    }    public String getErrorMsg() {        return errorMsg;    }    public void setErrorMsg(String errorMsg) {        this.errorMsg = errorMsg;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String getImageCode() {        return imageCode;    }    public void setImageCode(String imageCode) {        this.imageCode = imageCode;    }}

很多网站都会加个验证码,比如百度贴吧啥的,验证码一般是防止有人利用机器人自动批量注册、对特定的注册用户用特定程序暴力破解方式进行不断的登陆、灌水。因为验证码是一个混合了数字或符号的图片,人眼看起来都费劲,机器识别起来就更困难。map可以很好的存取字符串和图片来实现验证码,所以这里主要了解map的用法就行啦!

5 4