1.请参见项目代码地址
一.集成redis
1.在common模块中添加redis依赖以及池连接工厂。在common中编写redis工具类RedisCache。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
public class RedisCache {
@Autowired
public RedisTemplate redisTemplate;
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
public boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS);
}
public Boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
public Boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
public Long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
public <T> Long setCacheList(final String key, final List<T> dataList) {
return redisTemplate.opsForList().rightPushAll(key, dataList);
}
public <T> List<T> getCacheList(final String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
Iterator<T> it = dataSet.iterator();
while (it.hasNext()) {
setOperation.add(it.next());
}
return setOperation;
}
public <T> Set<T> getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
public <T> Map<String, T> getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
public <T> T getCacheMapValue(final String key, final String hKey) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
public void delCacheMapValue(final String key, final String hKey) {
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hKey);
}
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}
}
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0
spring.redis.password=
spring.redis.timeout=1000
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-wait=-1ms
二.验证码功能(图形验证码/数学验证码)
1.在framework中添加验证码依赖,在父工程中添加相关的依赖管理。
<properties>
<kaptcha.version>2.3.2</kaptcha.version>
</properties>
<dependencyManagement>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
</dependencyManagement>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
2.编写验证码配置类CaptchaConfig配置bean以及自定义验证码文本生成器KaptchaTextCreator。
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();
}
}
@Configuration
public class CaptchaConfig {
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean() {
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
properties.setProperty(KAPTCHA_BORDER_COLOR, "yes");
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
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();
properties.setProperty(KAPTCHA_BORDER, "yes");
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.mashirro.framework.config.KaptchaTextCreator");
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
2.编写配置类RuoYiConfig
@Component
@ConfigurationProperties(prefix = "ruoyi")
public class RuoYiConfig {
private static String captchaType;
public static String getCaptchaType() {
return captchaType;
}
public void setCaptchaType(String captchaType) {
RuoYiConfig.captchaType = captchaType;
}
}
3.配置文件中添加下面配置
ruoyi.captchaType=math
4.编写验证码控制器CaptchaController
@RestController
public class CaptchaController {
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;
@Autowired
private RedisCache redisCache;
@GetMapping("/captchaImage")
public AjaxResult getCode(HttpServletResponse response) throws IOException {
AjaxResult ajax = AjaxResult.success();
String uuid = IdUtil.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
String capStr = null, code = null;
BufferedImage image = null;
String captchaType = RuoYiConfig.getCaptchaType();
if ("math".equals(captchaType)) {
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
} else if ("char".equals(captchaType)) {
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", os);
} catch (IOException e) {
return AjaxResult.error(e.getMessage());
}
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
}
}
三.使用postman测试验证码
四.存在的问题:使用redis工具查看为二进制数据,对开发者不友好
4.1 注意
1.用户自定义类型和原始类型之间的转换通过RedisSerializer接口(负责序列化过程)在Spring Data Redis中处理。
2.JDkserializationRedisserializer是RestTemplate类默认的序列化方式,缺点:(1)要求存储的对象必须实现java.io.Serializable接口(2)存储的为二进制数据,这对开发者不友好(3)序列化后的结果非常庞大,是JSON格式的5倍左右,这样就会消耗redis服务器的大量内存。优点:反序列化时不需要提供(传入)类型信息(class)。
3.StringRedisserializer是StringRedisTemplate默认的序列化方式,推荐使用!
4.GenericJackson2JsonRedisSerializer将对象序列化成json存储,不需要实现Serializable接口,推荐使用。GenericJackson2JsonRedisSerializer序列化器需要使用jackson包。
5.建议Key/hashKey都用StringRedisSerializer来序列化,Value/hashValue分为两种情况:(1)简单的String字符串我们使用StringRedisSerializer(2)存储对象,我们建议使用GenericJackson2JsonRedisSerializer。
4.2 解决方法–>配置序列化器
1.在framework模块中编写RedisConfig–>为RedisTemplate配置序列化器。
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
4.3 再次使用postman验证
|