一、验证码生成类
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中,当用户登录时即可和用户输入的验证码的值进行判断,如果验证相同,则进行后续操作。