From a548f7af0b357c77250e03e39fd8fdb18b9cc464 Mon Sep 17 00:00:00 2001 From: synchronized Date: Fri, 27 Jul 2018 12:02:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=AA=8C=E8=AF=81=E7=A0=81?= =?UTF-8?q?=E4=BD=8D=E6=95=B0=E7=9A=84bug=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 43 ++-- .idea/encodings.xml | 6 + .idea/libraries/Maven__junit_junit_4_7.xml | 13 ++ .idea/uiDesigner.xml | 124 ++++++++++++ EasyCaptcha.iml | 2 + pom.xml | 161 ++++++++++++--- src/main/java/com/wf/captcha/Captcha.java | 178 +++++++++-------- src/main/java/com/wf/captcha/Encoder.java | 39 +--- src/main/java/com/wf/captcha/GifCaptcha.java | 117 +++++------ src/main/java/com/wf/captcha/GifEncoder.java | 14 +- src/main/java/com/wf/captcha/Quant.java | 31 ++- src/main/java/com/wf/captcha/Randoms.java | 67 +++++-- src/main/java/com/wf/captcha/SpecCaptcha.java | 113 ++++++----- .../wf/captcha/servlet/CaptchaServlet.java | 13 +- .../com/wf/captcha/utils/CaptchaUtil.java | 188 ++++++------------ src/test/java/com/wf/captcha/CaptchaTest.java | 27 +++ 16 files changed, 675 insertions(+), 461 deletions(-) create mode 100644 .idea/encodings.xml create mode 100644 .idea/libraries/Maven__junit_junit_4_7.xml create mode 100644 .idea/uiDesigner.xml create mode 100644 src/test/java/com/wf/captcha/CaptchaTest.java diff --git a/.gitignore b/.gitignore index f6eee71..82eca33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,25 @@ -# Compiled class file -*.class +/target/ +!.mvn/wrapper/maven-wrapper.jar -# Log file -*.log +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache -# BlueJ files -*.ctxt +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -/bin -/target +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..b26911b --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__junit_junit_4_7.xml b/.idea/libraries/Maven__junit_junit_4_7.xml new file mode 100644 index 0000000..1c50f8b --- /dev/null +++ b/.idea/libraries/Maven__junit_junit_4_7.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EasyCaptcha.iml b/EasyCaptcha.iml index 0317dc6..f1dd1f9 100644 --- a/EasyCaptcha.iml +++ b/EasyCaptcha.iml @@ -5,10 +5,12 @@ + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 660684f..bb293b9 100644 --- a/pom.xml +++ b/pom.xml @@ -1,30 +1,137 @@ - 4.0.0 - EasyCaptcha - EasyCaptcha - 1.1.0-RELEASE - - - - org.apache.maven.plugins - maven-compiler-plugin - - 6 - 6 - - - - - EasyCaptcha + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - - - - javax.servlet - javax.servlet-api - 3.1.0 - provided - - + com.github.whvcse + + EasyCaptcha + 1.1.0-RELEASE + jar + + EasyCaptcha + Java web图形验证码,支持gif验证码。 + https://github.com/whvcse/EasyCaptcha + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + org.sonatype.oss + oss-parent + 7 + + + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + junit + junit + 4.7 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 6 + 6 + + + + + + + https://github.com/whvcse/EasyCaptcha + scm:git:git@github.com:whvcse/EasyCaptcha + scm:git:git@github.com:whvcse/EasyCaptcha + HEAD + + + + + whvcse + whvcse@foxmail.com + https://github.com/whvcse + + + + + + oss + OSS Snapshots Repository + https://oss.sonatype.org/content/repositories/snapshots/ + + + oss + OSS Staging Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + release + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + package + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + package + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/wf/captcha/Captcha.java b/src/main/java/com/wf/captcha/Captcha.java index 3d7c798..8618e16 100644 --- a/src/main/java/com/wf/captcha/Captcha.java +++ b/src/main/java/com/wf/captcha/Captcha.java @@ -5,100 +5,114 @@ import java.awt.Font; import java.io.OutputStream; /** - *

- * 验证码抽象类,暂时不支持中文 - *

- * - * @author: wuhongjun - * @version:1.0 + * 验证码抽象类 + * Created by 王帆 on 2018-07-27 上午 10:08. */ public abstract class Captcha extends Randoms { - protected Font font = new Font("Verdana", Font.ITALIC | Font.BOLD, 28); // 字体 - protected int len = 5; // 验证码随机字符长度 - protected int width = 150; // 验证码显示跨度 - protected int height = 40; // 验证码显示高度 - private String chars = null; // 随机字符串 + protected Font font = new Font("Verdana", Font.ITALIC | Font.BOLD, 28); // 字体 + protected int len = 5; // 验证码随机字符长度 + protected int width = 150; // 验证码显示宽度 + protected int height = 40; // 验证码显示高度 + private String chars = null; // 当前验证码 - /** - * 生成随机字符数组 - * - * @return 字符数组 - */ - protected char[] alphas() { - char[] cs = new char[len]; - for (int i = 0; i < len; i++) { - cs[i] = alpha(); - } - chars = new String(cs); - return cs; - } + /** + * 生成随机验证码 + * + * @return 验证码字符数组 + */ + protected char[] alphas() { + char[] cs = new char[len]; + for (int i = 0; i < len; i++) { + cs[i] = alpha(); + } + chars = new String(cs); + return cs; + } - public Font getFont() { - return font; - } + /** + * 给定范围获得随机颜色 + * + * @param fc 0-255 + * @param bc 0-255 + * @return 随机颜色 + */ + protected Color color(int fc, int bc) { + if (fc > 255) + fc = 255; + if (bc > 255) + bc = 255; + int r = fc + num(bc - fc); + int g = fc + num(bc - fc); + int b = fc + num(bc - fc); + return new Color(r, g, b); + } - public void setFont(Font font) { - this.font = font; - } + /** + * 验证码输出,抽象方法,由子类实现 + * + * @param os 输出流 + * @return 是否成功 + */ + public abstract boolean out(OutputStream os); - public int getLen() { - return len; - } + /** + * 获取当前的验证码 + * + * @return 字符串 + */ + public String text() { + checkAlpha(); + return chars; + } - public void setLen(int len) { - this.len = len; - } + /** + * 获取当前验证码的字符数组 + * + * @return 字符数组 + */ + public char[] textChar() { + checkAlpha(); + return chars.toCharArray(); + } - public int getWidth() { - return width; - } + /** + * 检查验证码是否生成,没有这立即生成 + */ + public void checkAlpha() { + if (chars == null) { + alphas(); // 生成验证码 + } + } - public void setWidth(int width) { - this.width = width; - } + public Font getFont() { + return font; + } - public int getHeight() { - return height; - } + public void setFont(Font font) { + this.font = font; + } - public void setHeight(int height) { - this.height = height; - } + public int getLen() { + return len; + } - /** - * 给定范围获得随机颜色 - * - * @return Color 随机颜色 - */ - protected Color color(int fc, int bc) { - if (fc > 255) - fc = 255; - if (bc > 255) - bc = 255; - int r = fc + num(bc - fc); - int g = fc + num(bc - fc); - int b = fc + num(bc - fc); - return new Color(r, g, b); - } + public void setLen(int len) { + this.len = len; + } - /** - * 验证码输出,抽象方法,由子类实现 - * - * @param os - * 输出流 - */ - public abstract void out(OutputStream os); + public int getWidth() { + return width; + } - /** - * 获取随机字符串 - * - * @return string - */ - public String text() { - return chars; - } - - public char[] textChar() { - return chars.toCharArray(); - } + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } } \ No newline at end of file diff --git a/src/main/java/com/wf/captcha/Encoder.java b/src/main/java/com/wf/captcha/Encoder.java index f934d4a..70cf4bd 100644 --- a/src/main/java/com/wf/captcha/Encoder.java +++ b/src/main/java/com/wf/captcha/Encoder.java @@ -4,40 +4,20 @@ import java.io.IOException; import java.io.OutputStream; /** - * @author: wuhongjun - * @version:1.0 + * */ -public class Encoder -{ +public class Encoder { private static final int EOF = -1; - + // 图片的宽高 private int imgW, imgH; private byte[] pixAry; - private int initCodeSize; - private int remaining; - private int curPixel; - - // GIFCOMPR.C - GIF Image compression routines - // - // Lempel-Ziv compression based on 'compress'. GIF modifications by - // David Rowley (mgardi@watdcsu.waterloo.edu) - - // General DEFINEs + private int initCodeSize; // 验证码位数 + private int remaining; // 剩余数量 + private int curPixel; // 像素 static final int BITS = 12; - static final int HSIZE = 5003; // 80% occupancy - - // GIF Image compression - modified 'compress' - // - // Based on: compress.c - File compression ala IEEE Computer, June 1984. - // - // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) - // Jim McKie (decvax!mcvax!jim) - // Steve Davies (decvax!vax135!petsd!peora!srd) - // Ken Turkowski (decvax!decwrl!turtlevax!ken) - // James A. Woods (decvax!ihnp4!ames!jaw) - // Joe Orost (decvax!vax135!petsd!joe) + static final int HSIZE = 5003; // 80% 占用率 int n_bits; // number of bits/code int maxbits = BITS; // user settable max # bits/code @@ -108,7 +88,7 @@ public class Encoder 0x1FFF, 0x3FFF, 0x7FFF, - 0xFFFF }; + 0xFFFF}; // Number of characters so far in this 'packet' int a_count; @@ -184,7 +164,8 @@ public class Encoder output(ClearCode, outs); - outer_loop : while ((c = nextPixel()) != EOF) { + outer_loop: + while ((c = nextPixel()) != EOF) { fcode = (c << maxbits) + ent; i = (c << hshift) ^ ent; // xor hashing diff --git a/src/main/java/com/wf/captcha/GifCaptcha.java b/src/main/java/com/wf/captcha/GifCaptcha.java index 38bc874..4962194 100644 --- a/src/main/java/com/wf/captcha/GifCaptcha.java +++ b/src/main/java/com/wf/captcha/GifCaptcha.java @@ -7,98 +7,87 @@ import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; + /** - *

Gif验证码类

- * - * @author: wuhongjun - * @version:1.0 + * Gif验证码类 + * Created by 王帆 on 2018-07-27 上午 10:08. */ -public class GifCaptcha extends Captcha -{ - public GifCaptcha() - { +public class GifCaptcha extends Captcha { + + public GifCaptcha() { } - public GifCaptcha(int width,int height){ - this.width = width; - this.height = height; - alphas(); + public GifCaptcha(int width, int height) { + setWidth(width); + setHeight(height); } - public GifCaptcha(int width,int height,int len){ - this(width,height); - this.len = len; + public GifCaptcha(int width, int height, int len) { + this(width, height); + setLen(len); } - public GifCaptcha(int width,int height,int len,Font font) - { - this(width,height,len); - this.font = font; + public GifCaptcha(int width, int height, int len, Font font) { + this(width, height, len); + setFont(font); } @Override - public void out(OutputStream os) - { - try - { - GifEncoder gifEncoder = new GifEncoder(); // gif编码类,这个利用了洋人写的编码类,所有类都在附件中 - //生成字符 + public boolean out(OutputStream os) { + checkAlpha(); + boolean ok = false; + try { + char[] rands = textChar(); // 获取验证码数组 + GifEncoder gifEncoder = new GifEncoder(); gifEncoder.start(os); gifEncoder.setQuality(180); gifEncoder.setDelay(100); gifEncoder.setRepeat(0); BufferedImage frame; - char[] rands = textChar(); - Color fontcolor[]=new Color[len]; - for(int i=0;i>1) ; - int w = width/len; + int h = height - ((height - font.getSize()) >> 1); + int w = width / len; g2d.setFont(font); - for(int i=0;i len ? (num *r - s) : num * r; + private float getAlpha(int i, int j) { + int num = i + j; + float r = (float) 1 / len, s = (len + 1) * r; + return num > len ? (num * r - s) : num * r; } } diff --git a/src/main/java/com/wf/captcha/GifEncoder.java b/src/main/java/com/wf/captcha/GifEncoder.java index 877aaa0..8a1f4c9 100644 --- a/src/main/java/com/wf/captcha/GifEncoder.java +++ b/src/main/java/com/wf/captcha/GifEncoder.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.io.OutputStream; /** + * Gif生成工具 * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or * more frames. *
@@ -25,13 +26,8 @@ import java.io.OutputStream;
  * for any purpose, however, refer to the Unisys LZW patent for restrictions
  * on use of the associated Encoder class.  Please forward any corrections
  * to questions at fmsware.com.
- *
- * @author wuhongjun
- * @version 1.03 November 2003
- *
  */
-public class GifEncoder
-{
+public class GifEncoder {
     protected int width; // image size
     protected int height;
     protected Color transparent = null; // transparent color if given
@@ -67,6 +63,7 @@ public class GifEncoder
      * Sets the GIF frame disposal code for the last added frame
      * and any subsequent frames.  Default is 0 if no transparent
      * color has been set, otherwise 2.
+     *
      * @param code int disposal code.
      */
     public void setDispose(int code) {
@@ -322,7 +319,6 @@ public class GifEncoder
 
     /**
      * Returns index of palette color closest to c
-     *
      */
     protected int findClosest(Color c) {
         if (colorTab == null) return -1;
@@ -332,7 +328,7 @@ public class GifEncoder
         int minpos = 0;
         int dmin = 256 * 256 * 256;
         int len = colorTab.length;
-        for (int i = 0; i < len;) {
+        for (int i = 0; i < len; ) {
             int dr = r - (colorTab[i++] & 0xff);
             int dg = g - (colorTab[i++] & 0xff);
             int db = b - (colorTab[i] & 0xff);
@@ -473,7 +469,7 @@ public class GifEncoder
     }
 
     /**
-     *    Write 16-bit value to output stream, LSB first
+     * Write 16-bit value to output stream, LSB first
      */
     protected void writeShort(int value) throws IOException {
         out.write(value & 0xff);
diff --git a/src/main/java/com/wf/captcha/Quant.java b/src/main/java/com/wf/captcha/Quant.java
index cee82c8..ed6cbf9 100644
--- a/src/main/java/com/wf/captcha/Quant.java
+++ b/src/main/java/com/wf/captcha/Quant.java
@@ -1,24 +1,20 @@
 package com.wf.captcha;
 
 /**
- * 

* - * @author: wuhongjun - * @version:1.0 */ -public class Quant -{ +public class Quant { protected static final int netsize = 256; /* number of colours used */ /* four primes near 500 - assume no image has a length so large */ - /* that it is divisible by all four primes */ + /* that it is divisible by all four primes */ protected static final int prime1 = 499; protected static final int prime2 = 491; protected static final int prime3 = 487; protected static final int prime4 = 503; protected static final int minpicturebytes = (3 * prime4); - /* minimum size for input image */ + /* minimum size for input image */ /* Program Skeleton ---------------- @@ -80,13 +76,13 @@ public class Quant protected int[][] network; /* the network itself - [netsize][4] */ protected int[] netindex = new int[256]; - /* for network lookup - really 256 */ + /* for network lookup - really 256 */ protected int[] bias = new int[netsize]; /* bias and freq arrays for learning */ protected int[] freq = new int[netsize]; protected int[] radpower = new int[initrad]; - /* radpower for precomputation */ + /* radpower for precomputation */ /* Initialise network in range (0,0,0) to (255,255,255) and set parameters ----------------------------------------------------------------------- */ @@ -139,7 +135,7 @@ public class Quant p = network[i]; smallpos = i; smallval = p[1]; /* index on g */ - /* find smallest in i..netsize-1 */ + /* find smallest in i..netsize-1 */ for (j = i + 1; j < netsize; j++) { q = network[j]; if (q[1] < smallval) { /* index on g */ @@ -148,7 +144,7 @@ public class Quant } } q = network[smallpos]; - /* swap p (i) and q (smallpos) entries */ + /* swap p (i) and q (smallpos) entries */ if (i != smallpos) { j = q[0]; q[0] = p[0]; @@ -163,7 +159,7 @@ public class Quant q[3] = p[3]; p[3] = j; } - /* smallval entry is now in position i */ + /* smallval entry is now in position i */ if (smallval != previouscol) { netindex[previouscol] = (startpos + i) >> 1; for (j = previouscol + 1; j < smallval; j++) @@ -320,6 +316,7 @@ public class Quant } return (best); } + public byte[] process() { learn(); unbiasnet(); @@ -385,7 +382,7 @@ public class Quant ---------------------------------------------------- */ protected void altersingle(int alpha, int i, int b, int g, int r) { - /* alter hit neuron */ + /* alter hit neuron */ int[] n = network[i]; n[0] -= (alpha * (n[0] - b)) / initalpha; n[1] -= (alpha * (n[1] - g)) / initalpha; @@ -396,10 +393,10 @@ public class Quant ---------------------------- */ protected int contest(int b, int g, int r) { - /* finds closest neuron (min dist) and updates freq */ - /* finds best neuron (min dist-bias) and returns position */ - /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */ - /* bias[i] = gamma*((1/netsize)-freq[i]) */ + /* finds closest neuron (min dist) and updates freq */ + /* finds best neuron (min dist-bias) and returns position */ + /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */ + /* bias[i] = gamma*((1/netsize)-freq[i]) */ int i, dist, a, biasdist, betafreq; int bestpos, bestbiaspos, bestd, bestbiasd; diff --git a/src/main/java/com/wf/captcha/Randoms.java b/src/main/java/com/wf/captcha/Randoms.java index 158b105..6c4127e 100644 --- a/src/main/java/com/wf/captcha/Randoms.java +++ b/src/main/java/com/wf/captcha/Randoms.java @@ -3,41 +3,64 @@ package com.wf.captcha; import java.util.Random; /** - *

随机工具类

- * - * @author: wuhongjun - * @version:1.0 + * 随机数工具类 + * Created by 王帆 on 2018-07-27 上午 10:08. */ -public class Randoms -{ +public class Randoms { private static final Random RANDOM = new Random(); - //定义验证码字符.去除了O和I等容易混淆的字母 - public static final char ALPHA[]={'A','B','C','D','E','F','G','H','G','K','M','N','P','Q','R','S','T','U','V','W','X','Y','Z' - ,'a','b','c','d','e','f','g','h','i','j','k','m','n','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7','8','9'}; + // 定义验证码字符.去除了O和I等容易混淆的字母 + public static final char ALPHA[] = {'2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'G', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; /** * 产生两个数之间的随机数 - * @param min 小数 - * @param max 比min大的数 - * @return int 随机数字 + * + * @param min 最小值 + * @param max 最大值 + * @return 随机数 */ - public static int num(int min, int max) - { + public static int num(int min, int max) { return min + RANDOM.nextInt(max - min); } /** - * 产生0--num的随机数,不包括num - * @param num 数字 - * @return int 随机数字 + * 产生0-num的随机数,不包括num + * + * @param num 最大值 + * @return 随机数 */ - public static int num(int num) - { + public static int num(int num) { return RANDOM.nextInt(num); } - public static char alpha() - { - return ALPHA[num(0, ALPHA.length)]; + /** + * 返回ALPHA中的随机字符 + * + * @return 随机字符 + */ + public static char alpha() { + return ALPHA[num(ALPHA.length)]; + } + + /** + * 返回ALPHA中第0位到第num位的随机字符 + * + * @param num 到第几位结束 + * @return 随机字符 + */ + public static char alpha(int num) { + return ALPHA[num(num)]; + } + + /** + * 返回ALPHA中第min位到第max位的随机字符 + * + * @param min 从第几位开始 + * @param max 到第几位结束 + * @return 随机字符 + */ + public static char alpha(int min, int max) { + return ALPHA[num(min, max)]; } } \ No newline at end of file diff --git a/src/main/java/com/wf/captcha/SpecCaptcha.java b/src/main/java/com/wf/captcha/SpecCaptcha.java index 12c693c..4899dad 100644 --- a/src/main/java/com/wf/captcha/SpecCaptcha.java +++ b/src/main/java/com/wf/captcha/SpecCaptcha.java @@ -9,90 +9,93 @@ import java.io.IOException; import java.io.OutputStream; import javax.imageio.ImageIO; + /** - *

png格式验证码

- * - * @author: wuhongjun - * @version:1.0 + * png格式验证码 + * Created by 王帆 on 2018-07-27 上午 10:08. */ -public class SpecCaptcha extends Captcha -{ - public SpecCaptcha() - { +public class SpecCaptcha extends Captcha { + + public SpecCaptcha() { } - public SpecCaptcha(int width, int height) - { - this.width = width; - this.height = height; + + public SpecCaptcha(int width, int height) { + setWidth(width); + setHeight(height); } - public SpecCaptcha(int width, int height, int len){ - this(width,height); - this.len = len; + + public SpecCaptcha(int width, int height, int len) { + this(width, height); + setLen(len); } - public SpecCaptcha(int width, int height, int len, Font font){ - this(width,height,len); - this.font = font; - } - /** - * 生成验证码 - * @throws java.io.IOException IO异常 - */ - @Override - public void out(OutputStream out){ - graphicsImage(alphas(), out); + + public SpecCaptcha(int width, int height, int len, Font font) { + this(width, height, len); + setFont(font); } /** - * 画随机码图 - * @param strs 文本 + * 生成验证码 + * * @param out 输出流 + * @return 是否成功 */ - private boolean graphicsImage(char[] strs, OutputStream out){ - boolean ok = false; - try - { - BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB); - Graphics2D g = (Graphics2D)bi.getGraphics(); + @Override + public boolean out(OutputStream out) { + checkAlpha(); + return graphicsImage(textChar(), out); + } + + /** + * 生成验证码图形 + * + * @param strs 验证码 + * @param out 输出流 + * @return boolean + */ + private boolean graphicsImage(char[] strs, OutputStream out) { + boolean ok; + try { + BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g = (Graphics2D) bi.getGraphics(); AlphaComposite ac3; - Color color ; + Color color; int len = strs.length; g.setColor(Color.WHITE); - g.fillRect(0,0,width,height); - // 随机画干扰的蛋蛋 - for(int i=0;i<15;i++){ + g.fillRect(0, 0, width, height); + // 随机画干扰的圆圈 + for (int i = 0; i < 15; i++) { color = color(150, 250); g.setColor(color); - g.drawOval(num(width), num(height), 5+num(10), 5+num(10));// 画蛋蛋,有蛋的生活才精彩 + g.drawOval(num(width), num(height), 5 + num(10), 5 + num(10)); color = null; } g.setFont(font); - int h = height - ((height - font.getSize()) >>1), - w = width/len, - size = w-font.getSize()+1; - /* 画字符串 */ - for(int i=0;i> 1); + int w = width / len; + int size = w - font.getSize() + 1; + // 画字符串 + for (int i = 0; i < len; i++) { ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);// 指定透明度 g.setComposite(ac3); color = new Color(20 + num(110), 20 + num(110), 20 + num(110));// 对每个字符都用随机颜色 g.setColor(color); - g.drawString(strs[i]+"",(width-(len-i)*w)+size, h-4); + g.drawString(String.valueOf(strs[i]), (width - (len - i) * w) + size, h - 4); color = null; ac3 = null; } ImageIO.write(bi, "png", out); out.flush(); ok = true; - }catch (IOException e){ + } catch (IOException e) { ok = false; - }finally - { - try { - out.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + e.printStackTrace(); + } finally { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } } return ok; } diff --git a/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java b/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java index ee5d777..e273a03 100644 --- a/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java +++ b/src/main/java/com/wf/captcha/servlet/CaptchaServlet.java @@ -11,23 +11,14 @@ import com.wf.captcha.utils.CaptchaUtil; /** * 验证码servlet - * - * @author wangfan - * @date 2018-5-14 上午9:53:01 + * Created by 王帆 on 2018-07-27 上午 10:08. */ public class CaptchaServlet extends HttpServlet { private static final long serialVersionUID = -90304944339413093L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - // 是否有key决定是存在session中还是servletContext中 - String key = request.getParameter("key"); - CaptchaUtil cu = new CaptchaUtil(); - if (key != null && !key.trim().isEmpty()) { - cu.out(key, request, response); - } else { - cu.out(request, response); - } + CaptchaUtil.out(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) diff --git a/src/main/java/com/wf/captcha/utils/CaptchaUtil.java b/src/main/java/com/wf/captcha/utils/CaptchaUtil.java index ea11f7f..23cb243 100644 --- a/src/main/java/com/wf/captcha/utils/CaptchaUtil.java +++ b/src/main/java/com/wf/captcha/utils/CaptchaUtil.java @@ -2,7 +2,6 @@ package com.wf.captcha.utils; import java.io.IOException; -import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -11,136 +10,75 @@ import com.wf.captcha.GifCaptcha; /** * 图形验证码工具类 - * - * @author wangfan - * @date 2018-5-14 上午9:41:06 + * Created by 王帆 on 2018-07-27 上午 10:08. */ public class CaptchaUtil { - private String codeName = "captcha"; - private int width = 130; - private int height = 38; - private int len = 5; + private static final String SESSION_KEY = "captcha"; - public CaptchaUtil() { - } + /** + * 验证验证码 + */ + public static boolean ver(String code, HttpServletRequest request) { + if (code != null && !code.trim().isEmpty()) { + String captcha = (String) request.getSession().getAttribute(SESSION_KEY); + return code.trim().toLowerCase().equals(captcha); + } + return false; + } - /** - * 验证码的宽、高、位数 - */ - public CaptchaUtil(int width, int height, int len) { - set(width, height, len); - } + /** + * 输出验证码 + * + * @param request + * @param response + * @throws IOException + */ + public static void out(HttpServletRequest request, HttpServletResponse response) + throws IOException { + out(130, 38, 5, request, response); + } - /** - * 验证验证码 - */ - public boolean ver(String code, HttpServletRequest request) { - String captcha = (String) request.getSession().getAttribute(codeName); - return code.equals(captcha); - } + /** + * 输出验证码 + * + * @param len 长度 + * @param request + * @param response + * @throws IOException + */ + public static void out(int len, HttpServletRequest request, HttpServletResponse response) + throws IOException { + out(130, 38, len, request, response); + } - /** - * 验证验证码,用于分离的项目 - */ - public boolean ver(String key, String code, HttpServletRequest rq) { - ServletContext sc = rq.getServletContext(); - String keyName = codeName + "-" + key; - String captcha = (String) sc.getAttribute(keyName); - return code.equals(captcha); - } + /** + * 输出验证码 + * + * @param width 宽度 + * @param height 高度 + * @param len 长度 + * @param request + * @param response + * @throws IOException + */ + public static void out(int width, int height, int len, HttpServletRequest request, HttpServletResponse response) + throws IOException { + setHeader(response); + Captcha captcha = new GifCaptcha(130, 38, 5); + request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase()); + captcha.out(response.getOutputStream()); + } - /** - * 输出验证码 - */ - public void out(HttpServletRequest rq, HttpServletResponse rp) - throws IOException { + /** + * 设置相应头 + * + * @param response + */ + private static void setHeader(HttpServletResponse response) { + response.setContentType("image/gif"); + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setDateHeader("Expires", 0); + } - setHeader(rp); - - // 验证码的宽、高、位数 - Captcha captcha = new GifCaptcha(width, height, len); - // 存入缓存 - rq.getSession().setAttribute(codeName, captcha.text().toLowerCase()); - - // 输入图片 - captcha.out(rp.getOutputStream()); - } - - /** - * 输出验证码,用于分离项目 - */ - public void out(String key, HttpServletRequest rq, HttpServletResponse rp) - throws IOException { - - setHeader(rp); - - // 验证码的宽、高、位数 - Captcha captcha = new GifCaptcha(width, height, len); - // 存入缓存 - ServletContext sc = rq.getServletContext(); - sc.setAttribute(codeName, captcha.text().toLowerCase()); - - // 输入图片 - captcha.out(rp.getOutputStream()); - } - - private void setHeader(HttpServletResponse rp) { - rp.setContentType("image/gif"); - rp.setHeader("Pragma", "No-cache"); - rp.setHeader("Cache-Control", "no-cache"); - rp.setDateHeader("Expires", 0); - } - - public String getCodeName() { - return codeName; - } - - /** - * 设置保存code的key - */ - public void setCodeName(String codeName) { - this.codeName = codeName; - } - - public int getWidth() { - return width; - } - - /** - * 设置验证码的宽度 - */ - public void setWidth(int width) { - this.width = width; - } - - public int getHeight() { - return height; - } - - /** - * 设置验证码的高度 - */ - public void setHeight(int height) { - this.height = height; - } - - public int getLen() { - return len; - } - - /** - * 设置验证码的位数 - */ - public void setLen(int len) { - this.len = len; - } - - /** - * 设置验证码的宽、高、位数 - */ - public void set(int width, int height, int len) { - setWidth(width); - setHeight(height); - setLen(len); - } } diff --git a/src/test/java/com/wf/captcha/CaptchaTest.java b/src/test/java/com/wf/captcha/CaptchaTest.java new file mode 100644 index 0000000..1a25a47 --- /dev/null +++ b/src/test/java/com/wf/captcha/CaptchaTest.java @@ -0,0 +1,27 @@ +package com.wf.captcha; + +import org.junit.Test; + +import java.io.File; +import java.io.FileOutputStream; + +/** + * 测试类 + * Created by 王帆 on 2018-07-27 上午 10:08. + */ +public class CaptchaTest { + + @Test + public void test() throws Exception { + SpecCaptcha specCaptcha = new SpecCaptcha(150, 40, 4); + System.out.println(specCaptcha.text()); + specCaptcha.out(new FileOutputStream(new File("D:/a/aa.png"))); + } + + @Test + public void testGIf() throws Exception { + GifCaptcha specCaptcha = new GifCaptcha(150, 40, 4); + System.out.println(specCaptcha.text()); + specCaptcha.out(new FileOutputStream(new File("D:/a/aa.gif"))); + } +}