java图形验证码生成工具类 web页面校验验证码

时间:2022-06-08 17:31:19

最近做验证码,参考网上案例,发现有不少问题,特意进行了修改和完善。

验证码生成器:

?
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
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.Random;
 
/**
 * 验证码生成器
 *
 * @author
 */
public class ValidateCode {
 // 图片的宽度。
 private int width = 160;
 // 图片的高度。
 private int height = 40;
 // 验证码字符个数
 private int codeCount = 5;
 // 验证码干扰线数
 private int lineCount = 150;
 // 验证码
 private String code = null;
 // 验证码图片Buffer
 private BufferedImage buffImg = null;
 
 // 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了)
 private char[] codeSequence = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
   'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
 
 /**
  * 默认构造函数,设置默认参数
  */
 public ValidateCode() {
  this.createCode();
 }
 
 /**
  * @param width 图片宽
  * @param height 图片高
  */
 public ValidateCode(int width, int height) {
  this.width = width;
  this.height = height;
  this.createCode();
 }
 
 /**
  * @param width  图片宽
  * @param height 图片高
  * @param codeCount 字符个数
  * @param lineCount 干扰线条数
  */
 public ValidateCode(int width, int height, int codeCount, int lineCount) {
  this.width = width;
  this.height = height;
  this.codeCount = codeCount;
  this.lineCount = lineCount;
  this.createCode();
 }
 
 public void createCode() {
  int x = 0, fontHeight = 0, codeY = 0;
  int red = 0, green = 0, blue = 0;
 
  x = width / (codeCount + 2);//每个字符的宽度(左右各空出一个字符)
  fontHeight = height - 2;//字体的高度
  codeY = height - 4;
 
  // 图像buffer
  buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
  Graphics2D g = buffImg.createGraphics();
  // 生成随机数
  Random random = new Random();
  // 将图像填充为白色
  g.setColor(Color.WHITE);
  g.fillRect(0, 0, width, height);
  // 创建字体,可以修改为其它的
  Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
//  Font font = new Font("Times New Roman", Font.ROMAN_BASELINE, fontHeight);
  g.setFont(font);
 
  for (int i = 0; i < lineCount; i++) {
   // 设置随机开始和结束坐标
   int xs = random.nextInt(width);//x坐标开始
   int ys = random.nextInt(height);//y坐标开始
   int xe = xs + random.nextInt(width / 8);//x坐标结束
   int ye = ys + random.nextInt(height / 8);//y坐标结束
 
   // 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。
   red = random.nextInt(255);
   green = random.nextInt(255);
   blue = random.nextInt(255);
   g.setColor(new Color(red, green, blue));
   g.drawLine(xs, ys, xe, ye);
  }
 
  // randomCode记录随机产生的验证码
  StringBuffer randomCode = new StringBuffer();
  // 随机产生codeCount个字符的验证码。
  for (int i = 0; i < codeCount; i++) {
   String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
   // 产生随机的颜色值,让输出的每个字符的颜色值都将不同。
   red = random.nextInt(255);
   green = random.nextInt(255);
   blue = random.nextInt(255);
   g.setColor(new Color(red, green, blue));
   g.drawString(strRand, (i + 1) * x, codeY);
   // 将产生的四个随机数组合在一起。
   randomCode.append(strRand);
  }
  // 将四位数字的验证码保存到Session中。
  code = randomCode.toString();
 }
 
 public void write(String path) throws IOException {
  OutputStream sos = new FileOutputStream(path);
  this.write(sos);
 }
 
 public void write(OutputStream sos) throws IOException {
  ImageIO.write(buffImg, "png", sos);
  sos.close();
 }
 
 public BufferedImage getBuffImg() {
  return buffImg;
 }
 
 public String getCode() {
  return code;
 }
 
 /**
  * 测试函数,默认生成到d盘
  * @param args
  */
 public static void main(String[] args) {
  ValidateCode vCode = new ValidateCode(160,40,5,150);
  try {
   String path="D:/"+new Date().getTime()+".png";
   System.out.println(vCode.getCode()+" >"+path);
   vCode.write(path);
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

下面是页面JS调用验证码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 刷新图片
  function changeImg() {
   var imgSrc = $("#imgObj");
   var url = imgSrc.attr("src");
   imgSrc.attr("src", changeUrl(url));
  }
  //为了使每次生成图片不一致,即不让浏览器读缓存,所以需要加上时间戳
  function changeUrl(url) {
   var timestamp = (new Date()).valueOf();
   var index = url.indexOf("?");
   console.log(index);
   if (index > 0) {
    url = url.substring(0, url.indexOf("?"));
   }
   console.log(url);
   if ((url.indexOf("&") > 0)) {
    url = url + "×tamp=" + timestamp;
    console.log(url);
   } else {
    url = url + "?timestamp=" + timestamp;
    console.log(url);
    }
   return url;
  }

下面是controller层输出验证码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 响应验证码页面
 * @return
 */
@RequestMapping(value="/validateCode")
public String validateCode(HttpServletRequest request,HttpServletResponse response) throws Exception{
 // 设置响应的类型格式为图片格式
 response.setContentType("image/jpeg");
 //禁止图像缓存。
 response.setHeader("Pragma", "no-cache");
 response.setHeader("Cache-Control", "no-cache");
 response.setDateHeader("Expires", 0);
 
 HttpSession session = request.getSession();
 
 ValidateCode vCode = new ValidateCode(120,40,5,100);
 session.setAttribute("code", vCode.getCode());
 vCode.write(response.getOutputStream());
 return null;
}

下面是controller层验证验证码输入是否正确

?
1
2
3
4
5
6
String code = request.getParameter("code");
HttpSession session = request.getSession();
String sessionCode = (String) session.getAttribute("code");
if (!StringUtils.equalsIgnoreCase(code, sessionCode)) { //忽略验证码大小写
 throw new RuntimeException("验证码对应不上code=" + code + " sessionCode=" + sessionCode);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。