通用公共配置

生成验证码的两种方式,SpringBoot项目,下面是完整代码,直接就可以用

公共依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- redis 缓存 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- pool 对象池,springboot2.x以后用得是lettuce,添加连接池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

<!-- 方法二需要用到的jar包 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>

配置 application.yml 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
spring:
# redis 配置
redis:
# 地址
host: localhost
# 端口,默认为6379
port: 6379
# 数据库索引
database: 0
# 密码
password:
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms

公共常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 公共常量
*/
public class ConstantCode {

/**
* 系统缓存常量
*/
public static final String KAPTCHA_KEY = "ss:kaptcha";
public static final Long REDIS_EXP_TIME = 60 * 60L;
public static final Long KAPTCHA_EXP_TIME = 60 * 3L;

/**
* 验证码宽高常量
*/
public static final Integer WIDTH = 200;
public static final Integer HEIGHT = 55;

/**
* 图片后缀名称
*/
public static final String IMG_JPG = "jpg";
public static final String IMG_PNG = "png";
public static final String IMG_JPEG = "jpeg";

}

Redis 序列化配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// 为了自己开发方便,一般直接使用 <String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);

// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();

return template;
}
}

Redis 工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.concurrent.TimeUnit;

/**
* Redis工具类
*/
@Component
@SuppressWarnings("all")
public class RedisUtils {

/**
* 日志对象
*/
private static Logger logger = LoggerFactory.getLogger(RedisUtils.class);

@Autowired
private RedisTemplate redisTemplate;

/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}

/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}

/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}

/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}

/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
logger.error("RedisUtils expire(String key,long time) failure." + e.getMessage());
return false;
}
}

/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}

/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
logger.error("RedisUtils hasKey(String key) failure." + e.getMessage());
return false;
}
}

/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}

//============================String=============================

/**
* 普通缓存获取
*
* @param key 键
* @return
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}

/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
logger.error("RedisUtils set(String key,Object value) failure." + e.getMessage());
return false;
}
}

/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
logger.error("RedisUtils set(String key,Object value,long time) failure." + e.getMessage());
return false;
}
}
}

通用返回结果封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import java.util.HashMap;

/**
* 操作消息提醒
*/
public class Result extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;

/**
* 状态码
*/
public static final String CODE_TAG = "code";

/**
* 返回内容
*/
public static final String MSG_TAG = "msg";

/**
* 数据对象
*/
public static final String DATA_TAG = "data";

/**
* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
*/
public Result() {
}

/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
*/
public Result(int code, String msg) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
}

/**
* 初始化一个新创建的 AjaxResult 对象
*
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
*/
public Result(int code, String msg, Object data) {
super.put(CODE_TAG, code);
super.put(MSG_TAG, msg);
if (!StringUtils.isEmpty(data)) {
super.put(DATA_TAG, data);
}
}

/**
* 返回成功消息
*
* @return 成功消息
*/
public static Result success() {
return Result.success("操作成功");
}

/**
* 返回成功数据
*
* @return 成功消息
*/
public static Result success(Object data) {
return Result.success("操作成功", data);
}

/**
* 返回成功消息
*
* @param msg 返回内容
* @return 成功消息
*/
public static Result success(String msg) {
return Result.success(msg, null);
}

/**
* 返回成功消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
*/
public static Result success(String msg, Object data) {
return new Result(HttpStatus.OK.value(), msg, data);
}

/**
* 返回错误消息
*
* @return
*/
public static Result error() {
return Result.error("操作失败");
}

/**
* 返回错误消息
*
* @param msg 返回内容
* @return 警告消息
*/
public static Result error(String msg) {
return Result.error(msg, null);
}

/**
* 返回错误消息
*
* @param msg 返回内容
* @param data 数据对象
* @return 警告消息
*/
public static Result error(String msg, Object data) {
return new Result(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg, data);
}

/**
* 返回错误消息
*
* @param code 状态码
* @param msg 返回内容
* @return 警告消息
*/
public static Result error(int code, String msg) {
return new Result(code, msg, null);
}

/**
* 方便链式调用
*
* @param key 键
* @param value 值
* @return 数据对象
*/
@Override
public Result put(String key, Object value) {
super.put(key, value);
return this;
}
}

方法一:Graphics2D 画图实现

使用 jdk 画图 Graphics2D 生成验证码

1、验证码工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

/**
* 验证码工具类
*/
public class VerifyCodeUtils {

/**
* 传入BufferedImage对象,并将生成好的验证码保存到BufferedImage中
*/
public static String drawRandomText(BufferedImage bufferedImage, int width, int height) {
Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();
// 验证码背景色
graphics.setColor(new Color(255, 255, 255));
// 填充线条背景
graphics.fillRect(0, 0, width, height);
graphics.setFont(new Font("宋体,楷体,微软雅黑", Font.BOLD, 35));
// 数字和字母的组合
String baseNumLetter = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder builder = new StringBuilder();
// 旋转原点的 x 坐标
int x = 40;
String ch;
Random random = new Random();
for (int i = 0; i < 4; i++) {
graphics.setColor(getRandomColor());
//设置字体旋转角度,角度小于30度
int degree = random.nextInt() % 30;
int dot = random.nextInt(baseNumLetter.length());
ch = baseNumLetter.charAt(dot) + "";
builder.append(ch);
//正向旋转
graphics.rotate(degree * Math.PI / 180, x, 45);
graphics.drawString(ch, x, 45);
//反向旋转
graphics.rotate(-degree * Math.PI / 180, x, 45);
// 字母间距记录
x += 35;
}
// 画干扰线
for (int i = 0; i < 6; i++) {
// 设置随机颜色
graphics.setColor(getRandomColor());
// 随机画线
graphics.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
}
// 添加噪点
for (int i = 0; i < 30; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
graphics.setColor(getRandomColor());
graphics.fillRect(x1, y1, 2, 2);
}
return builder.toString();
}

/**
* 随机取色
*/
private static Color getRandomColor() {
Random ran = new Random();
return new Color(ran.nextInt(256), ran.nextInt(256), ran.nextInt(256));
}
}

2、Controller 控制层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Base64;
import java.util.UUID;

@RestController
public class VerificationController {

@Autowired
private RedisUtils redisUtils;

/**
* 验证码生成工具,返回图片信息
* 适合学习练手使用,redis 呢能存在一个
* @param response
* @throws IOException
*/
@GetMapping("/getImageCode")
public void getImageCode(HttpServletResponse response) throws IOException {
// 禁止缓存
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
response.addHeader("Cache-Control", "post-check=0, pre-check=0");
response.setHeader("Pragma", "no-cache");
// 设置响应格式为png图片
response.setContentType("image/png");
// 生成图片验证码
BufferedImage image = new BufferedImage(ConstantCode.WIDTH, ConstantCode.HEIGHT, BufferedImage.TYPE_INT_RGB);
String randomText = VerifyCodeUtils.drawRandomText(image, ConstantCode.WIDTH, ConstantCode.HEIGHT);
// 存入redis
redisUtils.set(ConstantCode.KAPTCHA_KEY, randomText, ConstantCode.KAPTCHA_EXP_TIME);
ServletOutputStream out = response.getOutputStream();
ImageIO.write(image, ConstantCode.IMG_JPG, out);
out.flush();
out.close();
}

/**
* 验证码 Base64
* 可生成多个
* @return
*/
@GetMapping("/getCaptchaInfo")
public Result getCaptchaInfo() {
Result success = Result.success();
// 生成图片验证码
BufferedImage image = new BufferedImage(ConstantCode.WIDTH, ConstantCode.HEIGHT, BufferedImage.TYPE_INT_RGB);
String uuid = UUID.randomUUID().toString().replace("-", "");
// 验证码key
String verifyKey = ConstantCode.KAPTCHA_KEY + uuid;
String randomText = VerifyCodeUtils.drawRandomText(image, ConstantCode.WIDTH, ConstantCode.HEIGHT);
// 存入redis
redisUtils.set(verifyKey, randomText, ConstantCode.KAPTCHA_EXP_TIME);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", os);
} catch (IOException e) {
return Result.error(e.getMessage());
}
success.put("uuid", uuid);
success.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));
return success;
}
}

方法二:kaptcha 依赖实现

1、验证码配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
import static com.google.code.kaptcha.Constants.*;

/**
* 验证码配置
*/
@Configuration
public class CaptchaConfig {
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yes,no
properties.setProperty(KAPTCHA_BORDER, "yes");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}

@Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yes,no
properties.setProperty(KAPTCHA_BORDER, "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
// 验证码文本生成器 注意:KaptchaTextCreator的路径
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.test.demo.KaptchaTextCreator");
// 验证码文本字符间距 默认为2
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
// 干扰实现类
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}

2、验证码文本生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
import java.util.Random;

/**
* 验证码文本生成器
*/
public class KaptchaTextCreator extends DefaultTextCreator {
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");

@Override
public String getText() {
Integer result = 0;
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder();
int randomoperands = (int) Math.round(Math.random() * 2);
if (randomoperands == 0) {
result = x * y;
suChinese.append(CNUMBERS[x]);
suChinese.append("*");
suChinese.append(CNUMBERS[y]);
} else if (randomoperands == 1) {
if (!(x == 0) && y % x == 0) {
result = y / x;
suChinese.append(CNUMBERS[y]);
suChinese.append("/");
suChinese.append(CNUMBERS[x]);
} else {
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
} else if (randomoperands == 2) {
if (x >= y) {
result = x - y;
suChinese.append(CNUMBERS[x]);
suChinese.append("-");
suChinese.append(CNUMBERS[y]);
} else {
result = y - x;
suChinese.append(CNUMBERS[y]);
suChinese.append("-");
suChinese.append(CNUMBERS[x]);
}
} else {
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
suChinese.append("=?@" + result);
return suChinese.toString();
}
}

3、测试正码生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import com.google.code.kaptcha.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Base64;
import java.util.UUID;

/**
* 验证码操作处理
*/
@RestController
public class CaptchaController {
@Resource(name = "captchaProducer")
private Producer captchaProducer;

@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;

@Autowired
private RedisUtils redisUtils;

/**
* 文本验证码
*
* @return
*/
@GetMapping("/captchaCharImage")
public Result getCharCode() {
Result ajax = Result.success();
// 生成验证码
String capText = captchaProducerMath.createText();
String capStr = capText.substring(0, capText.lastIndexOf("@"));
String code = capText.substring(capText.lastIndexOf("@") + 1);
BufferedImage image = captchaProducerMath.createImage(capStr);
// 保存验证码信息
String uuid = UUID.randomUUID().toString().replace("-", "");
String verifyKey = ConstantCode.KAPTCHA_KEY + uuid;
redisUtils.set(verifyKey, code, ConstantCode.KAPTCHA_EXP_TIME);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", os);
} catch (IOException e) {
return Result.error(e.getMessage());
}
ajax.put("uuid", uuid);
ajax.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));
return ajax;
}

/**
* 生成验证码
*/
@GetMapping("/captchaMathImage")
public Result getMathCode() {
Result ajax = Result.success();
// 生成验证码
String capText = captchaProducer.createText();
BufferedImage image = captchaProducerMath.createImage(capText);

// 保存验证码信息
String uuid = UUID.randomUUID().toString().replace("-", "");
String verifyKey = ConstantCode.KAPTCHA_KEY + uuid;
redisUtils.set(verifyKey, capText, ConstantCode.KAPTCHA_EXP_TIME);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", os);
} catch (IOException e) {
return Result.error(e.getMessage());
}
ajax.put("uuid", uuid);
ajax.put("img", Base64.getEncoder().encodeToString(os.toByteArray()));
return ajax;
}
}