大多网站登录时需要输入一个验证码,这主要是基于安全性方面的考虑。在这里将详细的说明一下验证码的生成和验证。
首先是java文件(这段java主要写了验证码图片的生成及各种特效,比如旋转、干扰线、噪点等,并将其用流的方式传到前端页面):
package com.servlet; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Stroke; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class ImageServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { int width=100;//验证码图片宽度 int height=40;//验证码图片高度 BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_3BYTE_BGR); Graphics g=image.getGraphics(); Graphics2D g2d = (Graphics2D) g; Random random=new Random(); g.setColor(Color.white);//背景颜色(或getRandColor(160,250)) g.fillRect(0, 0, width, height);//画背景 //g.setColor(getRandColor(0,255));//边框颜色 // g.drawRect(0, 0, width-1, height-1);//画边框 // 随机产生20条干扰线,使图象中的认证码不易被其它程序探测到 g.setColor(getRandColor(160,200)); //Stroke stroke=new BasicStroke(3.0f);//设置线宽为3.0 for(int i=0;i<20;i++){ int x=random.nextInt(width); int y=random.nextInt(height); int x1=random.nextInt(20); int y1=random.nextInt(20); g.drawLine(x,y,x+x1,y+y1); //g2d.setStroke(stroke); } // 随机产生20点,使图象中的认证码不易被其它程序探测到 g.setColor(getRandColor(160,200)); for(int i=0;i<20;i++){ int x=random.nextInt(width); int y=random.nextInt(height); g.drawLine(x, y, x, y); } //随机生成不同的字体、字体样式和字体大小 String[] fontName = {"微软雅黑","黑体","Georgia","Verdana","Arial","Comic Sans MS","Lucida Console"}; int [] fontEffect = {Font.PLAIN, Font.ITALIC, Font.BOLD}; int [] fontSize = {28, 30, 32, 26}; Font[] fonts = new Font[fontName.length*fontEffect.length*fontSize.length]; int fontsIndex=0; for(String str: fontName){ for(int effect: fontEffect){ for(int size : fontSize){ Font font = new Font(str, effect, size); fonts[fontsIndex]=font; fontsIndex = fontsIndex +1; } } } String s="abcdefghijknpqrstuvxyzABCDEFGHJKLNPQRSTUVXYZ23456789"; // 设置备选验证码 String sRand=""; // 用随机产生的颜色将验证码绘制到图像中。 int length = 4; // 设置默认生成4个验证码 for(int i=0;i<length;i++){ g.setColor(new Color(20+random.nextInt(110), 20+random.nextInt(110), 20+random.nextInt(110))); // 生成随机颜色(因为是做前景,所以偏深) g.setFont(fonts[random.nextInt(fonts.length)]); //调用上方的随机字体 String ch=String.valueOf(s.charAt(random.nextInt(s.length()))); //设置字体旋转 int zhuan = random.nextInt(20); int fzhuan = -random.nextInt(20); g2d.rotate(Math.toRadians(zhuan),25*(i-1),20); /// 坐标系顺时针转 g2d.rotate(Math.toRadians(fzhuan),25*(i-1),20); /// 坐标系逆时针转 sRand+=ch; g.drawString(ch, 18 * i + 15, 30); //将认证码用 drawString 函数显示到图象里 g2d.rotate(Math.toRadians(-1*zhuan),25*(i-1),20); g2d.rotate(Math.toRadians(-1*fzhuan),25*(i-1),20); } //将生成的字符串存储在session中 HttpSession session=request.getSession(); //在认证码的上端画一条不规则的线 int visit[] = new int[6]; for (int i = 0; i < visit.length; i++) { visit[i] = 1 + (int) (Math.random() * 10); } int visitValue = 0; g.setColor(Color.BLACK); int drawHigh[] = new int[6]; int drawwidth[] = new int[6]; //折点坐标 for (int i = 0; i < 6; i++) { drawHigh[i] = 40 - (int) (Math.ceil(visit[i] * 3.8)); drawwidth[i] = 5 + i * 17; } //g2d.setXORMode(Color.WHITE); g2d.setStroke(new BasicStroke(3.0f)); //折线粗细 g2d.setPaint(Color.gray);//折线的颜色 g2d.drawPolyline(drawwidth, drawHigh, 6); //画折线 session.setAttribute("checkCode", sRand); g.dispose();//图像生效 //禁止图像缓存 response.setHeader("Pragma", "No-cache"); response.setHeader("Cache-Control", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); //创建二进制的输出流 ServletOutputStream sos=response.getOutputStream(); // 将图像输出到Servlet输出流中。 ImageIO.write(image, "jpeg", sos); sos.flush(); sos.close(); } public Color getRandColor(int lower,int upper){ Random random = new Random(); if(upper>255) upper=255; if(upper<1) upper=1; if(lower<1) lower=1; if(lower>255) lower=255; int r=lower+random.nextInt(upper-lower); int g=lower+random.nextInt(upper-lower); int b=lower+random.nextInt(upper-lower); return new Color(r,g,b); } }
然后是前端的jsp展示页面(这里主要是写了一个方法来调用后端,将生成的验证码图片展示出来)
<%@ 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>验证码的生成和验证</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script> <script type="text/javascript" language="javascript"> function changeImg(){ $("#img").attr("src", "ImageServlet?time="+new Date()); } $(function(){ $("#button").click(function(){ changeImg(); var v_inputCode = document.getElementById("validate").value.toLowerCase(); if(v_inputCode == ""){ alert("请输入验证码"); }else{ $.post("<%=basePath%>test.htm",{inputCode:v_inputCode}, function(data){ data = $.parseJSON(data); if(data.test== 1){ alert("请输入正确的验证码"); }else{ alert("验证码输入正确"); location.href='../jsp/index.html';//跳转页面 } }); } }); }); </script> </head> <body> <form action="#"> <table> <caption>验证码测试</caption> <tr> <td>验证码</td> <td colspan="2"> <input type="text" id="validate" /> <a href='javascript:changeImg();' title="看不清请点我" > <img id="img" align="middle" src="ImageServlet" /> </a> </td> </tr> <tr> <td colspan="2"><input id="button" type="button" value="查 询" /></td> </tr> </table> </form> </body> </html>
最后是验证(这里主要是将前端传入的用户输入的验证码与session中的验证码作对比,再返回给前端):
import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import javax.mail.Session; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sf.json.util.NewBeanInstanceStrategy; import org.omg.CORBA.PUBLIC_MEMBER; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import com.util.StringUtil; @Controller public class TestController { @Resource(name = "stringutil") private StringUtil stringUtil; @RequestMapping(value = "test.htm",method = RequestMethod.POST) public @ResponseBody Map<String, Object> querycard(HttpServletRequest request, HttpServletResponse response){ Map<String, Object> result = new HashMap<String, Object>(); String string = request.getSession().getAttribute("checkCode").toString(); Map<String, Object> requestMap = stringUtil.getParamsForJqgrid(request); Map<String, Object> map = (Map<String, Object>) requestMap.get("paraMap"); if((string.toLowerCase()).equals(map.get("inputCode").toString().toLowerCase())){//不区分大小写(将两个值都转换成小写再进行比较) result.put("test",0);//true }else { result.put("test",1);//false } return result; } }