实现图像验证码类ImageValidateCode:
package com.myhome; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * 防止暴力破解,使用的图像验证码 * */ public class ImageValidateCode extends HttpServlet { /** * 实现java.io.Serializable这个接口是为序列化, * serialVersionUID 用来表明实现序列化类的不同版本间的兼容性。 * 如果你修改了此类, 要修改此值。否则以前用老版本的类序列化的类恢复时会出错。 * 为了在反序列化时,确保类版本的兼容性。序列化时为了保持版本的兼容性, * 即在版本升级时反序列化仍保持对象的唯一性。 */ private static final long serialVersionUID = 5403703649596352260L; //产生随机数 private Random random =new Random(); //定义图形验证码中绘制字符的字体,字体名称,字体样式,字体大小l;如:"Arial Black"或"Fixedsys", Font.CENTER_BASELINE, 18 private final Font mFont=new Font("Arial Black", Font.PLAIN, 24); //定义验证码的大小,即高度和宽度 private final int IMG_WIDTH=90; private final int IMG_HEIGHT=25; //干扰线的数量 private final int LineSize=50; //产生的随机字符数量 private int stringNum = 4; /** * 获取随机颜色的方法 * */ private Color getRandColor(int fc,int bc) { if(fc>255) { fc=255; } if(bc>255) { bc=255; } //产生随机的RGB三原色 int r=fc+random.nextInt(bc-fc-16); int g=fc+random.nextInt(bc-fc-14); int b=fc+random.nextInt(bc-fc-18); return new Color(r, g, b); } /** * 获取大、小写字母和数字随机字符串方法 * */ private String getRandString() { //Math.random()---random()方法,是返回一个[0,1)的浮点数。 //一般我们是这样运用的,比如我要取一个1~9的随机数int a=(int)(Math.random()*10)注意是是乘上10再转。 //Math.round()方法,round 就是四舍五入, //math.round(-8.9) -9;math.round(-8.1) -8;math.round(8.9) 9;math.round(8.1) 8 //生成0、1、2的随机数字 int randi=(int) Math.round(Math.random()*2); //用来存储数据的ASC码 long itmp=0; //用于存储字符 char ctmp='\u0000'; //以“\u”开头的是一个Unicode码的字符,每一个'\u0000'都代表了一个空格。 //Unicode可同时包含65536个字符,ASCII/ANSI只包含255个字符,实际上是Unicode的一个子集。 //Unicode字符通常用十六进制编码方案表示,范围在'\u0000'到'\uFFFF'之间。 //\u0000到\u00FF表示ASCII/ANSI字符。 //“\u”表示这是一个Unicode值.\u0000代表的应该是NULL,输出控制台是一个空格... switch(randi) { //生成大写字母 case 1: itmp=Math.round(Math.random()*25+65);//long类型 ctmp=(char) itmp;//char类型 return String.valueOf(ctmp);//String类型 //生成小写字母 case 2: itmp=Math.round(Math.random()*25+97); ctmp=(char) itmp; return String.valueOf(ctmp); //生成数字 default : itmp=Math.round(Math.random()*9); return itmp+"";//将整型数字连接成字符串 } } /** * 绘制随机字符串 * */ private String drawString(Graphics g,String randomString,int i) { g.setFont(mFont);//设置字符串字体 g.setColor(new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255)));//设置字符串颜色 String rands=getRandString(); randomString+=rands; g.translate(random.nextInt(3), random.nextInt(2));//设置画在图片上的文字的x,y坐标,随即偏移值 g.drawString(rands, 18*i+5, 18);//字符间距设置为15px ,使用此图形上下文的当前字体和颜色绘制由指定 string 给定的文本。最左侧字符的基线位于此图形上下文坐标系统的 (x, y) 位置处。即:str - 要绘制的 string。x - x 坐标。y - y 坐标。//从图像左面10个像素个像素(后15*i+10),距上面16个像素的位置开始从左到右的方向输出rands的值。 return randomString; } /** * 绘制干扰线 * */ private void drawLine1(Graphics g) { //参数:x1 - 第一个点的 x 坐标。y1 - 第一个点的 y 坐标。x2 - 第二个点的 x 坐标。y2 - 第二个点的 y 坐标。x1和x2是起点坐标,x2和y2是终点坐标 int x=random.nextInt(IMG_WIDTH); int y=random.nextInt(IMG_HEIGHT); int x1=random.nextInt(13); int y1=random.nextInt(15); g.drawLine(x, y, x+x1, y+y1); } private void drawLine2(Graphics g) { //参数:x1 - 第一个点的 x 坐标。y1 - 第一个点的 y 坐标。x2 - 第二个点的 x 坐标。y2 - 第二个点的 y 坐标。x1和x2是起点坐标,x2和y2是终点坐标 int x=random.nextInt(IMG_WIDTH); int y=random.nextInt(IMG_HEIGHT); int x1=random.nextInt(13); int y1=random.nextInt(15); g.drawLine(x, y, x-x1, y-y1); } /** * 图像验证码的生成 * */ @Override protected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { System.out.println("验证码开始生成了"); //设置禁止缓存 response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg");//设置输出流内容格式为图片格式 /*禁用IE缓存 * HTTP消息报头包括普通报头、请求报头、响应报头、实体报头。 * 普通报头中的Cache-Control用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。 * 请求时的缓存指令包括:no-cache(用于指示请示或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached; * 响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage。 * 例:为了指示IE浏览器(客户端)不要缓存页面,服务器端的jsp程序可以编写如下:response.setHeader(“Cache-Control”, “no-cache”);//response.setHeader(“Pragma”, “no-cache”); * 作用相当于上行代码,通常两者合用Expires实体报头域给出响应过期的日期和时间。为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面,我们可以使用Expires实体报头域指定页面过期时间。 * 例:Expires:Thu,15 Sep 2006 16:23:12 GMTHTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。 * 如:为了让浏览器不要缓存页面,也可以利用Expires实体报关域,设置为0,jsp程序如下:response.setDateHeader(“Expires”, “0”); * */ //在内存中创建一副图像,宽90像素,高25像素,rgb模式的色彩 BufferedImage image=new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB); //在内存中创建一个画笔 Graphics g=image.getGraphics(); //设置画笔颜色 g.setColor(getRandColor(200, 250)); //填充背景色,使用当前的画笔颜色修改图片背景色 g.fillRect(1, 1, IMG_WIDTH-1, IMG_HEIGHT-1);//4个参数的意思分别为,起始X坐标,起始Y坐标,宽度,高度。 //为图形验证码绘制边框 g.setColor(new Color(155,155,155)); g.drawRect(0, 0, IMG_WIDTH,IMG_HEIGHT); //生成随机干扰线 g.setColor(getRandColor(110, 133)); for(int i=0;i<=LineSize;i++){ drawLine1(g); drawLine2(g); } //用于保存系统生成的随机字符串 String randomString = ""; //绘制随机字符串 for(int j=0;j<stringNum;j++){ randomString=drawString(g, randomString, j); } //获取HttpSesssion对象 HttpSession session=request.getSession(true); //getSession(true):true: 如果session存在,则返回该session,否则创建一个新的session;false: 如果session存在,则返回该session,否则返回null. //将随机字符串放入到HttpSession对象中,验证码中的随机数不区分大小写 session.setAttribute("rand", randomString.toLowerCase()); String rands=(String) session.getAttribute("rand"); System.out.println("验证码生成成功"+rands); System.out.println("验证码生成成功"+randomString.toLowerCase().toString()); //释放画笔对象 g.dispose(); //向输出流中输出图像 ImageIO.write(image, "JPEG", response.getOutputStream()); } }
jsp界面实现index.jsp和validat.jsp:
validat.jsp:
<body> <img src="checkServlet" /> <a href="validat.jsp" >看不清楚,换张图片</a> </body>
index.jsp:
<head> <script type="text/javascript"> //看不清图片,重新加载一张图像验证码 function reloadVercode(){ document.getElementById("authImg").src="auth.jpg?now="+new Date(); } </script> </head> <body> <img src="auth.jpg" id="authImg" /><a href="javascript:void(null)" onclick="reloadVercode()">看不清,换一张</a> </body>
web.xml配置:
<!-- 定义图像验证码的servlet index.jsp配置--> <servlet> <servlet-name>img</servlet-name> <servlet-class>com.myhome.ImageValidateCode</servlet-class> </servlet> <servlet-mapping> <servlet-name>img</servlet-name> <url-pattern>/auth.jpg</url-pattern> </servlet-mapping> <!-- 定义图像验证码的servlet validat.jsp配置--> <servlet> <servlet-name>CheckServlet</servlet-name> <servlet-class>com.myhome.ImageValidateCode</servlet-class> </servlet> <servlet-mapping> <servlet-name>CheckServlet</servlet-name> <url-pattern>/checkServlet</url-pattern> </servlet-mapping>
效果图:
其他:
package com.myhome; public class Test { /** * 产生随机字符串 * */ private String getRandomChar() { int rand = (int)Math.round(Math.random() * 2); System.out.println("随机数:"+rand); long itmp = 0; char ctmp = '\u0000'; System.out.println("字符:"+ctmp); switch (rand) { case 1: itmp = Math.round(Math.random() * 25 + 65); String s1=getType(itmp); System.out.println(s1+itmp); ctmp = (char)itmp; String s2=getType(ctmp); System.out.println(s2+itmp); System.out.println(getType(String.valueOf(ctmp))+String.valueOf(ctmp)); return String.valueOf(ctmp); case 2: itmp = Math.round(Math.random() * 25 + 97); System.out.println(itmp); ctmp = (char)itmp; System.out.println(ctmp); System.out.println(String.valueOf(ctmp)); return String.valueOf(ctmp); default : itmp = Math.round(Math.random() * 9); String.valueOf(itmp); return itmp + ""; } } /** * 判断对象的类型 * */ private <T> String getType(T t) { if(t instanceof String) { return "String"; }else if(t instanceof Integer) { return "int"; }else if(t instanceof Character) { return "char"; }else if(t instanceof Long) { return "long"; }else { return "don't know Type of" +t; } } public static void main(String[] args) { Test t=new Test(); t.getRandomChar(); } }