这篇随笔主要是java中制作验证码的效果,由于是在国庆前做的,现在也找不到原载了。我对自己整理的发表一份
生成的验证码效果如下:
一、建立一个工具类,用来生成验证码
1 package com.dkt.util; 2 3 import java.awt.Color; 4 import java.awt.Font; 5 import java.awt.Graphics; 6 import java.awt.Graphics2D; 7 import java.awt.RenderingHints; 8 import java.awt.geom.AffineTransform; 9 import java.awt.image.BufferedImage; 10 import java.io.File; 11 import java.io.FileOutputStream; 12 import java.io.IOException; 13 import java.io.OutputStream; 14 import java.util.Arrays; 15 import java.util.Random; 16 17 import javax.imageio.ImageIO; 18 /** 19 * <p><b>VerifyCodeUtils Description:</b> (验证码生成)</p> 20 * <b>DATE:</b> 2016年6月2日 下午3:53:34 21 */ 22 public class VerifyCodeUtils{ 23 24 //使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符 25 public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; 26 private static Random random = new Random(); 27 28 29 /** 30 * 使用系统默认字符源生成验证码 31 * @param verifySize 验证码长度 32 * @return 33 */ 34 public static String generateVerifyCode(int verifySize){ 35 return generateVerifyCode(verifySize, VERIFY_CODES); 36 } 37 /** 38 * 使用指定源生成验证码 39 * @param verifySize 验证码长度 40 * @param sources 验证码字符源 41 * @return 42 */ 43 public static String generateVerifyCode(int verifySize, String sources){ 44 if(sources == null || sources.length() == 0){ 45 sources = VERIFY_CODES; 46 } 47 int codesLen = sources.length(); 48 Random rand = new Random(System.currentTimeMillis()); 49 StringBuilder verifyCode = new StringBuilder(verifySize); 50 for(int i = 0; i < verifySize; i++){ 51 //随机在验证字符中取一个值 52 verifyCode.append(sources.charAt(rand.nextInt(codesLen-1))); 53 } 54 return verifyCode.toString();//得到四位数的验证码 55 } 56 57 /** 58 * 生成随机验证码文件,并返回验证码值 59 * @param w 60 * @param h 61 * @param outputFile 62 * @param verifySize 63 * @return 64 * @throws IOException 65 */ 66 public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{ 67 String verifyCode = generateVerifyCode(verifySize); 68 outputImage(w, h, outputFile, verifyCode); 69 return verifyCode; 70 } 71 72 /** 73 * 输出随机验证码图片流,并返回验证码值 74 * @param w 75 * @param h 76 * @param os 77 * @param verifySize 78 * @return 79 * @throws IOException 80 */ 81 public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{ 82 String verifyCode = generateVerifyCode(verifySize); 83 outputImage(w, h, os, verifyCode); 84 return verifyCode; 85 } 86 87 /** 88 * 生成指定验证码图像文件 89 * @param w 90 * @param h 91 * @param outputFile 92 * @param code 93 * @throws IOException 94 */ 95 public static void outputImage(int w, int h, File outputFile, String code) throws IOException{ 96 if(outputFile == null){ 97 return; 98 } 99 File dir = outputFile.getParentFile();//文件目录 100 if(!dir.exists()){ 101 dir.mkdirs(); 102 } 103 try{ 104 outputFile.createNewFile();//创建文件 105 FileOutputStream fos = new FileOutputStream(outputFile); 106 outputImage(w, h, fos, code); 107 fos.close(); 108 } catch(IOException e){ 109 throw e; 110 } 111 } 112 113 /** 114 * 输出指定验证码图片流 115 * @param w 宽 116 * @param h 高 117 * @param os 输出流方式 118 * @param code 验证码 119 * @throws IOException 120 */ 121 public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{ 122 int verifySize = code.length(); 123 //类型为预定义图像类型之一的 BufferedImage。 124 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); 125 Random rand = new Random(); 126 Graphics2D g2 = image.createGraphics(); 127 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); 128 Color[] colors = new Color[5]; 129 Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, 130 Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, 131 Color.PINK, Color.YELLOW }; 132 float[] fractions = new float[colors.length]; 133 for(int i = 0; i < colors.length; i++){ 134 colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)]; 135 fractions[i] = rand.nextFloat(); 136 } 137 Arrays.sort(fractions); 138 139 g2.setColor(Color.GRAY);// 设置边框色 140 g2.fillRect(0, 0, w, h); 141 142 Color c = getRandColor(200, 250); 143 g2.setColor(c);// 设置背景色 144 g2.fillRect(0, 2, w, h-4); 145 146 //绘制干扰线 147 Random random = new Random(); 148 g2.setColor(getRandColor(160, 200));// 设置线条的颜色 149 for (int i = 0; i < 20; i++) { 150 int x = random.nextInt(w - 1); 151 int y = random.nextInt(h - 1); 152 int xl = random.nextInt(6) + 1; 153 int yl = random.nextInt(12) + 1; 154 g2.drawLine(x, y, x + xl + 40, y + yl + 20); 155 } 156 157 // 添加噪点 158 float yawpRate = 0.05f;// 噪声率 159 int area = (int) (yawpRate * w * h); 160 for (int i = 0; i < area; i++) { 161 int x = random.nextInt(w); 162 int y = random.nextInt(h); 163 int rgb = getRandomIntColor(); 164 image.setRGB(x, y, rgb); 165 } 166 167 shear(g2, w, h, c);// 使图片扭曲 168 169 g2.setColor(getRandColor(100, 160)); 170 int fontSize = h-4; 171 Font font = new Font("Algerian", Font.ITALIC, fontSize); 172 g2.setFont(font); 173 char[] chars = code.toCharArray(); 174 for(int i = 0; i < verifySize; i++){ 175 AffineTransform affine = new AffineTransform(); 176 affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2); 177 g2.setTransform(affine); 178 g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10); 179 } 180 181 g2.dispose(); 182 ImageIO.write(image, "jpg", os); 183 } 184 185 private static Color getRandColor(int fc, int bc) { 186 if (fc > 255) 187 fc = 255; 188 if (bc > 255) 189 bc = 255; 190 int r = fc + random.nextInt(bc - fc); 191 int g = fc + random.nextInt(bc - fc); 192 int b = fc + random.nextInt(bc - fc); 193 return new Color(r, g, b); 194 } 195 196 private static int getRandomIntColor() { 197 int[] rgb = getRandomRgb(); 198 int color = 0; 199 for (int c : rgb) { 200 color = color << 8; 201 color = color | c; 202 } 203 return color; 204 } 205 206 private static int[] getRandomRgb() { 207 int[] rgb = new int[3]; 208 for (int i = 0; i < 3; i++) { 209 rgb[i] = random.nextInt(255); 210 } 211 return rgb; 212 } 213 214 private static void shear(Graphics g, int w1, int h1, Color color) { 215 shearX(g, w1, h1, color); 216 shearY(g, w1, h1, color); 217 } 218 219 private static void shearX(Graphics g, int w1, int h1, Color color) { 220 221 int period = random.nextInt(2); 222 223 boolean borderGap = true; 224 int frames = 1; 225 int phase = random.nextInt(2); 226 227 for (int i = 0; i < h1; i++) { 228 double d = (double) (period >> 1) 229 * Math.sin((double) i / (double) period 230 + (6.2831853071795862D * (double) phase) 231 / (double) frames); 232 g.copyArea(0, i, w1, 1, (int) d, 0); 233 if (borderGap) { 234 g.setColor(color); 235 g.drawLine((int) d, i, 0, i); 236 g.drawLine((int) d + w1, i, w1, i); 237 } 238 } 239 240 } 241 242 private static void shearY(Graphics g, int w1, int h1, Color color) { 243 244 int period = random.nextInt(40) + 10; // 50; 245 246 boolean borderGap = true; 247 int frames = 20; 248 int phase = 7; 249 for (int i = 0; i < w1; i++) { 250 double d = (double) (period >> 1) 251 * Math.sin((double) i / (double) period 252 + (6.2831853071795862D * (double) phase) 253 / (double) frames); 254 g.copyArea(i, 0, 1, h1, 0, (int) d); 255 if (borderGap) { 256 g.setColor(color); 257 g.drawLine(i, (int) d, i, 0); 258 g.drawLine(i, (int) d + h1, i, h1); 259 } 260 261 } 262 263 } 264 public static void main(String[] args) throws IOException{ 265 File dir = new File("e:/verifies");// 生成的验证码存放目录 266 int w = 200, h = 80; 267 268 String verifyCode = generateVerifyCode(4); 269 File file = new File(dir, verifyCode + ".jpg"); 270 outputImage(w, h, file, verifyCode); 271 272 /*String verifyCode = generateVerifyCode(4); 273 System.out.println(verifyCode);*/ 274 275 } 276 }
二、建立一个CodeEnt实体类
1 package com.dkt.entity; 2 3 public class CodeEnt { 4 private String code;//验证码 5 private long nowtime;//失效的毫秒时间 6 public String getCode() { 7 return code; 8 } 9 public void setCode(String code) { 10 this.code = code; 11 } 12 public long getNowtime() { 13 return nowtime; 14 } 15 public void setNowtime(long nowtime) { 16 this.nowtime = nowtime; 17 } 18 public CodeEnt(String code, long nowtime) { 19 super(); 20 this.code = code; 21 this.nowtime = nowtime; 22 } 23 public CodeEnt() { 24 super(); 25 } 26 27 }
三、建立servlet类,作为服务器,调用上面的类生成验证码,并把验证码发送到页面,且验证验证码输入是否正确
我在这里为了方便理解,建立了两个servlet类,
一个类是 AuthImage 就是用来调用工具类 VerifyCodeUtils ,生成验证码并发送到页面上
1 package com.dkt.servlet; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.http.HttpServlet; 7 import javax.servlet.http.HttpServletRequest; 8 import javax.servlet.http.HttpServletResponse; 9 import javax.servlet.http.HttpSession; 10 11 import com.dkt.entity.CodeEnt; 12 import com.dkt.util.VerifyCodeUtils; 13 14 public class AuthImage extends HttpServlet { 15 static final long serialVersionUID = 1L; 16 public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 17 response.setHeader("Pragma", "No-cache"); //不缓存 18 response.setHeader("Cache-Control", "no-cache"); 19 response.setDateHeader("Expires", 0); 20 response.setContentType("image/jpeg"); //输出的图片 21 22 //生成随机字串 23 String verifyCode = VerifyCodeUtils.generateVerifyCode(4); 24 //存入会话session 25 HttpSession session = request.getSession(); 26 //保存 27 long nowtime = System.currentTimeMillis(); 28 CodeEnt codeEnt = new CodeEnt(verifyCode, nowtime); 29 session.setAttribute("codeent", codeEnt); 30 //生成图片 并发送到页面中 31 int w = 100, h = 30; 32 VerifyCodeUtils.outputImage(w, h, response.getOutputStream(), verifyCode); 33 34 } 35 }
另一个类是 CodeServlet 主要是判断用户输入的验证码是否正确,并给出提示
1 package com.dkt.servlet; 2 3 import java.io.IOException; 4 import java.util.Calendar; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 import javax.servlet.http.HttpSession; 11 12 import com.dkt.entity.CodeEnt; 13 14 public class CodeServlet extends HttpServlet { 15 16 public void doGet(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 doPost(request, response); 19 } 20 public void doPost(HttpServletRequest request, HttpServletResponse response) 21 throws ServletException, IOException { 22 23 response.setContentType("text/html"); 24 request.setCharacterEncoding("utf-8"); 25 response.setCharacterEncoding("utf-8"); 26 //存入会话session 27 HttpSession session = request.getSession(); 28 String op = request.getParameter("op"); 29 if (("reg").equals(op)) { 30 // 判断用户输入的验证是否正确且没有超时 31 String code = request.getParameter("code"); 32 System.out.println("code--------->"+code); 33 if (code!=null&&!("").equals(code)) { 34 code = code.toUpperCase();//全部转成大写字母 35 } 36 CodeEnt codeEnt = (CodeEnt)session.getAttribute("codeent"); 37 long nowT = Calendar.getInstance().getTimeInMillis(); 38 //System.out.println(System.currentTimeMillis()); 39 //System.out.println(nowT); 40 long diffT = nowT-codeEnt.getNowtime(); 41 System.out.println("时间差:"+diffT); 42 if (diffT<30000) { 43 if (code.equals(codeEnt.getCode())) { 44 System.out.println("验证成功"); 45 request.getRequestDispatcher("success.jsp").forward(request, response); 46 }else { 47 request.setAttribute("error", "验证码输入错误,请重新输入"); 48 request.getRequestDispatcher("verify.jsp").forward(request, response); 49 } 50 }else { 51 //验证不成功重新刷新验证码 52 request.setAttribute("error", "验证码失效,请重新刷新"); 53 request.getRequestDispatcher("verify.jsp").forward(request, response); 54 } 55 }else { 56 System.out.println("else"); 57 } 58 59 } 60 }
四,xml中的配置信息
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="2.5" 3 xmlns="http://java.sun.com/xml/ns/javaee" 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 7 <servlet> 8 <description>This is the description of my J2EE component</description> 9 <display-name>This is the display name of my J2EE component</display-name> 10 <servlet-name>AuthImage</servlet-name> 11 <servlet-class>com.dkt.servlet.AuthImage</servlet-class> 12 </servlet> 25 <servlet> 26 <description>This is the description of my J2EE component</description> 27 <display-name>This is the display name of my J2EE component</display-name> 28 <servlet-name>CodeServlet</servlet-name> 29 <servlet-class>com.dkt.servlet.CodeServlet</servlet-class> 30 </servlet> 41 42 <servlet-mapping> 43 <servlet-name>AuthImage</servlet-name> 44 <url-pattern>/AuthImage</url-pattern> 45 </servlet-mapping> 54 <servlet-mapping> 55 <servlet-name>CodeServlet</servlet-name> 56 <url-pattern>/CodeServlet</url-pattern> 57 </servlet-mapping> 62 <welcome-file-list> 63 <welcome-file>verify.jsp</welcome-file> 64 </welcome-file-list> 65 </web-app>
五、写页面 jsp ,添加事件
1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> 2 <% 3 String path = request.getContextPath(); 4 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 5 %> 6 7 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 8 <html> 9 <head> 10 <base href="<%=basePath%>"> 11 12 <title>My JSP 'verify.jsp' starting page</title> 13 14 <meta http-equiv="pragma" content="no-cache"> 15 <meta http-equiv="cache-control" content="no-cache"> 16 <meta http-equiv="expires" content="0"> 17 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 18 <meta http-equiv="description" content="This is my page"> 19 <!-- 20 <link rel="stylesheet" type="text/css" href="styles.css"> 21 --> 22 23 <script type="text/javascript"> 24 function change(img){ 25 img.src = img.src+"?"+new Date(); 26 } 27 28 </script> 29 </head> 30 31 <body> 32 <form action="CodeServlet?op=reg" method="post"> 33 <span style="font-size: 12px;color: red;">${error}</span><br/> 34 用户名:<input type="text" name="name" value=""><br/><br/> 35 验证码:<input type="text" name="code" value=""/> 36 <img src="AuthImage" alt="验证码" onclick="change(this)"/> 37 <input type="submit" value="提交"> 38 </form> 39 </body> 40 </html>
五、执行结果
启动服务器,在浏览器地址栏中访问,
当输入错误时,会显示:
当输入时验证码失效时,会提示:
输入成功时会跳到 success.jsp 页面,这个页面就请大家自己随便写洛。