一、验证码生成类
11 /**
12 * 验证码生成器
13 *
14 */
15 public class SCaptcha {
16 // 图片的宽度。
17 private int width = 120;
18 // 图片的高度。
19 private int height = 40;
20 // 验证码字符个数
21 private int codeCount = 4;
22 // 验证码干扰线数
23 private int lineCount = 50;
24 // 验证码
25 private String code = null;
26 // 验证码图片Buffer
27 private BufferedImage buffImg = null;
28
29 private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'M', 'N', 'P', 'Q', 'R',
30 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };
31 // 生成随机数
32 private Random random = new Random();
33
34 public SCaptcha() {
35 this.createCode();
36 }
37
38 /**
39 *
40 * @param width 图片宽
41 * @param height 图片高
42 */
43 public SCaptcha(int width, int height) {
44 this.width = width;
45 this.height = height;
46 this.createCode();
47 }
48
49 /**
50 *
51 * @param width 图片宽
52 * @param height 图片高
53 * @param codeCount 字符个数
54 * @param lineCount 干扰线条数
55 */
56 public SCaptcha(int width, int height, int codeCount, int lineCount) {
57 this.width = width;
58 this.height = height;
59 this.codeCount = codeCount;
60 this.lineCount = lineCount;
61 this.createCode();
62 }
63
64 public void createCode() {
65 int codeX = 0;
66 int fontHeight = 0;
67 fontHeight = height - 5;// 字体的高度
68 codeX = width / (codeCount + 3);// 每个字符的宽度
69
70 // 图像buffer
71 buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
72 Graphics2D g = buffImg.createGraphics();
73
74 // 将图像填充为白色
75 g.setColor(Color.WHITE);
76 g.fillRect(0, 0, width, height);
77
78 // 创建字体
79 ImgFontByte imgFont = new ImgFontByte();
80 Font font = imgFont.getFont(fontHeight);
81 g.setFont(font);
82
83 StringBuffer randomCode = new StringBuffer();
84 // 随机产生验证码字符
85 for (int i = 0; i < codeCount; i++) {
86 String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
87 // 设置字体颜色
88 g.setColor(getRandomColor());
89 // 设置字体位置
90 g.drawString(strRand, (i + 1) * codeX, getRandomNumber(height / 2) + 25);
91 randomCode.append(strRand);
92 }
93 code = randomCode.toString();
94 }
95
96 /** 获取随机颜色 */
97 private Color getRandomColor() {
98 int r = getRandomNumber(255);
99 int g = getRandomNumber(255);
100 int b = getRandomNumber(255);
101 return new Color(r, g, b);
102 }
103
104 /** 获取随机数 */
105 private int getRandomNumber(int number) {
106 return random.nextInt(number);
107 }
108
109 public void write(String path) throws IOException {
110 OutputStream sos = new FileOutputStream(path);
111 this.write(sos);
112 }
113
114 public void write(OutputStream sos) throws IOException {
115 ImageIO.write(buffImg, "png", sos);
116 sos.close();
117 }
118
119 public BufferedImage getBuffImg() {
120 return buffImg;
121 }
122
123 public String getCode() {
124 return code;
125 }
126
127 /** 字体样式类 */
128 class ImgFontByte {
129 public Font getFont(int fontHeight) {
130 try {
131 Font baseFont = Font.createFont(Font.HANGING_BASELINE, new ByteArrayInputStream(
132 hex2byte(getFontByteStr())));
133 return baseFont.deriveFont(Font.PLAIN, fontHeight);
134 } catch (Exception e) {
135 return new Font("Arial", Font.PLAIN, fontHeight);
136 }
137 }
138
139 private byte[] hex2byte(String str) {
140 if (str == null)
141 return null;
142 str = str.trim();
143 int len = str.length();
144 if (len == 0 || len % 2 == 1)
145 return null;
146
147 byte[] b = new byte[len / 2];
148 try {
149 for (int i = 0; i < str.length(); i += 2) {
150 b[i / 2] = (byte) Integer.decode("0x" + str.substring(i, i + 2)).intValue();
151 }
152 return b;
153 } catch (Exception e) {
154 return null;
155 }
156 }
157
158 // 字体文件的十六进制字符串
159 private String getFontByteStr() {
160 //防止报字符串长度过长错误,改为从配置文件读取
161 return ReadFontByteProperties.getFontByteStr();
162 }
163 }
164 }
二、读取字体文件类
4 public class ReadFontByteProperties {
5 static private String fontByteStr = null;
6 static {
7 loads();
8 }
9 synchronized static public void loads() {
10 if (fontByteStr == null) {
11 InputStream is = ReadFontByteProperties.class.getResourceAsStream("/fontByte.properties");
12 Properties dbproperties = new Properties();
13 try {
14 dbproperties.load(is);
15 fontByteStr = dbproperties.getProperty("fontByteStr").toString();
16 } catch (Exception e) {
17 //System.err.println("不能读取属性文件. " + "请确保fontByte.properties在CLASSPATH指定的路径中");
18 }
19 }
20 }
21 public static String getFontByteStr() {
22 if (fontByteStr == null)
23 loads();
24 return fontByteStr;
25 }
26 }
三、生成验证码接口
1 /**
3 * @date 2017/8/23
4 * @description 生成图片验证码
5 */
6 @RequestMapping(value = "/userInfo/verification", method = {RequestMethod.POST, RequestMethod.GET})
7 @ResponseBody
8 public void verification(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
9 // 设置响应的类型格式为图片格式
10 response.setContentType("image/jpeg");
11 // 禁止图像缓存。
12 response.setHeader("Pragma", "no-cache");
13 response.setHeader("Cache-Control", "no-cache");
14 response.setDateHeader("Expires", 0);
15 //实例生成验证码对象
16 SCaptcha instance = new SCaptcha();
17 //将验证码存入session
18 session.setAttribute("verification", instance.getCode());
19 //向页面输出验证码图片
20 instance.write(response.getOutputStream());
21 }
将生成的验证码图片存在session中,当用户登录时即可和用户输入的验证码的值进行判断,如果验证相同,则进行后续操作。
三、附件资源
https://pan.baidu.com/s/16ButlDDnnTh6qDF2xwbFbw
链接中是fontByte.properties字体二进制文件,放在项目的根目录下进行读取加载。