mirror of https://github.com/halo-dev/halo
Add custom temporary store support
parent
58e5da4ac5
commit
5771b42c25
8
pom.xml
8
pom.xml
|
@ -48,6 +48,7 @@
|
||||||
<qiniu-java-sdk.version>7.2.18</qiniu-java-sdk.version>
|
<qiniu-java-sdk.version>7.2.18</qiniu-java-sdk.version>
|
||||||
<thumbnailator.version>0.4.8</thumbnailator.version>
|
<thumbnailator.version>0.4.8</thumbnailator.version>
|
||||||
<commonmark.version>0.12.1</commonmark.version>
|
<commonmark.version>0.12.1</commonmark.version>
|
||||||
|
<commons-lang3.version>3.8.1</commons-lang3.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -213,6 +214,13 @@
|
||||||
<version>2.9.2</version>
|
<version>2.9.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Apache commons lang3-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>${commons-lang3.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package cc.ryanc.halo.cache;
|
||||||
|
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache store interface.
|
||||||
|
*
|
||||||
|
* @param <K> cache key type
|
||||||
|
* @param <V> cache value type
|
||||||
|
* @author johnniang
|
||||||
|
* *
|
||||||
|
*/
|
||||||
|
public interface CacheStore<K, V> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets by cache key.
|
||||||
|
*
|
||||||
|
* @param key must not be null
|
||||||
|
* @return cache value
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Optional<V> get(@NonNull K key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Puts a cache.
|
||||||
|
*
|
||||||
|
* @param key cache key must not be null
|
||||||
|
* @param value cache value must not be null
|
||||||
|
* @param timeout the key expiration must not be less than 0
|
||||||
|
* @param timeUnit timeout unit
|
||||||
|
*/
|
||||||
|
void put(@NonNull K key, @NonNull V value, long timeout, @NonNull TimeUnit timeUnit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a key.
|
||||||
|
*
|
||||||
|
* @param key cache key must not be null
|
||||||
|
*/
|
||||||
|
void delete(@NonNull K key);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package cc.ryanc.halo.cache;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache wrapper.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class CacheWrapper<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache key.
|
||||||
|
*/
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache data
|
||||||
|
*/
|
||||||
|
private T data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expired time.
|
||||||
|
*/
|
||||||
|
private Date expireAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create time.
|
||||||
|
*/
|
||||||
|
private Date createAt;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package cc.ryanc.halo.cache;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In-memory cache store.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
public class InMemoryCacheStore extends StringCacheStore {
|
||||||
|
|
||||||
|
private final static ConcurrentHashMap<String, String> cacheContainer = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<String> get(String key) {
|
||||||
|
return Optional.ofNullable(cacheContainer.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void put(String key, String value, long timeout, TimeUnit timeUnit) {
|
||||||
|
cacheContainer.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String key) {
|
||||||
|
// TODO Consider to delete the cache periodic
|
||||||
|
cacheContainer.remove(key);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package cc.ryanc.halo.cache;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.exception.ServiceException;
|
||||||
|
import cc.ryanc.halo.utils.JsonUtils;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wechat cache store.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class StringCacheStore implements CacheStore<String, String> {
|
||||||
|
|
||||||
|
public <T> void putForWechat(String key, T value, long timeout, TimeUnit timeUnit) {
|
||||||
|
Assert.hasText(key, "Cache key must not be blank");
|
||||||
|
Assert.notNull(value, "Cache value must not be null");
|
||||||
|
Assert.isTrue(timeout > 0, "Timeout must not be less than 0");
|
||||||
|
Assert.notNull(timeUnit, "Time unit must not be null");
|
||||||
|
|
||||||
|
// Convert to second
|
||||||
|
Long seconds = timeUnit.toSeconds(timeout);
|
||||||
|
|
||||||
|
// Round the seconds
|
||||||
|
if (seconds == 0) {
|
||||||
|
seconds = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
// Calculate expire at
|
||||||
|
Date expireAt = DateUtils.addSeconds(now, seconds.intValue());
|
||||||
|
|
||||||
|
// Build cache wrapper
|
||||||
|
CacheWrapper<T> wrapper = new CacheWrapper<>();
|
||||||
|
wrapper.setCreateAt(now);
|
||||||
|
wrapper.setExpireAt(expireAt);
|
||||||
|
wrapper.setKey(key);
|
||||||
|
wrapper.setData(value);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Convert wrapper to json
|
||||||
|
String valueJson = JsonUtils.objectToJson(wrapper);
|
||||||
|
// Put the the value json to cache store
|
||||||
|
put(key, valueJson, timeout, timeUnit);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new ServiceException("Failed to convert object to json", e).setErrorData(wrapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@NonNull
|
||||||
|
public <T> Optional<T> getForWechat(@NonNull String key, @NonNull Class<T> type) {
|
||||||
|
Assert.hasText(key, "Cache key must not be blank");
|
||||||
|
Assert.notNull(type, "Cache type must not be null");
|
||||||
|
|
||||||
|
return get(key).map(value -> {
|
||||||
|
try {
|
||||||
|
CacheWrapper<?> cacheWrapper = JsonUtils.jsonToObject(value, CacheWrapper.class);
|
||||||
|
|
||||||
|
if (cacheWrapper == null) {
|
||||||
|
log.error("Cache wrapper is null, key: [{}]", key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Cache wrapper: [{}]", cacheWrapper);
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
if (cacheWrapper.getExpireAt().before(now)) {
|
||||||
|
// Expired then delete it
|
||||||
|
log.debug("Cache key: [{}] has been expired", key);
|
||||||
|
|
||||||
|
delete(key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object data = cacheWrapper.getData();
|
||||||
|
|
||||||
|
if (data != null && data.getClass().isAssignableFrom(type)) {
|
||||||
|
return (T) data;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.error("Data type: [{}], but specified type: [{}]", data == null ? null : data.getClass(), type);
|
||||||
|
throw new ServiceException("Cache value type is mismatched with the specified type");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException("Failed to convert from json to object", e).setErrorData(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package cc.ryanc.halo.config;
|
package cc.ryanc.halo.config;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.cache.InMemoryCacheStore;
|
||||||
|
import cc.ryanc.halo.cache.StringCacheStore;
|
||||||
import cc.ryanc.halo.config.properties.HaloProperties;
|
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||||
import cc.ryanc.halo.filter.CorsFilter;
|
import cc.ryanc.halo.filter.CorsFilter;
|
||||||
import cc.ryanc.halo.filter.LogFilter;
|
import cc.ryanc.halo.filter.LogFilter;
|
||||||
|
@ -8,6 +10,7 @@ import cc.ryanc.halo.security.filter.ApiAuthenticationFilter;
|
||||||
import cc.ryanc.halo.security.handler.AdminAuthenticationFailureHandler;
|
import cc.ryanc.halo.security.handler.AdminAuthenticationFailureHandler;
|
||||||
import cc.ryanc.halo.security.handler.DefaultAuthenticationFailureHandler;
|
import cc.ryanc.halo.security.handler.DefaultAuthenticationFailureHandler;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -23,6 +26,12 @@ import org.springframework.core.Ordered;
|
||||||
@EnableConfigurationProperties(HaloProperties.class)
|
@EnableConfigurationProperties(HaloProperties.class)
|
||||||
public class HaloConfiguration {
|
public class HaloConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
public StringCacheStore stringCacheStore() {
|
||||||
|
return new InMemoryCacheStore();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a CorsFilter.
|
* Creates a CorsFilter.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue