1.短信防刷设置有感
我们做redis集群 可能有2种方式 :
1.使用JedisCluster
2.使用RedisTemplate
短信功能使用的是第一种
一定要注意 使用这些组件一定要写一个配置类将属性值注入到相应的+工具类里面,就像是 对一个jdbc连接赋值连接配置一样,特别是这种集群的配置更有点意思需要好好琢磨
这两种功能均遇到了一些问题
比如端口连不上 但是根据断点源码发现 没有加重试次数 该值一直为0,但是改成1 就解决了这个问题,接着在本地再次重启发现还是连不上 估计是本地环境问题,就发到docker2环境进行发布发现
可以正常启动
中间发生了不少问题,比如 我们在 yml 文件 写了配置之后 需要写一个 ExtProperties 类 该类上需要加一个注解
@ConfigurationProperties(prefix = "ext", ignoreInvalidFields = false)
prefix就是我们yml 配置的 大 key,如下:key 下面的每个key 是一个类,类下面的key 是属性
ext 大key,redisCluster 类 ,clusterNodes成员属性
ext:
swagger: # swagger is enabled. It can be disabled by pasing 'no-swagger' profile at run time as well
enabled: true
userConfiguration:
adminUsername: sms-admin
apiUsername: sms-user
adminPassword: $2a$10$ECbjM49.ZUe.YwUisEmA0.gxVMDUb81u7MqORBmKsE.Jo9PJhgYlW
apiPassword: $2a$10$S8CPC5eM6QbNaAtyO0Im6eCKtJAVuyHXmFmemP/HUtMgV2BdduL4.
couponMq:
topicName: Topic_sms_prod
tag: coupon_sms
serviceName:
vip: LIQUAN-VIP
redisCluster:
clusterNodes: 121.43.172.116:7000,121.43.172.116:7001,121.43.172.116:7002,121.43.172.116:7003,121.43.172.116:7004,121.43.172.116:7005
commandTimeout: 5
password: v7sxIHPkrT91
tryNum: 1
messageSendLimit:
oneMinuteLimit: 1
oneDayLimit: 5
在ExtProperties类中要么写set get 方法 要么直接实例化,就不需要写set 方法 ,但是需要写get 方法 否则获取对象报空指针
还有JedisCluster 的key-value 映射一般都是String,当然value也可以是其他格式,但是如果我们存的是字符串1、2、3 之类的 是可以直接使用jedisCluster.incr(key);方法对值加1
一开始我使用的是 jedisCluster.getSet(key, value); 发现根本没有用 过期时间和 值都是最新的 没起到防刷的作用,这个问题上栽了跟头浪费了时间
还有根据经验来谈 我们写redis 服务时最好都写一个redis 的 服务基类 不要在其他Java 代码里面直接使用 redis 类,有污染不方便维护
下面我们会将 集群的配置代码附上:
第一步:配置属性application-docker2.yml
ext:
redisCluster:
clusterNodes: 121.43.172.116:7000,121.43.172.116:7001,121.43.172.116:7002,121.43.172.116:7003,121.43.172.116:7004,121.43.172.116:7005
commandTimeout: 5
password: v7sxIHPkrT91
tryNum: 1
messageSendLimit:
oneMinuteLimit: 1
oneDayLimit: 5
第二步:配置属性文件
@Configuration
@ConfigurationProperties(prefix = "ext", ignoreInvalidFields = false)
public class ExtProperties {private MessageSendLimit messageSendLimit; // 方式一 不直接new 而是写set/get 方法
private final RedisCluster redisCluster = new RedisCluster(); // 直接new 只需写get 方法public RedisCluster getRedisCluster() {
return redisCluster;
}
public MessageSendLimit getMessageSendLimit() {
return messageSendLimit;
}
public void setMessageSendLimit(MessageSendLimit messageSendLimit) {
this.messageSendLimit = messageSendLimit;
}@Data
public static class RedisCluster {private int expireSeconds;
private String clusterNodes;
private int commandTimeout;
private String password;
private int timeout;
private int maxRedirections;
private int tryNum;}
@Data
public static class MessageSendLimit {
private int oneMinuteLimit;
private int oneDayLimit; }
第三步:写redis 服务类:
@Service
@Slf4j
public class RedisService {@Autowired
private JedisCluster jedisCluster;
public <T> boolean cacheObject(String key, int time ,String value) {
try {
jedisCluster.setex(key, time, value);
log.info("cacheString>>> key:{}, value:{}, expire time:{}(s) success!!!", key, value, time);
return true;
} catch (Exception t) {
log.error("cacheString>>> key:{}, value:{}, expire time:{}(s) error!!!", key, value, time, t);
return false;
}
}}
第四步:redis 集群配置类 ,需要加上@Configuration注解
@Configuration
public class RedisConfig {@Autowired
private ExtProperties extProperties;
@Bean
public JedisCluster getJedisCluster() {
RedisCluster redisCluster = extProperties.getRedisCluster();
String[] serverArray = redisCluster.getClusterNodes().split(",");
Set<HostAndPort> nodes = new HashSet<>();for (String ipPort : serverArray) {
String[] ipPortPair = ipPort.split(":");
nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim())));
}JedisPoolConfig pool = new JedisPoolConfig();
pool.setMaxWaitMillis(3000);
pool.setMaxTotal(3000);
pool.setMinIdle(10);
pool.setMaxIdle(100);JedisCluster jedisCluster = new JedisCluster(nodes, redisCluster.getCommandTimeout(), redisCluster.getMaxRedirections(), redisCluster.getTryNum(), redisCluster.getPassword(), pool);
return jedisCluster;
}
@Bean
public <V> RedisTemplate<String, V> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, V> redisTemplate = new RedisTemplate<>();
StringRedisSerializer serializer = new StringRedisSerializer();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(serializer);
redisTemplate.setValueSerializer(redisSerializer());
redisTemplate.setHashKeySerializer(serializer);
redisTemplate.setHashValueSerializer(redisSerializer());
return redisTemplate;
}
@Bean
public GenericJackson2JsonRedisSerializer redisSerializer() {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
om.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
return new GenericJackson2JsonRedisSerializer(om);
}
}
这样就大功告成了 接着就可以在其他service类直接使用了
别忘了引入pom 依赖哦~ 版本号自己定
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
}