前段时间学习Struts2做了个验证码的小例子,今天在火狐下查看遇到点问题,在这里记录一下。
制作图形验证码关键在于编写生成图形的Servlet
- package com.petrochina.servlet;
- import <a href="http://lib.csdn.net/base/javase" class='replace_word' title="Java SE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.awt.Color;
- import java.awt.Font;
- import java.awt.Graphics;
- import java.awt.image.BufferedImage;
- import java.io.IOException;
- import java.util.Random;
- import javax.imageio.ImageIO;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- public class AuthImg extends HttpServlet {
- // 设置图形验证码中字符串的字体和大小
- private Font myFont = new Font("Arial Black", Font.PLAIN, 16);
- @Override
- public void init() throws ServletException {
- super.init();
- }
- // 生成随机颜色
- 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);
- }
- @Override
- public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- // 阻止生成的页面内容被缓存,保证每次重新生成随机验证码
- response.setHeader("Pragma", "No-cache");
- response.setHeader("Cache-Control", "no-cache");
- response.setDateHeader("Expires", 0);
- response.setContentType("image/jpeg");
- // 指定图形验证码图片的大小
- int width = 100, 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(1, 1, width - 1, height - 1);
- g.setColor(new Color(102, 102, 102));
- g.drawRect(0, 0, width - 1, height - 1);
- g.setFont(myFont);
- // 随机生成线条,让图片看起来更加杂乱
- g.setColor(getRandColor(160, 200));
- for (int i = 0; i < 155; i++) {
- int x = random.nextInt(width - 1);// 起点的x坐标
- int y = random.nextInt(height - 1);// 起点的y坐标
- int x1 = random.nextInt(6) + 1;// x轴偏移量
- int y1 = random.nextInt(12) + 1;// y轴偏移量
- g.drawLine(x, y, x + x1, y + y1);
- }
- // 随机生成线条,让图片看起来更加杂乱
- for (int i = 0; i < 70; i++) {
- int x = random.nextInt(width - 1);
- int y = random.nextInt(height - 1);
- int x1 = random.nextInt(12) + 1;
- int y1 = random.nextInt(6) + 1;
- g.drawLine(x, y, x - x1, y - y1);
- }
- // 该变量用来保存系统生成的随机字符串
- String sRand = "";
- for (int i = 0; i < 6; i++) {
- // 取得一个随机字符
- String tmp = getRandomChar();
- sRand += tmp;
- // 将系统生成的随机字符添加到图形验证码图片上
- g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
- g.drawString(tmp, 15 * i + 10, 15);
- }
- // 取得用户Session
- HttpSession session = request.getSession(true);
- // 将系统生成的图形验证码添加
- session.setAttribute("rand", sRand);
- g.dispose();
- // 输出图形验证码图片
- ImageIO.write(image, "JPEG", response.getOutputStream());
- }
- // 随机生成一个字符
- private String getRandomChar() {
- int rand = (int) Math.round(Math.random() * 2);// 将0~2的小数四舍五入生成整数
- long itmp = 0;
- char ctmp = '/u0000';
- // 根据rand的值来决定是生成一个大写字母、小写字母和数字
- switch (rand) {
- // 生成大写字母的情形
- case 1:
- itmp = Math.round(Math.random() * 25 + 65);
- ctmp = (char) itmp;
- return String.valueOf(ctmp);
- // 生成小写字母
- case 2:
- itmp = Math.round(Math.random() * 25 + 97);
- ctmp = (char) itmp;
- return String.valueOf(ctmp);
- // 生成数字
- default:
- itmp = Math.round(Math.random() * 9);
- return String.valueOf(itmp);
- }
- }
- }
在web.xml中添加Servlet配置
- <!-- 生成验证码 -->
- <servlet>
- <servlet-name>authImg</servlet-name>
- <servlet-class>com.petrochina.servlet.AuthImg</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>authImg</servlet-name>
- <url-pattern>/authImg</url-pattern>
- </servlet-mapping>
注册页面regist.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>注册页面</title>
- <mce:script type="text/<a href="http://lib.csdn.net/base/javascript" class='replace_word' title="JavaScript知识库" target='_blank' style='color:#df3434; font-weight:bold;'>JavaScript</a>" src="js/<a href="http://lib.csdn.net/base/jquery" class='replace_word' title="jQuery知识库" target='_blank' style='color:#df3434; font-weight:bold;'>jQuery</a>.1.4.2.js" mce_src="js/jquery.1.4.2.js"></mce:script>
- <mce:script type="text/javascript"><!--
- //刷新验证码
- function refresh()
- {
- document.getElementById("authImg").src="authImg?now="+new Date();//使用时间作为参数避免浏览器从缓存取图片
- }
- // --></mce:script>
- </head>
- <body>
- <form action="registe.action" method="post" id="registe">
- <table>
- <caption><h2>用户注册</h2></caption>
- <tr>
- <td>用 户 名:</td><td><input type="text" name="username" id="username"/></td>
- </tr>
- <tr>
- <td>密 码:</td><td><input type="text" name="password" id="password"/> </td>
- </tr>
- <tr>
- <td>确认密码:</td><td><input type="text" name="chkpassword"/> </td>
- </tr>
- <tr>
- <td>Email:</td><td><input type="text" name="email"/> </td>
- </tr>
- <tr>
- <td>验证码:</td><td valign="bottom"><input type="text" name="vercode" size="10"/> <img alt="" src="authImg" mce_src="authImg" id="authImg" align="absmiddle"><a href="#" mce_href="#" onclick="refresh()"><span style="font-size:12px" mce_style="font-size:12px">刷新验证码</span></a></td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="提交"/><input type="reset" value="重填"/></td>
- </tr>
- </table>
- </form>
- </body>
- </html>
后台RegistAction
- @Override
- public String execute() throws Exception {
- Map session = ActionContext.getContext().getSession();
- String ver2 = (String) session.get("rand");
- session.put("rand", null);
- // 判断验证码是否正确
- if (vercode.equals(ver2)) {
- if (userManager.validName(username)) {
- if (userManager.addUser(username, password, email) > 0)
- return SUCCESS;
- else
- addActionError("注册失败,请重试!");
- } else {
- addActionError("该用户名已存在,请重新输入!");
- }
- } else {
- addActionError("验证码不匹配,请重新输入");
- }
- return INPUT;
- }
结果如下:
到这里就完成了。但是今天在FireFox3.6下使用firedebug调试时发现会再请求一次验证码,这样导致session中的验证码刷新之后和页面上的不一致,问题截图如下:
在关闭firedebug的情况下只请求一次验证码,在IE下也正常,寻思可能是firedebug的问题,但是在网上查找不到相关内容。折腾了半天发现鼠标展开GET authImg的URL时才会第二次请求验证码,所以明白是因为验证码图片没有缓存造成在firedebug调试窗口查看时需要再次请求的缘故。