java实现图片验证码

时间:2023-02-05 08:48:52

一、验证码生成类

  1 package hbi.tech.utils;
  2 import javax.imageio.ImageIO;
  3 import java.awt.*;
  4 import java.awt.image.BufferedImage;
  5 import java.io.ByteArrayInputStream;
  6 import java.io.FileOutputStream;
  7 import java.io.IOException;
  8 import java.io.OutputStream;
  9 import java.util.Random;
 10 
 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 }

二、读取字体文件类

 

 1 package hbi.tech.utils;
 2 import java.io.InputStream;
 3 import java.util.Properties;
 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    /**
 2      * @author jiaqing.xu@hand-china.com
 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中,当用户登录时即可和用户输入的验证码的值进行判断,如果验证相同,则进行后续操作。

java实现图片验证码