java生成验证码(多种抗OCR识别技术)随机间距、干扰线、背景变化、旋转、扭曲等

来源:互联网 发布:怎样注册.com域名? 编辑:程序博客网 时间:2024/05/01 19:35
package cmcc.jx.ict.xsgj.system.yzm.action;import java.awt.Color;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.image.BufferedImage;import java.io.IOException;import java.io.OutputStream;import java.util.Date;import java.util.Random;import javax.imageio.ImageIO;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.struts2.ServletActionContext;import sun.font.FontDesignMetrics;import com.opensymphony.xwork2.ActionSupport;/** * @author 朱银涛  * @version : 2017年2月8日 */public class ValidateCodeAction extends ActionSupport{//验证码存在session中的namepublic static final String VALIDATE_CODE = "code";//可选字体String[] fontTypes = {"Arial","Arial Black","AvantGarde Bk BT","Calibri","Times New Roman","宋体","黑体","Arial Unicode MS","Lucida Sans"};//随机字符的范围char[] codeSeq = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J','K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W','X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};//验证码长度private final int CODE_LENGTH = 4;//验证码的宽和高private int w;private int h = 25;Random random = new Random();public static boolean validate(HttpServletRequest request, String validateCode){String code = (String)request.getSession().getAttribute(VALIDATE_CODE);return validateCode.toUpperCase().equals(code); }public void validateCode(){HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();String rd = (String) request.getSession().getAttribute("rd");String rd2 = request.getParameter("rd2");System.out.println("session中的数字"+rd);System.out.println("request中的数字"+rd2);request.getSession().removeAttribute("rd");   //删除session中的数字try {if (rd != null && rd.equals(rd2)) {createImage(request,response);}else{response.sendRedirect("error.jsp");}} catch (IOException e) {e.printStackTrace();}}/** * 生成图像数据 * */private void createImage(HttpServletRequest request,HttpServletResponse response) throws IOException {response.setHeader("Pragma", "no-cache");response.setHeader("Cache-Control", "no-cache");response.setDateHeader("Expires", 0);response.setContentType("image/jpeg");/* * 得到参数高,宽,都为数字时,则使用设置高宽,否则使用默认值 */String width = request.getParameter("width");String height = request.getParameter("height");if ((width != null && "".equals(width))&&(height != null && "".equals(height))) {w = Integer.valueOf(width);h = Integer.valueOf(height);}else{w = CODE_LENGTH * 18 +20;}BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);//获取图片上下文Graphics g = image.getGraphics();Graphics2D g2 = (Graphics2D) g;/* * 生成背景 */createBackground(g2);/* * 生成字符 */String s = createCharacter(g2);request.getSession().setAttribute(VALIDATE_CODE, s);g2.dispose();OutputStream out = response.getOutputStream();ImageIO.write(image, "JPEG", out);out.close();}/** * 生成随机颜色 * @param fc 产生颜色值下限 * @param bc 产生颜色值上限 * @return 生成的随机颜色对象 */private Color getRandColor(int fc,int bc) { int f = fc;int b = bc;if(f>255) {f=255; }if (f<1) {f=1;}if(b>255) {b=255; }if (b<1) {b=1;}return new Color(f+random.nextInt(b-f),f+random.nextInt(b-f),f+random.nextInt(b-f)); }private void createBackground(Graphics2D g) {// 填充背景g.setColor(getRandColor(220,250)); g.fillRect(0, 0, w, h);// 加入干扰线条for (int i = 0; i < 7; i++) {g.setColor(getRandColor(40,150));int x = random.nextInt(w);int y = random.nextInt(h);int x1 = random.nextInt(w);int y1 = random.nextInt(h);g.drawLine(x, y, x1, y1);}}//生成随机字符并且返回private String createCharacter(Graphics2D g) {StringBuilder s = new StringBuilder();int fontsize;  //生成字符的字体大小int charX = 0; //生成字符x的位置int chartY = h - 5; //生成字符y的位置Color color = g.getColor();//旋转或扭曲        int rotateOrWarp = random.nextInt(2);for (int i = 0; i < CODE_LENGTH; i++) {String r = String.valueOf(codeSeq[random.nextInt(codeSeq.length)]);//random.nextInt(10));//随机设置字体颜色g.setColor(new Color(50 + random.nextInt(100), 50 + random.nextInt(100), 50 + random.nextInt(100)));//随机字体大小18-22fontsize = Math.abs(18+random.nextInt(4));Font font = new Font(fontTypes[random.nextInt(fontTypes.length)],Font.BOLD,fontsize);g.setFont(font); FontMetrics fontMetrics = FontDesignMetrics.getMetrics(font);              int charWidth = fontMetrics.stringWidth("M"); //当前随机生成字符的宽度              int charsRealWidth = charWidth * CODE_LENGTH;            //第一次循环的时候初始化            if (i == 0) {            if(w > charsRealWidth){                      charX = (w - charsRealWidth)/2;                  } }if(rotateOrWarp == 0){//画旋转文字            double radianPercent = 0D;              radianPercent =  Math.PI * (random.nextInt(40)/180D);              if(random.nextBoolean()) radianPercent = -radianPercent;              g.rotate(radianPercent, charX + 9, chartY);              g.drawString(r, charX, chartY);              g.rotate(-radianPercent, charX + 9, chartY);              charX += charWidth;  }else{g.drawString(r, charX, chartY);charX += charWidth;}s.append(r);}if (rotateOrWarp == 1) {//扭曲shear(g, w, h, color);}return s.toString();}// 扭曲方法private void shear(Graphics g, int w1, int h1, Color color) {shearX(g, w1, h1, color);shearY(g, w1, h1, color);}private void shearX(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(2);boolean borderGap = true;int frames = 1;int phase = random.nextInt(2);for (int i = 0; i < h1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(0, i, w1, 1, (int) d, 0);if (borderGap) {g.setColor(color);g.drawLine((int) d, i, 0, i);g.drawLine((int) d + w1, i, w1, i);}}}private void shearY(Graphics g, int w1, int h1, Color color) {int period = random.nextInt(8)+8;boolean borderGap = true;int frames = 20;int phase = 7;for (int i = 0; i < w1; i++) {double d = (double) (period >> 1)* Math.sin((double) i / (double) period+ (6.2831853071795862D * (double) phase)/ (double) frames);g.copyArea(i, 0, 1, h1, 0, (int) d);if (borderGap) {g.setColor(color);g.drawLine(i, (int) d, i, 0);g.drawLine(i, (int) d + h1, i, h1);}}}//验证码安全检验public void safetyTest(){HttpServletRequest request = ServletActionContext.getRequest();HttpServletResponse response = ServletActionContext.getResponse();String rd="";Random random = new Random();for(int i=0;i<5;i++){rd += random.nextInt(10);}System.out.println("随机出的数字:"+rd);request.getSession().setAttribute("rd", rd);long d = new Date().getTime();System.out.println("当前验证码的时间:"+d);String json = rd+"-"+d;try {response.getWriter().write(json);} catch (IOException e) {e.printStackTrace();}}}


<package name="system-validateCode" extends="struts-default"><action name="validateCode" class="validateCodeAction" method="validateCode"></action><action name="safetyTest" class="validateCodeAction" method="safetyTest"></action></package>

<%//properties 配置文件名称PropertyResourceBundle res = (PropertyResourceBundle) PropertyResourceBundle.getBundle("validateCode");// 获取properties配置文件中的验证码过期时间的值String oldTime = res.getString("validateCode.oldTime");%><script src="./js/jquery-1.7.2.min.js"></script><script language="javascript">$(document).ready(function (){$("#validateCode2").trigger("click");});var ddd;   //验证码生成的时间var timeArray;  //记录验证码每次刷新的时间 10秒钟最多刷新4次function validateCodeRefresh(){if(limitRefresh(10,4)){$.post("safetyTest.action",function(data){var data2 = data.split("-");ddd = data2[1];$("#validateCode2").attr("src","validateCode.action?"+new Date().getTime()+"&rd2="+data2[0]);});}else{ alert("刷新过于频繁,请稍后再试...");}}//点击登录按钮function mysubmit() {var a = $("#validateCode").val();if(a == "" || a == null){alert("请输入验证码!");return false;}var newDate = new Date().getTime();var oldTime = parseInt("<%=oldTime %>");if(isNaN(oldTime)){oldTime = 10;}//验证码超时判断if(ddd != "" && ddd != null && newDate - ddd >= oldTime*1000){alert("验证码超时...");$("#validateCode2").trigger("click");}else{//提交表单}return true;}function limitRefresh(allTime,count){var newTime = new Date().getTime();if (timeArray == undefined) {timeArray = new Array();}else{var ttt = 0;for (var i=0;i<timeArray.length;i++) {if (newTime - timeArray[i] < allTime*1000) {ttt++;}else{//每隔十秒就可以清空一次timeArray = new Array();break;}if (ttt >= count) {return false;}}}timeArray.push(newTime);return true;}</script><td height="30" align="right" nowrap><strong>验证码:</strong></td><td nowrap><input id="validateCode" name="j_code" maxlength="5" type="text" style="position:relative; top:1px;width:87px;">        <img id="validateCode2" onclick="validateCodeRefresh()" style="position:relative; top:4px;"></td>


0 0
原创粉丝点击