修复验证码位数的bug,优化代码
This commit is contained in:
@@ -5,100 +5,114 @@ import java.awt.Font;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 验证码抽象类,暂时不支持中文
|
||||
* </p>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
||||
|
@@ -7,98 +7,87 @@ import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* <p>Gif验证码类</p>
|
||||
*
|
||||
* @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<len;i++)
|
||||
{
|
||||
fontcolor[i]=new Color(20 + num(110), 20 + num(110), 20 + num(110));
|
||||
Color fontcolor[] = new Color[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
fontcolor[i] = new Color(20 + num(110), 20 + num(110), 20 + num(110));
|
||||
}
|
||||
for(int i=0;i<len;i++)
|
||||
{
|
||||
frame=graphicsImage(fontcolor, rands, i);
|
||||
for (int i = 0; i < len; i++) {
|
||||
frame = graphicsImage(fontcolor, rands, i);
|
||||
gifEncoder.addFrame(frame);
|
||||
frame.flush();
|
||||
}
|
||||
gifEncoder.finish();
|
||||
}finally
|
||||
{
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ok = true;
|
||||
} finally {
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/**
|
||||
* 画随机码图
|
||||
*
|
||||
* @param fontcolor 随机字体颜色
|
||||
* @param strs 字符数组
|
||||
* @param flag 透明度使用
|
||||
* @param strs 字符数组
|
||||
* @param flag 透明度使用
|
||||
* @return BufferedImage
|
||||
*/
|
||||
private BufferedImage graphicsImage(Color[] fontcolor,char[] strs,int flag)
|
||||
{
|
||||
BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);
|
||||
//或得图形上下文
|
||||
//Graphics2D g2d=image.createGraphics();
|
||||
Graphics2D g2d = (Graphics2D)image.getGraphics();
|
||||
//利用指定颜色填充背景
|
||||
g2d.setColor(Color.WHITE);
|
||||
private BufferedImage graphicsImage(Color[] fontcolor, char[] strs, int flag) {
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||
g2d.setColor(Color.WHITE); // 填充背景颜色
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
AlphaComposite ac3;
|
||||
int h = height - ((height - font.getSize()) >>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;i++)
|
||||
{
|
||||
for (int i = 0; i < len; i++) {
|
||||
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
|
||||
g2d.setComposite(ac3);
|
||||
g2d.setColor(fontcolor[i]);
|
||||
g2d.drawOval(num(width), num(height), 5+num(10), 5+num(10));
|
||||
g2d.drawString(strs[i]+"", (width-(len-i)*w)+(w-font.getSize())+1, h-4);
|
||||
g2d.drawOval(num(width), num(height), 5 + num(10), 5 + num(10));
|
||||
g2d.drawString(String.valueOf(strs[i]), (width - (len - i) * w) + (w - font.getSize()) + 1, h - 4);
|
||||
}
|
||||
g2d.dispose();
|
||||
return image;
|
||||
@@ -106,13 +95,15 @@ public class GifCaptcha extends Captcha
|
||||
|
||||
/**
|
||||
* 获取透明度,从0到1,自动计算步长
|
||||
* @return float 透明度
|
||||
*
|
||||
* @param i
|
||||
* @param j
|
||||
* @return 透明度
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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.
|
||||
* <pre>
|
||||
@@ -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);
|
||||
|
@@ -1,24 +1,20 @@
|
||||
package com.wf.captcha;
|
||||
|
||||
/**
|
||||
* <p></p>
|
||||
*
|
||||
* @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;
|
||||
|
@@ -3,41 +3,64 @@ package com.wf.captcha;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* <p>随机工具类</p>
|
||||
*
|
||||
* @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)];
|
||||
}
|
||||
}
|
@@ -9,90 +9,93 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
/**
|
||||
* <p>png格式验证码</p>
|
||||
*
|
||||
* @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<len;i++)
|
||||
{
|
||||
int h = height - ((height - font.getSize()) >> 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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
27
src/test/java/com/wf/captcha/CaptchaTest.java
Normal file
27
src/test/java/com/wf/captcha/CaptchaTest.java
Normal file
@@ -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")));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user