1.新增邮件,阿里,腾讯短信调用接口
2.新增微信模板通知,目前通知接口都是同步调用 3.添加redisson,延迟消息队列,超时订单自动取消
This commit is contained in:
@ -1,17 +1,12 @@
|
||||
package co.yixiang.redis;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
@ -19,6 +14,7 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
@ -31,7 +27,7 @@ import java.time.Duration;
|
||||
// 自动配置
|
||||
@ConditionalOnClass(RedisOperations.class)
|
||||
@EnableConfigurationProperties(RedisProperties.class)
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
public class RedisConfig {
|
||||
|
||||
/**
|
||||
* 设置 redis 数据默认过期时间,默认1天
|
||||
@ -75,52 +71,5 @@ public class RedisConfig extends CachingConfigurerSupport {
|
||||
return template;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,默认将使用该策略
|
||||
* 使用方法 @Cacheable
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(target.getClass().getName());
|
||||
sb.append(method.getName());
|
||||
for (Object obj : params) {
|
||||
sb.append(JSON.toJSONString(obj).hashCode());
|
||||
}
|
||||
return sb.toString();
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public CacheErrorHandler errorHandler() {
|
||||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
||||
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
|
||||
@Override
|
||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheClearError(RuntimeException e, Cache cache) {
|
||||
log.error("Redis occur handleCacheClearError:", e);
|
||||
}
|
||||
};
|
||||
return cacheErrorHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
16
yshop-common/src/main/java/co/yixiang/redisson/DelayJob.java
Normal file
16
yshop-common/src/main/java/co/yixiang/redisson/DelayJob.java
Normal file
@ -0,0 +1,16 @@
|
||||
package co.yixiang.redisson;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/7/20.
|
||||
* Content :延时job
|
||||
*/
|
||||
@Data
|
||||
public class DelayJob implements Serializable {
|
||||
private Integer oderId;//job执行参数
|
||||
private Class aClass;//具体执行实例实现
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package co.yixiang.redisson;
|
||||
|
||||
import org.redisson.api.RBlockingQueue;
|
||||
import org.redisson.api.RDelayedQueue;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/7/20.
|
||||
* Content :订单延时job服务
|
||||
*/
|
||||
@Component
|
||||
public class DelayJobService {
|
||||
|
||||
@Autowired
|
||||
private RedissonClient client;
|
||||
|
||||
/**
|
||||
* 添加超时任务到redis队列
|
||||
* @param job 任务
|
||||
* @param delay 超时时间
|
||||
*/
|
||||
public void submitJob(DelayJob job, Long delay){
|
||||
RBlockingQueue blockingQueue = client.getBlockingQueue(JobTimer.CUSTOMER_JOB_TIMER_JOBS);
|
||||
RDelayedQueue delayedQueue = client.getDelayedQueue(blockingQueue);
|
||||
delayedQueue.offer(job,delay,TimeUnit.MILLISECONDS);
|
||||
delayedQueue.destroy();
|
||||
}
|
||||
/**
|
||||
* 用户付款后取消队列
|
||||
* @param job 任务
|
||||
*/
|
||||
public void cancelJob(DelayJob job){
|
||||
RBlockingQueue blockingQueue = client.getBlockingQueue(JobTimer.CUSTOMER_JOB_TIMER_JOBS);
|
||||
RDelayedQueue delayedQueue = client.getDelayedQueue(blockingQueue);
|
||||
delayedQueue.remove(job);
|
||||
delayedQueue.destroy();
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package co.yixiang.redisson;
|
||||
|
||||
/**
|
||||
* Created by kl on 2018/7/20.
|
||||
* Content :延时job执行器接口
|
||||
*/
|
||||
public interface ExecuteJob {
|
||||
|
||||
void execute(DelayJob job);
|
||||
}
|
68
yshop-common/src/main/java/co/yixiang/redisson/JobTimer.java
Normal file
68
yshop-common/src/main/java/co/yixiang/redisson/JobTimer.java
Normal file
@ -0,0 +1,68 @@
|
||||
package co.yixiang.redisson;
|
||||
|
||||
import org.redisson.api.RBlockingQueue;
|
||||
import org.redisson.api.RDelayedQueue;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 消费已经到点的延时job服务,通过job参数调用业务执行器实现
|
||||
*/
|
||||
@Component
|
||||
public class JobTimer {
|
||||
|
||||
static final String CUSTOMER_JOB_TIMER_JOBS = "customer_job_timer_jobs";
|
||||
@Autowired
|
||||
private RedissonClient client;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
|
||||
@PostConstruct
|
||||
public void startJobTimer() {
|
||||
RBlockingQueue blockingQueue = client.getBlockingQueue(CUSTOMER_JOB_TIMER_JOBS);
|
||||
RDelayedQueue delayedQueue = client.getDelayedQueue(blockingQueue);
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
DelayJob job = (DelayJob) blockingQueue.take();
|
||||
executorService.execute(new ExecutorTask(context, job));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
try {
|
||||
TimeUnit.SECONDS.sleep(60);
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
}finally {
|
||||
delayedQueue.destroy();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
class ExecutorTask implements Runnable {
|
||||
|
||||
private ApplicationContext context;
|
||||
|
||||
private DelayJob delayJob;
|
||||
|
||||
public ExecutorTask(ApplicationContext context, DelayJob delayJob) {
|
||||
this.context = context;
|
||||
this.delayJob = delayJob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ExecuteJob service = (ExecuteJob) context.getBean(delayJob.getAClass());
|
||||
service.execute(delayJob);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package co.yixiang.redisson;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.spring.cache.CacheConfig;
|
||||
import org.redisson.spring.cache.RedissonSpringCacheManager;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* redisson 配置类
|
||||
* Created on 2018/6/19
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@Slf4j
|
||||
public class RedissonConfig extends CachingConfigurerSupport {
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private String port;
|
||||
|
||||
@Value("${spring.redis.password}")
|
||||
private String password;
|
||||
|
||||
@Bean
|
||||
public RedissonClient getRedisson(){
|
||||
|
||||
Config config = new Config();
|
||||
config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);
|
||||
//添加主从配置
|
||||
// config.useMasterSlaveServers().setMasterAddress("").setPassword("").addSlaveAddress(new String[]{"",""});
|
||||
|
||||
return Redisson.create(config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheManager cacheManager(RedissonClient redissonClient){
|
||||
Map<String, CacheConfig> config = new HashMap<>(16);
|
||||
// create "testMap" cache with ttl = 24 minutes and maxIdleTime = 12 minutes
|
||||
config.put("testMap",new CacheConfig(24*60*1000,12*60*1000));
|
||||
return new RedissonSpringCacheManager(redissonClient,config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,默认将使用该策略
|
||||
* 使用方法 @Cacheable
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(target.getClass().getName());
|
||||
sb.append(method.getName());
|
||||
for (Object obj : params) {
|
||||
sb.append(JSON.toJSONString(obj).hashCode());
|
||||
}
|
||||
return sb.toString();
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public CacheErrorHandler errorHandler() {
|
||||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
||||
CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
|
||||
@Override
|
||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheClearError(RuntimeException e, Cache cache) {
|
||||
log.error("Redis occur handleCacheClearError:", e);
|
||||
}
|
||||
};
|
||||
return cacheErrorHandler;
|
||||
}
|
||||
|
||||
}
|
24
yshop-common/src/main/java/co/yixiang/utils/BeanUtil.java
Normal file
24
yshop-common/src/main/java/co/yixiang/utils/BeanUtil.java
Normal file
@ -0,0 +1,24 @@
|
||||
package co.yixiang.utils;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class BeanUtil implements ApplicationContextAware {
|
||||
protected static ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
context = applicationContext;
|
||||
}
|
||||
|
||||
public static Object getBean(String name) {
|
||||
return context.getBean(name);
|
||||
}
|
||||
|
||||
public static <T> T getBean(Class<T> c){
|
||||
return context.getBean(c);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user