我们一般在做登录的时候,都会用到图像验证码,一般都是数字和字符,今天我们就来实现下。
搭建一个maven项目
导入所需的maven依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<dcsoft-framework-utility.version>2.0-SNAPSHOT</dcsoft-framework-utility.version>
</properties>
<dependencies>
<!-- redis 集成-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--阿里json包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springboot起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--spring-boot测试工具起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
然后创建启动类,把项目跑起来
@SpringBootApplication
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class ZiGaoApplication {
public static void main(String[] args) {
SpringApplication.run(ZiGaoApplication.class, args);
}
}
常量定义:
public class Consts {
/**
* 验证码
*/
public static final String LOGIN_CAPTCHA = "login_captcha:";
/**
* 一秒钟
*/
public static final long ONE_SECOND = 1;
/**
* 一分钟
*/
public static final long ONE_MINUTE = ONE_SECOND * 60;
/**
*一小时
*/
public static final long ONE_HOUR = ONE_MINUTE * 60;
/**
* 一天
*/
public static final long ONE_DAY = ONE_HOUR * 24;
}
图形验证码类:
public class CaptchaHelper {
private String randString = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private int width = 95;
private int height = 25;
public CaptchaHelper() {
}
private Font getFont() {
return new Font("Fixedsys", 1, 18);
}
private Color getRandColor(int fc, int bc) {
if (fc > 255) {
fc = 255;
}
if (bc > 255) {
bc = 255;
}
Random random = new Random();
int r = fc + random.nextInt(bc - fc - 16);
int g = fc + random.nextInt(bc - fc - 14);
int b = fc + random.nextInt(bc - fc - 18);
return new Color(r, g, b);
}
private String drawString(Graphics g, String randomString, int i) {
g.setFont(this.getFont());
Random random = new Random();
g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));
String rand = this.getRandomString(random.nextInt(this.randString.length()));
randomString = randomString + rand;
g.translate(random.nextInt(3), random.nextInt(3));
g.drawString(rand, 13 * i, 16);
return randomString;
}
private void drawLine(Graphics g) {
Random random = new Random();
int x = random.nextInt(this.width);
int y = random.nextInt(this.height);
int xl = random.nextInt(13);
int yl = random.nextInt(15);
g.drawLine(x, y, x + xl, y + yl);
}
private String getRandomString(int num) {
return String.valueOf(this.randString.charAt(num));
}
public Map<String, String> getCaptchaImg(int length) throws IOException {
if (length < 4) {
length = 4;
}
int width = 85 + 5 * (length - 4);
int height = 25;
int lineSize = 40 + 2 * (length - 4);
int stringNum = length;
BufferedImage image = new BufferedImage(width, height, 4);
Graphics g = image.getGraphics();
g.fillRect(0, 0, width, height);
g.setFont(new Font("Times New Roman", 0, 18));
g.setColor(this.getRandColor(110, 133));
for(int i = 0; i <= lineSize; ++i) {
this.drawLine(g);
}
String randomString = "";
for(int i = 1; i <= stringNum; ++i) {
randomString = this.drawString(g, randomString, i);
}
g.dispose();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image, "jpeg", out);
String base64bytes = Base64.getEncoder().encodeToString(out.toByteArray());
String src = "data:image/jpeg;base64," + base64bytes;
Map<String, String> mapResult = new LinkedHashMap();
mapResult.put("captcha", randomString);
mapResult.put("img", src);
return mapResult;
}
}
redis缓存操作类:
@Component
public class RedisRepository {
String preFixKey;
String mode;
@Resource
private RedisTemplate<String, String> redisTemplate;
@Resource
private RedisTemplate<String, String> templateForDbChange;
private boolean dbChanged = false;
private int changedDbNum = 0;
private static final SerializeConfig _config;
private static final SerializerFeature[] _features;
public RedisRepository() {
}
public void setPreFixKey(String preFixKey) {
this.preFixKey = preFixKey;
}
public String getMode() {
return this.mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public String getPreFixKey() {
return this.preFixKey;
}
public int getChangedDbNum() {
return this.changedDbNum;
}
public void setChangedDbNum(int changedDbNum) {
this.changedDbNum = changedDbNum;
}
public RedisTemplate<String, String> getTemplateForDbChange() {
return this.templateForDbChange;
}
public boolean isDbChanged() {
return this.dbChanged;
}
public RedisTemplate<String, String> getRedisTemplate() {
return this.redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void init(int dbNum) {
if (dbNum >= 0 && dbNum <= 15) {
this.templateForDbChange = new RedisTemplate();
BeanUtils.copyProperties(this.redisTemplate, this.templateForDbChange);
LettuceConnectionFactory jedisConnectionFactory = (LettuceConnectionFactory)this.redisTemplate.getConnectionFactory();
int changeNum = jedisConnectionFactory.getDatabase();
LettuceConnectionFactory tempCon2 = null;
if (this.mode.equalsIgnoreCase("cluster")) {
tempCon2 = new LettuceConnectionFactory(jedisConnectionFactory.getClusterConfiguration());
} else if (this.mode.equalsIgnoreCase("sentinel")) {
tempCon2 = new LettuceConnectionFactory(jedisConnectionFactory.getSentinelConfiguration());
} else {
tempCon2 = new LettuceConnectionFactory(jedisConnectionFactory.getStandaloneConfiguration());
}
tempCon2.setDatabase(dbNum);
tempCon2.afterPropertiesSet();
tempCon2.resetConnection();
this.templateForDbChange.setConnectionFactory(tempCon2);
this.templateForDbChange.afterPropertiesSet();
this.dbChanged = true;
this.changedDbNum = dbNum;
System.out.println("将redis从database-" + changeNum + "切换到database-" + dbNum);
}
}
private String getRedisKey(String key) {
return this.preFixKey + key;
}
public boolean addItem(String key, String value, long seconds) {
try {
if (seconds > 0L) {
if (this.dbChanged) {
this.templateForDbChange.opsForValue().set(this.getRedisKey(key), value, seconds, TimeUnit.SECONDS);
} else {
this.redisTemplate.opsForValue().set(this.getRedisKey(key), value, seconds, TimeUnit.SECONDS);
}
} else {
this.addForever(this.getRedisKey(key), value);
}
return true;
} catch (Exception var6) {
var6.printStackTrace();
return false;
}
}
public boolean addItem(String key, Object object, long seconds) {
return object.getClass().equals("".getClass()) ? this.addItem(key, (String)object, seconds) : this.addItem(key, this.object2Json(object), seconds);
}
public boolean addForever(String key, String item) {
try {
if (this.dbChanged) {
this.templateForDbChange.opsForValue().set(this.getRedisKey(key), item);
} else {
this.redisTemplate.opsForValue().set(this.getRedisKey(key), item);
}
return true;
} catch (Exception var4) {
var4.printStackTrace();
return false;
}
}
public boolean addForever(String key, Object object) {
return object.getClass().equals("".getClass()) ? this.addForever(key, (String)object) : this.addForever(key, this.object2Json(object));
}
public boolean updateItem(String key, String value, long seconds) {
return this.addItem(key, value, seconds);
}
public boolean updateItem(String key, Object object, long seconds) {
return object.getClass().equals("".getClass()) ? this.updateItem(key, object, seconds) : this.updateItem(key, this.object2Json(object), seconds);
}
public boolean updateExpireTime(String key, long seconds) throws Exception {
if (seconds < 0L) {
throw new Exception("有效期不能小于0 !");
} else {
try {
if (this.dbChanged) {
this.templateForDbChange.expire(this.getRedisKey(key), seconds, TimeUnit.SECONDS);
} else {
this.redisTemplate.expire(this.getRedisKey(key), seconds, TimeUnit.SECONDS);
}
return true;
} catch (Exception var5) {
var5.printStackTrace();
return false;
}
}
}
public void removeByKey(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
if (this.dbChanged) {
this.templateForDbChange.delete(this.getRedisKey(key[0]));
} else {
this.redisTemplate.delete(this.getRedisKey(key[0]));
}
} else {
List<String> listKeys = CollectionUtils.arrayToList(key);
List<String> listNewKeys = new ArrayList();
listKeys.forEach((k) -> {
listNewKeys.add(this.getRedisKey(k));
});
if (this.dbChanged) {
this.templateForDbChange.delete(listNewKeys);
} else {
this.redisTemplate.delete(listNewKeys);
}
}
}
}
public Long removeByRegex(String pattern) {
Set keys;
if (this.dbChanged) {
keys = this.templateForDbChange.keys(this.getRedisKey(pattern));
return this.templateForDbChange.delete(keys);
} else {
keys = this.redisTemplate.keys(this.getRedisKey(pattern));
return this.redisTemplate.delete(keys);
}
}
public boolean isExists(String key) {
return this.dbChanged ? this.templateForDbChange.hasKey(this.getRedisKey(key)) : this.redisTemplate.hasKey(this.getRedisKey(key));
}
public String getItem(String key) {
if (null == key) {
return null;
} else {
String obj = null;
if (this.dbChanged) {
obj = (String)this.templateForDbChange.opsForValue().get(this.getRedisKey(key));
} else {
String tmp = (String)this.redisTemplate.opsForValue().get(this.getRedisKey(key));
obj = tmp;
}
return obj;
}
}
public Long increment(String key) {
if (null == key) {
return 0L;
} else {
Long obj = null;
if (this.dbChanged) {
obj = this.templateForDbChange.opsForValue().increment(this.getRedisKey(key));
} else {
obj = this.redisTemplate.opsForValue().increment(this.getRedisKey(key));
}
return obj;
}
}
public Long increment(String key, long delta) {
if (null == key) {
return 0L;
} else {
Long obj = null;
if (this.dbChanged) {
obj = this.templateForDbChange.opsForValue().increment(this.getRedisKey(key), delta);
} else {
obj = this.redisTemplate.opsForValue().increment(this.getRedisKey(key), delta);
}
return obj;
}
}
public Long leftPush(String key, Object obj) {
long l = -1L;
if (this.dbChanged) {
l = this.templateForDbChange.opsForList().leftPush(key, this.object2Json(obj));
} else {
l = this.redisTemplate.opsForList().leftPush(key, this.object2Json(obj));
}
return l;
}
public String rightPop(String key) {
String str = null;
if (this.dbChanged) {
str = (String)this.templateForDbChange.opsForList().rightPop(key);
} else {
str = (String)this.redisTemplate.opsForList().rightPop(key);
}
return str;
}
public void trim(String key, long start, long end) {
if (this.dbChanged) {
this.templateForDbChange.opsForList().trim(key, start, end);
} else {
this.redisTemplate.opsForList().trim(key, start, end);
}
}
public long size(String key) {
return this.dbChanged ? this.templateForDbChange.opsForList().size(key) : this.redisTemplate.opsForList().size(key);
}
private String object2Json(Object obj) {
String json = JSON.toJSONString(obj, _config, _features);
return json;
}
static {
_features = new SerializerFeature[]{SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteNullBooleanAsFalse, SerializerFeature.WriteDateUseDateFormat};
_config = new SerializeConfig();
}
}
数据格式返回类:
public class ResponseMessage implements Serializable {
int status;
Object message;
String errmsg;
public int getStatus() {
return this.status;
}
public void setStatus(int status) {
this.status = status;
}
public Object getMessage() {
return this.message;
}
public void setMessage(Object message) {
this.message = message;
}
public String getErrmsg() {
return this.errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public ResponseMessage() {
}
public ResponseMessage(int status) {
this.status = status;
}
public ResponseMessage(Object data) {
this.status = 0;
this.message = data;
}
public ResponseMessage(int status, Object data) {
this.status = status;
this.message = data;
}
public ResponseMessage(int status, Object data, String err) {
this.status = status;
this.message = data;
this.errmsg = err;
}
public ResponseMessage(int status, String err) {
this.status = status;
this.errmsg = err;
}
}
Controller层公共类:
public class BaseController {
//日志
public Logger logger = LoggerFactory.getLogger(this.getClass());
}
Controller层类
@RestController
@RequestMapping("/verify")
public class VerifyCodeController extends BaseController{
//redis 缓存操作
@Autowired
RedisRepository redisRepository;
/**
* 获取验证码
* @return
*/
@GetMapping("/code")
public ResponseMessage getGeneratCaptcha() {
ResponseMessage responseMessage = new ResponseMessage(0);
try {
CaptchaHelper captchaHelper = new CaptchaHelper();
Map<String, String> captchaMap = new LinkedHashMap<>();
// 生成4位随机验证码
captchaMap = captchaHelper.getCaptchaImg(4);
// 封装后返回
String captchaKey = UtilsCodes.genernateGuid();
Map<String, Object> mapResult = new LinkedHashMap<>();
mapResult.put("captchaKey", captchaKey);
mapResult.put("img", captchaMap.get("img"));
responseMessage.setMessage(mapResult);
// redis缓存验证码1分钟
Map<String, Object> mapCache = new LinkedHashMap<>();
mapCache.put(captchaKey, captchaMap.get("captcha"));
redisRepository.addItem(Consts.LOGIN_CAPTCHA + captchaKey, mapCache, Consts.ONE_MINUTE);
} catch (Exception ex) {
logger.error("生成验证码异常", ex);
responseMessage.setStatus(-1);
responseMessage.setMessage("生成验证码异常" + ex.getMessage());
}
return responseMessage;
}
}
application配置文件:
server:
port: 8888
servlet:
# 上下文路径
context-path: /api
tomcat:
uri-encoding: UTF-8
# redis 配置
ccvb:
framework:
redis:
# 前缀
prefix: 'zigao:'
# 模式,默认单例
mode: single
我们来用post测试下:
复制验证码到浏览器进行测试:
验证码出来了。