当前位置: 移动技术网 > IT编程>开发语言>Java > J2EE验证码图片如何生成和点击刷新验证码

J2EE验证码图片如何生成和点击刷新验证码

2019年07月22日  | 移动技术网IT编程  | 我要评论

验证码图片生成步骤

创建bufferedimage对象。
获取bufferedimage的画笔,即调用getgraphics()方法获取graphics对象。
调用graphics对象的setcolor()方法和fillrect()方法设置图片背景颜色。
调用graphics对象的setcolor()方法和drawline()方法设置图片干扰线。
调用bufferedimaged对象的setrgb()方法设置图片的噪点。
调用graphics对象的setcolor()方法、setfont()方法和drawstring()方法设置图片验证码。

因为验证码的图片的宽度和高度要根据网站的风格来确定的,所以字体的大小需要根据图片的宽度和高度来确定,用到了小小的技巧。

package util;

import java.awt.color;
import java.awt.font;
import java.awt.graphics;
import java.awt.image;
import java.awt.image.bufferedimage;
import java.io.bytearrayoutputstream;
import java.io.ioexception;
import java.util.random;

import javax.imageio.imageio;

public class verification {
  private static final string alphabet = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz1234567890";
  
  /**
   * 生成一个宽为width, 高为height, 验证码为code的图片
   * @param width 图片的宽
   * @param height 图片的高
   * @param code 验证码字符串
   * @return 返回图片验证码
   */
  public static bufferedimage getimage(int width, int height, string code){
    return getimage(width, height, code, 20);
  }
  /**
   * 生成一个宽为width, 高为height, 验证码为code的图片,图片中干扰线的条数为linecnt
   * @param width 图片的宽
   * @param height 图片的高
   * @param code 验证码字符串
   * @param linecnt 干扰线的条数,建议为10条左右,可根据结果适当调整
   * @return 返回图片验证码
   */
  public static bufferedimage getimage(int width, int height, string code, int linecnt){
    return createimage(width, height, code, linecnt, 0.01);
  }
  /**
   * 生成一个宽为width, 高为height, 验证码为code的图片,图片中干扰线的条数为linecnt
   * 噪声比为noiserate,即图片中噪音像素点的百分比
   * @param width 图片的宽
   * @param height 图片的高
   * @param code 验证码字符串
   * @param linecnt 干扰线的条数,建议为10条左右,可根据结果适当调整
   * @param noiserate 图片中噪音像素点占总像素的百分比
   * @return 返回图片验证码
   */
  public static bufferedimage getimage(int width, int height, string code, int linecnt, double noiserate){
    return createimage(width, height, code, linecnt, noiserate);
  }
  
  /**
   * 
   * 生成一个宽为width, 高为height, 验证码为code的图片,图片中干扰线的条数为linecnt
   * 噪声比为noiserate,即图片中噪音像素点的百分比
   * @param width 图片的宽
   * @param height 图片的高
   * @param code 验证码字符串
   * @param linecnt 干扰线的条数,建议为10条左右,可根据结果适当调整
   * @param noiserate 图片中噪音像素点占总像素的百分比
   * @return 返回图片验证码
   */
  private static bufferedimage createimage(int width, int height, string code, int linecnt, double noiserate){
    int fontwidth = ((int)(width * 0.8)) / code.length();
    int fontheight = (int)(height * 0.7);
    //为了在任意的width和height下都能生成良好的验证码,
    //字体的大小为fontwdith何fontheight中的小者,
    int fontsize = math.min(fontwidth, fontheight);
    //drawstring时要用到
    int paddingx = (int) (width * 0.1);
    int paddingy = height - (height - fontsize) / 2;
    
    //创建图像
    bufferedimage buffimg = new bufferedimage(width, height, bufferedimage.type_int_rgb);
    //获得画笔
    graphics g = buffimg.getgraphics();
    //设置画笔的颜色
    g.setcolor(getrandcolor(200, 255));
    //然后填充一个矩形,即设置背景色
    g.fillrect(0, 0, width, height);
    
    // 设置干扰线
    for (int i = 0; i < linecnt; i++) {
        //随机获取干扰线的起点和终点
      int xs = (int)(math.random() * width);
      int ys = (int)(math.random() * height);
      int xe = (int)(math.random() * width);
      int ye = (int)(math.random() * height);
      g.setcolor(getrandcolor(1, 255));
      g.drawline(xs, ys, xe, ye);
    }
    // 添加噪点
    int area = (int) (noiserate * width * height);
    for(int i=0; i<area; ++i){
        int x = (int)(math.random() * width);
        int y = (int)(math.random() * height);
        buffimg.setrgb(x, y, (int)(math.random() * 255));
    }
    //设置字体
    font font = new font("ravie", font.plain, fontsize);
    g.setfont(font);
    
    for(int i=0; i<code.length(); ++i){
        string ch = code.substring(i, i+1);
        g.setcolor(getrandcolor(1, 199));
        g.drawstring(ch, paddingx + fontwidth * i, paddingy);
    }
    return buffimg;
    
  }
  /**
   * 获取随机的颜色,r,g,b的取值在l到r之间
   * @param l 左区间
   * @param r 右区间
   * @return 返回随机颜色值
   */
  private static color getrandcolor(int l, int r){
    if(l > 255)
      l = 255;
    if(r > 255)
      r = 255;
    if(l < 0)
      l = 0;
    if(r < 0)
      r = 0;
    int interval = r - l; 
    int r = l + (int)(math.random() * interval);
    int g = l + (int)(math.random() * interval);
    int b = l + (int)(math.random() * interval);
    return new color(r, g, b);
  }

  /**
   * 随机生成若干个由大小写字母和数字组成的字符串
   * @param len 随机生成len个字符
   * @return 返回随机生成的若干个由大小写字母和数字组成的字符串
   */
  public static string getrandcode(int len){
    string code = "";
    for(int i=0; i<len; ++i){
      int index = (int)(math.random() * alphabet.length());
      code = code + alphabet.charat(index);
    }
    return code;
  }
  /**
   * 将图片转为byte数组
   * @param image 图片
   * @return 返回byte数组
   * @throws ioexception
   */
  public static byte[] getbytearray(bufferedimage image) throws ioexception{
    bytearrayoutputstream baos = new bytearrayoutputstream();
    imageio.write(image, "png", baos);
    return baos.tobytearray();
    //bytearrayoutputstream 不需要close
    
  }
}

使用验证码图片

在verificationcode.java这个servlet中调用上面的类生成验证码图片,然后将图片返回给客户端。

protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
    httpsession session = request.getsession();
    //随机生成字符串,并写入session
    string code = verification.getrandcode(4);
    session.setattribute("verification", code);
    bufferedimage image = util.verification.getimage(100,30, code, 5);
    response.setcontenttype("image/png");
    
    outputstream out = response.getoutputstream();
    out.write(util.verification.getbytearray(image));
    out.flush();
    out.close();
    
  }
 

在index.jsp中设置验证码,用户点击验证码时,调用js代码请求服务器得到新的验证码。因为上面的那个生成验证码的servlet会被浏览器缓存,所以js代码中需要给该servlet一个随机的参数,这样浏览器就会向服务器发请求得到新的验证码,而不是去缓存中读取。

<%@page import="util.verification"%>
<%@ 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>insert title here</title>

<script type="text/javascript">
    function refreshcode(){
      document.getelementbyid("verification").src= "/verificationcode/verificationcode?hehe="+math.random();
    }
  </script>
</head>
<body>
  
  <form action="<%=request.getcontextpath()+"/checkverification" %>" method="post">
    验证码:<input type="text" name="submitverification">
    <img id="verification" alt="" title="看不清点击刷新验证码" src="<%=request.getcontextpath()+"/verificationcode" %>"
    onclick="refreshcode()"><br>
    <input type="submit" name="submit" value="提交">
  </form>
  
</body>
</html>

最后是在checkverification.java这个servlet中判断用户输入的验证码是否正确,为了方便用户,验证码一般都设置成大小写不敏感,所以要先转化为小写字母再比对。

protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
  httpsession session = request.getsession();
  string verification = (string)session.getattribute("verification");
  string submitverification = request.getparameter("submitverification");
  printwriter out = response.getwriter();
  if(verification!=null && submitverification!=null){
   if(verification.tolowercase().equals(submitverification.tolowercase())){
    out.println("yes!!!");
   }
   else{
    out.println("no!!!");
   }
   
  }
  else{
   out.println("no!!!");
  }
  session.removeattribute("verification");//防止用户重复提交表单

 }

 /**
  * @see httpservlet#dopost(httpservletrequest request, httpservletresponse response)
  */
 protected void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
  // todo auto-generated method stub
  doget(request, response);
 }

最后运行的效果图如下

以上就是本文的全部内容,希望对大家的学习有所帮助。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网