1.获取图形验证码接口
功能要求
1、随机生成6位字符
2、将字符生成base64位格式的图片,返回给前端
3、将生成的字符存储到redis中,用匿名身份id(clientId)作为key,验证码作为value。
clientId通过/login/getClientId接口获取
4、验证码15分钟后过期
依赖包
XML
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.10</version>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.7.5</version>
</dependency>
redis缓存配置并完善图形验证码接口
# redis配置
redis:
database: 0
port: 6379
lettuce:
pool:
#连接池中最大空闲连接数为 30。这意味着连接池可以保持最多 30 个空闲的 Redis 连接,以便在需要时重用。
max-idle: 30
#连接池中最小空闲连接数为 10。这表示连接池至少会保持 10 个空闲连接,以便在需要时快速获取可用连接。
min-idle: 10
#连接池中的最大活动连接数为 30。这是指连接池在同一时间可以支持的最大活动(使用中)连接数量。
max-active: 30
#当连接池已用尽且达到最大活动连接数时,从连接池获取连接的最大等待时间为 10,000 毫秒(10 秒)。如果在等待时间内没有可用连接,将抛出连接超时异常。
max-wait: 10000
# 应用程序关闭时Lettuce 将等待最多 3 秒钟来完成关闭操作。如果超过这个时间仍未完成,则会强制关闭连接。
shutdown-timeout: 3000
host: 127.0.0.1
RedisTemplateDefaultConfig.java
java
package com.bage.common.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.CachingConfigurerSupport;
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;
/**
* Redis Template 配置
**/
@ConditionalOnProperty(prefix = "sys",name = "redis-template-config",havingValue = "true")
@Configuration
@Slf4j
public class RedisTemplateDefaultConfig<T> {
/**
* redisTemplate相关配置
*
* @param factory
* @return
*/
@Bean
public RedisTemplate<String, T> redisTemplate(RedisConnectionFactory factory) {
log.info("RedisTemplateConfig init start ...");
RedisTemplate<String, T> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer<Object> jacksonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jacksonSerializer.setObjectMapper(om);
// 值采用json序列化
template.setValueSerializer(jacksonSerializer);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
// 设置hash key 和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSerializer);
template.afterPropertiesSet();
log.info("RedisTemplateConfig init end");
return template;
}
}
LoginController.java
java
import com.bage.finance.biz.dto.form.GetBase64CodeForm;
import com.bage.finance.biz.service.MemberLoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 啟王朝
* date2024/6/6 18:24
*/
@Api(tags = "用户登录模块")
@RestController
@RequestMapping("/login")
@RequiredArgsConstructor
/** @RequiredArgsConstructor final
* 作用: 可以省略 @Autowired 和 @Rescuorce 需要注入包的前面必须加上final
*/
@Slf4j
public class LoginController {
final MemberLoginService memberLoginService;
// 获得游客登录的getClientId
@ApiOperation(value = "获取客户端id")
@GetMapping("/getClientId")
public com.bage.common.dto.ApiResponse<String> getClientId() {
String clientId = memberLoginService.getClientId();
return com.bage.common.dto.ApiResponse.success(clientId);
}
/**
* 作用:
*/
@ApiOperation(value = "生成base64位格式的图片")
@GetMapping("/getBase6Code")
/**
* 作用: GetBase64CodeForm form 是将生成的字符存储到redis中,用匿名身份id(clientId)作为key,验证码作为value。
* 0
*/
// @Validated 必须加统一拦截才能起作用
public com.bage.common.dto.ApiResponse<String> getBase64Code(@Validated @ModelAttribute GetBase64CodeForm form) {
// 返回的是code 为Base64的验证码图片
String code = memberLoginService.getBase64Code(form);
return com.bage.common.dto.ApiResponse.success(code);
}
}
MemberLoginService.java
java
import com.bage.finance.biz.dto.form.GetBase64CodeForm;
/**
* @Author:啟王朝
* @name:MemberLoginService
* @Date:2024/6/6 18:18
* @Filename:MemberLoginService
*/
public interface MemberLoginService {
// 获取客户端id
String getClientId();
/**
* 作用:获得Base64的图形编码
*/
String getBase64Code(GetBase64CodeForm form);
}
MemberLoginServiceImpl.java
java
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.bage.finance.biz.dto.form.GetBase64CodeForm;
import com.bage.finance.biz.service.MemberLoginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static com.bage.finance.biz.constant.RedisKeyConstant.GRAPHIC_VERIFICATION_CODE;
/**
* @author 啟王朝
* date2024/6/6 18:19
*/
@Service
@Slf4j
@RequiredArgsConstructor // 构造参数的注解
public class MemberLoginServiceImpl implements MemberLoginService {
final RedisTemplate<String, String> redisTemplate;
/**
* @Date:获取客户端id // date变量下面会用内置函数进行赋值
* @Author:
* @return:
*/
@Override
public String getClientId() {
return UUID.randomUUID().toString().replace("-", "");
}
/**
* 作用:获取图形验证码界面
*/
@Override
public String getBase64Code(GetBase64CodeForm form) {
// TODO CaptchaUtil 用工具形成验证码图片
/**
* 作用:
* <dependency>
* <groupId>cn.hutool</groupId>
* <artifactId>hutool-all</artifactId>
* <version>5.8.10</version>
* </dependency>
* 300,192代表长和宽 5 代表5个字符 lineCount的数字越大,代表的数字越模糊 1000
*/
LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(300, 192, 5, 1000);
// 将验证码内容读出来
String code = lineCaptcha.getCode();
// todo 将验证码保存到redis中
redisTemplate.opsForValue().set(GRAPHIC_VERIFICATION_CODE + form.getClientId(), code,15, TimeUnit.MINUTES);
// 返回base64的图形验证码
return lineCaptcha.getImageBase64();
}
}