时间格式工具类:
具体代码:
import cn.hutool.core.date.format.FastDateFormat;
import java.util.Date;
import static com.sugon.cloud.lowcode.utils.ObjectUtil.isNotNull;
/**
* @desc 时间工具类
*/
public class DateUtil {
public static final String COMMON_DATE = "yyyy-MM-dd hh:mm:ss";
public static final String TIME_STAMP = "yyyyMMddhhmmss";
/**
* 格式化时间
*
* @param date 时间
* @param format 时间格式化
* @return
*/
public static String formatDate(Date date, String format) {
if (isNotNull(date)) {
return FastDateFormat.getInstance(format).format(date);
}
return null;
}
}
示例:
// 时间戳格式
String key_1 = formatDate(new Date(), TIME_STAMP);
// 普通时间格式
String key_2 = formatDate(new Date(), COMMON_DATE);
RedisCache工具类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
@Component
public class RedisCache {
@Autowired
private RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value)
{
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
{
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout)
{
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit)
{
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获取有效时间
*
* @param key Redis键
* @return 有效时间
*/
public long getExpire(final String key)
{
return redisTemplate.getExpire(key);
}
/**
* 判断 key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public Boolean hasKey(String key)
{
return redisTemplate.hasKey(key);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key)
{
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public void deleteObject(String key)
{
redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public void deleteObject(final Collection collection)
{
redisTemplate.delete(collection);
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList)
{
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key)
{
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
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;
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public <T> Set<T> getCacheSet(final String key)
{
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
{
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key)
{
return redisTemplate.opsForHash().entries(key);
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public Set<String> getCacheMapKeys(final String key)
{
return redisTemplate.opsForHash().keys(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
{
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey)
{
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
{
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 删除Hash中的某条数据
*
* @param key Redis键
* @param hKey Hash键
* @return 是否成功
*/
public boolean deleteCacheMapValue(final String key, final String hKey)
{
return redisTemplate.opsForHash().delete(key, hKey) > 0;
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern)
{
return redisTemplate.keys(pattern);
}
}
基于RedisTemplate的Redis分布式锁:
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 基于RedisTemplate的Redis分布式锁
*/
@Component
public class RedisLockTool {
private static final Logger logger = LoggerFactory.getLogger(RedisLockTool.class);
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RedisTemplate redisTemplate;
/**
* 默认锁的超时时间(毫秒)
*/
public static final Integer DEFAULT_LOCK_EXP = 3000;
/**
* 默认redis的超时时间(毫秒)
*/
public static final Long DEFAULT_REDIS_TIMEOUT = 3000L;
private static final RedisScript<Long> SCRIPT_DEL = new DefaultRedisScript("if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end", Long.class);
//private static final RedisScript<String> SCRIPT_LOCK = new DefaultRedisScript("return redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2])", String.class);
private static final RedisScript<Long> SCRIPT_LOCK = new DefaultRedisScript("if redis.call('SET', KEYS[1], ARGV[1], 'NX', 'PX', ARGV[2]) then return 1 else return 0 end", Long.class);
/**
* 加锁
*
* @param key 锁的key
* @param identifier 锁标识
* @param lockExp 锁的超时时间 毫秒
* @param timeout 超时时间
* @return 锁标识 null表示加锁失败
*/
public String lock(String key, String identifier, int lockExp, long timeout) {
identifier = getIdentifier(identifier);
key = getKey(key);
// 根据并发调整超时时间
long end = System.currentTimeMillis() + timeout;
while (System.currentTimeMillis() < end) {
if (setNx(key, identifier, lockExp)) {
// 返回value值,用于释放锁时间确认
logger.info("lock success, key:{}, identifier:{}", key, identifier);
return identifier;
} else {
logger.info("lock fail, key:{}", key);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// 业务自行处理
Thread.currentThread().interrupt();
}
}
return null;
}
private String getIdentifier(String identifier) {
if (StrUtil.isBlank(identifier)) {
identifier = DateUtil.now() + "-" + getLocalHostName();
}
return identifier;
}
private String getLocalHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
logger.error("InetAddress.getLocalHost出现异常", e);
return StrUtil.EMPTY;
}
}
public String getValue(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
public String getLockValue(String key) {
return stringRedisTemplate.opsForValue().get(getKey(key));
}
public String getKey(String keyName) {
return "LOCK:" + keyName;
}
private void remove(String key) {
stringRedisTemplate.delete(key);
}
/**
* 释放锁
*
* @param key 锁的key
* @param identifier 释放锁的标识
* @return
*/
public boolean unlock(String key, String identifier) {
key = getKey(key);
Object execute = redisTemplate.execute(SCRIPT_DEL, Collections.singletonList(key), identifier);
return Objects.equals(execute, 1L);
//return StrUtil.equals((String)execute, "1");
}
/**
* @param key
* @param value
* @param ms
* @return
*/
private boolean setNx(final String key, final String value, int ms) {
try {
Object execute = redisTemplate.execute(SCRIPT_LOCK, Collections.singletonList(key), value, ms);
return Objects.equals(execute, 1L);
//return "1".equals(execute);
} catch (Exception e) {
logger.error("lock失败------------", e);
logger.error("redis setNxEx error, key : {}", key);
return false;
}
}
private void expireByMill(String key, long exp) {
stringRedisTemplate.expire(key, exp, TimeUnit.MILLISECONDS);
}
/**
* @param key
* @return 秒
*/
public Long ttl(String key) {
return stringRedisTemplate.getExpire(key);
}
public String getUUIDIdentifier() {
return UUID.randomUUID().toString().replace("-","");
}
}
对Redis的一些常用操作:
import cn.hutool.core.collection.CollUtil;
import com.sugon.cloud.dav.cache.lock.RedisLockTool;
import com.sugon.cloud.dav.config.RedisCacheConfig;
import com.sugon.cloud.dav.dto.ViewDashboardDataset;
import com.sugon.cloud.dav.util.cache.CacheKeyUtil;
import com.sugon.cloud.dav.util.cache.RedisCache;
import com.sugon.cloud.dav.v2.domain.model.entity.datacontainer.cache.ViewDatasetListResult;
import com.sugon.cloud.dav.v2.domain.model.valueobject.datacontainer.DatasetId;
import com.sugon.cloud.dav.v2.domain.model.valueobject.system.UserId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DatasetCacheRepository {
@Autowired
private RedisLockTool redisLockTool;
@Autowired
private RedisCache redisCache;
@Autowired
private RedisCacheConfig redisCacheConfig;
// 查询缓存
public ViewDatasetListResult queryViewDatasetList(UserId userIdObj) {
ViewDatasetListResult result = null;
// redisKey作为LockKey
String redisKey = calculateViewDatasetListKey(userIdObj);
String uuidIdentifier = redisLockTool.getUUIDIdentifier();
try {
// 加锁
redisLockTool.lock(redisKey, uuidIdentifier , RedisLockTool.DEFAULT_LOCK_EXP, RedisLockTool.DEFAULT_REDIS_TIMEOUT);
// 查询
result = handleQueryViewDatasetList(userIdObj, redisKey);
return result;
} finally {
// 解锁
redisLockTool.unlock(redisKey, uuidIdentifier);
}
}
private ViewDatasetListResult handleQueryViewDatasetList(UserId userIdObj, String redisKey) {
ViewDatasetListResult result = new ViewDatasetListResult();
result.setUserId(userIdObj.getId());
if (!existDatasetListKey(redisKey)) {
result.setExist(false);
return result;
} else {
result.setExist(true);
}
// 查询
List<ViewDashboardDataset> cacheList = redisCache.getCacheList(redisKey);
result.setDatasetList(cacheList);
return result;
}
// 写入缓存
/**
* 将工作表集合放入缓存
*/
public void pushViewDatasetList(UserId userIdObj, List<ViewDashboardDataset> list) {
// redisKey作为LockKey
String redisKey = calculateViewDatasetListKey(userIdObj);
String uuidIdentifier = redisLockTool.getUUIDIdentifier();
try {
// 加锁
redisLockTool.lock(redisKey, uuidIdentifier , RedisLockTool.DEFAULT_LOCK_EXP, RedisLockTool.DEFAULT_REDIS_TIMEOUT);
// 真正的执行逻辑
handlePushViewDatasetList(userIdObj, list);
} finally {
// 解锁
redisLockTool.unlock(redisKey, uuidIdentifier);
}
}
/**
* 将工作表集合放入缓存
*/
private void handlePushViewDatasetList(UserId userIdObj, List<ViewDashboardDataset> list) {
String redisKey = calculateViewDatasetListKey(userIdObj);
// 转换为Object存入Redis
if (CollUtil.isNotEmpty(list)) {
redisCache.deleteObject(redisKey);
redisCache.setCacheList(redisKey, list);
redisCache.expire(redisKey, redisCacheConfig.getDefaultTimeout(), redisCacheConfig.getDefaultTimeUnit());
}
}
public void updateDatasetName(UserId userIdObj, DatasetId datasetIdObj, String updateName) {
// redisKey作为LockKey
String redisKey = calculateViewDatasetListKey(userIdObj);
String uuidIdentifier = redisLockTool.getUUIDIdentifier();
try {
// 加锁
redisLockTool.lock(redisKey, uuidIdentifier , RedisLockTool.DEFAULT_LOCK_EXP, RedisLockTool.DEFAULT_REDIS_TIMEOUT);
// 查询
ViewDatasetListResult result = handleQueryViewDatasetList(userIdObj, redisKey);
if (!result.isExist()) {
return;
}
boolean needUpdate = false;
List<ViewDashboardDataset> datasetList = result.getDatasetList();
for (ViewDashboardDataset dataset : datasetList) {
if (dataset.getId().equals(datasetIdObj.getId())) {
dataset.setName(updateName);
dataset.setDatasetTitle(updateName);
needUpdate = true;
break;
}
}
if (needUpdate) {
// 真正的执行逻辑
handlePushViewDatasetList(userIdObj, datasetList);
}
} finally {
// 解锁
redisLockTool.unlock(redisKey, uuidIdentifier);
}
}
// 判断是否包含key
/**
* 用户是否存在工作表集合的缓存
* @param userIdObj
* @return
*/
public boolean existDatasetListKey(UserId userIdObj) {
// 计算redisKey (工作表集合的key)
String redisKey = calculateViewDatasetListKey(userIdObj);
// redis中是否有工作表集合----通过redisTemplate.hasKey(key)来实现
return redisCache.hasKey(redisKey);
}
/**
* 用户是否存在工作表集合的缓存
* @return
*/
public boolean existDatasetListKey(String redisKey) {
return redisCache.hasKey(redisKey);
}
// 计算redisKey
/**
* 获取工作表集合的key
* @param userIdObj
* @return
*/
public String calculateViewDatasetListKey(UserId userIdObj) {
// 其实是拼接了 user_id 和 resType
return CacheKeyUtil.getUserDatasetListKey(userIdObj.getId());
}
}