diff --git a/mall-security/pom.xml b/mall-security/pom.xml index 1ed891e..68b15ad 100644 --- a/mall-security/pom.xml +++ b/mall-security/pom.xml @@ -29,6 +29,10 @@ org.springframework.boot spring-boot-starter-security + + org.springframework.boot + spring-boot-starter-data-redis + io.jsonwebtoken jjwt diff --git a/mall-security/src/main/java/com/macro/mall/security/annotation/CacheException.java b/mall-security/src/main/java/com/macro/mall/security/annotation/CacheException.java new file mode 100644 index 0000000..615fbeb --- /dev/null +++ b/mall-security/src/main/java/com/macro/mall/security/annotation/CacheException.java @@ -0,0 +1,12 @@ +package com.macro.mall.security.annotation; + +import java.lang.annotation.*; + +/** + * 自定义注解,有该注解的缓存方法会抛出异常 + */ +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface CacheException { +} diff --git a/mall-security/src/main/java/com/macro/mall/security/aspect/RedisCacheAspect.java b/mall-security/src/main/java/com/macro/mall/security/aspect/RedisCacheAspect.java new file mode 100644 index 0000000..abd8d9e --- /dev/null +++ b/mall-security/src/main/java/com/macro/mall/security/aspect/RedisCacheAspect.java @@ -0,0 +1,50 @@ +package com.macro.mall.security.aspect; + +import com.macro.mall.security.annotation.CacheException; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; + +/** + * Redis缓存切面,防止Redis宕机影响正常业务逻辑 + * Created by macro on 2020/3/17. + */ +@Aspect +@Component +@Order(2) +public class RedisCacheAspect { + private static Logger LOGGER = LoggerFactory.getLogger(RedisCacheAspect.class); + + @Pointcut("execution(public * com.macro.mall.portal.service.*CacheService.*(..)) || execution(public * com.macro.mall.service.*CacheService.*(..))") + public void cacheAspect() { + } + + @Around("cacheAspect()") + public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + Object result = null; + try { + result = joinPoint.proceed(); + } catch (Throwable throwable) { + //有CacheException注解的方法需要抛出异常 + if (method.isAnnotationPresent(CacheException.class)) { + throw throwable; + } else { + LOGGER.error(throwable.getMessage()); + } + } + return result; + } + +} diff --git a/mall-security/src/main/java/com/macro/mall/security/config/RedisConfig.java b/mall-security/src/main/java/com/macro/mall/security/config/RedisConfig.java new file mode 100644 index 0000000..faf6912 --- /dev/null +++ b/mall-security/src/main/java/com/macro/mall/security/config/RedisConfig.java @@ -0,0 +1,63 @@ +package com.macro.mall.security.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.cache.RedisCacheWriter; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.RedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; + +/** + * Redis配置类 + * Created by macro on 2020/3/2. + */ +@EnableCaching +@Configuration +public class RedisConfig extends CachingConfigurerSupport { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisSerializer serializer = redisSerializer(); + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + @Bean + public RedisSerializer redisSerializer() { + //创建JSON序列化器 + Jackson2JsonRedisSerializer 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); + return serializer; + } + + @Bean + public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { + RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory); + //设置Redis缓存有效期为1天 + RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer())).entryTtl(Duration.ofDays(1)); + return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); + } + +} diff --git a/mall-security/src/main/java/com/macro/mall/security/service/RedisService.java b/mall-security/src/main/java/com/macro/mall/security/service/RedisService.java new file mode 100644 index 0000000..a33943b --- /dev/null +++ b/mall-security/src/main/java/com/macro/mall/security/service/RedisService.java @@ -0,0 +1,182 @@ +package com.macro.mall.security.service; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * redis操作Service + * Created by macro on 2020/3/3. + */ +public interface RedisService { + + /** + * 保存属性 + */ + void set(String key, Object value, long time); + + /** + * 保存属性 + */ + void set(String key, Object value); + + /** + * 获取属性 + */ + Object get(String key); + + /** + * 删除属性 + */ + Boolean del(String key); + + /** + * 批量删除属性 + */ + Long del(List keys); + + /** + * 设置过期时间 + */ + Boolean expire(String key, long time); + + /** + * 获取过期时间 + */ + Long getExpire(String key); + + /** + * 判断是否有该属性 + */ + Boolean hasKey(String key); + + /** + * 按delta递增 + */ + Long incr(String key, long delta); + + /** + * 按delta递减 + */ + Long decr(String key, long delta); + + /** + * 获取Hash结构中的属性 + */ + Object hGet(String key, String hashKey); + + /** + * 向Hash结构中放入一个属性 + */ + Boolean hSet(String key, String hashKey, Object value, long time); + + /** + * 向Hash结构中放入一个属性 + */ + void hSet(String key, String hashKey, Object value); + + /** + * 直接获取整个Hash结构 + */ + Map hGetAll(String key); + + /** + * 直接设置整个Hash结构 + */ + Boolean hSetAll(String key, Map map, long time); + + /** + * 直接设置整个Hash结构 + */ + void hSetAll(String key, Map 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 sMembers(String key); + + /** + * 向Set结构中添加属性 + */ + Long sAdd(String key, Object... values); + + /** + * 向Set结构中添加属性 + */ + Long sAdd(String key, long time, Object... values); + + /** + * 是否为Set中的属性 + */ + Boolean sIsMember(String key, Object value); + + /** + * 获取Set结构的长度 + */ + Long sSize(String key); + + /** + * 删除Set结构中的属性 + */ + Long sRemove(String key, Object... values); + + /** + * 获取List结构中的属性 + */ + List 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); +} \ No newline at end of file diff --git a/mall-security/src/main/java/com/macro/mall/security/service/impl/RedisServiceImpl.java b/mall-security/src/main/java/com/macro/mall/security/service/impl/RedisServiceImpl.java new file mode 100644 index 0000000..0347ea3 --- /dev/null +++ b/mall-security/src/main/java/com/macro/mall/security/service/impl/RedisServiceImpl.java @@ -0,0 +1,199 @@ +package com.macro.mall.security.service.impl; + +import com.macro.mall.security.service.RedisService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * redis操作实现类 + * Created by macro on 2020/3/3. + */ +@Service +public class RedisServiceImpl implements RedisService { + @Autowired + private RedisTemplate 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 Boolean del(String key) { + return redisTemplate.delete(key); + } + + @Override + public Long del(List keys) { + return 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 Boolean hasKey(String key) { + return redisTemplate.hasKey(key); + } + + @Override + public Long incr(String key, long delta) { + return redisTemplate.opsForValue().increment(key, delta); + } + + @Override + public Long decr(String key, long delta) { + return redisTemplate.opsForValue().increment(key, -delta); + } + + @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 void hSet(String key, String hashKey, Object value) { + redisTemplate.opsForHash().put(key, hashKey, value); + } + + @Override + public Map hGetAll(String key) { + return redisTemplate.opsForHash().entries(key); + } + + @Override + public Boolean hSetAll(String key, Map map, long time) { + redisTemplate.opsForHash().putAll(key, map); + return expire(key, time); + } + + @Override + public void hSetAll(String key, Map 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 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(String key, long time, 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 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); + } +} diff --git a/mall-security/src/main/java/com/macro/mall/security/util/SpringUtil.java b/mall-security/src/main/java/com/macro/mall/security/util/SpringUtil.java new file mode 100644 index 0000000..4ad2f8e --- /dev/null +++ b/mall-security/src/main/java/com/macro/mall/security/util/SpringUtil.java @@ -0,0 +1,44 @@ +package com.macro.mall.security.util; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * Spring工具类 + * Created by macro on 2020/3/3. + */ +@Component +public class SpringUtil implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + // 获取applicationContext + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (SpringUtil.applicationContext == null) { + SpringUtil.applicationContext = applicationContext; + } + } + + // 通过name获取Bean + public static Object getBean(String name) { + return getApplicationContext().getBean(name); + } + + // 通过class获取Bean + public static T getBean(Class clazz) { + return getApplicationContext().getBean(clazz); + } + + // 通过name,以及Clazz返回指定的Bean + public static T getBean(String name, Class clazz) { + return getApplicationContext().getBean(name, clazz); + } + +}