1.新增邮件,阿里,腾讯短信调用接口

2.新增微信模板通知,目前通知接口都是同步调用
3.添加redisson,延迟消息队列,超时订单自动取消
This commit is contained in:
Administrator
2019-11-22 17:00:44 +08:00
parent 17f6d107ce
commit f60e8d816a
31 changed files with 1782 additions and 130 deletions

View File

@ -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 handleCacheGetErrorkey -> [{}]", key, e);
}
@Override
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
log.error("Redis occur handleCachePutErrorkey -> [{}]value -> [{}]", key, value, e);
}
@Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
log.error("Redis occur handleCacheEvictErrorkey -> [{}]", key, e);
}
@Override
public void handleCacheClearError(RuntimeException e, Cache cache) {
log.error("Redis occur handleCacheClearError", e);
}
};
return cacheErrorHandler;
}
}

View 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;//具体执行实例实现
}

View File

@ -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();
}
}

View File

@ -0,0 +1,10 @@
package co.yixiang.redisson;
/**
* Created by kl on 2018/7/20.
* Content :延时job执行器接口
*/
public interface ExecuteJob {
void execute(DelayJob job);
}

View 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);
}
}
}

View File

@ -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 handleCacheGetErrorkey -> [{}]", key, e);
}
@Override
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
log.error("Redis occur handleCachePutErrorkey -> [{}]value -> [{}]", key, value, e);
}
@Override
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
log.error("Redis occur handleCacheEvictErrorkey -> [{}]", key, e);
}
@Override
public void handleCacheClearError(RuntimeException e, Cache cache) {
log.error("Redis occur handleCacheClearError", e);
}
};
return cacheErrorHandler;
}
}

View 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);
}
}