内容速览:
1.Kaptcha 框架介绍与配置类开发2.池化思想应⽤-Redis6.X配置连接池实战连接池好处
3.实战图形验证码接口编写
4.结果测试
Kaptcha 框架介绍 ⾕歌开源的⼀个可⾼度配置的实⽤验证码⽣成⼯具
验证码的字体/⼤⼩/颜⾊
验证码内容的范围(数字,字⺟,中⽂汉字!)
验证码图⽚的⼤⼩,边框,边框粗细,边框颜⾊
验证码的⼲扰线
验证码的样式(⻥眼样式、3D、普通模糊)
聚合⼯程依赖添加(使⽤国内baomidou⼆次封装的springboot整合starter)
<!--kaptcha依赖包-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>kaptcha-spring-bootstarter</artifactId>
<version>1.1.0</version>
</dependency>
配置类
@Configuration
public class CaptchaConfig {
@Bean
@Qualifier("captchaProducer")
public DefaultKaptcha kaptcha() {
DefaultKaptcha kaptcha = new DefaultKaptcha();
Properties properties = new Properties();
//
properties.setProperty(Constants.KAPTCHA_BORDER, "yes");
//
properties.setProperty(Constants.KAPTCHA_BORDER_COLOR, "220,220,220");
//
//properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_COLOR, "38,29,12");
//
properties.setProperty(Constants.KAPTCHA_IMAGE_WIDTH, "147");
//
properties.setProperty(Constants.KAPTCHA_IMAGE_HEIGHT, "34");
//
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_SIZE, "25");
//
//properties.setProperty(Constants.KAPTCHA_SESSION_KEY, "code");
//验证码个数
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
//
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Courier");
//字体间隔
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_SPACE,"8");
//⼲扰线颜⾊
//
properties.setProperty(Constants.KAPTCHA_NOISE_COLOR, "white");
//⼲扰实现类
properties.setProperty(Constants.KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
//图⽚样式
properties.setProperty(Constants.KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.WaterRipple");
//⽂字来源
properties.setProperty(Constants.KAPTCHA_TEXTPRODUCER_CHAR_STRING, "0123456789");
Config config = new Config(properties);
kaptcha.setConfig(config);
return kaptcha;
}
}
池化思想应⽤-Redis6.X配置连接池实战连接池好处
使⽤连接池不⽤每次都⾛三次握⼿、每次都关闭Jedis相对于直连,使⽤相对麻烦,在资源管理上需要很多参数来保证,规划不合理也会出现问题
如果pool已经分配了maxActive个jedis实例,则此时pool的状态就成exhausted了
Maven
<!--redis客户端-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置Redis连接
redis:
client-type: jedis
host: 127.0.0.1
password: 123456
port: 6379
jedis:
pool:
# 连接池最⼤连接数(使⽤负值表示没有限制)
max-active: 100
# 连接池中的最⼤空闲连接
max-idle: 100
# 连接池中的最⼩空闲连接
min-idle: 100
# 连接池最⼤阻塞等待时间(使⽤负值表示没有限制)
max-wait: 60000
注意将配置里的host和password改为你自己的
序列化配置
@Configuration
public class RedisTemplateConfiguration {
@Bean
public RedisTemplate<Object, Object>
redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使⽤Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置key和value的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// 设置hashKey和hashValue的序列化规则
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
}
实战图形验证码接口编写:
@RestController
@RequestMapping("/api/v1/notify")
@Slf4j
public class NotifyController {
public static final int CAPTCHA_CODE_EXPIRED = 60 * 1000 * 10;
@Autowired
private Producer captchaProduce;
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 图形验证码生成流程
* 1.用captcha创建文本 String captchaText = captchaProduce.createText();
* 2.生成文本图像 BufferedImage bufferedImage = captchaProduce.createImage(captchaText);
* 3.用流写出 try(ServletOutputStream outputStream = response.getOutputStream();) {
* ImageIO.write(bufferedImage,"jpg",outputStream);
* outputStream.flush();
* @param request
* @param response
*/
@GetMapping("captcha")
public void getCaptcha(HttpServletRequest request, HttpServletResponse response){
String captchaText = captchaProduce.createText();
log.info("验证码内容{}",captchaText);
redisTemplate.opsForValue().set(getCaptchaKey(request),captchaText,CAPTCHA_CODE_EXPIRED, TimeUnit.SECONDS);
BufferedImage bufferedImage = captchaProduce.createImage(captchaText);
try(ServletOutputStream outputStream = response.getOutputStream();) {
ImageIO.write(bufferedImage,"jpg",outputStream);
outputStream.flush();
}catch (Exception e){
log.info("图形验证码异常");
}
}
/**
使用用户ip加user-agent并用md5进行加密
**/
private String getCaptchaKey(HttpServletRequest request){
String ip = CommonUtil.getIpAddr(request);
String userAgent = request.getHeader("User-Agent");
String key = "account-service:captcha:"+CommonUtil.MD5(ip+userAgent);
log.info("key{}",key);
return key;
}
}
CommonUtil工具类,直接cv即可,在工作中也是这样:
@Slf4j
public class CommonUtil {
/**
* 获取ip
*
* @param request
* @return
*/
public static String
getIpAddr(HttpServletRequest request) {
String ipAddress = null;
try {
ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null ||
ipAddress.length() == 0 ||
"unknown".equalsIgnoreCase(ipAddress)) {
ipAddress =
request.getHeader("Proxy-Client-IP");
}
if (ipAddress == null ||
ipAddress.length() == 0 ||
"unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddress == null ||
ipAddress.length() == 0 ||
"unknown".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1")) {
// 根据⽹卡取本机配置的IP
InetAddress inet = null;
try {
inet =
InetAddress.getLocalHost();
} catch (UnknownHostException e)
{
log.warn("[]",e);
}
ipAddress =
inet.getHostAddress();
}
}
// 对于通过多个代理的情况,第⼀个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null &&
ipAddress.length() > 15) {
// "***.***.***.***".length()
// = 15
if (ipAddress.indexOf(",") > 0) {
ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
}
}
} catch (Exception e) {
ipAddress = "";
}
return ipAddress;
}
/**
* 获取全部请求头
* @param request
* @return
*/
public static Map<String, String>
getAllRequestHeader(HttpServletRequest request){
Enumeration<String> headerNames = request.getHeaderNames();
Map<String, String> map = new HashMap<>();
while (headerNames.hasMoreElements()) {
String key = (String)headerNames.nextElement();
//根据名称获取请求头的值
String value = request.getHeader(key);
map.put(key,value);
}
return map;
}
/**
* MD5加密
*
* @param data
* @return
*/
public static String MD5(String data) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] array = md.digest(data.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte item : array) {
sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString().toUpperCase();
} catch (Exception exception) {
}
return null;
}
/**
* 获取验证码随机数
*
* @param length
* @return
*/
public static String getRandomCode(int length) {
String sources = "0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder();
for (int j = 0; j < length; j++) {
sb.append(sources.charAt(random.nextInt(9)));
}
return sb.toString();
}
/**
* 获取当前时间戳
*
* @return
*/
public static long getCurrentTimestamp() {
return System.currentTimeMillis();
}
/**
* ⽣成uuid
*
* @return
*/
public static String generateUUID() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
}
/**
* 获取随机⻓度的串
*
* @param length
* @return
*/
private static final String ALL_CHAR_NUM = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static String getStringNumRandom(int length) {
//⽣成随机数字和字⺟,
Random random = new Random();
StringBuilder saltString = new
StringBuilder(length);
for (int i = 1; i <= length; ++i) {
saltString.append(ALL_CHAR_NUM.charAt(random.nextInt(ALL_CHAR_NUM.length())));
}
return saltString.toString();
}
/**
* 响应json数据给前端
*
* @param response
* @param obj
*/
public static void
sendJsonMessage(HttpServletResponse response, Object obj) {
response.setContentType("application/json;charset=utf-8");
try (PrintWriter writer =
response.getWriter()) {
writer.print(JsonUtil.obj2Json(obj));
response.flushBuffer();
} catch (IOException e) {
log.warn("响应json数据给前端异常:{}",e);
}
}
}
浏览器访问结果如下:
同时控制台打印:
redis可视化工具查看: