mirror of
https://github.com/whvcse/EasyCaptcha.git
synced 2024-11-23 10:09:19 +08:00
增加内置字体、贝塞尔曲线、算术验证码、base64输出
This commit is contained in:
parent
366f54ea80
commit
8ebe5918c9
388
README.md
388
README.md
@ -5,48 +5,54 @@
|
|||||||
|
|
||||||
|
|
||||||
## 1.简介
|
## 1.简介
|
||||||
|
 Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。
|
||||||
|
|
||||||
  Java图形验证码,支持gif验证码、中文验证码,可用于Java Web、JavaSE项目。
|
---
|
||||||
|
|
||||||
|
|
||||||
## 2.效果展示
|
## 2.效果展示
|
||||||
|
|
||||||
**gif效果:**
|
![验证码](https://s2.ax1x.com/2019/08/23/msFrE8.png)
|
||||||
|
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd30vgc2g303m01c0st.jpg)
|
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd22ixh9g303m01c3yj.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msF0DP.png)
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd2k0gjug303m01ct8t.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msFwut.png)
|
||||||
|
<br/>
|
||||||
**png效果:**
|
![验证码](https://s2.ax1x.com/2019/08/23/msFzVK.gif)
|
||||||
|
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd09lqpaj303m01cwee.jpg)
|
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd0tj6nhj303m01ct8m.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msFvb6.gif)
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd1cw3pcj303m01c0sn.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msFXK1.gif)
|
||||||
|
|
||||||
|
**算术类型:**
|
||||||
|
|
||||||
**中文验证码:**
|
![验证码](https://s2.ax1x.com/2019/08/23/mskKPg.png)
|
||||||
|
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovnvbgx6g303m01cjrc.jpg)
|
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovojp2gng303m01cq2w.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msknIS.png)
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovp5u4c4g303m01cdft.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/mskma8.png)
|
||||||
|
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmfxg71j303m01cq2s.jpg)
|
**中文类型:**
|
||||||
|
|
||||||
|
![验证码](https://s2.ax1x.com/2019/08/23/mskcdK.png)
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmy720dj303m01cq2s.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msk6Z6.png)
|
||||||
  
|
  
|
||||||
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovn68um6j303m01cglf.jpg)
|
![验证码](https://s2.ax1x.com/2019/08/23/msksqx.png)
|
||||||
|
|
||||||
|
**内置字体:**
|
||||||
|
|
||||||
|
![验证码](https://s2.ax1x.com/2019/08/23/msAVSJ.png)
|
||||||
|
  
|
||||||
|
![验证码](https://s2.ax1x.com/2019/08/23/msAAW4.png)
|
||||||
|
  
|
||||||
|
![验证码](https://s2.ax1x.com/2019/08/23/msAkYF.png)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 3.导入项目
|
## 3.导入项目
|
||||||
|
|
||||||
### 2.1.gradle方式的引入
|
### 3.1.gradle方式的引入
|
||||||
需要先在project的build.gradle中添加:
|
需要先在project的build.gradle中添加:
|
||||||
```text
|
```text
|
||||||
allprojects {
|
allprojects {
|
||||||
@ -58,11 +64,11 @@ allprojects {
|
|||||||
在项目的build.gradle中添加
|
在项目的build.gradle中添加
|
||||||
```text
|
```text
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.github.whvcse:EasyCaptcha:1.5.0'
|
compile 'com.github.whvcse:EasyCaptcha:1.6.0'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.2.maven方式引入
|
### 3.2.maven方式引入
|
||||||
在你的pom.xml中添加如下代码:
|
在你的pom.xml中添加如下代码:
|
||||||
```xml
|
```xml
|
||||||
<project>
|
<project>
|
||||||
@ -77,33 +83,49 @@ dependencies {
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.whvcse</groupId>
|
<groupId>com.github.whvcse</groupId>
|
||||||
<artifactId>EasyCaptcha</artifactId>
|
<artifactId>EasyCaptcha</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.6.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2.3.jar包下载
|
### 3.3.jar包下载
|
||||||
[EasyCaptcha-1.5.0.jar](https://gitee.com/whvse/EasyCaptcha/releases)
|
[EasyCaptcha-1.6.0.jar](https://gitee.com/whvse/EasyCaptcha/releases)
|
||||||
|
|
||||||
maven导入jar包,在项目根目录创建`libs`文件夹,然后pom.xml添加如下:
|
maven导入jar包,在项目根目录创建`libs`文件夹,然后pom.xml添加如下:
|
||||||
```
|
```
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.whvcse</groupId>
|
<groupId>com.github.whvcse</groupId>
|
||||||
<artifactId>EasyCaptcha</artifactId>
|
<artifactId>EasyCaptcha</artifactId>
|
||||||
<version>1.5.0</version>
|
<version>1.6.0</version>
|
||||||
<systemPath>${basedir}/libs/EasyCaptcha-1.5.0.jar</systemPath>
|
<systemPath>${basedir}/libs/EasyCaptcha-1.6.0.jar</systemPath>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 4.使用方法
|
||||||
|
|
||||||
## 3.使用方法
|
### 4.1.在SpringMVC中使用
|
||||||
|
```java
|
||||||
|
@Controller
|
||||||
|
public class CaptchaController {
|
||||||
|
|
||||||
### 3.1.快速使用
|
@RequestMapping("/captcha")
|
||||||
1.在web.xml里面加入如下配置:
|
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||||
|
CaptchaUtil.out(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
前端html代码:
|
||||||
|
```html
|
||||||
|
<img src="/captcha" width="130px" height="48px" />
|
||||||
|
```
|
||||||
|
|
||||||
|
> 不要忘了把`/captcha`路径排除登录拦截,比如shiro的拦截。
|
||||||
|
|
||||||
|
### 4.2.在servlet中使用
|
||||||
|
web.xml中配置servlet:
|
||||||
```xml
|
```xml
|
||||||
<web-app>
|
<web-app>
|
||||||
<!-- 图形验证码servlet -->
|
<!-- 图形验证码servlet -->
|
||||||
@ -113,163 +135,130 @@ maven导入jar包,在项目根目录创建`libs`文件夹,然后pom.xml添
|
|||||||
</servlet>
|
</servlet>
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>CaptchaServlet</servlet-name>
|
<servlet-name>CaptchaServlet</servlet-name>
|
||||||
<url-pattern>/images/captcha</url-pattern>
|
<url-pattern>/captcha</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
</web-app>
|
</web-app>
|
||||||
|
|
||||||
```
|
```
|
||||||
2.前端代码
|
前端html代码:
|
||||||
```html
|
```html
|
||||||
<img src="/images/captcha" />
|
<img src="/captcha" width="130px" height="48px" />
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.2.在SpringMVC中使用
|
### 4.3.判断验证码是否正确
|
||||||
也可以使用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.判断验证码是否正确
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@Controller
|
@Controller
|
||||||
public class LoginController {
|
public class LoginController {
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public JsonResult login(String username,String password,String code){
|
public JsonResult login(String username,String password,String verCode){
|
||||||
|
if (!CaptchaUtil.ver(verCode, request)) {
|
||||||
if (!CaptchaUtil.ver(code, request)) {
|
CaptchaUtil.clear(request); // 清除session中的验证码
|
||||||
CaptchaUtil.clear(request);
|
|
||||||
return JsonResult.error("验证码不正确");
|
return JsonResult.error("验证码不正确");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3.4.设置宽高和位数
|
### 4.4.设置宽高和位数
|
||||||
```java
|
```java
|
||||||
@Controller
|
@Controller
|
||||||
public class MainController {
|
public class CaptchaController {
|
||||||
|
|
||||||
@RequestMapping("/images/captcha")
|
@RequestMapping("/captcha")
|
||||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||||
// 设置位数
|
// 设置位数
|
||||||
CaptchaUtil.out(5, request, response);
|
CaptchaUtil.out(5, request, response);
|
||||||
|
|
||||||
// 设置宽、高、位数
|
// 设置宽、高、位数
|
||||||
CaptchaUtil.out(130, 48, 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.不使用工具类
|
### 4.5.不使用工具类
|
||||||
|
 CaptchaUtil封装了输出验证码、存session、判断验证码等功能,也可以不使用此工具类:
|
||||||
  CaptchaUtil是为了简化操作,封装了生成验证码、存session、判断验证码等功能。CaptchaUtil使用的GifCaptcha
|
|
||||||
生成的字母数字混合的gif验证码,如果需要设置更多的参数,请参照如下操作使用:
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
@Controller
|
@Controller
|
||||||
public class MainController {
|
public class CaptchaController {
|
||||||
|
|
||||||
@RequestMapping("/images/captcha")
|
@RequestMapping("/captcha")
|
||||||
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
|
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
|
// 验证码存入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")
|
@PostMapping("/login")
|
||||||
public JsonResult login(String username,String password,String code){
|
public JsonResult login(String username,String password,String verCode){
|
||||||
// 获取session中的验证码
|
// 获取session中的验证码
|
||||||
String sessionCode = request.getSession().getAttribute("captcha");
|
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("验证码不正确");
|
return JsonResult.error("验证码不正确");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4.更多设置
|
## 5.更多设置
|
||||||
|
|
||||||
### 4.1.使用Gif验证码
|
### 5.1.验证码类型
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class Test {
|
public class Test {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.gif"));
|
// png类型
|
||||||
|
SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
|
||||||
|
captcha.text(); // 获取验证码的字符
|
||||||
|
captcha.textChar(); // 获取验证码的字符数组
|
||||||
|
|
||||||
// 三个参数分别为宽、高、位数
|
// gif类型
|
||||||
GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5);
|
GifCaptcha captcha = new GifCaptcha(130, 48, 5);
|
||||||
|
|
||||||
// 设置字体
|
// 中文类型
|
||||||
gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
|
ChineseCaptcha captcha = new ChineseCaptcha(130, 48, 5);
|
||||||
|
|
||||||
// 设置类型,纯数字、纯字母、字母数字混合
|
// 中文gif类型
|
||||||
gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
ChineseGifCaptcha captcha = new ChineseGifCaptcha(130, 48, 5);
|
||||||
|
|
||||||
// 生成的验证码
|
// 算术类型
|
||||||
String code = gifCaptcha.text();
|
ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48, 5);
|
||||||
|
captcha.setLen(3); // 几位数运算,默认是两位
|
||||||
|
captcha.getArithmeticString(); // 获取运算的公式:3+2=?
|
||||||
|
captcha.text(); // 获取运算的结果:5
|
||||||
|
|
||||||
// 输出图片流
|
captcha.out(outputStream); // 输出验证码
|
||||||
gifCaptcha.out(outputStream);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.2.使用png验证码
|
> 注意:<br/>
|
||||||
|
>  算术验证码的len表示是几位数运算,而其他验证码的len表示验证码的位数,算术验证码的text()表示的是公式的结果,
|
||||||
|
> 对于算术验证码,你应该把公式的结果存储session,而不是公式。
|
||||||
|
|
||||||
```java
|
### 5.2.验证码字符类型
|
||||||
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.验证码类型
|
|
||||||
|
|
||||||
类型 | 描述
|
类型 | 描述
|
||||||
:--- | :---
|
:--- | :---
|
||||||
@ -280,60 +269,145 @@ public class Test {
|
|||||||
TYPE_ONLY_LOWER | 纯小写字母
|
TYPE_ONLY_LOWER | 纯小写字母
|
||||||
TYPE_NUM_AND_UPPER | 数字和大写字母
|
TYPE_NUM_AND_UPPER | 数字和大写字母
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
```
|
||||||
|
SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
|
||||||
|
captcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
|
||||||
|
```
|
||||||
|
|
||||||
### 4.4.中文验证码
|
> 只有`SpecCaptcha`和`GifCaptcha`设置才有效果。
|
||||||
|
|
||||||
中文png验证码:
|
### 5.3.字体设置
|
||||||
|
内置字体:
|
||||||
|
|
||||||
|
字体 | 效果
|
||||||
|
:--- | :---
|
||||||
|
Captcha.FONT_1 | ![](https://s2.ax1x.com/2019/08/23/msMe6U.png)
|
||||||
|
Captcha.FONT_2 | ![](https://s2.ax1x.com/2019/08/23/msMAf0.png)
|
||||||
|
Captcha.FONT_3 | ![](https://s2.ax1x.com/2019/08/23/msMCwj.png)
|
||||||
|
Captcha.FONT_4 | ![](https://s2.ax1x.com/2019/08/23/msM9mQ.png)
|
||||||
|
Captcha.FONT_5 | ![](https://s2.ax1x.com/2019/08/23/msKz6S.png)
|
||||||
|
Captcha.FONT_6 | ![](https://s2.ax1x.com/2019/08/23/msKxl8.png)
|
||||||
|
Captcha.FONT_7 | ![](https://s2.ax1x.com/2019/08/23/msMPTs.png)
|
||||||
|
Captcha.FONT_8 | ![](https://s2.ax1x.com/2019/08/23/msMmXF.png)
|
||||||
|
Captcha.FONT_9 | ![](https://s2.ax1x.com/2019/08/23/msMVpV.png)
|
||||||
|
Captcha.FONT_10 | ![](https://s2.ax1x.com/2019/08/23/msMZlT.png)
|
||||||
|
|
||||||
|
使用方法:
|
||||||
|
```
|
||||||
|
SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
|
||||||
|
|
||||||
|
// 设置内置字体
|
||||||
|
captcha.setFont(Captcha.FONT_1);
|
||||||
|
|
||||||
|
// 设置系统字体
|
||||||
|
captcha.setFont(new Font("楷体", Font.PLAIN, 28));
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4.输出base64编码
|
||||||
|
```
|
||||||
|
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
|
||||||
|
specCaptcha.toBase64();
|
||||||
|
|
||||||
|
// 如果不想要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);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6.前后端分离项目的使用
|
||||||
|
|
||||||
|
 前后端分离项目建议不要存储在session中,存储在redis中,redis存储需要一个key,key一同返回给前端用于验证输入:
|
||||||
```java
|
```java
|
||||||
public class Test {
|
@Controller
|
||||||
|
public class CaptchaController {
|
||||||
|
@Autowired
|
||||||
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
@ResponseBody
|
||||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
|
@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
|
||||||
ChineseCaptcha chineseCaptcha = new ChineseCaptcha(130, 48, 4);
|
@PostMapping("/login")
|
||||||
|
public JsonResult login(String username,String password,String verCode,String verKey){
|
||||||
// 设置字体
|
// 获取redis中的验证码
|
||||||
chineseCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
|
String redisCode = redisUtil.get(verKey);
|
||||||
|
// 判断验证码
|
||||||
// 生成的验证码
|
if (verCode==null || !redisCode.equals(verCode.trim().toLowerCase())) {
|
||||||
String code = chineseCaptcha.text();
|
return JsonResult.error("验证码不正确");
|
||||||
|
}
|
||||||
// 输出图片流
|
|
||||||
chineseCaptcha.out(outputStream);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
前端使用ajax获取验证码:
|
||||||
|
```html
|
||||||
|
<img id="verImg" />
|
||||||
|
|
||||||
中文gif验证码:
|
<script>
|
||||||
|
var verKey;
|
||||||
|
// 获取验证码
|
||||||
|
$.get('/captcha', function(res) {
|
||||||
|
verKey = res.key;
|
||||||
|
$('#verImg').attr('src', res.image);
|
||||||
|
},'json');
|
||||||
|
|
||||||
```java
|
// 登录
|
||||||
public class Test {
|
$.post('/login', {
|
||||||
|
verKey: verKey,
|
||||||
public static void main(String[] args) {
|
verCode: '8u6h',
|
||||||
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
|
username: 'admin',
|
||||||
|
password: 'admin'
|
||||||
// 三个参数分别为宽、高、位数
|
}, function(res) {
|
||||||
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha(130, 48, 4);
|
console.log(res);
|
||||||
|
}, 'json');
|
||||||
// 设置字体
|
</script>
|
||||||
chineseGifCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
|
|
||||||
|
|
||||||
// 生成的验证码
|
|
||||||
String code = chineseGifCaptcha.text();
|
|
||||||
|
|
||||||
// 输出图片流
|
|
||||||
chineseGifCaptcha.out(outputStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4.5.前后端分离项目的使用
|
> RedisUtil到这里获取[https://gitee.com/whvse/RedisUtil](https://gitee.com/whvse/RedisUtil)
|
||||||
|
|
||||||
  分离项目建议不要存储在session中,存储在redis中。
|
---
|
||||||
|
|
||||||
|
## 7.自定义效果
|
||||||
|
|
||||||
## 5.自定义效果
|
 继承`Captcha`实现`out`方法,中文验证码可继承`ChineseCaptchaAbstract`,算术验证码可继承`ArithmeticCaptchaAbstract`。
|
||||||
|
|
||||||
参考源代码中的SpecCaptcha和GifCaptcha继承Captcha即可。
|
---
|
||||||
|
|
||||||
|
## 8.更新日志
|
||||||
|
|
||||||
|
- **2019-08-23 (v1.6.0)**
|
||||||
|
- 增加10种漂亮的内置字体,不依赖系统字体
|
||||||
|
|
||||||
|
- 增加算术验证码,运算位数可自由配置
|
||||||
|
- 增加输出base64编码的功能
|
||||||
|
- 增加贝塞尔曲线作为干扰线
|
||||||
|
|
||||||
|
- **2018-08-09 (v1.5.0)**
|
||||||
|
- 增加纯大写字母、纯小写字母、数字和大写字母配置
|
||||||
|
|
||||||
|
- 增加中文验证码、中文gif验证码
|
||||||
|
- 增加抗锯齿效果,优化文字颜色
|
||||||
|
- 增加CaptchaUtil便于Web项目使用
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9.推荐
|
||||||
|
 **EasyWeb管系统模板**,一个开箱即用的后台模板,使用简单,功能丰富,包含ifram版和spa单页面版,[前往查看](https://easyweb.vip)。
|
||||||
|
|
||||||
|
![](https://s2.ax1x.com/2019/08/23/msiO78.png)
|
||||||
|
4
pom.xml
4
pom.xml
@ -5,7 +5,7 @@
|
|||||||
<groupId>org.wf</groupId>
|
<groupId>org.wf</groupId>
|
||||||
|
|
||||||
<artifactId>easy-captcha</artifactId>
|
<artifactId>easy-captcha</artifactId>
|
||||||
<version>1.5.0-RELEASE</version>
|
<version>1.6.0-RELEASE</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>EasyCaptcha</name>
|
<name>EasyCaptcha</name>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.7</version>
|
<version>4.12</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -38,10 +38,14 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean out(OutputStream out) {
|
public boolean out(OutputStream out) {
|
||||||
checkAlpha();
|
|
||||||
return graphicsImage(textChar(), out);
|
return graphicsImage(textChar(), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toBase64() {
|
||||||
|
return toBase64("data:image/png;base64,");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成验证码图形
|
* 生成验证码图形
|
||||||
*
|
*
|
||||||
@ -50,54 +54,34 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
private boolean graphicsImage(char[] strs, OutputStream out) {
|
private boolean graphicsImage(char[] strs, OutputStream out) {
|
||||||
boolean ok;
|
|
||||||
try {
|
try {
|
||||||
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||||
Graphics2D g = (Graphics2D) bi.getGraphics();
|
Graphics2D g2d = (Graphics2D) bi.getGraphics();
|
||||||
AlphaComposite ac3;
|
// 填充背景
|
||||||
int len = strs.length;
|
g2d.setColor(Color.WHITE);
|
||||||
g.setColor(Color.WHITE);
|
g2d.fillRect(0, 0, width, height);
|
||||||
g.fillRect(0, 0, width, height);
|
|
||||||
// 抗锯齿
|
// 抗锯齿
|
||||||
g.setColor(color());
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
Font font = getFont();
|
// 画干扰圆
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
drawOval(3, g2d);
|
||||||
int hp = (height - font.getSize()) >> 1;
|
// 画干扰线
|
||||||
int h = height - hp;
|
g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||||
int w = width / strs.length;
|
drawBesselLine(1, g2d);
|
||||||
int sp = (w - font.getSize()) / 2;
|
|
||||||
// 画字符串
|
// 画字符串
|
||||||
for (int i = 0; i < len; i++) {
|
g2d.setFont(getFont());
|
||||||
// 计算坐标
|
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||||
int x = i * w + sp + num(-5, 5);
|
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||||
int y = h + num(-5, 5);
|
int fSp = (fW - (int) fontMetrics.getStringBounds("王", g2d).getWidth()) / 2; // 字符的左右边距
|
||||||
if (x < 5) {
|
for (int i = 0; i < strs.length; i++) {
|
||||||
x = 5;
|
g2d.setColor(color());
|
||||||
}
|
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||||
if (x + font.getSize() > width) {
|
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
|
||||||
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.dispose();
|
||||||
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);
|
|
||||||
ImageIO.write(bi, "png", out);
|
ImageIO.write(bi, "png", out);
|
||||||
out.flush();
|
out.flush();
|
||||||
ok = true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
ok = false;
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
@ -106,6 +90,6 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.wf.captcha.base.ChineseCaptchaAbstract;
|
|||||||
import com.wf.captcha.utils.GifEncoder;
|
import com.wf.captcha.utils.GifEncoder;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.geom.CubicCurve2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -30,24 +31,39 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean out(OutputStream os) {
|
public boolean out(OutputStream os) {
|
||||||
checkAlpha();
|
|
||||||
boolean ok;
|
|
||||||
try {
|
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 gifEncoder = new GifEncoder();
|
||||||
gifEncoder.start(os);
|
|
||||||
gifEncoder.setQuality(180);
|
gifEncoder.setQuality(180);
|
||||||
gifEncoder.setDelay(100);
|
gifEncoder.setDelay(100);
|
||||||
gifEncoder.setRepeat(0);
|
gifEncoder.setRepeat(0);
|
||||||
BufferedImage frame;
|
gifEncoder.start(os);
|
||||||
Color fontcolor = color();
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
frame = graphicsImage(fontcolor, rands, i);
|
BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
|
||||||
gifEncoder.addFrame(frame);
|
gifEncoder.addFrame(frame);
|
||||||
frame.flush();
|
frame.flush();
|
||||||
}
|
}
|
||||||
gifEncoder.finish();
|
gifEncoder.finish();
|
||||||
ok = true;
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
os.close();
|
os.close();
|
||||||
@ -55,60 +71,53 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toBase64() {
|
||||||
|
return toBase64("data:image/gif;base64,");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 画随机码图
|
* 画随机码图
|
||||||
*
|
*
|
||||||
* @param fontcolor 随机字体颜色
|
* @param fontColor 随机字体颜色
|
||||||
* @param strs 字符数组
|
* @param strs 字符数组
|
||||||
* @param flag 透明度使用
|
* @param flag 透明度
|
||||||
|
* @param besselXY 干扰线参数
|
||||||
* @return BufferedImage
|
* @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);
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||||
g2d.setColor(Color.WHITE); // 填充背景颜色
|
// 填充背景颜色
|
||||||
|
g2d.setColor(Color.WHITE);
|
||||||
g2d.fillRect(0, 0, width, height);
|
g2d.fillRect(0, 0, width, height);
|
||||||
// 抗锯齿
|
// 抗锯齿
|
||||||
AlphaComposite ac3;
|
|
||||||
g2d.setColor(fontcolor);
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
// 画验证码
|
|
||||||
Font font = getFont();
|
|
||||||
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();
|
g2d.dispose();
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ import com.wf.captcha.base.Captcha;
|
|||||||
import com.wf.captcha.utils.GifEncoder;
|
import com.wf.captcha.utils.GifEncoder;
|
||||||
|
|
||||||
import java.awt.*;
|
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.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -34,27 +37,39 @@ public class GifCaptcha extends Captcha {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean out(OutputStream os) {
|
public boolean out(OutputStream os) {
|
||||||
checkAlpha();
|
|
||||||
boolean ok;
|
|
||||||
try {
|
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 gifEncoder = new GifEncoder();
|
||||||
gifEncoder.start(os);
|
|
||||||
gifEncoder.setQuality(180);
|
gifEncoder.setQuality(180);
|
||||||
gifEncoder.setDelay(100);
|
gifEncoder.setDelay(100);
|
||||||
gifEncoder.setRepeat(0);
|
gifEncoder.setRepeat(0);
|
||||||
BufferedImage frame;
|
gifEncoder.start(os);
|
||||||
Color fontcolor[] = new Color[len];
|
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
fontcolor[i] = new Color(20 + num(110), 20 + num(110), 20 + num(110));
|
BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
|
||||||
}
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
frame = graphicsImage(fontcolor, rands, i);
|
|
||||||
gifEncoder.addFrame(frame);
|
gifEncoder.addFrame(frame);
|
||||||
frame.flush();
|
frame.flush();
|
||||||
}
|
}
|
||||||
gifEncoder.finish();
|
gifEncoder.finish();
|
||||||
ok = true;
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
os.close();
|
os.close();
|
||||||
@ -62,18 +77,24 @@ public class GifCaptcha extends Captcha {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ok;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toBase64() {
|
||||||
|
return toBase64("data:image/gif;base64,");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 画随机码图
|
* 画随机码图
|
||||||
*
|
*
|
||||||
* @param fontcolor 随机字体颜色
|
* @param fontColor 随机字体颜色
|
||||||
* @param strs 字符数组
|
* @param strs 字符数组
|
||||||
* @param flag 透明度使用
|
* @param flag 透明度
|
||||||
|
* @param besselXY 干扰线参数
|
||||||
* @return BufferedImage
|
* @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);
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||||
// 填充背景颜色
|
// 填充背景颜色
|
||||||
@ -81,39 +102,27 @@ public class GifCaptcha extends Captcha {
|
|||||||
g2d.fillRect(0, 0, width, height);
|
g2d.fillRect(0, 0, width, height);
|
||||||
// 抗锯齿
|
// 抗锯齿
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
g2d.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
|
||||||
// 画干扰圆圈
|
// 画干扰圆圈
|
||||||
drawOval(4, g2d);
|
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
|
||||||
// 随机画干扰线
|
drawOval(2, g2d);
|
||||||
drawLine(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);
|
||||||
// 画验证码
|
// 画验证码
|
||||||
Font font = getFont();
|
g2d.setFont(getFont());
|
||||||
int hp = (height - font.getSize()) >> 1;
|
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||||
int h = height - hp;
|
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||||
int w = width / strs.length;
|
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
|
||||||
int sp = (w - font.getSize()) / 2;
|
|
||||||
for (int i = 0; i < strs.length; i++) {
|
for (int i = 0; i < strs.length; i++) {
|
||||||
|
// 设置透明度
|
||||||
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
|
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
|
||||||
g2d.setComposite(ac3);
|
g2d.setComposite(ac3);
|
||||||
g2d.setColor(fontcolor[i]);
|
g2d.setColor(fontColor[i]);
|
||||||
// 计算坐标
|
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||||
int x = i * w + sp + num(3);
|
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 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.dispose();
|
g2d.dispose();
|
||||||
return image;
|
return image;
|
||||||
|
@ -45,6 +45,11 @@ public class SpecCaptcha extends Captcha {
|
|||||||
return graphicsImage(textChar(), out);
|
return graphicsImage(textChar(), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toBase64() {
|
||||||
|
return toBase64("data:image/png;base64,");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成验证码图形
|
* 生成验证码图形
|
||||||
*
|
*
|
||||||
@ -55,45 +60,28 @@ public class SpecCaptcha extends Captcha {
|
|||||||
private boolean graphicsImage(char[] strs, OutputStream out) {
|
private boolean graphicsImage(char[] strs, OutputStream out) {
|
||||||
try {
|
try {
|
||||||
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||||
Graphics2D g = (Graphics2D) bi.getGraphics();
|
Graphics2D g2d = (Graphics2D) bi.getGraphics();
|
||||||
// 填充背景
|
// 填充背景
|
||||||
g.setColor(Color.WHITE);
|
g2d.setColor(Color.WHITE);
|
||||||
g.fillRect(0, 0, width, height);
|
g2d.fillRect(0, 0, width, height);
|
||||||
// 抗锯齿
|
// 抗锯齿
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
// 画干扰圆
|
||||||
// 随机画干扰线
|
drawOval(2, g2d);
|
||||||
// drawLine(3, g);
|
// 画干扰线
|
||||||
// 随机画干扰圆
|
g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||||
// drawOval(8, g);
|
drawBesselLine(1, g2d);
|
||||||
drawBesselLine(2, g);
|
|
||||||
// 画字符串
|
// 画字符串
|
||||||
// AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度
|
g2d.setFont(getFont());
|
||||||
// g.setComposite(ac3);
|
FontMetrics fontMetrics = g2d.getFontMetrics();
|
||||||
g.setFont(getFont());
|
|
||||||
int fontSize = getFont().getSize();
|
|
||||||
int fY = height - ((height - fontSize) >> 1); // 文字的纵坐标
|
|
||||||
int fW = width / strs.length; // 每一个字符所占的宽度
|
int fW = width / strs.length; // 每一个字符所占的宽度
|
||||||
int fSp = (fW - fontSize) / 2; // 字符的左右边距
|
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
|
||||||
for (int i = 0; i < strs.length; i++) {
|
for (int i = 0; i < strs.length; i++) {
|
||||||
g.setColor(color());
|
g2d.setColor(color());
|
||||||
// 计算坐标
|
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
|
||||||
int x = i * fW + fSp;
|
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
|
||||||
int y = fY/* - num(3, 6)*/;
|
|
||||||
/*if (x < 8) {
|
|
||||||
x = 8;
|
|
||||||
}
|
|
||||||
if (x + fontSize > width) {
|
|
||||||
x = width - fontSize;
|
|
||||||
}*/
|
|
||||||
/*if (y > height) {
|
|
||||||
y = height;
|
|
||||||
}
|
|
||||||
if (y - fontSize < 0) {
|
|
||||||
y = fontSize;
|
|
||||||
}*/
|
|
||||||
g.drawString(String.valueOf(strs[i]), x, y);
|
|
||||||
}
|
}
|
||||||
|
g2d.dispose();
|
||||||
ImageIO.write(bi, "png", out);
|
ImageIO.write(bi, "png", out);
|
||||||
out.flush();
|
out.flush();
|
||||||
return true;
|
return true;
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.wf.captcha.base;
|
||||||
|
|
||||||
|
import javax.script.ScriptEngine;
|
||||||
|
import javax.script.ScriptEngineManager;
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
|
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,8 +1,11 @@
|
|||||||
package com.wf.captcha.base;
|
package com.wf.captcha.base;
|
||||||
|
|
||||||
|
import sun.misc.BASE64Encoder;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.CubicCurve2D;
|
import java.awt.geom.CubicCurve2D;
|
||||||
import java.awt.geom.QuadCurve2D;
|
import java.awt.geom.QuadCurve2D;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -108,6 +111,20 @@ public abstract class Captcha extends Randoms {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean out(OutputStream os);
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前的验证码
|
* 获取当前的验证码
|
||||||
*
|
*
|
||||||
@ -156,7 +173,7 @@ public abstract class Captcha extends Randoms {
|
|||||||
*/
|
*/
|
||||||
public void drawLine(int num, Color color, Graphics2D g) {
|
public void drawLine(int num, Color color, Graphics2D g) {
|
||||||
for (int i = 0; i < num; i++) {
|
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 x1 = num(-10, width - 10);
|
||||||
int y1 = num(5, height - 5);
|
int y1 = num(5, height - 5);
|
||||||
int x2 = num(10, width + 10);
|
int x2 = num(10, width + 10);
|
||||||
@ -172,10 +189,7 @@ public abstract class Captcha extends Randoms {
|
|||||||
* @param g Graphics2D
|
* @param g Graphics2D
|
||||||
*/
|
*/
|
||||||
public void drawOval(int num, Graphics2D g) {
|
public void drawOval(int num, Graphics2D g) {
|
||||||
for (int i = 0; i < num; i++) {
|
drawOval(num, null, g);
|
||||||
g.setColor(color(100, 250));
|
|
||||||
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,8 +201,9 @@ public abstract class Captcha extends Randoms {
|
|||||||
*/
|
*/
|
||||||
public void drawOval(int num, Color color, Graphics2D g) {
|
public void drawOval(int num, Color color, Graphics2D g) {
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
g.setColor(color == null ? color(100, 250) : color);
|
g.setColor(color == null ? color() : color);
|
||||||
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
|
int w = 5 + num(10);
|
||||||
|
g.drawOval(num(width - 25), num(height - 15), w, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,19 +227,20 @@ public abstract class Captcha extends Randoms {
|
|||||||
public void drawBesselLine(int num, Color color, Graphics2D g) {
|
public void drawBesselLine(int num, Color color, Graphics2D g) {
|
||||||
for (int i = 0; i < num; i++) {
|
for (int i = 0; i < num; i++) {
|
||||||
g.setColor(color == null ? color() : color);
|
g.setColor(color == null ? color() : color);
|
||||||
int x1 = 5;
|
int x1 = 5, y1 = num(5, height / 2);
|
||||||
int y1 = num(5, height - 5);
|
int x2 = width - 5, y2 = num(height / 2, height - 5);
|
||||||
int x2 = width - 5;
|
int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
|
||||||
int y2 = num(5, height - 5);
|
if (num(2) == 0) {
|
||||||
int ctrlx = num(5, width - 5);
|
int ty = y1;
|
||||||
int ctrly = num(5, height - 5);
|
y1 = y2;
|
||||||
|
y2 = ty;
|
||||||
|
}
|
||||||
if (num(2) == 0) { // 二阶贝塞尔曲线
|
if (num(2) == 0) { // 二阶贝塞尔曲线
|
||||||
QuadCurve2D shape = new QuadCurve2D.Double();
|
QuadCurve2D shape = new QuadCurve2D.Double();
|
||||||
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
|
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
|
||||||
g.draw(shape);
|
g.draw(shape);
|
||||||
} else { // 三阶贝塞尔曲线
|
} else { // 三阶贝塞尔曲线
|
||||||
int ctrlx1 = num(5, width - 5);
|
int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
|
||||||
int ctrly1 = num(5, height - 5);
|
|
||||||
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
|
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
|
||||||
g.draw(shape);
|
g.draw(shape);
|
||||||
}
|
}
|
||||||
@ -247,7 +263,11 @@ public abstract class Captcha extends Randoms {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setFont(int font) throws IOException, FontFormatException {
|
public void setFont(int font) throws IOException, FontFormatException {
|
||||||
setFont(font, Font.BOLD, 32f);
|
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 {
|
public void setFont(int font, int style, float size) throws IOException, FontFormatException {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package com.wf.captcha.base;
|
package com.wf.captcha.base;
|
||||||
|
|
||||||
import com.wf.captcha.base.Captcha;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
public abstract class ChineseCaptchaAbstract extends Captcha {
|
public abstract class ChineseCaptchaAbstract extends Captcha {
|
||||||
@ -37,16 +35,4 @@ public abstract class ChineseCaptchaAbstract extends Captcha {
|
|||||||
return DELTA.charAt(num(DELTA.length()));
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import com.wf.captcha.base.Captcha;
|
import com.wf.captcha.base.Captcha;
|
||||||
import com.wf.captcha.GifCaptcha;
|
|
||||||
import com.wf.captcha.SpecCaptcha;
|
import com.wf.captcha.SpecCaptcha;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,21 +15,9 @@ import com.wf.captcha.SpecCaptcha;
|
|||||||
*/
|
*/
|
||||||
public class CaptchaUtil {
|
public class CaptchaUtil {
|
||||||
private static final String SESSION_KEY = "captcha";
|
private static final String SESSION_KEY = "captcha";
|
||||||
|
private static final int DEFAULT_LEN = 4; // 默认长度
|
||||||
/**
|
private static final int DEFAULT_WIDTH = 130; // 默认宽度
|
||||||
* 验证验证码
|
private static final int DEFAULT_HEIGHT = 48; // 默认高度
|
||||||
*
|
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 输出验证码
|
* 输出验证码
|
||||||
@ -41,7 +28,7 @@ public class CaptchaUtil {
|
|||||||
*/
|
*/
|
||||||
public static void out(HttpServletRequest request, HttpServletResponse response)
|
public static void out(HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException {
|
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)
|
public static void out(int len, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
out(130, 48, len, request, response);
|
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,42 +62,14 @@ public class CaptchaUtil {
|
|||||||
/**
|
/**
|
||||||
* 输出验证码
|
* 输出验证码
|
||||||
*
|
*
|
||||||
* @param width 宽度
|
|
||||||
* @param height 高度
|
|
||||||
* @param len 长度
|
|
||||||
* @param font 字体
|
* @param font 字体
|
||||||
* @param request HttpServletRequest
|
* @param request HttpServletRequest
|
||||||
* @param response HttpServletResponse
|
* @param response HttpServletResponse
|
||||||
* @throws IOException IO异常
|
* @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 {
|
throws IOException {
|
||||||
outCaptcha(width, height, len, font, 1, request, response);
|
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_LEN, font, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,24 +81,9 @@ public class CaptchaUtil {
|
|||||||
* @param response HttpServletResponse
|
* @param response HttpServletResponse
|
||||||
* @throws IOException IO异常
|
* @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 {
|
throws IOException {
|
||||||
outPng(130, 48, len, font, request, response);
|
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,39 +97,46 @@ public class CaptchaUtil {
|
|||||||
* @param response HttpServletResponse
|
* @param response HttpServletResponse
|
||||||
* @throws IOException IO异常
|
* @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 {
|
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 captcha Captcha
|
||||||
* @param height 高度
|
|
||||||
* @param len 长度
|
|
||||||
* @param font 字体
|
|
||||||
* @param cType 类型
|
|
||||||
* @param request HttpServletRequest
|
* @param request HttpServletRequest
|
||||||
* @param response HttpServletResponse
|
* @param response HttpServletResponse
|
||||||
* @throws IOException IO异常
|
* @throws IOException IO异常
|
||||||
*/
|
*/
|
||||||
private static void outCaptcha(int width, int height, int len, Font font, int cType, HttpServletRequest request, HttpServletResponse response)
|
private static void out(Captcha captcha, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
setHeader(response);
|
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());
|
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
|
||||||
captcha.out(response.getOutputStream());
|
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中的验证码
|
* 清除session中的验证码
|
||||||
*
|
*
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
package com.wf.captcha;
|
package com.wf.captcha;
|
||||||
|
|
||||||
import com.wf.captcha.base.Captcha;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.geom.QuadCurve2D;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试类
|
* 测试类
|
||||||
@ -19,98 +13,59 @@ public class CaptchaTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
for (int i = 0; i < 5; i++) {
|
/*for (int i = 0; i < 10; i++) {
|
||||||
SpecCaptcha specCaptcha = new SpecCaptcha();
|
SpecCaptcha specCaptcha = new SpecCaptcha();
|
||||||
// specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER);
|
specCaptcha.setLen(4);
|
||||||
|
specCaptcha.setFont(i, 32f);
|
||||||
System.out.println(specCaptcha.text());
|
System.out.println(specCaptcha.text());
|
||||||
// specCaptcha.setFont(Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/actionj.ttf").getFile())).deriveFont(Font.BOLD, 32));
|
specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
|
||||||
specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
|
}*/
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGIf() throws Exception {
|
public void testGIf() throws Exception {
|
||||||
/*for (int i = 0; i < 5; i++) {
|
/*for (int i = 0; i < 10; i++) {
|
||||||
GifCaptcha gifCaptcha = new GifCaptcha();
|
GifCaptcha gifCaptcha = new GifCaptcha();
|
||||||
|
gifCaptcha.setLen(5);
|
||||||
|
gifCaptcha.setFont(i, 32f);
|
||||||
System.out.println(gifCaptcha.text());
|
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
|
@Test
|
||||||
public void testHan() throws Exception {
|
public void testHan() throws Exception {
|
||||||
/*for (int i = 0; i < 5; i++) {
|
/*for (int i = 0; i < 10; i++) {
|
||||||
ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
|
ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
|
||||||
System.out.println(chineseCaptcha.text());
|
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
|
@Test
|
||||||
public void testGifHan() throws Exception {
|
public void testGifHan() throws Exception {
|
||||||
/*for (int i = 0; i < 5; i++) {
|
/*for (int i = 0; i < 10; i++) {
|
||||||
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
|
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
|
||||||
System.out.println(chineseGifCaptcha.text());
|
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
|
@Test
|
||||||
public void test2() throws Exception {
|
public void testArit() throws Exception {
|
||||||
String[] colors = new String[]{"#8cc540", "#009f5d", "#019fa0", "#019fde", "#007cdc", "#887ddd", "#cd7bdd", "#ff5675", "#ff1244", "#ff8345", "#f8bd0b", "#d1d2d4"};
|
/*for (int i = 0; i < 10; i++) {
|
||||||
String[] fonts = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"};
|
ArithmeticCaptcha specCaptcha = new ArithmeticCaptcha();
|
||||||
int i = 0;
|
specCaptcha.setLen(3);
|
||||||
for (String f : fonts) {
|
specCaptcha.setFont(i, 28f);
|
||||||
i++;
|
System.out.println(specCaptcha.getArithmeticString() + " " + specCaptcha.text());
|
||||||
FileOutputStream out = new FileOutputStream(new File("D:/Java/aa" + i + ".png"));
|
specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
|
||||||
try {
|
}*/
|
||||||
int width = 130, height = 48;
|
|
||||||
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);
|
|
||||||
// 抗锯齿
|
|
||||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
|
||||||
// 画字符串
|
|
||||||
float fontSize = 32f;
|
|
||||||
Font font = Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/" + f).getFile())).deriveFont(Font.BOLD, fontSize);
|
|
||||||
g.setFont(font);
|
|
||||||
char[] chars = "N4WbS".toCharArray();
|
|
||||||
float sp = (width / chars.length - fontSize) / 2;
|
|
||||||
int j = 0;
|
|
||||||
for (char c : chars) {
|
|
||||||
j++;
|
|
||||||
g.setColor(Color.getColor(colors[j]));
|
|
||||||
float x = sp * j + fontSize * (j - 1);
|
|
||||||
float y = (height - fontSize) / 2 + fontSize;
|
|
||||||
System.out.println(x + "-" + y);
|
|
||||||
g.drawString(String.valueOf(c), x, y);
|
|
||||||
}
|
|
||||||
g.drawString("Hello", 8, 37);
|
|
||||||
//
|
|
||||||
QuadCurve2D shape = new QuadCurve2D.Double();
|
|
||||||
shape.setCurve(8, 38, 38, 10, 120, 40);
|
|
||||||
g.draw(shape);
|
|
||||||
ImageIO.write(bi, "png", out);
|
|
||||||
out.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test3() throws Exception {
|
public void testBase64() throws Exception {
|
||||||
String filePath = getClass().getResource("/actionj.ttf").getFile();
|
/*GifCaptcha specCaptcha = new GifCaptcha();
|
||||||
System.out.println(filePath);
|
System.out.println(specCaptcha.toBase64(""));*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user