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

时间:2022-05-23 11:12:07

验证码图片生成步骤

创建BufferedImage对象。
获取BufferedImage的画笔,即调用getGraphics()方法获取Graphics对象。
调用Graphics对象的setColor()方法和fillRect()方法设置图片背景颜色。
调用Graphics对象的setColor()方法和drawLine()方法设置图片干扰线。
调用BufferedImaged对象的setRGB()方法设置图片的噪点。
调用Graphics对象的setColor()方法、setFont()方法和drawString()方法设置图片验证码。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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中调用上面的类生成验证码图片,然后将图片返回给客户端。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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一个随机的参数,这样浏览器就会向服务器发请求得到新的验证码,而不是去缓存中读取。

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<%@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中判断用户输入的验证码是否正确,为了方便用户,验证码一般都设置成大小写不敏感,所以要先转化为小写字母再比对。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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);
 }

 

最后运行的效果图如下

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

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