Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ma yanling
hutool-5-master
Commits
45cda665
Commit
45cda665
authored
Sep 25, 2024
by
ma yanling
Browse files
project commit
parent
ad2fb30a
Pipeline
#2354
failed with stages
in 0 seconds
Changes
369
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1698 additions
and
0 deletions
+1698
-0
hutool-cache/src/test/java/cn/hutool/cache/CacheTest.java
hutool-cache/src/test/java/cn/hutool/cache/CacheTest.java
+124
-0
hutool-cache/src/test/java/cn/hutool/cache/FileCacheTest.java
...ol-cache/src/test/java/cn/hutool/cache/FileCacheTest.java
+19
-0
hutool-cache/src/test/java/cn/hutool/cache/LRUCacheTest.java
hutool-cache/src/test/java/cn/hutool/cache/LRUCacheTest.java
+88
-0
hutool-cache/src/test/java/cn/hutool/cache/WeakCacheTest.java
...ol-cache/src/test/java/cn/hutool/cache/WeakCacheTest.java
+51
-0
hutool-captcha/pom.xml
hutool-captcha/pom.xml
+31
-0
hutool-captcha/src/main/java/cn/hutool/captcha/AbstractCaptcha.java
...tcha/src/main/java/cn/hutool/captcha/AbstractCaptcha.java
+255
-0
hutool-captcha/src/main/java/cn/hutool/captcha/CaptchaUtil.java
...-captcha/src/main/java/cn/hutool/captcha/CaptchaUtil.java
+109
-0
hutool-captcha/src/main/java/cn/hutool/captcha/CircleCaptcha.java
...aptcha/src/main/java/cn/hutool/captcha/CircleCaptcha.java
+100
-0
hutool-captcha/src/main/java/cn/hutool/captcha/GifCaptcha.java
...l-captcha/src/main/java/cn/hutool/captcha/GifCaptcha.java
+218
-0
hutool-captcha/src/main/java/cn/hutool/captcha/ICaptcha.java
hutool-captcha/src/main/java/cn/hutool/captcha/ICaptcha.java
+40
-0
hutool-captcha/src/main/java/cn/hutool/captcha/LineCaptcha.java
...-captcha/src/main/java/cn/hutool/captcha/LineCaptcha.java
+96
-0
hutool-captcha/src/main/java/cn/hutool/captcha/ShearCaptcha.java
...captcha/src/main/java/cn/hutool/captcha/ShearCaptcha.java
+199
-0
hutool-captcha/src/main/java/cn/hutool/captcha/generator/AbstractGenerator.java
...n/java/cn/hutool/captcha/generator/AbstractGenerator.java
+48
-0
hutool-captcha/src/main/java/cn/hutool/captcha/generator/CodeGenerator.java
.../main/java/cn/hutool/captcha/generator/CodeGenerator.java
+29
-0
hutool-captcha/src/main/java/cn/hutool/captcha/generator/MathGenerator.java
.../main/java/cn/hutool/captcha/generator/MathGenerator.java
+84
-0
hutool-captcha/src/main/java/cn/hutool/captcha/generator/RandomGenerator.java
...ain/java/cn/hutool/captcha/generator/RandomGenerator.java
+47
-0
hutool-captcha/src/main/java/cn/hutool/captcha/generator/package-info.java
...c/main/java/cn/hutool/captcha/generator/package-info.java
+7
-0
hutool-captcha/src/main/java/cn/hutool/captcha/package-info.java
...captcha/src/main/java/cn/hutool/captcha/package-info.java
+7
-0
hutool-captcha/src/test/java/cn/hutool/captcha/CaptchaTest.java
...-captcha/src/test/java/cn/hutool/captcha/CaptchaTest.java
+131
-0
hutool-captcha/src/test/java/cn/hutool/captcha/CaptchaUtilTest.java
...tcha/src/test/java/cn/hutool/captcha/CaptchaUtilTest.java
+15
-0
No files found.
Too many changes to show.
To preserve performance only
369 of 369+
files are displayed.
Plain diff
Email patch
hutool-cache/src/test/java/cn/hutool/cache/CacheTest.java
0 → 100644
View file @
45cda665
package
cn.hutool.cache
;
import
cn.hutool.cache.impl.TimedCache
;
import
cn.hutool.core.date.DateUnit
;
import
cn.hutool.core.thread.ThreadUtil
;
import
cn.hutool.core.util.RandomUtil
;
import
org.junit.Assert
;
import
org.junit.Test
;
/**
* 缓存测试用例
* @author Looly
*
*/
public
class
CacheTest
{
@Test
public
void
fifoCacheTest
(){
Cache
<
String
,
String
>
fifoCache
=
CacheUtil
.
newFIFOCache
(
3
);
fifoCache
.
setListener
((
key
,
value
)->{
// 监听测试,此测试中只有key1被移除,测试是否监听成功
Assert
.
assertEquals
(
"key1"
,
key
);
Assert
.
assertEquals
(
"value1"
,
value
);
});
fifoCache
.
put
(
"key1"
,
"value1"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
fifoCache
.
put
(
"key2"
,
"value2"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
fifoCache
.
put
(
"key3"
,
"value3"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
fifoCache
.
put
(
"key4"
,
"value4"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
//由于缓存容量只有3,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
String
value1
=
fifoCache
.
get
(
"key1"
);
Assert
.
assertNull
(
value1
);
}
@Test
public
void
fifoCacheCapacityTest
(){
Cache
<
String
,
String
>
fifoCache
=
CacheUtil
.
newFIFOCache
(
100
);
for
(
int
i
=
0
;
i
<
RandomUtil
.
randomInt
(
100
,
1000
);
i
++)
{
fifoCache
.
put
(
"key"
+
i
,
"value"
+
i
);
}
Assert
.
assertEquals
(
100
,
fifoCache
.
size
());
}
@Test
public
void
lfuCacheTest
(){
Cache
<
String
,
String
>
lfuCache
=
CacheUtil
.
newLFUCache
(
3
);
lfuCache
.
put
(
"key1"
,
"value1"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
//使用次数+1
lfuCache
.
get
(
"key1"
);
lfuCache
.
put
(
"key2"
,
"value2"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
lfuCache
.
put
(
"key3"
,
"value3"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
lfuCache
.
put
(
"key4"
,
"value4"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
//由于缓存容量只有3,当加入第四个元素的时候,根据LFU规则,最少使用的将被移除(2,3被移除)
String
value1
=
lfuCache
.
get
(
"key1"
);
String
value2
=
lfuCache
.
get
(
"key2"
);
String
value3
=
lfuCache
.
get
(
"key3"
);
Assert
.
assertNotNull
(
value1
);
Assert
.
assertNull
(
value2
);
Assert
.
assertNull
(
value3
);
}
@Test
public
void
lfuCacheTest2
(){
Cache
<
String
,
String
>
lfuCache
=
CacheUtil
.
newLFUCache
(
3
);
final
String
s
=
lfuCache
.
get
(
null
);
Assert
.
assertNull
(
s
);
}
@Test
public
void
lruCacheTest
(){
Cache
<
String
,
String
>
lruCache
=
CacheUtil
.
newLRUCache
(
3
);
//通过实例化对象创建
// LRUCache<String, String> lruCache = new LRUCache<String, String>(3);
lruCache
.
put
(
"key1"
,
"value1"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
lruCache
.
put
(
"key2"
,
"value2"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
lruCache
.
put
(
"key3"
,
"value3"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
//使用时间推近
lruCache
.
get
(
"key1"
);
lruCache
.
put
(
"key4"
,
"value4"
,
DateUnit
.
SECOND
.
getMillis
()
*
3
);
String
value1
=
lruCache
.
get
(
"key1"
);
Assert
.
assertNotNull
(
value1
);
//由于缓存容量只有3,当加入第四个元素的时候,根据LRU规则,最少使用的将被移除(2被移除)
String
value2
=
lruCache
.
get
(
"key2"
);
Assert
.
assertNull
(
value2
);
}
@Test
public
void
timedCacheTest
(){
TimedCache
<
String
,
String
>
timedCache
=
CacheUtil
.
newTimedCache
(
4
);
// TimedCache<String, String> timedCache = new TimedCache<String, String>(DateUnit.SECOND.getMillis() * 3);
timedCache
.
put
(
"key1"
,
"value1"
,
1
);
//1毫秒过期
timedCache
.
put
(
"key2"
,
"value2"
,
DateUnit
.
SECOND
.
getMillis
()
*
5
);
//5秒过期
timedCache
.
put
(
"key3"
,
"value3"
);
//默认过期(4毫秒)
timedCache
.
put
(
"key4"
,
"value4"
,
Long
.
MAX_VALUE
);
//永不过期
//启动定时任务,每5毫秒秒检查一次过期
timedCache
.
schedulePrune
(
5
);
//等待5毫秒
ThreadUtil
.
sleep
(
5
);
//5毫秒后由于value2设置了5毫秒过期,因此只有value2被保留下来
String
value1
=
timedCache
.
get
(
"key1"
);
Assert
.
assertNull
(
value1
);
String
value2
=
timedCache
.
get
(
"key2"
);
Assert
.
assertEquals
(
"value2"
,
value2
);
//5毫秒后,由于设置了默认过期,key3只被保留4毫秒,因此为null
String
value3
=
timedCache
.
get
(
"key3"
);
Assert
.
assertNull
(
value3
);
String
value3Supplier
=
timedCache
.
get
(
"key3"
,
()
->
"Default supplier"
);
Assert
.
assertEquals
(
"Default supplier"
,
value3Supplier
);
// 永不过期
String
value4
=
timedCache
.
get
(
"key4"
);
Assert
.
assertEquals
(
"value4"
,
value4
);
//取消定时清理
timedCache
.
cancelPruneSchedule
();
}
}
hutool-cache/src/test/java/cn/hutool/cache/FileCacheTest.java
0 → 100644
View file @
45cda665
package
cn.hutool.cache
;
import
org.junit.Assert
;
import
org.junit.Test
;
import
cn.hutool.cache.file.LFUFileCache
;
/**
* 文件缓存单元测试
* @author looly
*
*/
public
class
FileCacheTest
{
@Test
public
void
lfuFileCacheTest
()
{
LFUFileCache
cache
=
new
LFUFileCache
(
1000
,
500
,
2000
);
Assert
.
assertNotNull
(
cache
);
}
}
hutool-cache/src/test/java/cn/hutool/cache/LRUCacheTest.java
0 → 100644
View file @
45cda665
package
cn.hutool.cache
;
import
cn.hutool.cache.impl.LRUCache
;
import
cn.hutool.core.thread.ThreadUtil
;
import
cn.hutool.core.util.RandomUtil
;
import
cn.hutool.core.util.StrUtil
;
import
org.junit.Assert
;
import
org.junit.Ignore
;
import
org.junit.Test
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.atomic.AtomicInteger
;
/**
* 见:https://github.com/dromara/hutool/issues/1895<br>
* 并发问题测试,在5.7.15前,LRUCache存在并发问题,多线程get后,map结构变更,导致null的位置不确定,
* 并可能引起死锁。
*/
public
class
LRUCacheTest
{
@Test
@Ignore
public
void
putTest
(){
//https://github.com/dromara/hutool/issues/2227
final
LRUCache
<
String
,
String
>
cache
=
CacheUtil
.
newLRUCache
(
100
,
10
);
for
(
int
i
=
0
;
i
<
10000
;
i
++)
{
//ThreadUtil.execute(()-> cache.put(RandomUtil.randomString(5), "1243", 10));
ThreadUtil
.
execute
(()->
cache
.
get
(
RandomUtil
.
randomString
(
5
),
()->
RandomUtil
.
randomString
(
10
)));
}
ThreadUtil
.
sleep
(
3000
);
}
@Test
public
void
readWriteTest
()
throws
InterruptedException
{
final
LRUCache
<
Integer
,
Integer
>
cache
=
CacheUtil
.
newLRUCache
(
10
);
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
cache
.
put
(
i
,
i
);
}
final
CountDownLatch
countDownLatch
=
new
CountDownLatch
(
10
);
// 10个线程分别读0-9 10000次
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
final
int
finalI
=
i
;
new
Thread
(()
->
{
for
(
int
j
=
0
;
j
<
10000
;
j
++)
{
cache
.
get
(
finalI
);
}
countDownLatch
.
countDown
();
}).
start
();
}
// 等待读线程结束
countDownLatch
.
await
();
// 按顺序读0-9
final
StringBuilder
sb1
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
sb1
.
append
(
cache
.
get
(
i
));
}
Assert
.
assertEquals
(
"0123456789"
,
sb1
.
toString
());
// 新加11,此时0最久未使用,应该淘汰0
cache
.
put
(
11
,
11
);
final
StringBuilder
sb2
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
sb2
.
append
(
cache
.
get
(
i
));
}
Assert
.
assertEquals
(
"null123456789"
,
sb2
.
toString
());
}
@Test
public
void
issue2647Test
(){
final
AtomicInteger
removeCount
=
new
AtomicInteger
();
final
LRUCache
<
String
,
Integer
>
cache
=
CacheUtil
.
newLRUCache
(
3
,
1
);
cache
.
setListener
((
key
,
value
)
->
{
// 共移除7次
removeCount
.
incrementAndGet
();
//Console.log("Start remove k-v, key:{}, value:{}", key, value);
});
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
cache
.
put
(
StrUtil
.
format
(
"key-{}"
,
i
),
i
);
}
Assert
.
assertEquals
(
7
,
removeCount
.
get
());
Assert
.
assertEquals
(
3
,
cache
.
size
());
}
}
hutool-cache/src/test/java/cn/hutool/cache/WeakCacheTest.java
0 → 100644
View file @
45cda665
package
cn.hutool.cache
;
import
cn.hutool.cache.impl.WeakCache
;
import
cn.hutool.core.lang.Console
;
import
org.junit.Assert
;
import
org.junit.Ignore
;
import
org.junit.Test
;
public
class
WeakCacheTest
{
@Test
public
void
removeTest
(){
final
WeakCache
<
String
,
String
>
cache
=
new
WeakCache
<>(-
1
);
cache
.
put
(
"abc"
,
"123"
);
cache
.
put
(
"def"
,
"456"
);
Assert
.
assertEquals
(
2
,
cache
.
size
());
// 检查被MutableObj包装的key能否正常移除
cache
.
remove
(
"abc"
);
Assert
.
assertEquals
(
1
,
cache
.
size
());
}
@Test
@Ignore
public
void
removeByGcTest
(){
// https://gitee.com/dromara/hutool/issues/I51O7M
WeakCache
<
String
,
String
>
cache
=
new
WeakCache
<>(-
1
);
cache
.
put
(
"a"
,
"1"
);
cache
.
put
(
"b"
,
"2"
);
// 监听
Assert
.
assertEquals
(
2
,
cache
.
size
());
cache
.
setListener
(
Console:
:
log
);
// GC测试
int
i
=
0
;
while
(
true
){
if
(
2
==
cache
.
size
()){
i
++;
Console
.
log
(
"Object is alive for {} loops - "
,
i
);
System
.
gc
();
}
else
{
Console
.
log
(
"Object has been collected."
);
Console
.
log
(
cache
.
size
());
break
;
}
}
}
}
hutool-captcha/pom.xml
0 → 100644
View file @
45cda665
<?xml version='1.0' encoding='utf-8'?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<packaging>
jar
</packaging>
<parent>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-parent
</artifactId>
<version>
5.8.19
</version>
</parent>
<artifactId>
hutool-captcha
</artifactId>
<name>
${project.artifactId}
</name>
<description>
Hutool 验证码工具
</description>
<properties>
<Automatic-Module-Name>
cn.hutool.captcha
</Automatic-Module-Name>
</properties>
<dependencies>
<dependency>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-core
</artifactId>
<version>
${project.parent.version}
</version>
</dependency>
</dependencies>
</project>
hutool-captcha/src/main/java/cn/hutool/captcha/AbstractCaptcha.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
cn.hutool.captcha.generator.CodeGenerator
;
import
cn.hutool.captcha.generator.RandomGenerator
;
import
cn.hutool.core.codec.Base64
;
import
cn.hutool.core.img.ImgUtil
;
import
cn.hutool.core.io.FileUtil
;
import
cn.hutool.core.io.IORuntimeException
;
import
cn.hutool.core.io.IoUtil
;
import
cn.hutool.core.util.URLUtil
;
import
java.awt.AlphaComposite
;
import
java.awt.Color
;
import
java.awt.Font
;
import
java.awt.Image
;
import
java.awt.image.BufferedImage
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.OutputStream
;
/**
* 抽象验证码<br>
* 抽象验证码实现了验证码字符串的生成、验证,验证码图片的写出<br>
* 实现类通过实现{@link #createImage(String)} 方法生成图片对象
*
* @author looly
*/
public
abstract
class
AbstractCaptcha
implements
ICaptcha
{
private
static
final
long
serialVersionUID
=
3180820918087507254L
;
/**
* 图片的宽度
*/
protected
int
width
;
/**
* 图片的高度
*/
protected
int
height
;
/**
* 验证码干扰元素个数
*/
protected
int
interfereCount
;
/**
* 字体
*/
protected
Font
font
;
/**
* 验证码
*/
protected
String
code
;
/**
* 验证码图片
*/
protected
byte
[]
imageBytes
;
/**
* 验证码生成器
*/
protected
CodeGenerator
generator
;
/**
* 背景色
*/
protected
Color
background
;
/**
* 文字透明度
*/
protected
AlphaComposite
textAlpha
;
/**
* 构造,使用随机验证码生成器生成验证码
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param interfereCount 验证码干扰元素个数
*/
public
AbstractCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
interfereCount
)
{
this
(
width
,
height
,
new
RandomGenerator
(
codeCount
),
interfereCount
);
}
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
* @param generator 验证码生成器
* @param interfereCount 验证码干扰元素个数
*/
public
AbstractCaptcha
(
int
width
,
int
height
,
CodeGenerator
generator
,
int
interfereCount
)
{
this
.
width
=
width
;
this
.
height
=
height
;
this
.
generator
=
generator
;
this
.
interfereCount
=
interfereCount
;
// 字体高度设为验证码高度-2,留边距
this
.
font
=
new
Font
(
Font
.
SANS_SERIF
,
Font
.
PLAIN
,
(
int
)
(
this
.
height
*
0.75
));
}
@Override
public
void
createCode
()
{
generateCode
();
final
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
ImgUtil
.
writePng
(
createImage
(
this
.
code
),
out
);
this
.
imageBytes
=
out
.
toByteArray
();
}
/**
* 生成验证码字符串
*
* @since 3.3.0
*/
protected
void
generateCode
()
{
this
.
code
=
generator
.
generate
();
}
/**
* 根据生成的code创建验证码图片
*
* @param code 验证码
* @return Image
*/
protected
abstract
Image
createImage
(
String
code
);
@Override
public
String
getCode
()
{
if
(
null
==
this
.
code
)
{
createCode
();
}
return
this
.
code
;
}
@Override
public
boolean
verify
(
String
userInputCode
)
{
return
this
.
generator
.
verify
(
getCode
(),
userInputCode
);
}
/**
* 验证码写出到文件
*
* @param path 文件路径
* @throws IORuntimeException IO异常
*/
public
void
write
(
String
path
)
throws
IORuntimeException
{
this
.
write
(
FileUtil
.
touch
(
path
));
}
/**
* 验证码写出到文件
*
* @param file 文件
* @throws IORuntimeException IO异常
*/
public
void
write
(
File
file
)
throws
IORuntimeException
{
try
(
OutputStream
out
=
FileUtil
.
getOutputStream
(
file
))
{
this
.
write
(
out
);
}
catch
(
IOException
e
)
{
throw
new
IORuntimeException
(
e
);
}
}
@Override
public
void
write
(
OutputStream
out
)
{
IoUtil
.
write
(
out
,
false
,
getImageBytes
());
}
/**
* 获取图形验证码图片bytes
*
* @return 图形验证码图片bytes
* @since 4.5.17
*/
public
byte
[]
getImageBytes
()
{
if
(
null
==
this
.
imageBytes
)
{
createCode
();
}
return
this
.
imageBytes
;
}
/**
* 获取验证码图
*
* @return 验证码图
*/
public
BufferedImage
getImage
()
{
return
ImgUtil
.
read
(
IoUtil
.
toStream
(
getImageBytes
()));
}
/**
* 获得图片的Base64形式
*
* @return 图片的Base64
* @since 3.3.0
*/
public
String
getImageBase64
()
{
return
Base64
.
encode
(
getImageBytes
());
}
/**
* 获取图片带文件格式的 Base64
*
* @return 图片带文件格式的 Base64
* @since 5.3.11
*/
public
String
getImageBase64Data
(){
return
URLUtil
.
getDataUriBase64
(
"image/png"
,
getImageBase64
());
}
/**
* 自定义字体
*
* @param font 字体
*/
public
void
setFont
(
Font
font
)
{
this
.
font
=
font
;
}
/**
* 获取验证码生成器
*
* @return 验证码生成器
*/
public
CodeGenerator
getGenerator
()
{
return
generator
;
}
/**
* 设置验证码生成器
*
* @param generator 验证码生成器
*/
public
void
setGenerator
(
CodeGenerator
generator
)
{
this
.
generator
=
generator
;
}
/**
* 设置背景色
*
* @param background 背景色
* @since 4.1.22
*/
public
void
setBackground
(
Color
background
)
{
this
.
background
=
background
;
}
/**
* 设置文字透明度
*
* @param textAlpha 文字透明度,取值0~1,1表示不透明
* @since 4.5.17
*/
public
void
setTextAlpha
(
float
textAlpha
)
{
this
.
textAlpha
=
AlphaComposite
.
getInstance
(
AlphaComposite
.
SRC_OVER
,
textAlpha
);
}
}
hutool-captcha/src/main/java/cn/hutool/captcha/CaptchaUtil.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
/**
* 图形验证码工具
*
* @author looly
* @since 3.1.2
*/
public
class
CaptchaUtil
{
/**
* 创建线干扰的验证码,默认5位验证码,150条干扰线
*
* @param width 图片宽
* @param height 图片高
* @return {@link LineCaptcha}
*/
public
static
LineCaptcha
createLineCaptcha
(
int
width
,
int
height
)
{
return
new
LineCaptcha
(
width
,
height
);
}
/**
* 创建线干扰的验证码
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param lineCount 干扰线条数
* @return {@link LineCaptcha}
*/
public
static
LineCaptcha
createLineCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
lineCount
)
{
return
new
LineCaptcha
(
width
,
height
,
codeCount
,
lineCount
);
}
/**
* 创建圆圈干扰的验证码,默认5位验证码,15个干扰圈
*
* @param width 图片宽
* @param height 图片高
* @return {@link CircleCaptcha}
* @since 3.2.3
*/
public
static
CircleCaptcha
createCircleCaptcha
(
int
width
,
int
height
)
{
return
new
CircleCaptcha
(
width
,
height
);
}
/**
* 创建圆圈干扰的验证码
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param circleCount 干扰圆圈条数
* @return {@link CircleCaptcha}
* @since 3.2.3
*/
public
static
CircleCaptcha
createCircleCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
circleCount
)
{
return
new
CircleCaptcha
(
width
,
height
,
codeCount
,
circleCount
);
}
/**
* 创建扭曲干扰的验证码,默认5位验证码
*
* @param width 图片宽
* @param height 图片高
* @return {@link ShearCaptcha}
* @since 3.2.3
*/
public
static
ShearCaptcha
createShearCaptcha
(
int
width
,
int
height
)
{
return
new
ShearCaptcha
(
width
,
height
);
}
/**
* 创建扭曲干扰的验证码,默认5位验证码
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param thickness 干扰线宽度
* @return {@link ShearCaptcha}
* @since 3.3.0
*/
public
static
ShearCaptcha
createShearCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
thickness
)
{
return
new
ShearCaptcha
(
width
,
height
,
codeCount
,
thickness
);
}
/**
* 创建GIF验证码
*
* @param width 宽
* @param height 高
* @return {@link GifCaptcha}
*/
public
static
GifCaptcha
createGifCaptcha
(
int
width
,
int
height
)
{
return
new
GifCaptcha
(
width
,
height
);
}
/**
* 创建GIF验证码
*
* @param width 宽
* @param height 高
* @param codeCount 字符个数
* @return {@link GifCaptcha}
*/
public
static
GifCaptcha
createGifCaptcha
(
int
width
,
int
height
,
int
codeCount
)
{
return
new
GifCaptcha
(
width
,
height
,
codeCount
);
}
}
hutool-captcha/src/main/java/cn/hutool/captcha/CircleCaptcha.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
cn.hutool.core.img.GraphicsUtil
;
import
cn.hutool.core.img.ImgUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.RandomUtil
;
import
java.awt.Color
;
import
java.awt.Graphics2D
;
import
java.awt.Image
;
import
java.awt.image.BufferedImage
;
import
java.util.concurrent.ThreadLocalRandom
;
/**
* 圆圈干扰验证码
*
* @author looly
* @since 3.2.3
*
*/
public
class
CircleCaptcha
extends
AbstractCaptcha
{
private
static
final
long
serialVersionUID
=
-
7096627300356535494L
;
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
*/
public
CircleCaptcha
(
int
width
,
int
height
)
{
this
(
width
,
height
,
5
);
}
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
*/
public
CircleCaptcha
(
int
width
,
int
height
,
int
codeCount
)
{
this
(
width
,
height
,
codeCount
,
15
);
}
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param interfereCount 验证码干扰元素个数
*/
public
CircleCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
interfereCount
)
{
super
(
width
,
height
,
codeCount
,
interfereCount
);
}
@Override
public
Image
createImage
(
String
code
)
{
final
BufferedImage
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
final
Graphics2D
g
=
ImgUtil
.
createGraphics
(
image
,
ObjectUtil
.
defaultIfNull
(
this
.
background
,
Color
.
WHITE
));
// 随机画干扰圈圈
drawInterfere
(
g
);
// 画字符串
drawString
(
g
,
code
);
return
image
;
}
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
* @param g {@link Graphics2D}画笔
* @param code 验证码
*/
private
void
drawString
(
Graphics2D
g
,
String
code
)
{
// 指定透明度
if
(
null
!=
this
.
textAlpha
)
{
g
.
setComposite
(
this
.
textAlpha
);
}
GraphicsUtil
.
drawStringColourful
(
g
,
code
,
this
.
font
,
this
.
width
,
this
.
height
);
}
/**
* 画随机干扰
*
* @param g {@link Graphics2D}
*/
private
void
drawInterfere
(
Graphics2D
g
)
{
final
ThreadLocalRandom
random
=
RandomUtil
.
getRandom
();
for
(
int
i
=
0
;
i
<
this
.
interfereCount
;
i
++)
{
g
.
setColor
(
ImgUtil
.
randomColor
(
random
));
g
.
drawOval
(
random
.
nextInt
(
width
),
random
.
nextInt
(
height
),
random
.
nextInt
(
height
>>
1
),
random
.
nextInt
(
height
>>
1
));
}
}
// ----------------------------------------------------------------------------------------------------- Private method end
}
hutool-captcha/src/main/java/cn/hutool/captcha/GifCaptcha.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
cn.hutool.core.img.gif.AnimatedGifEncoder
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.RandomUtil
;
import
java.awt.AlphaComposite
;
import
java.awt.Color
;
import
java.awt.Graphics2D
;
import
java.awt.Image
;
import
java.awt.image.BufferedImage
;
import
java.io.ByteArrayOutputStream
;
/**
* Gif验证码类
*
* @author hsoftxl
* @since 5.5.2
*/
public
class
GifCaptcha
extends
AbstractCaptcha
{
private
static
final
long
serialVersionUID
=
7091627304326538464L
;
//量化器取样间隔 - 默认是10ms
private
int
quality
=
10
;
// 帧循环次数
private
int
repeat
=
0
;
//设置随机颜色时,最小的取色范围
private
int
minColor
=
0
;
//设置随机颜色时,最大的取色范围
private
int
maxColor
=
255
;
/**
* 可以设置验证码宽度,高度的构造函数
*
* @param width 验证码宽度
* @param height 验证码高度
*/
public
GifCaptcha
(
int
width
,
int
height
)
{
this
(
width
,
height
,
5
);
}
/**
* @param width 验证码宽度
* @param height 验证码高度
* @param codeCount 验证码个数
*/
public
GifCaptcha
(
int
width
,
int
height
,
int
codeCount
)
{
super
(
width
,
height
,
codeCount
,
10
);
}
/**
* 设置图像的颜色量化(转换质量 由GIF规范允许的最大256种颜色)。
* 低的值(最小值= 1)产生更好的颜色,但处理显著缓慢。
* 10是默认,并产生良好的颜色而且有以合理的速度。
* 值更大(大于20)不产生显著的改善速度
*
* @param quality 大于1
* @return this
*/
public
GifCaptcha
setQuality
(
int
quality
)
{
if
(
quality
<
1
)
{
quality
=
1
;
}
this
.
quality
=
quality
;
return
this
;
}
/**
* 设置GIF帧应该播放的次数。
* 默认是 0; 0意味着无限循环。
* 必须在添加的第一个图像之前被调用。
*
* @param repeat 必须大于等于0
* @return this
*/
public
GifCaptcha
setRepeat
(
int
repeat
)
{
if
(
repeat
>=
0
)
{
this
.
repeat
=
repeat
;
}
return
this
;
}
/**
* 设置验证码字符颜色
*
* @param maxColor 颜色
* @return this
*/
public
GifCaptcha
setMaxColor
(
int
maxColor
)
{
this
.
maxColor
=
maxColor
;
return
this
;
}
/**
* 设置验证码字符颜色
*
* @param minColor 颜色
* @return this
*/
public
GifCaptcha
setMinColor
(
int
minColor
)
{
this
.
minColor
=
minColor
;
return
this
;
}
@Override
public
void
createCode
()
{
generateCode
();
final
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
AnimatedGifEncoder
gifEncoder
=
new
AnimatedGifEncoder
();
// gif编码类
//生成字符
gifEncoder
.
start
(
out
);
gifEncoder
.
setQuality
(
quality
);
//设置量化器取样间隔
// 帧延迟 (默认100)
int
delay
=
100
;
gifEncoder
.
setDelay
(
delay
);
//设置帧延迟
gifEncoder
.
setRepeat
(
repeat
);
//帧循环次数
BufferedImage
frame
;
char
[]
chars
=
code
.
toCharArray
();
Color
[]
fontColor
=
new
Color
[
chars
.
length
];
for
(
int
i
=
0
;
i
<
chars
.
length
;
i
++)
{
fontColor
[
i
]
=
getRandomColor
(
minColor
,
maxColor
);
frame
=
graphicsImage
(
chars
,
fontColor
,
chars
,
i
);
gifEncoder
.
addFrame
(
frame
);
frame
.
flush
();
}
gifEncoder
.
finish
();
this
.
imageBytes
=
out
.
toByteArray
();
}
@Override
protected
Image
createImage
(
String
code
)
{
return
null
;
}
/**
* 画随机码图
*
* @param fontColor 随机字体颜色
* @param words 字符数组
* @param flag 透明度使用
* @return BufferedImage
*/
private
BufferedImage
graphicsImage
(
char
[]
chars
,
Color
[]
fontColor
,
char
[]
words
,
int
flag
)
{
BufferedImage
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
//或得图形上下文
Graphics2D
g2d
=
image
.
createGraphics
();
//利用指定颜色填充背景
g2d
.
setColor
(
ObjectUtil
.
defaultIfNull
(
this
.
background
,
Color
.
WHITE
));
g2d
.
fillRect
(
0
,
0
,
width
,
height
);
AlphaComposite
ac
;
// 字符的y坐标
float
y
=
(
height
>>
1
)
+
(
font
.
getSize
()
>>
1
);
float
m
=
1.0f
*
(
width
-
(
chars
.
length
*
font
.
getSize
()))
/
chars
.
length
;
//字符的x坐标
float
x
=
Math
.
max
(
m
/
2.0f
,
2
);
g2d
.
setFont
(
font
);
// 指定透明度
if
(
null
!=
this
.
textAlpha
)
{
g2d
.
setComposite
(
this
.
textAlpha
);
}
for
(
int
i
=
0
;
i
<
chars
.
length
;
i
++)
{
ac
=
AlphaComposite
.
getInstance
(
AlphaComposite
.
SRC_OVER
,
getAlpha
(
chars
.
length
,
flag
,
i
));
g2d
.
setComposite
(
ac
);
g2d
.
setColor
(
fontColor
[
i
]);
g2d
.
drawOval
(
RandomUtil
.
randomInt
(
width
),
RandomUtil
.
randomInt
(
height
),
RandomUtil
.
randomInt
(
5
,
30
),
5
+
RandomUtil
.
randomInt
(
5
,
30
)
);
//绘制椭圆边框
g2d
.
drawString
(
words
[
i
]
+
""
,
x
+
(
font
.
getSize
()
+
m
)
*
i
,
y
);
}
g2d
.
dispose
();
return
image
;
}
/**
* 获取透明度,从0到1,自动计算步长
*
* @return float 透明度
*/
private
float
getAlpha
(
int
v
,
int
i
,
int
j
)
{
int
num
=
i
+
j
;
float
r
=
(
float
)
1
/
v
;
float
s
=
(
v
+
1
)
*
r
;
return
num
>
v
?
(
num
*
r
-
s
)
:
num
*
r
;
}
/**
* 通过给定范围获得随机的颜色
*
* @return Color 获得随机的颜色
*/
private
Color
getRandomColor
(
int
min
,
int
max
)
{
if
(
min
>
255
)
{
min
=
255
;
}
if
(
max
>
255
)
{
max
=
255
;
}
if
(
min
<
0
)
{
min
=
0
;
}
if
(
max
<
0
)
{
max
=
0
;
}
if
(
min
>
max
)
{
min
=
0
;
max
=
255
;
}
return
new
Color
(
RandomUtil
.
randomInt
(
min
,
max
),
RandomUtil
.
randomInt
(
min
,
max
),
RandomUtil
.
randomInt
(
min
,
max
));
}
}
hutool-captcha/src/main/java/cn/hutool/captcha/ICaptcha.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
java.io.OutputStream
;
import
java.io.Serializable
;
/**
* 验证码接口,提供验证码对象接口定义
*
* @author looly
*
*/
public
interface
ICaptcha
extends
Serializable
{
/**
* 创建验证码,实现类需同时生成随机验证码字符串和验证码图片
*/
void
createCode
();
/**
* 获取验证码的文字内容
*
* @return 验证码文字内容
*/
String
getCode
();
/**
* 验证验证码是否正确,建议忽略大小写
*
* @param userInputCode 用户输入的验证码
* @return 是否与生成的一直
*/
boolean
verify
(
String
userInputCode
);
/**
* 将验证码写出到目标流中
*
* @param out 目标流
*/
void
write
(
OutputStream
out
);
}
hutool-captcha/src/main/java/cn/hutool/captcha/LineCaptcha.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
java.awt.Color
;
import
java.awt.Graphics
;
import
java.awt.Graphics2D
;
import
java.awt.Image
;
import
java.awt.image.BufferedImage
;
import
java.util.concurrent.ThreadLocalRandom
;
import
cn.hutool.core.img.GraphicsUtil
;
import
cn.hutool.core.img.ImgUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.RandomUtil
;
/**
* 使用干扰线方式生成的图形验证码
*
* @author looly
* @since 3.1.2
*/
public
class
LineCaptcha
extends
AbstractCaptcha
{
private
static
final
long
serialVersionUID
=
8691294460763091089L
;
// -------------------------------------------------------------------- Constructor start
/**
* 构造,默认5位验证码,150条干扰线
*
* @param width 图片宽
* @param height 图片高
*/
public
LineCaptcha
(
int
width
,
int
height
)
{
this
(
width
,
height
,
5
,
150
);
}
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param lineCount 干扰线条数
*/
public
LineCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
lineCount
)
{
super
(
width
,
height
,
codeCount
,
lineCount
);
}
// -------------------------------------------------------------------- Constructor end
@Override
public
Image
createImage
(
String
code
)
{
// 图像buffer
final
BufferedImage
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
final
Graphics2D
g
=
GraphicsUtil
.
createGraphics
(
image
,
ObjectUtil
.
defaultIfNull
(
this
.
background
,
Color
.
WHITE
));
// 干扰线
drawInterfere
(
g
);
// 字符串
drawString
(
g
,
code
);
return
image
;
}
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
* @param g {@link Graphics}画笔
* @param code 验证码
*/
private
void
drawString
(
Graphics2D
g
,
String
code
)
{
// 指定透明度
if
(
null
!=
this
.
textAlpha
)
{
g
.
setComposite
(
this
.
textAlpha
);
}
GraphicsUtil
.
drawStringColourful
(
g
,
code
,
this
.
font
,
this
.
width
,
this
.
height
);
}
/**
* 绘制干扰线
*
* @param g {@link Graphics2D}画笔
*/
private
void
drawInterfere
(
Graphics2D
g
)
{
final
ThreadLocalRandom
random
=
RandomUtil
.
getRandom
();
// 干扰线
for
(
int
i
=
0
;
i
<
this
.
interfereCount
;
i
++)
{
int
xs
=
random
.
nextInt
(
width
);
int
ys
=
random
.
nextInt
(
height
);
int
xe
=
xs
+
random
.
nextInt
(
width
/
8
);
int
ye
=
ys
+
random
.
nextInt
(
height
/
8
);
g
.
setColor
(
ImgUtil
.
randomColor
(
random
));
g
.
drawLine
(
xs
,
ys
,
xe
,
ye
);
}
}
// ----------------------------------------------------------------------------------------------------- Private method start
}
\ No newline at end of file
hutool-captcha/src/main/java/cn/hutool/captcha/ShearCaptcha.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
cn.hutool.core.img.GraphicsUtil
;
import
cn.hutool.core.img.ImgUtil
;
import
cn.hutool.core.util.ObjectUtil
;
import
cn.hutool.core.util.RandomUtil
;
import
java.awt.Color
;
import
java.awt.Graphics
;
import
java.awt.Graphics2D
;
import
java.awt.Image
;
import
java.awt.image.BufferedImage
;
/**
* 扭曲干扰验证码
*
* @author looly
* @since 3.2.3
*
*/
public
class
ShearCaptcha
extends
AbstractCaptcha
{
private
static
final
long
serialVersionUID
=
-
7096627300356535494L
;
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
*/
public
ShearCaptcha
(
int
width
,
int
height
)
{
this
(
width
,
height
,
5
);
}
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
*/
public
ShearCaptcha
(
int
width
,
int
height
,
int
codeCount
)
{
this
(
width
,
height
,
codeCount
,
4
);
}
/**
* 构造
*
* @param width 图片宽
* @param height 图片高
* @param codeCount 字符个数
* @param thickness 干扰线宽度
*/
public
ShearCaptcha
(
int
width
,
int
height
,
int
codeCount
,
int
thickness
)
{
super
(
width
,
height
,
codeCount
,
thickness
);
}
@Override
public
Image
createImage
(
String
code
)
{
final
BufferedImage
image
=
new
BufferedImage
(
this
.
width
,
this
.
height
,
BufferedImage
.
TYPE_INT_RGB
);
final
Graphics2D
g
=
GraphicsUtil
.
createGraphics
(
image
,
ObjectUtil
.
defaultIfNull
(
this
.
background
,
Color
.
WHITE
));
// 画字符串
drawString
(
g
,
code
);
// 扭曲
shear
(
g
,
this
.
width
,
this
.
height
,
ObjectUtil
.
defaultIfNull
(
this
.
background
,
Color
.
WHITE
));
// 画干扰线
drawInterfere
(
g
,
0
,
RandomUtil
.
randomInt
(
this
.
height
)
+
1
,
this
.
width
,
RandomUtil
.
randomInt
(
this
.
height
)
+
1
,
this
.
interfereCount
,
ImgUtil
.
randomColor
());
return
image
;
}
// ----------------------------------------------------------------------------------------------------- Private method start
/**
* 绘制字符串
*
* @param g {@link Graphics}画笔
* @param code 验证码
*/
private
void
drawString
(
Graphics2D
g
,
String
code
)
{
// 指定透明度
if
(
null
!=
this
.
textAlpha
)
{
g
.
setComposite
(
this
.
textAlpha
);
}
GraphicsUtil
.
drawStringColourful
(
g
,
code
,
this
.
font
,
this
.
width
,
this
.
height
);
}
/**
* 扭曲
*
* @param g {@link Graphics}
* @param w1 w1
* @param h1 h1
* @param color 颜色
*/
private
void
shear
(
Graphics
g
,
int
w1
,
int
h1
,
Color
color
)
{
shearX
(
g
,
w1
,
h1
,
color
);
shearY
(
g
,
w1
,
h1
,
color
);
}
/**
* X坐标扭曲
*
* @param g {@link Graphics}
* @param w1 宽
* @param h1 高
* @param color 颜色
*/
private
void
shearX
(
Graphics
g
,
int
w1
,
int
h1
,
Color
color
)
{
int
period
=
RandomUtil
.
randomInt
(
this
.
width
);
int
frames
=
1
;
int
phase
=
RandomUtil
.
randomInt
(
2
);
for
(
int
i
=
0
;
i
<
h1
;
i
++)
{
double
d
=
(
double
)
(
period
>>
1
)
*
Math
.
sin
((
double
)
i
/
(
double
)
period
+
(
6.2831853071795862
D
*
(
double
)
phase
)
/
(
double
)
frames
);
g
.
copyArea
(
0
,
i
,
w1
,
1
,
(
int
)
d
,
0
);
g
.
setColor
(
color
);
g
.
drawLine
((
int
)
d
,
i
,
0
,
i
);
g
.
drawLine
((
int
)
d
+
w1
,
i
,
w1
,
i
);
}
}
/**
* Y坐标扭曲
*
* @param g {@link Graphics}
* @param w1 宽
* @param h1 高
* @param color 颜色
*/
private
void
shearY
(
Graphics
g
,
int
w1
,
int
h1
,
Color
color
)
{
int
period
=
RandomUtil
.
randomInt
(
this
.
height
>>
1
);
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.2831853071795862
D
*
(
double
)
phase
)
/
(
double
)
frames
);
g
.
copyArea
(
i
,
0
,
1
,
h1
,
0
,
(
int
)
d
);
g
.
setColor
(
color
);
// 擦除原位置的痕迹
g
.
drawLine
(
i
,
(
int
)
d
,
i
,
0
);
g
.
drawLine
(
i
,
(
int
)
d
+
h1
,
i
,
h1
);
}
}
/**
* 干扰线
*
* @param g {@link Graphics}
* @param x1 x1
* @param y1 y1
* @param x2 x2
* @param y2 y2
* @param thickness 粗细
* @param c 颜色
*/
@SuppressWarnings
(
"SameParameterValue"
)
private
void
drawInterfere
(
Graphics
g
,
int
x1
,
int
y1
,
int
x2
,
int
y2
,
int
thickness
,
Color
c
)
{
// The thick line is in fact a filled polygon
g
.
setColor
(
c
);
int
dX
=
x2
-
x1
;
int
dY
=
y2
-
y1
;
// line length
double
lineLength
=
Math
.
sqrt
(
dX
*
dX
+
dY
*
dY
);
double
scale
=
(
double
)
(
thickness
)
/
(
2
*
lineLength
);
// The x and y increments from an endpoint needed to create a
// rectangle...
double
ddx
=
-
scale
*
(
double
)
dY
;
double
ddy
=
scale
*
(
double
)
dX
;
ddx
+=
(
ddx
>
0
)
?
0.5
:
-
0.5
;
ddy
+=
(
ddy
>
0
)
?
0.5
:
-
0.5
;
int
dx
=
(
int
)
ddx
;
int
dy
=
(
int
)
ddy
;
// Now we can compute the corner points...
int
[]
xPoints
=
new
int
[
4
];
int
[]
yPoints
=
new
int
[
4
];
xPoints
[
0
]
=
x1
+
dx
;
yPoints
[
0
]
=
y1
+
dy
;
xPoints
[
1
]
=
x1
-
dx
;
yPoints
[
1
]
=
y1
-
dy
;
xPoints
[
2
]
=
x2
-
dx
;
yPoints
[
2
]
=
y2
-
dy
;
xPoints
[
3
]
=
x2
+
dx
;
yPoints
[
3
]
=
y2
+
dy
;
g
.
fillPolygon
(
xPoints
,
yPoints
,
4
);
}
// ----------------------------------------------------------------------------------------------------- Private method end
}
hutool-captcha/src/main/java/cn/hutool/captcha/generator/AbstractGenerator.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha.generator
;
import
cn.hutool.core.util.RandomUtil
;
/**
* 随机字符验证码生成器<br>
* 可以通过传入的基础集合和长度随机生成验证码字符
*
* @author looly
* @since 4.1.2
*/
public
abstract
class
AbstractGenerator
implements
CodeGenerator
{
private
static
final
long
serialVersionUID
=
8685744597154953479L
;
/** 基础字符集合,用于随机获取字符串的字符集合 */
protected
final
String
baseStr
;
/** 验证码长度 */
protected
final
int
length
;
/**
* 构造,使用字母+数字做为基础
*
* @param count 生成验证码长度
*/
public
AbstractGenerator
(
int
count
)
{
this
(
RandomUtil
.
BASE_CHAR_NUMBER
,
count
);
}
/**
* 构造
*
* @param baseStr 基础字符集合,用于随机获取字符串的字符集合
* @param length 生成验证码长度
*/
public
AbstractGenerator
(
String
baseStr
,
int
length
)
{
this
.
baseStr
=
baseStr
;
this
.
length
=
length
;
}
/**
* 获取长度验证码
*
* @return 验证码长度
*/
public
int
getLength
()
{
return
this
.
length
;
}
}
hutool-captcha/src/main/java/cn/hutool/captcha/generator/CodeGenerator.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha.generator
;
import
java.io.Serializable
;
/**
* 验证码文字生成器
*
* @author looly
* @since 4.1.2
*/
public
interface
CodeGenerator
extends
Serializable
{
/**
* 生成验证码
*
* @return 验证码
*/
String
generate
();
/**
* 验证用户输入的字符串是否与生成的验证码匹配<br>
* 用户通过实现此方法定义验证码匹配方式
*
* @param code 生成的随机验证码
* @param userInputCode 用户输入的验证码
* @return 是否验证通过
*/
boolean
verify
(
String
code
,
String
userInputCode
);
}
hutool-captcha/src/main/java/cn/hutool/captcha/generator/MathGenerator.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha.generator
;
import
cn.hutool.core.math.Calculator
;
import
cn.hutool.core.util.CharUtil
;
import
cn.hutool.core.util.RandomUtil
;
import
cn.hutool.core.util.StrUtil
;
/**
* 数字计算验证码生成器
*
* @author looly
* @since 4.1.2
*/
public
class
MathGenerator
implements
CodeGenerator
{
private
static
final
long
serialVersionUID
=
-
5514819971774091076L
;
private
static
final
String
operators
=
"+-*"
;
/** 参与计算数字最大长度 */
private
final
int
numberLength
;
/**
* 构造
*/
public
MathGenerator
()
{
this
(
2
);
}
/**
* 构造
*
* @param numberLength 参与计算最大数字位数
*/
public
MathGenerator
(
int
numberLength
)
{
this
.
numberLength
=
numberLength
;
}
@Override
public
String
generate
()
{
final
int
limit
=
getLimit
();
String
number1
=
Integer
.
toString
(
RandomUtil
.
randomInt
(
limit
));
String
number2
=
Integer
.
toString
(
RandomUtil
.
randomInt
(
limit
));
number1
=
StrUtil
.
padAfter
(
number1
,
this
.
numberLength
,
CharUtil
.
SPACE
);
number2
=
StrUtil
.
padAfter
(
number2
,
this
.
numberLength
,
CharUtil
.
SPACE
);
return
StrUtil
.
builder
()
//
.
append
(
number1
)
//
.
append
(
RandomUtil
.
randomChar
(
operators
))
//
.
append
(
number2
)
//
.
append
(
'='
).
toString
();
}
@Override
public
boolean
verify
(
String
code
,
String
userInputCode
)
{
int
result
;
try
{
result
=
Integer
.
parseInt
(
userInputCode
);
}
catch
(
NumberFormatException
e
)
{
// 用户输入非数字
return
false
;
}
final
int
calculateResult
=
(
int
)
Calculator
.
conversion
(
code
);
return
result
==
calculateResult
;
}
/**
* 获取验证码长度
*
* @return 验证码长度
*/
public
int
getLength
()
{
return
this
.
numberLength
*
2
+
2
;
}
/**
* 根据长度获取参与计算数字最大值
*
* @return 最大值
*/
private
int
getLimit
()
{
return
Integer
.
parseInt
(
"1"
+
StrUtil
.
repeat
(
'0'
,
this
.
numberLength
));
}
}
hutool-captcha/src/main/java/cn/hutool/captcha/generator/RandomGenerator.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha.generator
;
import
cn.hutool.core.util.RandomUtil
;
import
cn.hutool.core.util.StrUtil
;
/**
* 随机字符验证码生成器<br>
* 可以通过传入的基础集合和长度随机生成验证码字符
*
* @author looly
* @since 4.1.2
*/
public
class
RandomGenerator
extends
AbstractGenerator
{
private
static
final
long
serialVersionUID
=
-
7802758587765561876L
;
/**
* 构造,使用字母+数字做为基础
*
* @param count 生成验证码长度
*/
public
RandomGenerator
(
int
count
)
{
super
(
count
);
}
/**
* 构造
*
* @param baseStr 基础字符集合,用于随机获取字符串的字符集合
* @param length 生成验证码长度
*/
public
RandomGenerator
(
String
baseStr
,
int
length
)
{
super
(
baseStr
,
length
);
}
@Override
public
String
generate
()
{
return
RandomUtil
.
randomString
(
this
.
baseStr
,
this
.
length
);
}
@Override
public
boolean
verify
(
String
code
,
String
userInputCode
)
{
if
(
StrUtil
.
isNotBlank
(
userInputCode
))
{
return
StrUtil
.
equalsIgnoreCase
(
code
,
userInputCode
);
}
return
false
;
}
}
hutool-captcha/src/main/java/cn/hutool/captcha/generator/package-info.java
0 → 100644
View file @
45cda665
/**
* 验证码生成策略实现
*
* @author looly
* @since 4.1.2
*/
package
cn.hutool.captcha.generator
;
\ No newline at end of file
hutool-captcha/src/main/java/cn/hutool/captcha/package-info.java
0 → 100644
View file @
45cda665
/**
* 图片验证码实现
*
* @author looly
*
*/
package
cn.hutool.captcha
;
\ No newline at end of file
hutool-captcha/src/test/java/cn/hutool/captcha/CaptchaTest.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
cn.hutool.captcha.generator.MathGenerator
;
import
cn.hutool.core.lang.Console
;
import
org.junit.Assert
;
import
org.junit.Ignore
;
import
org.junit.Test
;
import
java.awt.*
;
/**
* 直线干扰验证码单元测试
*
* @author looly
*/
public
class
CaptchaTest
{
@Test
public
void
lineCaptchaTest1
()
{
// 定义图形验证码的长和宽
LineCaptcha
lineCaptcha
=
CaptchaUtil
.
createLineCaptcha
(
200
,
100
);
Assert
.
assertNotNull
(
lineCaptcha
.
getCode
());
Assert
.
assertTrue
(
lineCaptcha
.
verify
(
lineCaptcha
.
getCode
()));
}
@Test
@Ignore
public
void
lineCaptchaTest3
()
{
// 定义图形验证码的长和宽
LineCaptcha
lineCaptcha
=
CaptchaUtil
.
createLineCaptcha
(
200
,
70
,
4
,
15
);
lineCaptcha
.
setBackground
(
Color
.
yellow
);
lineCaptcha
.
write
(
"f:/test/captcha/tellow.png"
);
}
@Test
@Ignore
public
void
lineCaptchaWithMathTest
()
{
// 定义图形验证码的长和宽
LineCaptcha
lineCaptcha
=
CaptchaUtil
.
createLineCaptcha
(
200
,
80
);
lineCaptcha
.
setGenerator
(
new
MathGenerator
());
lineCaptcha
.
setTextAlpha
(
0.8f
);
lineCaptcha
.
write
(
"f:/captcha/math.png"
);
}
@Test
@Ignore
public
void
lineCaptchaTest2
()
{
// 定义图形验证码的长和宽
LineCaptcha
lineCaptcha
=
CaptchaUtil
.
createLineCaptcha
(
200
,
100
);
// LineCaptcha lineCaptcha = new LineCaptcha(200, 100, 4, 150);
// 图形验证码写出,可以写出到文件,也可以写出到流
lineCaptcha
.
write
(
"f:/captcha/line.png"
);
Console
.
log
(
lineCaptcha
.
getCode
());
// 验证图形验证码的有效性,返回boolean值
lineCaptcha
.
verify
(
"1234"
);
lineCaptcha
.
createCode
();
lineCaptcha
.
write
(
"f:/captcha/line2.png"
);
Console
.
log
(
lineCaptcha
.
getCode
());
// 验证图形验证码的有效性,返回boolean值
lineCaptcha
.
verify
(
"1234"
);
}
@Test
@Ignore
public
void
circleCaptchaTest
()
{
// 定义图形验证码的长和宽
CircleCaptcha
captcha
=
CaptchaUtil
.
createCircleCaptcha
(
200
,
100
,
4
,
20
);
// CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
// 图形验证码写出,可以写出到文件,也可以写出到流
captcha
.
write
(
"f:/captcha/circle.png"
);
// 验证图形验证码的有效性,返回boolean值
captcha
.
verify
(
"1234"
);
}
@Test
@Ignore
public
void
shearCaptchaTest
()
{
// 定义图形验证码的长和宽
ShearCaptcha
captcha
=
CaptchaUtil
.
createShearCaptcha
(
203
,
100
,
4
,
4
);
// ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);
// 图形验证码写出,可以写出到文件,也可以写出到流
captcha
.
write
(
"f:/captcha/shear.png"
);
// 验证图形验证码的有效性,返回boolean值
captcha
.
verify
(
"1234"
);
}
@Test
@Ignore
public
void
shearCaptchaTest2
()
{
// 定义图形验证码的长和宽
ShearCaptcha
captcha
=
new
ShearCaptcha
(
200
,
100
,
4
,
4
);
// 图形验证码写出,可以写出到文件,也可以写出到流
captcha
.
write
(
"d:/test/shear.png"
);
// 验证图形验证码的有效性,返回boolean值
captcha
.
verify
(
"1234"
);
}
@Test
@Ignore
public
void
ShearCaptchaWithMathTest
()
{
// 定义图形验证码的长和宽
ShearCaptcha
captcha
=
CaptchaUtil
.
createShearCaptcha
(
200
,
45
,
4
,
4
);
captcha
.
setGenerator
(
new
MathGenerator
());
// ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);
// 图形验证码写出,可以写出到文件,也可以写出到流
captcha
.
write
(
"f:/captcha/shear_math.png"
);
// 验证图形验证码的有效性,返回boolean值
captcha
.
verify
(
"1234"
);
}
@Test
@Ignore
public
void
GifCaptchaTest
()
{
GifCaptcha
captcha
=
CaptchaUtil
.
createGifCaptcha
(
200
,
100
,
4
);
captcha
.
write
(
"d:/test/gif_captcha.gif"
);
assert
captcha
.
verify
(
captcha
.
getCode
());
}
@Test
@Ignore
public
void
bgTest
(){
LineCaptcha
captcha
=
CaptchaUtil
.
createLineCaptcha
(
200
,
100
,
4
,
1
);
captcha
.
setBackground
(
Color
.
WHITE
);
captcha
.
write
(
"d:/test/test.jpg"
);
}
}
hutool-captcha/src/test/java/cn/hutool/captcha/CaptchaUtilTest.java
0 → 100644
View file @
45cda665
package
cn.hutool.captcha
;
import
org.junit.Ignore
;
import
org.junit.Test
;
public
class
CaptchaUtilTest
{
@Test
@Ignore
public
void
createTest
()
{
for
(
int
i
=
0
;
i
<
1
;
i
++)
{
CaptchaUtil
.
createShearCaptcha
(
320
,
240
);
}
}
}
Prev
1
2
3
4
5
6
7
8
9
10
…
19
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment