验证码是一个很常见的一个功能,验证码可以防止黑客通过某种手段无间隔的注册等等
验证码是通过服务器端生成的一张图片,传到客户端
具体实现步骤(流程):
1)由服务器端比如servlet,随机产生几个字符数字等等,把这几个字符拼接成一个字符串,存到session域中
2)以图片的方式传给客户端,验证码上的具体值是在服务器端验证的,如果具体值在客户端验证的话,恐怕不太方便比如第一次访问静态登录界面的话,去取session的值是为空的,除非你再次刷新整个页面
3)客户端对验证码,验证是否为空,输入的字符的长度是否达到标准,
4)把输入的验证码传到服务器端,服务端在session中取到值,做具体判断
5)根据输入对否,跳转到另一界面,如果输入错误,一般跳回当前界面,验证码改变又被刷新一次
具体实现的页面:
产生验证码的 Response_3类 参考-------->点击打开链接
package cn.response; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.PrintWriter; 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; //输出随机认证码图片 public class Response_3 extends HttpServlet { private static final int WIDTH=120, HEIGHT=50; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //创建一幅图形 BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); //1.设置背景色 setBackGround(g); //2.设置边框 setBorder(g); //3.画干扰线 drawRandomLine(g); //4.写随机数 返回 具体的验证值 String validateValue = drawRandomNum((Graphics2D)g); System.out.println("验证码:"+validateValue); //把验证码的具体值 存到session中 request.getSession().setAttribute("validateValue", validateValue); //5.图形写给浏览器 //控制浏览器缓存 System.currentTimeMillis() 获取当前时间 //response.setDateHeader("Expires",System.currentTimeMillis() + 1000*3600); //缓存1小时 //控制浏览器不要缓存数据 response.setDateHeader("Expires", -1); response.setHeader("cache-control", "no-cache"); response.setHeader("pragma", "no-cache"); response.setContentType("image/jpeg");//告诉浏览器用什么方式打开 //把图形以JPG的格式存到流中然后调用 ImageIO.write输到浏览器 ImageIO.write(image,"jpg",response.getOutputStream()); } private void setBackGround(Graphics g) { g.setColor(Color.lightGray);//设置背景色 g.fillRect(0, 0, WIDTH, HEIGHT);//让颜色去填充这个矩形 } private void setBorder(Graphics g) { //设置边框的颜色 随机出现 if(0 == new Random().nextInt(3)) { g.setColor(Color.cyan);//设置边框颜色 } else if(1 == new Random().nextInt(5)) { g.setColor(Color.red);//设置边框颜色 } else { g.setColor(Color.yellow);//设置边框颜色 } g.drawRect(1, 1, WIDTH-2, HEIGHT-2);//绘制边框 } private void drawRandomLine(Graphics g) { g.setColor(Color.green); for(int i=0; i<5; i++) { //随机获得初始坐标,和结束坐标 int x1 = new Random().nextInt(WIDTH);//横坐标要在宽度之内 int y1 = new Random().nextInt(HEIGHT);//纵坐标要在高度之内 int x2 = new Random().nextInt(WIDTH); int y2 = new Random().nextInt(HEIGHT); g.drawLine(x1, y1, x2, y2);//画干扰线 } } private String drawRandomNum(Graphics2D g) { String validateValue = "" ; // 具体验证码的值 g.setColor(Color.red); g.setFont(new Font("宋体",Font.BOLD,28));//设置字体 //汉字 //String base="\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08\u4e09"; String base= "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" ; int x=5; //中文字体范围 [\u4e00-\u9fa5] for(int i=0; i<4; i++) { int theta = new Random().nextInt()%30;//获取-30到30的数 //String x1 = new Random().nextInt(9)+""; 随机输出数字 String ch = base.charAt( new Random().nextInt(base.length()) )+"";//获取字 g.rotate(theta*Math.PI/180, x, 30);//设置旋转角度(弧度) g.drawString(ch, x, 30);//写字到方框内 g.rotate(-theta*Math.PI/180, x, 30);//把位置旋转回去 //g.drawString(x1, x, 20); x+=30; //g.drawString(x1, x, 20); //x+=30; validateValue = validateValue + ch ; } return validateValue; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } }
Myeclipse 环境下
这里当然还要在WEB-INF目录下,配一个web.xml
总结:
控制浏览器要缓存:
response.setDateHeader("Expires",System.currentTimeMillis() + 1000*3600);注意:如果这句没添加 System.currentTimeMillis() 则没有缓存截止日期,默认是 1970年开始 缓存1小时,也就是过期了,所以System.currentTimeMillis() 这句的作用是获取当前日期时间,然后加上你要缓存的时间,1000代表1秒。
控制浏览器不要缓存:
response.setDateHeader("Expires", -1); 或者 response.setDateHeader("Expires", 0); 都一样
response.setHeader("cache-control", "no-cache");
response.setHeader("pragma", "no-cache");
这里设置了颜色,别忘了设置 把颜色填充,绘制边框,等等
绘制边框:g.drawRect(1, 1, WIDTH-2, HEIGHT-2);// 边框的宽和高,都要比背景色的宽高小1,这个边框是从x=1,y=1 (起使坐标(1,1) )开始画的,本来是从x=0,y=0画的,但贴近最左边效果不好所以WIDTH-2, HEIGHT-2 要减2
中文字体范围 [\u4e00-\u9fa5]
获取随机字符:String ch = base.charAt( new Random().nextInt(base.length()) )+"";
然后把字符转化为字符串
注意: 设置字的旋转角度,g.rotate(theta*Math.PI/180, x, 20);//设置旋转角度(一定要是弧度),把度转化为弧度(公式:theta*Math.PI/180 ;这个theta是度):int theta = new Random().nextInt()%30;//获取-30到30的数,
当你旋转完,把字放到方框里去后,还得注意一点就是把旋转角度,旋转为初始状态,以便下一个字进行旋转
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'ValidateLogin.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <BODY style="background-color:66CCFF" > <table cellspacing="10" border=1 background="" align="center"> <tr> <td> <b style="font-size:20;color:green;" >会员--登录</b> <hr width=220 align=left> <form name=form1 Action="LoginServlet" method="get" > <br /> 用户名: <input type="text" name="usename" value=543806053@qq.com size=19 maxlength=16 /> <br /> <br /> 密 码: <input type="password" name="password" maxlength=16 /> <br /><br /> 认证码: <input type="text" name="validateValue" size=19 onblur="checkVlidte(this)"/><br> <img id="image" src="servlet/Response_3"/> <a href="javascript:changeimage()" >看不清?换一张</a> <br /><br /> <br /><br /> <input type="submit" value="登录"/> <input type="reset" value="重置" /> <hr width=220 align=left> </form> </td> </tr> </table> </body> <script type="text/javascript"> function validate_required(field,alerttxt) { with(field) { /*if(value==null||value=="") { alert(alerttxt); return false ; } else return true ; */ i = value.indexOf("@"); //邮箱认证 j = value.lastIndexOf("."); if(i < 1 || j-i <2) { alert(alerttxt) ; return false ; } else return true ; } } function password_validate (_pass,alerttxt) { with(_pass) { if(value!="") return true ; else { alert(alerttxt) ; return false ; } } } function validate_form(thisform) { with(thisform) { if(validate_required(name1,"请输入有效的邮箱账号!") == false) { name1.focus(); return false ; } if(password_validate(pass,"请输入正确的密码!") == false) { pass.focus(); return false ; } } } </script> <script type="text/javascript"> function proving() { if(form1.pass.value!="") window.open("http://www.baidu.com/","_self"); else window.open("http://www.google.com/","_self"); } </script> <!--认证码按钮脚本--> <script type="text/javascript"> function changeimage() { var img = document.getElementById("image") ; if(img) img.src=img.src+ "?" + new Date().getTime(); } function checkVlidte(object) { if(object.value.length != 4 ) { alert("验证码错误!"); //object.focus() ;//重新定位到该输入框 //object.select() ;//把已有的内容选中 } } </script> </html>
服务器端验证,这里只对验证码进行验证
package cn.request; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //主要 服务器端验证码 的验证 public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String usename = request.getParameter("usename"); String password = request.getParameter("password"); String validateValue = request.getParameter("validateValue"); String vv = (String)request.getSession().getAttribute("validateValue"); //把验证码全转为小写在进行比较 if( (validateValue.toLowerCase()).equals(vv.toLowerCase()) ) { response.sendRedirect("index.jsp"); } else { request.getRequestDispatcher("ValidateLogin.jsp").forward(request, response); } } }