diff --git a/README.md b/README.md index 5145386..57aec3c 100644 --- a/README.md +++ b/README.md @@ -229,8 +229,10 @@ public class Test { captcha.setLen(3); // 几位数运算,默认是两位 captcha.getArithmeticString(); // 获取运算的公式:3+2=? captcha.text(); // 获取运算的结果:5 - + captcha.supportAlgorithmSign(2); // 可设置支持的算法:2 表示只生成带加减法的公式 + captcha.setDifficulty(50); // 设置计算难度,参与计算的每一个整数的最大值 captcha.out(outputStream); // 输出验证码 + //简单算术类型 SimpleArithmeticCaptcha,用法同ArithmeticCaptcha,只支持加减,计算结果为正整数 } } ``` diff --git a/src/main/java/com/wf/captcha/SimpleArithmeticCaptcha.java b/src/main/java/com/wf/captcha/SimpleArithmeticCaptcha.java new file mode 100644 index 0000000..c393f31 --- /dev/null +++ b/src/main/java/com/wf/captcha/SimpleArithmeticCaptcha.java @@ -0,0 +1,160 @@ +package com.wf.captcha; + +import com.wf.captcha.base.ArithmeticCaptchaAbstract; + +import javax.imageio.ImageIO; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Description:最后一位计算时保证结果为正,避免负号输入 + * 2位3位整数计算比较好,否则最后一位会数字会有点异常 + * + * @author Li Haoran + */ +public class SimpleArithmeticCaptcha extends ArithmeticCaptchaAbstract { + + public SimpleArithmeticCaptcha() { + } + + public SimpleArithmeticCaptcha(int width, int height) { + this(); + setWidth(width); + setHeight(height); + } + + public SimpleArithmeticCaptcha(int width, int height, int len) { + this(width, height); + setLen(len); + } + + public SimpleArithmeticCaptcha(int width, int height, int len, Font font) { + this(width, height, len); + setFont(font); + } + + public SimpleArithmeticCaptcha(int width, int height, int len, int font) throws IOException, FontFormatException { + this(width, height, len); + setFont(font,32f); + } + + /** + * 生成验证码 + * + * @param out 输出流 + * @return 是否成功 + */ + @Override + public boolean out(OutputStream out) { + checkAlpha(); + return graphicsImage(getArithmeticString().toCharArray(), out); + } + + @Override + public String toBase64() { + return toBase64("data:image/png;base64,"); + } + + /** + * 生成验证码图形 + * + * @param strs 验证码 + * @param out 输出流 + * @return boolean + */ + private boolean graphicsImage(char[] strs, OutputStream out) { + try { + BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = (Graphics2D) bi.getGraphics(); + // 填充背景 + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, width, height); + // 抗锯齿 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + // 画干扰圆 + drawOval(2, g2d); + // 画字符串 + g2d.setFont(getFont()); + FontMetrics fontMetrics = g2d.getFontMetrics(); + int fW = width / strs.length; // 每一个字符所占的宽度 + int fSp = (fW - (int) fontMetrics.getStringBounds("8", g2d).getWidth()) / 2; // 字符的左右边距 + for (int i = 0; i < strs.length; i++) { + g2d.setColor(color()); + int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标 + g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3); + } + g2d.dispose(); + ImageIO.write(bi, "png", out); + out.flush(); + return true; + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return false; + } + + /** + * 生成随机验证码 + * 不包含乘法、没有负数 + * @return 验证码字符数组 + */ + @Override + protected char[] alphas() { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len-1; i++) { + sb.append(num(difficulty)); + if (i < len - 1) { + int type = num(1, 3); + if (type == 1) { + sb.append("+"); + } else if (type == 2) { + sb.append("-"); + } + } + } + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("javascript"); + try { + chars = String.valueOf(engine.eval(sb.toString())); + } catch (ScriptException e) { + e.printStackTrace(); + } + + int parseInt = Integer.parseInt(chars); + if(parseInt<0){ + sb.append("+"); + sb.append(num(-parseInt,-parseInt+11)); + }else { + int type = num(1, 3); + if (type == 1) { + sb.append("+"); + sb.append(num(difficulty)); + } else if (type == 2) { + sb.append("-"); + sb.append(num(0,parseInt+1)); + } + } + + try { + chars = String.valueOf(engine.eval(sb.toString())); + } catch (ScriptException e) { + e.printStackTrace(); + } + + sb.append("=?"); + setArithmeticString(sb.toString()); + return chars.toCharArray(); + } + +} diff --git a/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java b/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java index daea140..490d8e8 100644 --- a/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java +++ b/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java @@ -11,6 +11,9 @@ import javax.script.ScriptException; public abstract class ArithmeticCaptchaAbstract extends Captcha { private String arithmeticString; // 计算公式 + protected static int difficulty = 10; + protected static int algorithmSign = 4; + public ArithmeticCaptchaAbstract() { setLen(2); } @@ -24,9 +27,9 @@ public abstract class ArithmeticCaptchaAbstract extends Captcha { protected char[] alphas() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i++) { - sb.append(num(10)); + sb.append(num(difficulty)); if (i < len - 1) { - int type = num(1, 4); + int type = num(1, algorithmSign); if (type == 1) { sb.append("+"); } else if (type == 2) { @@ -56,4 +59,18 @@ public abstract class ArithmeticCaptchaAbstract extends Captcha { public void setArithmeticString(String arithmeticString) { this.arithmeticString = arithmeticString; } + + public void setDifficulty(int difficulty) { + this.difficulty = difficulty; + } + + /** + * algorithmSign 2 : 支持加法 + * algorithmSign 3 : 支持加减法 + * algorithmSign 4 : 支持加减乘法 + * @param algorithmSign 计算公式标示 + */ + public void supportAlgorithmSign(int algorithmSign){ + this.algorithmSign = algorithmSign; + } } diff --git a/src/test/java/com/wf/captcha/CaptchaTest.java b/src/test/java/com/wf/captcha/CaptchaTest.java index d4ee3d5..27df97a 100644 --- a/src/test/java/com/wf/captcha/CaptchaTest.java +++ b/src/test/java/com/wf/captcha/CaptchaTest.java @@ -56,6 +56,8 @@ public class CaptchaTest { /*for (int i = 0; i < 10; i++) { ArithmeticCaptcha specCaptcha = new ArithmeticCaptcha(); specCaptcha.setLen(3); + specCaptcha.supportAlgorithmSign(2); + specCaptcha.setDifficulty(50); specCaptcha.setFont(i, 28f); System.out.println(specCaptcha.getArithmeticString() + " " + specCaptcha.text()); specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));