redis(支持多数据源)
spring:
# redis链接池配置
redis:
jedis:
pool:
max-active: 20
max-wait: 5000
max-idle: 20
min-idle: 5
# 默认redis配置
redis-default:
host: 127.0.0.1
port: 1234
database: 1
password: pwd123
# redis2配置
redis2:
host: 127.0.0.1
port: 1234
database: 0
password: pwd123
@Configuration
public class RedisDynamicConfig {
@Value("${spring.redis.jedis.pool.max-active}")
private int maxActive;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean("redisTemplate")
public RedisTemplate<String, Object> redisTemplate(@Value("${spring.redis-default.host}") String hostName,
@Value("${spring.redis-default.password}") String password,
@Value("${spring.redis-default.port}") int port,
@Value("${spring.redis-default.database}") int database) {
RedisConnectionFactory redisConnectionFactory = this.getRedisConnectionFactory(hostName, password, port, database);
//创建JSON序列化器
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean("redisService")
public RedisService redisService(
@Autowired @Qualifier(value = "redisTemplate") RedisTemplate<String, Object> redisTemplate) {
return new RedisServiceImpl(redisTemplate);
}
public RedisConnectionFactory getRedisConnectionFactory(String hostName, String password, int port,int database) {
JedisConnectionFactory jedisFactory = new JedisConnectionFactory();
jedisFactory.setHostName(hostName);
jedisFactory.setPort(port);
jedisFactory.setPassword(password);
jedisFactory.setDatabase(database);
JedisPoolConfig poolConfig = new JedisPoolConfig(); // 进行连接池配置
poolConfig.setMaxTotal(maxActive);
poolConfig.setMaxIdle(maxIdle);
poolConfig.setMinIdle(minIdle);
poolConfig.setMaxWaitMillis(maxWaitMillis);
jedisFactory.setPoolConfig(poolConfig);
jedisFactory.afterPropertiesSet(); // 初始化连接池配置
return jedisFactory;
}
}
public interface RedisService {
/**
* 保存属性
*/
void set(String key, Object value, long time);
/**
* 保存属性
*/
void set(String key, Object value);
/**
* 获取属性
*/
Object get(String key);
/**
* 批量获取属性
* @param keys
* @return
*/
List<Object> mget(List<String> keys);
/**
* 删除属性
*/
void del(String key);
/**
* 批量删除属性
*/
void del(List<String> keys);
/**
* 设置过期时间
*/
Boolean expire(String key, long time);
/**
* 获取过期时间
*/
Long getExpire(String key);
/**
* 递增
* @param key
* @param delta
* @return
*/
long incr(String key, long delta);
/**
* 判断是否有该属性
*/
Boolean hasKey(String key);
/**
* 获取Hash结构中的属性
*/
Object hGet(String key, String hashKey);
/**
* 向Hash结构中放入一个属性
*/
Boolean hSet(String key, String hashKey, Object value, long time);
/**
* 向Hash结构中放入一个不存在的属性
* @param key
* @param hashKey
* @param value
* @param time 秒级
* @return
*/
Boolean hSetIfAbsent(String key, String hashKey, Object value, long time);
/**
* 向Hash结构中放入一个属性
*/
void hSet(String key, String hashKey, Object value);
/**
* hincrby
*
* @return
*/
Long hincrby(String key, String hashKey, Long num);
/**
* 直接获取整个Hash结构
*/
Map<Object, Object> hGetAll(String key);
List<Object> hGetValues(String key);
/**
* 直接设置整个Hash结构
*/
Boolean hSetAll(String key, Map<String, Object> map, long time);
/**
* 直接设置整个Hash结构
*/
void hSetAll(String key, Map<String, Object> map);
/**
* 删除Hash结构中的属性
*/
void hDel(String key, Object... hashKey);
/**
* 判断Hash结构中是否有该属性
*/
Boolean hHasKey(String key, String hashKey);
/**
* Hash结构中属性递增
*/
Long hIncr(String key, String hashKey, Long delta);
/**
* Hash结构中属性递减
*/
Long hDecr(String key, String hashKey, Long delta);
/**
* 获取Set结构
*/
Set<Object> sMembers(String key);
/**
* 向Set结构中添加属性
*/
Long sAdd(String key, Object... values);
/**
* 向Set结构中添加属性
*/
Long sAdd(long time, String key, Object... values);
/**
* 是否为Set中的属性
*/
Boolean sIsMember(String key, Object value);
/**
* 获取Set结构的长度
*/
Long sSize(String key);
/**
* 删除Set结构中的属性
*/
Long sRemove(String key, Object... values);
/**
* 获取List结构中的属性
*/
List<Object> lRange(String key, long start, long end);
/**
* 获取List结构的长度
*/
Long lSize(String key);
/**
* 根据索引获取List中的属性
*/
Object lIndex(String key, long index);
/**
* 向List结构中添加属性
*/
Long lPush(String key, Object value);
/**
* 向List结构中添加属性
*/
Long lPush(String key, Object value, long time);
/**
* 向List结构中批量添加属性
*/
Long lPushAll(String key, Object... values);
/**
* 向List结构中批量添加属性
*/
Long lPushAll(String key, Long time, Object... values);
/**
* 从List结构中移除属性
*/
Long lRemove(String key, long count, Object value);
/**
* mget
*
* @param key
* @param fields
* @return
*/
Object hmget(String key, Collection fields);
Long hlen(String key);
/**
* 向zset 中添加元素
*
* @param key
* @param value
* @param score
*/
void zadd(String key, Object value, Integer score);
/**
* 排列输出 默认 0, -1
*
* @param key
* @return
*/
Set<Object> zrange(String key);
Set<Object> reverseRange(String key, int start, int end);
/**
* 查询在指定分数范围成员数量,包括边界
* @param key
* @param minScore
* @param maxScore
* @return
*/
Long zcount(String key, Integer minScore, Integer maxScore);
Long zrem(String key, Object field);
/**
* 出队
*/
Object pop(String key);
Long ttl(String key);
Boolean setIfAbsent(String key, String value, long expire);
/**
* 线上谨慎使用!!!
* @param key
* @param count
* @return
*/
int scanCount(String key, int count);
/**
* 线上谨慎使用!!!
* @param key
* @param count
* @return
*/
Set<String> scanAll(String key, int count);
/**
* 有序集合(升序)弹出元素并删除(原子操作
* @param key
* @param resultClass
* @return 弹出的元素
* @param <T>
*/
<T> T zsetLPop(String key, Class<T> resultClass);
}
public class RedisServiceImpl implements RedisService {
public RedisServiceImpl(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
private final RedisTemplate<String, Object> redisTemplate;
@Override
public void set(String key, Object value, long time) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}
@Override
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
@Override
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
@Override
public List<Object> mget(List<String> keys) {
return redisTemplate.opsForValue().multiGet(keys);
}
@Override
public void del(String key) {
redisTemplate.delete(key);
}
@Override
public void del(List<String> keys) {
redisTemplate.delete(keys);
}
@Override
public Boolean expire(String key, long time) {
return redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
@Override
public Long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
@Override
public long incr(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}
@Override
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
@Override
public Object hGet(String key, String hashKey) {
return redisTemplate.opsForHash().get(key, hashKey);
}
@Override
public Boolean hSet(String key, String hashKey, Object value, long time) {
redisTemplate.opsForHash().put(key, hashKey, value);
return expire(key, time);
}
@Override
public Boolean hSetIfAbsent(String key, String hashKey, Object value, long time) {
redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
return expire(key, time);
}
@Override
public void hSet(String key, String hashKey, Object value) {
redisTemplate.opsForHash().put(key, hashKey, value);
}
@Override
public Long hincrby(String key, String hashKey, Long num) {
return redisTemplate.opsForHash().increment(key, hashKey, num);
}
@Override
public Map<Object, Object> hGetAll(String key) {
return redisTemplate.opsForHash().entries(key);
}
@Override
public List<Object> hGetValues(String key) {
return redisTemplate.opsForHash().values(key);
}
@Override
public Boolean hSetAll(String key, Map<String, Object> map, long time) {
redisTemplate.opsForHash().putAll(key, map);
return expire(key, time);
}
@Override
public void hSetAll(String key, Map<String, Object> map) {
redisTemplate.opsForHash().putAll(key, map);
}
@Override
public void hDel(String key, Object... hashKey) {
redisTemplate.opsForHash().delete(key, hashKey);
}
@Override
public Boolean hHasKey(String key, String hashKey) {
return redisTemplate.opsForHash().hasKey(key, hashKey);
}
@Override
public Long hIncr(String key, String hashKey, Long delta) {
return redisTemplate.opsForHash().increment(key, hashKey, delta);
}
@Override
public Long hDecr(String key, String hashKey, Long delta) {
return redisTemplate.opsForHash().increment(key, hashKey, -delta);
}
@Override
public Set<Object> sMembers(String key) {
return redisTemplate.opsForSet().members(key);
}
@Override
public Long sAdd(String key, Object... values) {
return redisTemplate.opsForSet().add(key, values);
}
@Override
public Long sAdd(long time, String key, Object... values) {
Long count = redisTemplate.opsForSet().add(key, values);
expire(key, time);
return count;
}
@Override
public Boolean sIsMember(String key, Object value) {
return redisTemplate.opsForSet().isMember(key, value);
}
@Override
public Long sSize(String key) {
return redisTemplate.opsForSet().size(key);
}
@Override
public Long sRemove(String key, Object... values) {
return redisTemplate.opsForSet().remove(key, values);
}
@Override
public List<Object> lRange(String key, long start, long end) {
return redisTemplate.opsForList().range(key, start, end);
}
@Override
public Long lSize(String key) {
return redisTemplate.opsForList().size(key);
}
@Override
public Object lIndex(String key, long index) {
return redisTemplate.opsForList().index(key, index);
}
@Override
public Long lPush(String key, Object value) {
return redisTemplate.opsForList().rightPush(key, value);
}
@Override
public Long lPush(String key, Object value, long time) {
Long index = redisTemplate.opsForList().rightPush(key, value);
expire(key, time);
return index;
}
@Override
public Long lPushAll(String key, Object... values) {
return redisTemplate.opsForList().rightPushAll(key, values);
}
@Override
public Long lPushAll(String key, Long time, Object... values) {
Long count = redisTemplate.opsForList().rightPushAll(key, values);
expire(key, time);
return count;
}
@Override
public Long lRemove(String key, long count, Object value) {
return redisTemplate.opsForList().remove(key, count, value);
}
@Override
public Object hmget(String key, Collection fields) {
return redisTemplate.opsForHash().multiGet(key, fields);
}
@Override
public Long hlen(String key) {
return redisTemplate.opsForHash().size(key);
}
@Override
public void zadd(String key, Object value, Integer score) {
redisTemplate.opsForZSet().add(key, value, score);
}
@Override
public Set<Object> zrange(String key) {
return redisTemplate.opsForZSet().range(key, 0L, -1L);
}
@Override
public Set<Object> reverseRange(String key, int start, int end) {
return redisTemplate.opsForZSet().reverseRange(key, start, end);
}
@Override
public Long zcount(String key, Integer minScore, Integer maxScore) {
return redisTemplate.opsForZSet().count(key, minScore, maxScore);
}
@Override
public Long zrem(String key, Object field) {
Long remove = redisTemplate.opsForZSet().remove(key, field);
return remove;
}
@Override
public Object pop(String key) {
return redisTemplate.opsForList().rightPop(key);
}
@Override
public Long ttl(String key) {
Long ttlTime = redisTemplate.getExpire(key, TimeUnit.SECONDS);
return ttlTime;
}
@Override
public Boolean setIfAbsent(String key, String value, long expire) {
return redisTemplate.opsForValue().setIfAbsent(key, value, expire, TimeUnit.SECONDS);
}
@Override
public int scanCount(String key, int count) {
Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keysTmp = new HashSet<>();
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(count).build());
while (cursor.hasNext()) {
keysTmp.add(new String(cursor.next()));
}
return keysTmp;
});
return keys.size();
}
@Override
public Set<String> scanAll(String key, int count) {
Set<String> keys = redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keysTmp = new HashSet<>();
Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(key).count(count).build());
while (cursor.hasNext()) {
keysTmp.add(new String(cursor.next()));
}
return keysTmp;
});
return keys;
}
@Override
public <T> T zsetLPop(String key, Class<T> resultClass) {
return redisTemplate.execute(new DefaultRedisScript<>(LuaScript.ZSET_LPOP_SCRIPT, resultClass),
Collections.singletonList(key));
}
}
public class LuaScript {
/**
* 从有序集合(升序)中弹出一个元素
*/
public static final String ZSET_LPOP_SCRIPT = "local result = redis.call('ZRANGE', KEYS[1], 0, 0)\n"
+ "local element = result[1]\n"
+ "if element then\n"
+ " redis.call('ZREM', KEYS[1], element)\n"
+ " return element\n"
+ "else\n"
+ " return nil\n"
+ "end";
}
企业微信机器人通知
@Slf4j
public class WechatUtils {
private static final RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
private static final String TEST_HOOK = "你的测试机器人HOOK";
public static void sendTestMsg(String content, MsgType msgtype) {
sendMsg(TEST_HOOK, content, msgtype);
}
public static void sendMsgByEnv(String hook, String content, MsgType msgtype) {
if (Global.isTestEnv()) {
sendTestMsg(content, msgtype);
return;
}
sendMsg(hook, content, msgtype);
}
/**
* 发送信息
* @param hook 微信机器人 robothook
* @param content 内容
* @param msgtype 内容类型,markdown / text
*/
public static void sendMsg(String hook, String content, MsgType msgtype) {
StringEntity pyload = null;
if( MsgType.TEXT == msgtype){
pyload = buildTextPyload(content);
}else if(MsgType.MARK_DOWN == msgtype){
pyload = buildMarkDownPyload(content);
}else {
pyload = buildTextPyload(content);
}
HttpPost httpPost = new HttpPost(hook);
httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
httpPost.setEntity(pyload);
httpPost.setConfig(requestConfig);
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
if(log.isDebugEnabled()){
log.debug("alerting sucess | {} - {}", hook, pyload);
}
} else {
String result = EntityUtils.toString(response.getEntity(), "utf-8");
log.warn("alerting fail | {} - {} - {}", hook, pyload, result);
}
httpClient.close();
response.close();
} catch (Exception e) {
log.error("alerting error", e);
}
}
private static StringEntity buildMarkDownPyload(String content) {
return new StringEntity(
"{"msgtype": "markdown","markdown": {"content": "" + content + ""}}",
ContentType.APPLICATION_JSON );
}
private static StringEntity buildTextPyload(String content) {
return new StringEntity(
"{"msgtype": "text","text": {"content": "" + content + ""}}",
ContentType.APPLICATION_JSON );
}
public enum MsgType {
MARK_DOWN,
TEXT;
}
}
通用RestTemplate
GET请求
@Resource(name = "restTemplate")
private RestTemplate restTemplate;
/**
* get请求
* @param url 请求地址
* @param params 参数
* @param headers heder信息
* @return 请求返回的结果
*/
public String doGet(String url, Map<String, String> params, Map<String, String> headers) {
MultiValueMap<String, String> reqParams = new LinkedMultiValueMap<>();
reqParams.setAll(params);
String reqUrl = UriComponentsBuilder.fromHttpUrl(url).queryParams(reqParams).toUriString();
try {
HttpHeaders reqHeaders = new HttpHeaders();
for (Entry<String, String> entry : headers.entrySet()) {
reqHeaders.set(entry.getKey(), entry.getValue());
}
HttpEntity entity = new HttpEntity<>(reqHeaders);
ResponseEntity<String> response = restTemplate.exchange(reqUrl, HttpMethod.GET, entity, String.class);
return response.getBody();
} catch (Exception e) {
log.error("RestServiceImpl|doGet|" + reqUrl, e);
return null;
}
}
/**
* post请求
* @param url 请求地址
* @param data post请求body参数
* @param headers heder信息
* @return 请求返回的结果
*/
public <T> String doPost(String url, T data, Map<String, String> headers) {
try {
HttpHeaders reqHeaders = new HttpHeaders();
for (Entry<String, String> entry : headers.entrySet()) {
reqHeaders.set(entry.getKey(), entry.getValue());
}
reqHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<T> entity = new HttpEntity<>(data, reqHeaders);
ResponseEntity<String> response = restTemplate.postForEntity(url, entity, String.class);
return response.getBody();
} catch (Exception e) {
log.error("RestServiceImpl|doPost", e);
return null;
}
}
AES 对称加密算法
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang.StringUtils;
/**
* * java使用AES加密解密 AES-128-ECB加密,与mysql数据库AES加密算法通用
* *
* * 数据库AES加密解密方式如下
* * -- 加密
* * SELECT to_base64(AES_ENCRYPT('明文','你的自定义密钥'));
* * -- 解密
* * SELECT AES_DECRYPT(from_base64('加密后的字符串'),'你的自定义密钥');
*/
public class AESUtils {
/**
* 加解密密钥 16位可以自己定义
*/
public static final String AES_DATA_SECURITY_KEY = "abcdef1234567890";
/**
* 算法/加密模式/填充方式
*/
private static final String AES_PKCS5P = "AES/ECB/PKCS5Padding";
/**
* 加密
*
* @param str 需要加密的字符串
* @param key 密钥
* @return
* @throws Exception
*/
public static String encrypt(String str, String key) {
if (StringUtils.isEmpty(key)) {
throw new RuntimeException("key不能为空");
}
try {
if (str == null) {
return null;
}
// 判断Key是否为16位
if (key.length() != 16) {
return null;
}
byte[] raw = key.getBytes("UTF-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// "算法/模式/补码方式"
Cipher cipher = Cipher.getInstance(AES_PKCS5P);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(str.getBytes("UTF-8"));
// 此处使用BASE64做转码功能,同时能起到2次加密的作用。
Base64.Encoder encoder = Base64.getEncoder();
return new String(encoder.encode(encrypted));
} catch (Exception ex) {
return null;
}
}
/**
* 加密
*
* @param str 需要加密的字符串
* @return
* @throws Exception
*/
public static String encrypt(String str) {
return encrypt(str, AES_DATA_SECURITY_KEY);
}
/**
* 解密
*
* @param str 需要解密的字符串
* @param key 密钥
* @return
*/
public static String decrypt(String str, String key) {
if (StringUtils.isEmpty(key)) {
throw new RuntimeException("key不能为空");
}
try {
if (str == null) {
return null;
}
// 判断Key是否为16位
if (key.length() != 16) {
return null;
}
byte[] raw = key.getBytes("UTF-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance(AES_PKCS5P);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
// 先用base64解密
byte[] encrypted = Base64.getDecoder().decode(str);
try {
byte[] original = cipher.doFinal(encrypted);
String originalString = new String(original, "UTF-8");
return originalString;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} catch (Exception ex) {
return null;
}
}
/**
* 解密
*
* @param str 需要解密的字符串
* @return
*/
public static String decrypt(String str) {
return decrypt(str, AES_DATA_SECURITY_KEY);
}
public static void main(String[] args) {
String plainText = "hello world";
System.out.println("原文: " + plainText);
String encryptedText = encrypt(plainText);
System.out.println("加密后: " + encryptedText);
String decryptedText = decrypt(encryptedText);
System.out.println("解密后: " + decryptedText);
}
}