Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8be24c89ea | ||
|
1d9dc73bda | ||
|
4d3629aa2e | ||
|
8ebe5918c9 | ||
|
366f54ea80 | ||
|
b390fe3f3f | ||
|
f2053339a7 | ||
|
eec51ec8be |
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -7,7 +7,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/classes" />
|
||||
</component>
|
||||
</project>
|
407
README.md
407
README.md
@@ -5,48 +5,54 @@
|
||||
|
||||
|
||||
## 1.简介
|
||||
 Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。
|
||||
|
||||
  Java图形验证码,支持gif验证码、中文验证码,可用于Java Web、JavaSE项目。
|
||||
|
||||
---
|
||||
|
||||
## 2.效果展示
|
||||
|
||||
**gif效果:**
|
||||
|
||||

|
||||

|
||||
  
|
||||

|
||||

|
||||
  
|
||||

|
||||
|
||||
**png效果:**
|
||||
|
||||

|
||||

|
||||
<br/>
|
||||

|
||||
  
|
||||

|
||||

|
||||
  
|
||||

|
||||

|
||||
|
||||
**算术类型:**
|
||||
|
||||
**中文验证码:**
|
||||
|
||||

|
||||

|
||||
  
|
||||

|
||||

|
||||
  
|
||||

|
||||

|
||||
|
||||

|
||||
**中文类型:**
|
||||
|
||||

|
||||
  
|
||||

|
||||

|
||||
  
|
||||

|
||||

|
||||
|
||||
**内置字体:**
|
||||
|
||||

|
||||
  
|
||||

|
||||
  
|
||||

|
||||
|
||||
|
||||
---
|
||||
|
||||
## 3.导入项目
|
||||
|
||||
### 2.1.gradle方式的引入
|
||||
### 3.1.gradle方式的引入
|
||||
需要先在project的build.gradle中添加:
|
||||
```text
|
||||
allprojects {
|
||||
@@ -58,11 +64,11 @@ allprojects {
|
||||
在项目的build.gradle中添加
|
||||
```text
|
||||
dependencies {
|
||||
compile 'com.github.whvcse:EasyCaptcha:1.5.0'
|
||||
compile 'com.github.whvcse:EasyCaptcha:1.6.2'
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2.maven方式引入
|
||||
### 3.2.maven方式引入
|
||||
在你的pom.xml中添加如下代码:
|
||||
```xml
|
||||
<project>
|
||||
@@ -77,24 +83,49 @@ dependencies {
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
<artifactId>EasyCaptcha</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<version>1.6.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
```
|
||||
|
||||
### 2.3.jar包下载
|
||||
[EasyCaptcha-1.5.0.jar](https://gitee.com/whvse/EasyCaptcha/releases)
|
||||
### 3.3.jar包下载
|
||||
[EasyCaptcha-1.6.2.jar](https://gitee.com/whvse/EasyCaptcha/releases)
|
||||
|
||||
maven导入jar包,在项目根目录创建`libs`文件夹,然后pom.xml添加如下:
|
||||
```
|
||||
<dependency>
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
<artifactId>EasyCaptcha</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<systemPath>${basedir}/libs/EasyCaptcha-1.6.2.jar</systemPath>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4.使用方法
|
||||
|
||||
## 3.使用方法
|
||||
### 4.1.在SpringMVC中使用
|
||||
```java
|
||||
@Controller
|
||||
public class CaptchaController {
|
||||
|
||||
@RequestMapping("/captcha")
|
||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
CaptchaUtil.out(request, response);
|
||||
}
|
||||
}
|
||||
```
|
||||
前端html代码:
|
||||
```html
|
||||
<img src="/captcha" width="130px" height="48px" />
|
||||
```
|
||||
|
||||
### 3.1.快速使用
|
||||
1.在web.xml里面加入如下配置:
|
||||
> 不要忘了把`/captcha`路径排除登录拦截,比如shiro的拦截。
|
||||
|
||||
### 4.2.在servlet中使用
|
||||
web.xml中配置servlet:
|
||||
```xml
|
||||
<web-app>
|
||||
<!-- 图形验证码servlet -->
|
||||
@@ -104,163 +135,130 @@ dependencies {
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>CaptchaServlet</servlet-name>
|
||||
<url-pattern>/images/captcha</url-pattern>
|
||||
<url-pattern>/captcha</url-pattern>
|
||||
</servlet-mapping>
|
||||
</web-app>
|
||||
|
||||
```
|
||||
2.前端代码
|
||||
前端html代码:
|
||||
```html
|
||||
<img src="/images/captcha" />
|
||||
<img src="/captcha" width="130px" height="48px" />
|
||||
```
|
||||
|
||||
### 3.2.在SpringMVC中使用
|
||||
也可以使用controller的形式输出验证码,方法如下:
|
||||
```java
|
||||
@Controller
|
||||
public class MainController {
|
||||
|
||||
@RequestMapping("/images/captcha")
|
||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
CaptchaUtil.out(request, response);
|
||||
}
|
||||
}
|
||||
```
|
||||
前端代码:
|
||||
```html
|
||||
<img src="/images/captcha" />
|
||||
```
|
||||
|
||||
### 3.3.判断验证码是否正确
|
||||
### 4.3.判断验证码是否正确
|
||||
|
||||
```java
|
||||
@Controller
|
||||
public class LoginController {
|
||||
|
||||
@PostMapping("/login")
|
||||
public JsonResult login(String username,String password,String code){
|
||||
|
||||
if (!CaptchaUtil.ver(code, request)) {
|
||||
CaptchaUtil.clear(request);
|
||||
public JsonResult login(String username,String password,String verCode){
|
||||
if (!CaptchaUtil.ver(verCode, request)) {
|
||||
CaptchaUtil.clear(request); // 清除session中的验证码
|
||||
return JsonResult.error("验证码不正确");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4.设置宽高和位数
|
||||
### 4.4.设置宽高和位数
|
||||
```java
|
||||
@Controller
|
||||
public class MainController {
|
||||
public class CaptchaController {
|
||||
|
||||
@RequestMapping("/images/captcha")
|
||||
@RequestMapping("/captcha")
|
||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
// 设置位数
|
||||
CaptchaUtil.out(5, request, response);
|
||||
|
||||
// 设置宽、高、位数
|
||||
CaptchaUtil.out(130, 48, 5, request, response);
|
||||
|
||||
// 使用gif验证码
|
||||
GifCaptcha gifCaptcha = new GifCaptcha(130,48,4);
|
||||
CaptchaUtil.out(gifCaptcha, request, response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.5.不使用工具类
|
||||
|
||||
  CaptchaUtil是为了简化操作,封装了生成验证码、存session、判断验证码等功能。CaptchaUtil使用的GifCaptcha
|
||||
生成的字母数字混合的gif验证码,如果需要设置更多的参数,请参照如下操作使用:
|
||||
### 4.5.不使用工具类
|
||||
 CaptchaUtil封装了输出验证码、存session、判断验证码等功能,也可以不使用此工具类:
|
||||
|
||||
```java
|
||||
@Controller
|
||||
public class MainController {
|
||||
public class CaptchaController {
|
||||
|
||||
@RequestMapping("/images/captcha")
|
||||
@RequestMapping("/captcha")
|
||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
// 设置请求头为输出图片类型
|
||||
CaptchaUtil.setHeader(response);
|
||||
response.setContentType("image/gif");
|
||||
response.setHeader("Pragma", "No-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
|
||||
// 三个参数分别为宽、高、位数
|
||||
GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5);
|
||||
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
|
||||
// 设置字体
|
||||
gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
|
||||
|
||||
specCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
|
||||
// 设置类型,纯数字、纯字母、字母数字混合
|
||||
gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||
specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||
|
||||
// 验证码存入session
|
||||
request.getSession().setAttribute("captcha", gifCaptcha.text().toLowerCase());
|
||||
request.getSession().setAttribute("captcha", specCaptcha.text().toLowerCase());
|
||||
|
||||
// 输出图片流
|
||||
gifCaptcha.out(response.getOutputStream());
|
||||
specCaptcha.out(response.getOutputStream());
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public JsonResult login(String username,String password,String code){
|
||||
public JsonResult login(String username,String password,String verCode){
|
||||
// 获取session中的验证码
|
||||
String sessionCode = request.getSession().getAttribute("captcha");
|
||||
// 判断验证码
|
||||
if (code==null || !sessionCode.equals(code.trim().toLowerCase())) {
|
||||
if (verCode==null || !sessionCode.equals(verCode.trim().toLowerCase())) {
|
||||
return JsonResult.error("验证码不正确");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4.更多设置
|
||||
## 5.更多设置
|
||||
|
||||
### 4.1.使用Gif验证码
|
||||
### 5.1.验证码类型
|
||||
|
||||
```java
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.gif"));
|
||||
// png类型
|
||||
SpecCaptcha captcha = new SpecCaptcha(130, 48);
|
||||
captcha.text(); // 获取验证码的字符
|
||||
captcha.textChar(); // 获取验证码的字符数组
|
||||
|
||||
// 三个参数分别为宽、高、位数
|
||||
GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5);
|
||||
// gif类型
|
||||
GifCaptcha captcha = new GifCaptcha(130, 48);
|
||||
|
||||
// 设置字体
|
||||
gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
|
||||
// 中文类型
|
||||
ChineseCaptcha captcha = new ChineseCaptcha(130, 48);
|
||||
|
||||
// 设置类型,纯数字、纯字母、字母数字混合
|
||||
gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||
// 中文gif类型
|
||||
ChineseGifCaptcha captcha = new ChineseGifCaptcha(130, 48);
|
||||
|
||||
// 生成的验证码
|
||||
String code = gifCaptcha.text();
|
||||
// 算术类型
|
||||
ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48);
|
||||
captcha.setLen(3); // 几位数运算,默认是两位
|
||||
captcha.getArithmeticString(); // 获取运算的公式:3+2=?
|
||||
captcha.text(); // 获取运算的结果:5
|
||||
|
||||
// 输出图片流
|
||||
gifCaptcha.out(outputStream);
|
||||
captcha.out(outputStream); // 输出验证码
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2.使用png验证码
|
||||
> 注意:<br/>
|
||||
>  算术验证码的len表示是几位数运算,而其他验证码的len表示验证码的位数,算术验证码的text()表示的是公式的结果,
|
||||
> 对于算术验证码,你应该把公式的结果存储session,而不是公式。
|
||||
|
||||
```java
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
|
||||
|
||||
// 三个参数分别为宽、高、位数
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
|
||||
|
||||
// 设置字体
|
||||
specCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
|
||||
|
||||
// 设置类型,纯数字、纯字母、字母数字混合
|
||||
specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||
|
||||
// 生成的验证码
|
||||
String code = specCaptcha.text();
|
||||
|
||||
// 输出图片流
|
||||
specCaptcha.out(outputStream);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3.验证码类型
|
||||
### 5.2.验证码字符类型
|
||||
|
||||
类型 | 描述
|
||||
:--- | :---
|
||||
@@ -271,60 +269,145 @@ public class Test {
|
||||
TYPE_ONLY_LOWER | 纯小写字母
|
||||
TYPE_NUM_AND_UPPER | 数字和大写字母
|
||||
|
||||
|
||||
### 4.4.中文验证码
|
||||
|
||||
中文png验证码:
|
||||
|
||||
```java
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
|
||||
|
||||
// 三个参数分别为宽、高、位数
|
||||
ChineseCaptcha chineseCaptcha = new ChineseCaptcha(130, 48, 4);
|
||||
|
||||
// 设置字体
|
||||
chineseCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
|
||||
|
||||
// 生成的验证码
|
||||
String code = chineseCaptcha.text();
|
||||
|
||||
// 输出图片流
|
||||
chineseCaptcha.out(outputStream);
|
||||
}
|
||||
}
|
||||
使用方法:
|
||||
```
|
||||
SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
|
||||
captcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||
```
|
||||
|
||||
中文gif验证码:
|
||||
> 只有`SpecCaptcha`和`GifCaptcha`设置才有效果。
|
||||
|
||||
```java
|
||||
public class Test {
|
||||
|
||||
public static void main(String[] args) {
|
||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
|
||||
|
||||
// 三个参数分别为宽、高、位数
|
||||
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha(130, 48, 4);
|
||||
|
||||
// 设置字体
|
||||
chineseGifCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
|
||||
### 5.3.字体设置
|
||||
内置字体:
|
||||
|
||||
// 生成的验证码
|
||||
String code = chineseGifCaptcha.text();
|
||||
|
||||
// 输出图片流
|
||||
chineseGifCaptcha.out(outputStream);
|
||||
}
|
||||
}
|
||||
字体 | 效果
|
||||
:--- | :---
|
||||
Captcha.FONT_1 | 
|
||||
Captcha.FONT_2 | 
|
||||
Captcha.FONT_3 | 
|
||||
Captcha.FONT_4 | 
|
||||
Captcha.FONT_5 | 
|
||||
Captcha.FONT_6 | 
|
||||
Captcha.FONT_7 | 
|
||||
Captcha.FONT_8 | 
|
||||
Captcha.FONT_9 | 
|
||||
Captcha.FONT_10 | 
|
||||
|
||||
使用方法:
|
||||
```
|
||||
SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
|
||||
|
||||
// 设置内置字体
|
||||
captcha.setFont(Captcha.FONT_1);
|
||||
|
||||
// 设置系统字体
|
||||
captcha.setFont(new Font("楷体", Font.PLAIN, 28));
|
||||
```
|
||||
|
||||
### 4.5.前后端分离项目的使用
|
||||
### 5.4.输出base64编码
|
||||
```
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
|
||||
specCaptcha.toBase64();
|
||||
|
||||
  分离项目建议不要存储在session中,存储在redis中。
|
||||
// 如果不想要base64的头部data:image/png;base64,
|
||||
specCaptcha.toBase64(""); // 加一个空的参数即可
|
||||
```
|
||||
|
||||
### 5.5.输出到文件
|
||||
```
|
||||
FileOutputStream outputStream = new FileOutputStream(new File("C:/captcha.png"))
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
|
||||
specCaptcha.out(outputStream);
|
||||
```
|
||||
|
||||
## 5.自定义效果
|
||||
---
|
||||
|
||||
参考源代码中的SpecCaptcha和GifCaptcha继承Captcha即可。
|
||||
## 6.前后端分离项目的使用
|
||||
|
||||
 前后端分离项目建议不要存储在session中,存储在redis中,redis存储需要一个key,key一同返回给前端用于验证输入:
|
||||
```java
|
||||
@Controller
|
||||
public class CaptchaController {
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@ResponseBody
|
||||
@RequestMapping("/captcha")
|
||||
public JsonResult captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
|
||||
String verCode = specCaptcha.text().toLowerCase();
|
||||
String key = UUID.randomUUID().toString();
|
||||
// 存入redis并设置过期时间为30分钟
|
||||
redisUtil.setEx(key, verCode, 30, TimeUnit.MINUTES);
|
||||
// 将key和base64返回给前端
|
||||
return JsonResult.ok().put("key", key).put("image", specCaptcha.toBase64());
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@PostMapping("/login")
|
||||
public JsonResult login(String username,String password,String verCode,String verKey){
|
||||
// 获取redis中的验证码
|
||||
String redisCode = redisUtil.get(verKey);
|
||||
// 判断验证码
|
||||
if (verCode==null || !redisCode.equals(verCode.trim().toLowerCase())) {
|
||||
return JsonResult.error("验证码不正确");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
前端使用ajax获取验证码:
|
||||
```html
|
||||
<img id="verImg" width="130px" height="48px"/>
|
||||
|
||||
<script>
|
||||
var verKey;
|
||||
// 获取验证码
|
||||
$.get('/captcha', function(res) {
|
||||
verKey = res.key;
|
||||
$('#verImg').attr('src', res.image);
|
||||
},'json');
|
||||
|
||||
// 登录
|
||||
$.post('/login', {
|
||||
verKey: verKey,
|
||||
verCode: '8u6h',
|
||||
username: 'admin',
|
||||
password: 'admin'
|
||||
}, function(res) {
|
||||
console.log(res);
|
||||
}, 'json');
|
||||
</script>
|
||||
```
|
||||
|
||||
> RedisUtil到这里获取[https://gitee.com/whvse/RedisUtil](https://gitee.com/whvse/RedisUtil)
|
||||
|
||||
---
|
||||
|
||||
## 7.自定义效果
|
||||
|
||||
 继承`Captcha`实现`out`方法,中文验证码可继承`ChineseCaptchaAbstract`,算术验证码可继承`ArithmeticCaptchaAbstract`。
|
||||
|
||||
---
|
||||
|
||||
## 8.更新日志
|
||||
|
||||
- **2019-08-23 (v1.6.1)**
|
||||
- 增加10种漂亮的内置字体,不依赖系统字体
|
||||
|
||||
- 增加算术验证码,运算位数可自由配置
|
||||
- 增加输出base64编码的功能
|
||||
- 增加贝塞尔曲线作为干扰线
|
||||
|
||||
- **2018-08-09 (v1.5.0)**
|
||||
- 增加纯大写字母、纯小写字母、数字和大写字母配置
|
||||
|
||||
- 增加中文验证码、中文gif验证码
|
||||
- 增加抗锯齿效果,优化文字颜色
|
||||
- 增加CaptchaUtil便于Web项目使用
|
||||
|
||||
---
|
||||
|
||||
## 9.推荐
|
||||
 **EasyWeb管系统模板**,一个开箱即用的后台模板,使用简单,功能丰富,包含ifram版和spa单页面版,[前往查看](https://easyweb.vip)。
|
||||
|
||||

|
||||
|
102
pom.xml
102
pom.xml
@@ -2,24 +2,16 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.github.whvcse</groupId>
|
||||
<groupId>org.wf</groupId>
|
||||
|
||||
<artifactId>EasyCaptcha</artifactId>
|
||||
<version>1.5.0-RELEASE</version>
|
||||
<artifactId>easy-captcha</artifactId>
|
||||
<version>1.6.2-RELEASE</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>EasyCaptcha</name>
|
||||
<description>Java图形验证码,支持gif验证码、中文验证码,适用于Java Web、JavaSE项目。</description>
|
||||
<url>https://github.com/whvcse/EasyCaptcha</url>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<dependencies>
|
||||
<!-- j2ee环境 -->
|
||||
<dependency>
|
||||
@@ -31,7 +23,7 @@
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.7</version>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -49,81 +41,15 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<!--
|
||||
<scm>
|
||||
<url>https://github.com/whvcse/EasyCaptcha</url>
|
||||
<connection>https://github.com/whvcse/EasyCaptcha.git</connection>
|
||||
<developerConnection>https://github.com/whvcse/EasyCaptcha</developerConnection>
|
||||
</scm>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>whvcse</name>
|
||||
<email>whvcse@foxmail.com</email>
|
||||
<url>https://github.com/whvcse</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<!– Source –>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!– Javadoc –>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>-->
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>rdc-releases</id>
|
||||
<url>https://repo.rdc.aliyun.com/repository/70786-release-exL3mB/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>rdc-snapshots</id>
|
||||
<url>https://repo.rdc.aliyun.com/repository/70786-snapshot-Y0tgOa/</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
</project>
|
96
src/main/java/com/wf/captcha/ArithmeticCaptcha.java
Normal file
96
src/main/java/com/wf/captcha/ArithmeticCaptcha.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package com.wf.captcha;
|
||||
|
||||
import com.wf.captcha.base.ArithmeticCaptchaAbstract;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* png格式验证码
|
||||
* Created by 王帆 on 2018-07-27 上午 10:08.
|
||||
*/
|
||||
public class ArithmeticCaptcha extends ArithmeticCaptchaAbstract {
|
||||
|
||||
public ArithmeticCaptcha() {
|
||||
}
|
||||
|
||||
public ArithmeticCaptcha(int width, int height) {
|
||||
this();
|
||||
setWidth(width);
|
||||
setHeight(height);
|
||||
}
|
||||
|
||||
public ArithmeticCaptcha(int width, int height, int len) {
|
||||
this(width, height);
|
||||
setLen(len);
|
||||
}
|
||||
|
||||
public ArithmeticCaptcha(int width, int height, int len, Font font) {
|
||||
this(width, height, len);
|
||||
setFont(font);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码
|
||||
*
|
||||
* @param out 输出流
|
||||
* @return 是否成功
|
||||
*/
|
||||
@Override
|
||||
public boolean out(OutputStream out) {
|
||||
checkAlpha();
|
||||
return graphicsImage(getArithmeticString().toCharArray(), out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBase64() {
|
||||
return toBase64("data:image/png;base64,");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码图形
|
||||
*
|
||||
* @param strs 验证码
|
||||
* @param out 输出流
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean graphicsImage(char[] strs, OutputStream out) {
|
||||
try {
|
||||
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = (Graphics2D) bi.getGraphics();
|
||||
// 填充背景
|
||||
g2d.setColor(Color.WHITE);
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
// 抗锯齿
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
// 画干扰圆
|
||||
drawOval(2, g2d);
|
||||
// 画字符串
|
||||
g2d.setFont(getFont());
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||
int fSp = (fW - (int) fontMetrics.getStringBounds("8", g2d).getWidth()) / 2; // 字符的左右边距
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
g2d.setColor(color());
|
||||
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
|
||||
}
|
||||
g2d.dispose();
|
||||
ImageIO.write(bi, "png", out);
|
||||
out.flush();
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
package com.wf.captcha;
|
||||
|
||||
import com.wf.captcha.base.ChineseCaptchaAbstract;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -36,10 +38,14 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
|
||||
*/
|
||||
@Override
|
||||
public boolean out(OutputStream out) {
|
||||
checkAlpha();
|
||||
return graphicsImage(textChar(), out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBase64() {
|
||||
return toBase64("data:image/png;base64,");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码图形
|
||||
*
|
||||
@@ -48,53 +54,34 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
|
||||
* @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;
|
||||
int len = strs.length;
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(0, 0, width, height);
|
||||
Graphics2D g2d = (Graphics2D) bi.getGraphics();
|
||||
// 填充背景
|
||||
g2d.setColor(Color.WHITE);
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
// 抗锯齿
|
||||
g.setColor(color());
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
int hp = (height - font.getSize()) >> 1;
|
||||
int h = height - hp;
|
||||
int w = width / strs.length;
|
||||
int sp = (w - font.getSize()) / 2;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
// 画干扰圆
|
||||
drawOval(3, g2d);
|
||||
// 画干扰线
|
||||
g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
drawBesselLine(1, g2d);
|
||||
// 画字符串
|
||||
for (int i = 0; i < len; i++) {
|
||||
// 计算坐标
|
||||
int x = i * w + sp + num(-5, 5);
|
||||
int y = h + num(-5, 5);
|
||||
if (x < 5) {
|
||||
x = 5;
|
||||
}
|
||||
if (x + font.getSize() > width) {
|
||||
x = width - font.getSize();
|
||||
}
|
||||
if (y > height) {
|
||||
y = height;
|
||||
}
|
||||
if (y - font.getSize() < 0) {
|
||||
y = font.getSize();
|
||||
}
|
||||
g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
|
||||
g.drawString(String.valueOf(strs[i]), x, y);
|
||||
g2d.setFont(getFont());
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||
int fSp = (fW - (int) fontMetrics.getStringBounds("王", g2d).getWidth()) / 2; // 字符的左右边距
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
g2d.setColor(color());
|
||||
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
|
||||
}
|
||||
// 随机画干扰线
|
||||
g.setStroke(new BasicStroke(1.25f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); // 指定透明度
|
||||
g.setComposite(ac3);
|
||||
drawLine(2, g.getColor(), g);
|
||||
// 画干扰圆圈
|
||||
drawOval(5, g.getColor(), g);
|
||||
g2d.dispose();
|
||||
ImageIO.write(bi, "png", out);
|
||||
out.flush();
|
||||
ok = true;
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
ok = false;
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
@@ -103,6 +90,6 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,10 @@
|
||||
package com.wf.captcha;
|
||||
|
||||
import com.wf.captcha.base.ChineseCaptchaAbstract;
|
||||
import com.wf.captcha.utils.GifEncoder;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -27,24 +31,39 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
|
||||
|
||||
@Override
|
||||
public boolean out(OutputStream os) {
|
||||
checkAlpha();
|
||||
boolean ok;
|
||||
try {
|
||||
char[] rands = textChar(); // 获取验证码数组
|
||||
char[] strs = textChar(); // 获取验证码数组
|
||||
// 随机生成每个文字的颜色
|
||||
Color fontColor[] = new Color[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
fontColor[i] = color();
|
||||
}
|
||||
// 随机生成贝塞尔曲线参数
|
||||
int x1 = 5, y1 = num(5, height / 2);
|
||||
int x2 = width - 5, y2 = num(height / 2, height - 5);
|
||||
int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
|
||||
if (num(2) == 0) {
|
||||
int ty = y1;
|
||||
y1 = y2;
|
||||
y2 = ty;
|
||||
}
|
||||
int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
|
||||
int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};
|
||||
// 开始画gif每一帧
|
||||
GifEncoder gifEncoder = new GifEncoder();
|
||||
gifEncoder.start(os);
|
||||
gifEncoder.setQuality(180);
|
||||
gifEncoder.setDelay(100);
|
||||
gifEncoder.setRepeat(0);
|
||||
BufferedImage frame;
|
||||
Color fontcolor = color();
|
||||
gifEncoder.start(os);
|
||||
for (int i = 0; i < len; i++) {
|
||||
frame = graphicsImage(fontcolor, rands, i);
|
||||
BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
|
||||
gifEncoder.addFrame(frame);
|
||||
frame.flush();
|
||||
}
|
||||
gifEncoder.finish();
|
||||
ok = true;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
os.close();
|
||||
@@ -52,59 +71,53 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBase64() {
|
||||
return toBase64("data:image/gif;base64,");
|
||||
}
|
||||
|
||||
/**
|
||||
* 画随机码图
|
||||
*
|
||||
* @param fontcolor 随机字体颜色
|
||||
* @param fontColor 随机字体颜色
|
||||
* @param strs 字符数组
|
||||
* @param flag 透明度使用
|
||||
* @param flag 透明度
|
||||
* @param besselXY 干扰线参数
|
||||
* @return BufferedImage
|
||||
*/
|
||||
private BufferedImage graphicsImage(Color fontcolor, char[] strs, int flag) {
|
||||
private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||
g2d.setColor(Color.WHITE); // 填充背景颜色
|
||||
// 填充背景颜色
|
||||
g2d.setColor(Color.WHITE);
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
// 抗锯齿
|
||||
AlphaComposite ac3;
|
||||
g2d.setColor(fontcolor);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
// 画验证码
|
||||
int hp = (height - font.getSize()) >> 1;
|
||||
int h = height - hp;
|
||||
int w = width / strs.length;
|
||||
int sp = (w - font.getSize()) / 2;
|
||||
for (int i = 0; i < len; i++) {
|
||||
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
|
||||
g2d.setComposite(ac3);
|
||||
// 计算坐标
|
||||
int x = i * w + sp + num(-3, 3);
|
||||
int y = h + num(-3, 3);
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (x + font.getSize() > width) {
|
||||
x = width - font.getSize();
|
||||
}
|
||||
if (y > height) {
|
||||
y = height;
|
||||
}
|
||||
if (y - font.getSize() < 0) {
|
||||
y = font.getSize();
|
||||
}
|
||||
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
|
||||
g2d.drawString(String.valueOf(strs[i]), x, y);
|
||||
}
|
||||
// 随机画干扰线
|
||||
g2d.setStroke(new BasicStroke(1.25f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.45f);
|
||||
g2d.setComposite(ac3);
|
||||
drawLine(1, g2d.getColor(), g2d);
|
||||
// 画干扰圆圈
|
||||
drawOval(3, g2d.getColor(), g2d);
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
|
||||
drawOval(2, g2d);
|
||||
// 画干扰线
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // 设置透明度
|
||||
g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
g2d.setColor(fontColor[0]);
|
||||
CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);
|
||||
g2d.draw(shape);
|
||||
// 画验证码
|
||||
g2d.setFont(getFont());
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
// 设置透明度
|
||||
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
|
||||
g2d.setComposite(ac3);
|
||||
g2d.setColor(fontColor[i]);
|
||||
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp - 3, fY - 3);
|
||||
}
|
||||
g2d.dispose();
|
||||
return image;
|
||||
}
|
||||
|
@@ -1,6 +1,12 @@
|
||||
package com.wf.captcha;
|
||||
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import com.wf.captcha.utils.GifEncoder;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -31,27 +37,39 @@ public class GifCaptcha extends Captcha {
|
||||
|
||||
@Override
|
||||
public boolean out(OutputStream os) {
|
||||
checkAlpha();
|
||||
boolean ok;
|
||||
try {
|
||||
char[] rands = textChar(); // 获取验证码数组
|
||||
char[] strs = textChar(); // 获取验证码数组
|
||||
// 随机生成每个文字的颜色
|
||||
Color fontColor[] = new Color[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
fontColor[i] = color();
|
||||
}
|
||||
// 随机生成贝塞尔曲线参数
|
||||
int x1 = 5, y1 = num(5, height / 2);
|
||||
int x2 = width - 5, y2 = num(height / 2, height - 5);
|
||||
int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
|
||||
if (num(2) == 0) {
|
||||
int ty = y1;
|
||||
y1 = y2;
|
||||
y2 = ty;
|
||||
}
|
||||
int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
|
||||
int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};
|
||||
// 开始画gif每一帧
|
||||
GifEncoder gifEncoder = new GifEncoder();
|
||||
gifEncoder.start(os);
|
||||
gifEncoder.setQuality(180);
|
||||
gifEncoder.setDelay(100);
|
||||
gifEncoder.setRepeat(0);
|
||||
BufferedImage frame;
|
||||
Color fontcolor[] = new Color[len];
|
||||
gifEncoder.start(os);
|
||||
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);
|
||||
BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
|
||||
gifEncoder.addFrame(frame);
|
||||
frame.flush();
|
||||
}
|
||||
gifEncoder.finish();
|
||||
ok = true;
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
os.close();
|
||||
@@ -59,18 +77,24 @@ public class GifCaptcha extends Captcha {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBase64() {
|
||||
return toBase64("data:image/gif;base64,");
|
||||
}
|
||||
|
||||
/**
|
||||
* 画随机码图
|
||||
*
|
||||
* @param fontcolor 随机字体颜色
|
||||
* @param fontColor 随机字体颜色
|
||||
* @param strs 字符数组
|
||||
* @param flag 透明度使用
|
||||
* @param flag 透明度
|
||||
* @param besselXY 干扰线参数
|
||||
* @return BufferedImage
|
||||
*/
|
||||
private BufferedImage graphicsImage(Color[] fontcolor, char[] strs, int flag) {
|
||||
private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||
// 填充背景颜色
|
||||
@@ -78,38 +102,27 @@ public class GifCaptcha extends Captcha {
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
// 抗锯齿
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
// 画干扰圆圈
|
||||
drawOval(4, g2d);
|
||||
// 随机画干扰线
|
||||
drawLine(2, g2d);
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
|
||||
drawOval(2, g2d);
|
||||
// 画干扰线
|
||||
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // 设置透明度
|
||||
g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
g2d.setColor(fontColor[0]);
|
||||
CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);
|
||||
g2d.draw(shape);
|
||||
// 画验证码
|
||||
int hp = (height - font.getSize()) >> 1;
|
||||
int h = height - hp;
|
||||
int w = width / strs.length;
|
||||
int sp = (w - font.getSize()) / 2;
|
||||
g2d.setFont(getFont());
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
// 设置透明度
|
||||
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
|
||||
g2d.setComposite(ac3);
|
||||
g2d.setColor(fontcolor[i]);
|
||||
// 计算坐标
|
||||
int x = i * w + sp + num(3);
|
||||
int y = h - num(3, 6);
|
||||
// 调整溢出的字
|
||||
if (x < 8) {
|
||||
x = 8;
|
||||
}
|
||||
if (x + font.getSize() > width) {
|
||||
x = width - font.getSize();
|
||||
}
|
||||
if (y > height) {
|
||||
y = height;
|
||||
}
|
||||
if (y - font.getSize() < 0) {
|
||||
y = font.getSize();
|
||||
}
|
||||
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
|
||||
g2d.drawString(String.valueOf(strs[i]), x, y);
|
||||
g2d.setColor(fontColor[i]);
|
||||
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
|
||||
}
|
||||
g2d.dispose();
|
||||
return image;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package com.wf.captcha;
|
||||
|
||||
import com.wf.captcha.base.Captcha;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
@@ -40,10 +42,14 @@ public class SpecCaptcha extends Captcha {
|
||||
*/
|
||||
@Override
|
||||
public boolean out(OutputStream out) {
|
||||
checkAlpha();
|
||||
return graphicsImage(textChar(), out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toBase64() {
|
||||
return toBase64("data:image/png;base64,");
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成验证码图形
|
||||
*
|
||||
@@ -52,51 +58,34 @@ public class SpecCaptcha extends Captcha {
|
||||
* @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();
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(0, 0, width, height);
|
||||
Graphics2D g2d = (Graphics2D) bi.getGraphics();
|
||||
// 填充背景
|
||||
g2d.setColor(Color.WHITE);
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
// 抗锯齿
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
// 随机画干扰线
|
||||
drawLine(3, g);
|
||||
// 随机画干扰圆
|
||||
drawOval(8, g);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
// 画干扰圆
|
||||
drawOval(2, g2d);
|
||||
// 画干扰线
|
||||
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
drawBesselLine(1, g2d);
|
||||
// 画字符串
|
||||
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度
|
||||
g.setComposite(ac3);
|
||||
int hp = (height - font.getSize()) >> 1;
|
||||
int h = height - hp;
|
||||
int w = width / strs.length;
|
||||
int sp = (w - font.getSize()) / 2;
|
||||
g2d.setFont(getFont());
|
||||
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
|
||||
for (int i = 0; i < strs.length; i++) {
|
||||
g.setColor(new Color(20 + num(110), 20 + num(110), 20 + num(110)));
|
||||
// 计算坐标
|
||||
int x = i * w + sp + num(3);
|
||||
int y = h - num(3, 6);
|
||||
if (x < 8) {
|
||||
x = 8;
|
||||
}
|
||||
if (x + font.getSize() > width) {
|
||||
x = width - font.getSize();
|
||||
}
|
||||
if (y > height) {
|
||||
y = height;
|
||||
}
|
||||
if (y - font.getSize() < 0) {
|
||||
y = font.getSize();
|
||||
}
|
||||
g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
|
||||
g.drawString(String.valueOf(strs[i]), x, y);
|
||||
g2d.setColor(color());
|
||||
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
|
||||
}
|
||||
g2d.dispose();
|
||||
ImageIO.write(bi, "png", out);
|
||||
out.flush();
|
||||
ok = true;
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
ok = false;
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
@@ -105,6 +94,6 @@ public class SpecCaptcha extends Captcha {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
package com.wf.captcha.base;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* 算术验证码抽象类
|
||||
* Created by 王帆 on 2019-08-23 上午 10:08.
|
||||
*/
|
||||
public abstract class ArithmeticCaptchaAbstract extends Captcha {
|
||||
private String arithmeticString; // 计算公式
|
||||
|
||||
public ArithmeticCaptchaAbstract() {
|
||||
setLen(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机验证码
|
||||
*
|
||||
* @return 验证码字符数组
|
||||
*/
|
||||
@Override
|
||||
protected char[] alphas() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < len; i++) {
|
||||
sb.append(num(10));
|
||||
if (i < len - 1) {
|
||||
int type = num(1, 4);
|
||||
if (type == 1) {
|
||||
sb.append("+");
|
||||
} else if (type == 2) {
|
||||
sb.append("-");
|
||||
} else if (type == 3) {
|
||||
sb.append("x");
|
||||
}
|
||||
}
|
||||
}
|
||||
ScriptEngineManager manager = new ScriptEngineManager();
|
||||
ScriptEngine engine = manager.getEngineByName("javascript");
|
||||
try {
|
||||
chars = String.valueOf(engine.eval(sb.toString().replaceAll("x", "*")));
|
||||
} catch (ScriptException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
sb.append("=?");
|
||||
arithmeticString = sb.toString();
|
||||
return chars.toCharArray();
|
||||
}
|
||||
|
||||
public String getArithmeticString() {
|
||||
checkAlpha();
|
||||
return arithmeticString;
|
||||
}
|
||||
|
||||
public void setArithmeticString(String arithmeticString) {
|
||||
this.arithmeticString = arithmeticString;
|
||||
}
|
||||
}
|
@@ -1,6 +1,13 @@
|
||||
package com.wf.captcha;
|
||||
package com.wf.captcha.base;
|
||||
|
||||
import sun.misc.BASE64Encoder;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
@@ -8,20 +15,33 @@ import java.io.OutputStream;
|
||||
* Created by 王帆 on 2018-07-27 上午 10:08.
|
||||
*/
|
||||
public abstract class Captcha extends Randoms {
|
||||
protected Font font = new Font("Arial", Font.BOLD, 32); // 字体Verdana
|
||||
protected int len = 4; // 验证码随机字符长度
|
||||
protected int width = 130; // 验证码显示宽度
|
||||
protected int height = 48; // 验证码显示高度
|
||||
protected String chars = null; // 当前验证码
|
||||
protected int charType = TYPE_DEFAULT; // 验证码类型,1字母数字混合,2纯数字,3纯字母
|
||||
// 常用颜色
|
||||
public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}};
|
||||
// 验证码文本类型
|
||||
public static final int TYPE_DEFAULT = 1; // 字母数字混合
|
||||
public static final int TYPE_ONLY_NUMBER = 2; // 纯数字
|
||||
public static final int TYPE_ONLY_CHAR = 3; // 纯字母
|
||||
public static final int TYPE_ONLY_UPPER = 4; // 纯大写字母
|
||||
public static final int TYPE_ONLY_LOWER = 5; // 纯小写字母
|
||||
public static final int TYPE_NUM_AND_UPPER = 6; // 数字大写字母
|
||||
// 常用颜色
|
||||
public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}};
|
||||
// 内置字体
|
||||
public static final int FONT_1 = 0;
|
||||
public static final int FONT_2 = 1;
|
||||
public static final int FONT_3 = 2;
|
||||
public static final int FONT_4 = 3;
|
||||
public static final int FONT_5 = 4;
|
||||
public static final int FONT_6 = 5;
|
||||
public static final int FONT_7 = 6;
|
||||
public static final int FONT_8 = 7;
|
||||
public static final int FONT_9 = 8;
|
||||
public static final int FONT_10 = 9;
|
||||
private static final String[] FONT_NAMES = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"};
|
||||
private Font font = null; // 验证码的字体
|
||||
protected int len = 5; // 验证码随机字符长度
|
||||
protected int width = 130; // 验证码显示宽度
|
||||
protected int height = 48; // 验证码显示高度
|
||||
protected int charType = TYPE_DEFAULT; // 验证码类型
|
||||
protected String chars = null; // 当前验证码
|
||||
|
||||
/**
|
||||
* 生成随机验证码
|
||||
@@ -91,6 +111,20 @@ public abstract class Captcha extends Randoms {
|
||||
*/
|
||||
public abstract boolean out(OutputStream os);
|
||||
|
||||
public abstract String toBase64();
|
||||
|
||||
/**
|
||||
* 输出base64编码
|
||||
*
|
||||
* @param type 编码头
|
||||
* @return
|
||||
*/
|
||||
public String toBase64(String type) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
out(outputStream);
|
||||
return type + new BASE64Encoder().encode(outputStream.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的验证码
|
||||
*
|
||||
@@ -112,7 +146,7 @@ public abstract class Captcha extends Randoms {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查验证码是否生成,没有这立即生成
|
||||
* 检查验证码是否生成,没有则立即生成
|
||||
*/
|
||||
public void checkAlpha() {
|
||||
if (chars == null) {
|
||||
@@ -139,7 +173,7 @@ public abstract class Captcha extends Randoms {
|
||||
*/
|
||||
public void drawLine(int num, Color color, Graphics2D g) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color == null ? color(150, 250) : color);
|
||||
g.setColor(color == null ? color() : color);
|
||||
int x1 = num(-10, width - 10);
|
||||
int y1 = num(5, height - 5);
|
||||
int x2 = num(10, width + 10);
|
||||
@@ -155,10 +189,7 @@ public abstract class Captcha extends Randoms {
|
||||
* @param g Graphics2D
|
||||
*/
|
||||
public void drawOval(int num, Graphics2D g) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color(100, 250));
|
||||
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
|
||||
}
|
||||
drawOval(num, null, g);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,12 +201,60 @@ public abstract class Captcha extends Randoms {
|
||||
*/
|
||||
public void drawOval(int num, Color color, Graphics2D g) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color == null ? color(100, 250) : color);
|
||||
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
|
||||
g.setColor(color == null ? color() : color);
|
||||
int w = 5 + num(10);
|
||||
g.drawOval(num(width - 25), num(height - 15), w, w);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机画贝塞尔曲线
|
||||
*
|
||||
* @param num 数量
|
||||
* @param g Graphics2D
|
||||
*/
|
||||
public void drawBesselLine(int num, Graphics2D g) {
|
||||
drawBesselLine(num, null, g);
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机画贝塞尔曲线
|
||||
*
|
||||
* @param num 数量
|
||||
* @param color 颜色
|
||||
* @param g Graphics2D
|
||||
*/
|
||||
public void drawBesselLine(int num, Color color, Graphics2D g) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color == null ? color() : color);
|
||||
int x1 = 5, y1 = num(5, height / 2);
|
||||
int x2 = width - 5, y2 = num(height / 2, height - 5);
|
||||
int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
|
||||
if (num(2) == 0) {
|
||||
int ty = y1;
|
||||
y1 = y2;
|
||||
y2 = ty;
|
||||
}
|
||||
if (num(2) == 0) { // 二阶贝塞尔曲线
|
||||
QuadCurve2D shape = new QuadCurve2D.Double();
|
||||
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
|
||||
g.draw(shape);
|
||||
} else { // 三阶贝塞尔曲线
|
||||
int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
|
||||
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
|
||||
g.draw(shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
if (font == null) {
|
||||
try {
|
||||
setFont(FONT_1);
|
||||
} catch (Exception e) {
|
||||
setFont(new Font("Arial", Font.BOLD, 32));
|
||||
}
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
@@ -183,6 +262,18 @@ public abstract class Captcha extends Randoms {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
public void setFont(int font) throws IOException, FontFormatException {
|
||||
setFont(font, 32f);
|
||||
}
|
||||
|
||||
public void setFont(int font, float size) throws IOException, FontFormatException {
|
||||
setFont(font, Font.BOLD, size);
|
||||
}
|
||||
|
||||
public void setFont(int font, int style, float size) throws IOException, FontFormatException {
|
||||
this.font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("/" + FONT_NAMES[font])).deriveFont(style, size);
|
||||
}
|
||||
|
||||
public int getLen() {
|
||||
return len;
|
||||
}
|
@@ -1,7 +1,11 @@
|
||||
package com.wf.captcha;
|
||||
package com.wf.captcha.base;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* 中文验证码抽象类
|
||||
* Created by 王帆 on 2018-07-27 上午 10:08.
|
||||
*/
|
||||
public abstract class ChineseCaptchaAbstract extends Captcha {
|
||||
// 常用汉字
|
||||
public static final String DELTA = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";
|
||||
@@ -35,16 +39,4 @@ public abstract class ChineseCaptchaAbstract extends Captcha {
|
||||
return DELTA.charAt(num(DELTA.length()));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void drawLine(int num, Color color, Graphics2D g) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color == null ? color(150, 250) : color);
|
||||
int x1 = num(-10, width / 3);
|
||||
int y1 = num(5, height - 5);
|
||||
int x2 = num(width / 3 * 2, width + 10);
|
||||
int y2 = num(2, height - 2);
|
||||
g.drawLine(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,17 +1,17 @@
|
||||
package com.wf.captcha;
|
||||
package com.wf.captcha.base;
|
||||
|
||||
import java.util.Random;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* 随机数工具类
|
||||
* Created by 王帆 on 2018-07-27 上午 10:08.
|
||||
*/
|
||||
public class Randoms {
|
||||
protected static final Random RANDOM = new Random();
|
||||
// 定义验证码字符.去除了O和I等容易混淆的字母
|
||||
protected static final SecureRandom RANDOM = new SecureRandom();
|
||||
// 定义验证码字符.去除了0、O、I、L等容易混淆的字母
|
||||
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'};
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
|
||||
protected static final int numMaxIndex = 8; // 数字的最大索引,不包括最大值
|
||||
protected static final int charMinIndex = numMaxIndex; // 字符的最小索引,包括最小值
|
||||
protected static final int charMaxIndex = ALPHA.length; // 字符的最大索引,不包括最大值
|
@@ -6,8 +6,7 @@ import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.wf.captcha.Captcha;
|
||||
import com.wf.captcha.GifCaptcha;
|
||||
import com.wf.captcha.base.Captcha;
|
||||
import com.wf.captcha.SpecCaptcha;
|
||||
|
||||
/**
|
||||
@@ -16,21 +15,9 @@ import com.wf.captcha.SpecCaptcha;
|
||||
*/
|
||||
public class CaptchaUtil {
|
||||
private static final String SESSION_KEY = "captcha";
|
||||
|
||||
/**
|
||||
* 验证验证码
|
||||
*
|
||||
* @param code 用户输入的验证码
|
||||
* @param request HttpServletRequest
|
||||
* @return 是否正确
|
||||
*/
|
||||
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;
|
||||
}
|
||||
private static final int DEFAULT_LEN = 4; // 默认长度
|
||||
private static final int DEFAULT_WIDTH = 130; // 默认宽度
|
||||
private static final int DEFAULT_HEIGHT = 48; // 默认高度
|
||||
|
||||
/**
|
||||
* 输出验证码
|
||||
@@ -41,7 +28,7 @@ public class CaptchaUtil {
|
||||
*/
|
||||
public static void out(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
out(5, request, response);
|
||||
out(DEFAULT_LEN, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,21 +41,7 @@ public class CaptchaUtil {
|
||||
*/
|
||||
public static void out(int len, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
out(130, 48, len, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出验证码
|
||||
*
|
||||
* @param len 长度
|
||||
* @param font 字体
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
out(130, 48, len, font, request, response);
|
||||
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,42 +62,14 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 输出验证码
|
||||
*
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param len 长度
|
||||
* @param font 字体
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
public static void out(Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
outCaptcha(width, height, len, font, 1, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出验证码
|
||||
*
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void outPng(HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
outPng(5, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出验证码
|
||||
*
|
||||
* @param len 长度
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void outPng(int len, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
outPng(130, 48, len, request, response);
|
||||
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_LEN, font, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,24 +81,9 @@ public class CaptchaUtil {
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void outPng(int len, Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
outPng(130, 48, len, font, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出验证码
|
||||
*
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param len 长度
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void outPng(int width, int height, int len, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
outPng(width, height, len, null, request, response);
|
||||
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, font, request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,39 +97,46 @@ public class CaptchaUtil {
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public static void outPng(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
outCaptcha(width, height, len, font, 0, request, response);
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha(width, height, len);
|
||||
if (font != null) {
|
||||
specCaptcha.setFont(font);
|
||||
}
|
||||
out(specCaptcha, request, response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 输出验证码
|
||||
*
|
||||
* @param width 宽度
|
||||
* @param height 高度
|
||||
* @param len 长度
|
||||
* @param font 字体
|
||||
* @param cType 类型
|
||||
* @param captcha Captcha
|
||||
* @param request HttpServletRequest
|
||||
* @param response HttpServletResponse
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private static void outCaptcha(int width, int height, int len, Font font, int cType, HttpServletRequest request, HttpServletResponse response)
|
||||
public static void out(Captcha captcha, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException {
|
||||
setHeader(response);
|
||||
Captcha captcha = null;
|
||||
if (cType == 0) {
|
||||
captcha = new SpecCaptcha(width, height, len);
|
||||
} else if (cType == 1) {
|
||||
captcha = new GifCaptcha(width, height, len);
|
||||
}
|
||||
if (font != null) {
|
||||
captcha.setFont(font);
|
||||
}
|
||||
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
|
||||
captcha.out(response.getOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证验证码
|
||||
*
|
||||
* @param code 用户输入的验证码
|
||||
* @param request HttpServletRequest
|
||||
* @return 是否正确
|
||||
*/
|
||||
public static boolean ver(String code, HttpServletRequest request) {
|
||||
if (code != null) {
|
||||
String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
|
||||
return code.trim().toLowerCase().equals(captcha);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除session中的验证码
|
||||
*
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package com.wf.captcha;
|
||||
package com.wf.captcha.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
@@ -1,4 +1,4 @@
|
||||
package com.wf.captcha;
|
||||
package com.wf.captcha.utils;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
@@ -1,4 +1,4 @@
|
||||
package com.wf.captcha;
|
||||
package com.wf.captcha.utils;
|
||||
|
||||
/**
|
||||
*
|
BIN
src/main/resources/actionj.ttf
Normal file
BIN
src/main/resources/actionj.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/epilog.ttf
Normal file
BIN
src/main/resources/epilog.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/fresnel.ttf
Normal file
BIN
src/main/resources/fresnel.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/headache.ttf
Normal file
BIN
src/main/resources/headache.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/lexo.ttf
Normal file
BIN
src/main/resources/lexo.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/prefix.ttf
Normal file
BIN
src/main/resources/prefix.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/progbot.ttf
Normal file
BIN
src/main/resources/progbot.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/ransom.ttf
Normal file
BIN
src/main/resources/ransom.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/robot.ttf
Normal file
BIN
src/main/resources/robot.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/scandal.ttf
Normal file
BIN
src/main/resources/scandal.ttf
Normal file
Binary file not shown.
@@ -13,39 +13,59 @@ public class CaptchaTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
/*for (int i = 0; i < 5; i++) {
|
||||
/*for (int i = 0; i < 10; i++) {
|
||||
SpecCaptcha specCaptcha = new SpecCaptcha();
|
||||
specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER);
|
||||
specCaptcha.setLen(4);
|
||||
specCaptcha.setFont(i, 32f);
|
||||
System.out.println(specCaptcha.text());
|
||||
specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
|
||||
specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
|
||||
}*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGIf() throws Exception {
|
||||
/*for (int i = 0; i < 5; i++) {
|
||||
/*for (int i = 0; i < 10; i++) {
|
||||
GifCaptcha gifCaptcha = new GifCaptcha();
|
||||
gifCaptcha.setLen(5);
|
||||
gifCaptcha.setFont(i, 32f);
|
||||
System.out.println(gifCaptcha.text());
|
||||
gifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
|
||||
gifCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".gif")));
|
||||
}*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHan() throws Exception {
|
||||
/*for (int i = 0; i < 5; i++) {
|
||||
/*for (int i = 0; i < 10; i++) {
|
||||
ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
|
||||
System.out.println(chineseCaptcha.text());
|
||||
chineseCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
|
||||
chineseCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
|
||||
}*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGifHan() throws Exception {
|
||||
/*for (int i = 0; i < 5; i++) {
|
||||
/*for (int i = 0; i < 10; i++) {
|
||||
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
|
||||
System.out.println(chineseGifCaptcha.text());
|
||||
chineseGifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
|
||||
chineseGifCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".gif")));
|
||||
}*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArit() throws Exception {
|
||||
/*for (int i = 0; i < 10; i++) {
|
||||
ArithmeticCaptcha specCaptcha = new ArithmeticCaptcha();
|
||||
specCaptcha.setLen(3);
|
||||
specCaptcha.setFont(i, 28f);
|
||||
System.out.println(specCaptcha.getArithmeticString() + " " + specCaptcha.text());
|
||||
specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
|
||||
}*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBase64() throws Exception {
|
||||
/*GifCaptcha specCaptcha = new GifCaptcha();
|
||||
System.out.println(specCaptcha.toBase64(""));*/
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user