大多網站登陸時須要輸入一個驗證碼,這主要是基於安全性方面的考慮。在這裏將詳細的說明一下驗證碼的生成和驗證。javascript
首先是java文件(這段java主要寫了驗證碼圖片的生成及各類特效,好比旋轉、干擾線、噪點等,並將其用流的方式傳到前端頁面):html
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中的驗證碼做對比,再返回給前端):java
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; } }