diff --git a/anrui-timertask/pom.xml b/anrui-timertask/pom.xml
new file mode 100644
index 0000000000..bc420a86fb
--- /dev/null
+++ b/anrui-timertask/pom.xml
@@ -0,0 +1,85 @@
+
+
+
+ anrui
+ com.yxt.anrui
+ 0.0.1
+
+ 4.0.0
+
+ anrui-timertask
+
+
+ 8
+ 8
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ com.github.xiaoymin
+ knife4j-spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ io.lettuce
+ lettuce-core
+
+
+
+
+ redis.clients
+ jedis
+
+
+ com.alibaba
+ fastjson
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+
+
+ src/main/resources
+
+ **/*.*
+
+ false
+
+
+
+
\ No newline at end of file
diff --git a/anrui-timertask/src/main/java/com/yxt/anrui/timertask/AnruiTimerTaskApplication.java b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/AnruiTimerTaskApplication.java
new file mode 100644
index 0000000000..f2d1c49191
--- /dev/null
+++ b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/AnruiTimerTaskApplication.java
@@ -0,0 +1,54 @@
+/*********************************************************
+ *********************************************************
+ ******************** *******************
+ ************* ************
+ ******* _oo0oo_ *******
+ *** o8888888o ***
+ * 88" . "88 *
+ * (| -_- |) *
+ * 0\ = /0 *
+ * ___/`---'\___ *
+ * .' \\| |// '. *
+ * / \\||| : |||// \ *
+ * / _||||| -:- |||||- \ *
+ * | | \\\ - /// | | *
+ * | \_| ''\---/'' |_/ | *
+ * \ .-\__ '-' ___/-. / *
+ * ___'. .' /--.--\ `. .'___ *
+ * ."" '< `.___\_<|>_/___.' >' "". *
+ * | | : `- \`.;`\ _ /`;.`/ - ` : | | *
+ * \ \ `_. \_ __\ /__ _/ .-` / / *
+ * =====`-.____`.___ \_____/___.-`___.-'===== *
+ * `=---=' *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
+ *********__佛祖保佑__永无BUG__验收通过__钞票多多__*********
+ *********************************************************/
+package com.yxt.anrui.timertask;
+
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+
+/**
+ * Project: anrui-scm(进销存)
+ * File: AnruiScmApplication.java
+ * Class: com.yxt.anrui.scm.AnruiScmApp
+ * Description: .
+ * Copyright: Copyright (c) 2011
+ * Company: https://gitee.com/liuzp315
+ * Makedate: 2021-11-17 13:48:15
+ *
+ * @author liupopo
+ * @version 1.0
+ * @since 1.0
+ */
+@EnableDiscoveryClient
+@SpringBootApplication()
+@EnableFeignClients(basePackages = {"com.yxt.anrui.timertask"})
+public class AnruiTimerTaskApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(AnruiTimerTaskApplication.class, args);
+ }
+}
diff --git a/anrui-timertask/src/main/java/com/yxt/anrui/timertask/config/KeyExpiredListener.java b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/config/KeyExpiredListener.java
new file mode 100644
index 0000000000..ced8ff3727
--- /dev/null
+++ b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/config/KeyExpiredListener.java
@@ -0,0 +1,60 @@
+package com.yxt.anrui.timertask.config;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.Message;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.BoundValueOperations;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Component
+public class KeyExpiredListener extends KeyExpirationEventMessageListener {
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+ public KeyExpiredListener(RedisMessageListenerContainer listenerContainer) {
+ super(listenerContainer);
+ }
+ @Override
+ @Transactional
+ public void onMessage(Message message, byte[] pattern) {
+ //从消息队列中接收消息
+ // 获取过期的key,可以做自己的业务
+ //反序列化Key,否则出现乱码
+ String key = message.toString();
+ // 利用redis setIfAbsent命令,如果为空set返回true,如果不为空返回false,
+ // 类似setnx加锁操作
+ Boolean aBoolean = stringRedisTemplate.opsForValue().setIfAbsent( key, String.valueOf(System.currentTimeMillis()), 10, TimeUnit.SECONDS);
+ if (aBoolean) {
+ // 避免多个服务监听情况下重复消费
+ // 注意:只能获取失效的key值,不能获取key对应的value值
+ System.out.println(key);
+ try {
+ if(key.startsWith("stock-")){
+ // 过期监听后的具体逻辑
+ log.info("redisKey:{}",key);
+ String s = stringRedisTemplate.opsForValue().get("stock-in1");
+ log.info("redisValue:{}", s);
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+ super.onMessage(message, pattern);
+ }
+}
diff --git a/anrui-timertask/src/main/java/com/yxt/anrui/timertask/config/RedisConfiguration.java b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/config/RedisConfiguration.java
new file mode 100644
index 0000000000..c3db1b741f
--- /dev/null
+++ b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/config/RedisConfiguration.java
@@ -0,0 +1,17 @@
+package com.yxt.anrui.timertask.config;
+
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+
+@Configuration
+public class RedisConfiguration extends CachingConfigurerSupport {
+ @Bean
+ public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory ) {
+ RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
+ redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
+ return redisMessageListenerContainer;
+ }
+}
diff --git a/anrui-timertask/src/main/java/com/yxt/anrui/timertask/feign/FinKingDeeFeign.java b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/feign/FinKingDeeFeign.java
new file mode 100644
index 0000000000..9807c123dd
--- /dev/null
+++ b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/feign/FinKingDeeFeign.java
@@ -0,0 +1,18 @@
+package com.yxt.anrui.timertask.feign;
+
+import io.swagger.annotations.Api;
+import org.springframework.cloud.openfeign.FeignClient;
+
+
+/**
+ * 财务模块调用金蝶保存业务单据的接口
+ */
+@Api(tags = "财务模块调用金蝶保存业务单据的接口")
+@FeignClient(
+ contextId = "anrui-fin-FinKingDeeFeign",
+ name = "anrui-fin",
+ path = "/finKingDee"
+)
+public interface FinKingDeeFeign {
+
+}
diff --git a/anrui-timertask/src/main/java/com/yxt/anrui/timertask/util/RedisUtil.java b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/util/RedisUtil.java
new file mode 100644
index 0000000000..70b73e4f2f
--- /dev/null
+++ b/anrui-timertask/src/main/java/com/yxt/anrui/timertask/util/RedisUtil.java
@@ -0,0 +1,295 @@
+package com.yxt.anrui.timertask.util;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisStringCommands;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.core.types.Expiration;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.stereotype.Service;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class RedisUtil {
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+
+ /**
+ * 字符串类型:根据key设置value值,如果key中的value存在,那么返回false
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public Boolean setnx(final String key, final String value, final long expration, final TimeUnit timeUnit) {
+ return (Boolean) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
+ RedisSerializer redisSerializer = redisTemplate.getStringSerializer();
+ byte keys[] = redisSerializer.serialize(key);
+ byte values[] = redisSerializer.serialize(value);
+ return redisConnection.set(keys, values, Expiration.from(expration, timeUnit), RedisStringCommands.SetOption.SET_IF_ABSENT);
+ }
+ });
+ }
+
+ /**
+ * 写入缓存
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public boolean set(final String key, final String value) {
+
+ boolean result = (boolean) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
+ RedisSerializer serializer = redisTemplate.getStringSerializer();
+ connection.set(serializer.serialize(key), serializer.serialize(value));
+ return true;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * 写入缓存设置时效时间
+ *
+ * @param key
+ * @param value
+ * @return
+ */
+ public boolean set(final String key, Object value, Long expireTime) {
+ boolean result = false;
+ try {
+ ValueOperations operations = redisTemplate.opsForValue();
+ operations.set(key, value);
+ redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+ result = true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+ /**
+ * 刷新缓存到期时间
+ * @param key
+ * @param expire
+ * @return
+ */
+ public boolean expire(String key, long expire) {
+ return redisTemplate.expire(key, expire, TimeUnit.SECONDS);
+ }
+
+ /**
+ * 读取缓存
+ *
+ * @param key
+ * @return
+ */
+ public String get(final String key) {
+ String result = (String) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public String doInRedis(RedisConnection connection) throws DataAccessException {
+ RedisSerializer serializer = redisTemplate.getStringSerializer();
+ byte[] value = connection.get(serializer.serialize(key));
+ return serializer.deserialize(value);
+ }
+ });
+ return result;
+ }
+
+ /**
+ * 正则获取key集合
+ *
+ * @param pattern
+ * @return
+ */
+ public Set keys(String pattern) {
+ Set keys = redisTemplate.keys(pattern);
+ return keys;
+ }
+
+
+ /**
+ * 批量删除对应的value
+ *
+ * @param keys
+ */
+ public void remove(final String... keys) {
+ for (String key : keys) {
+ remove(key);
+ }
+ }
+
+ /**
+ * 批量删除key
+ *
+ * @param pattern
+ */
+ public void removePattern(final String pattern) {
+ Set keys = redisTemplate.keys(pattern);
+ if (keys.size() > 0) {
+ redisTemplate.delete(keys);
+ }
+
+ }
+
+
+ public Long remove(final String key) {
+ return (Long) redisTemplate.execute(new RedisCallback() {
+ @Override
+ public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
+ RedisSerializer serializer = redisTemplate.getStringSerializer();
+ byte keys[] = serializer.serialize(key);
+ return redisConnection.del(keys);
+ }
+ });
+ }
+
+
+ /**
+ * 判断缓存中是否有对应的value
+ *
+ * @param key
+ * @return
+ */
+ public boolean exists(final String key) {
+ return redisTemplate.hasKey(key);
+ }
+
+
+ /**
+ * 哈希 添加
+ *
+ * @param key
+ * @param hashKey
+ * @param value
+ */
+ public void hmSet(String key, Object hashKey, Object value) {
+ HashOperations hash = redisTemplate.opsForHash();
+ hash.put(key, hashKey, value);
+ }
+
+ /**
+ * 哈希获取数据
+ *
+ * @param key
+ * @param hashKey
+ * @return
+ */
+ public String hmGet(String key, Object hashKey) {
+ HashOperations hash = redisTemplate.opsForHash();
+ return hash.get(key, hashKey);
+ }
+
+ /**
+ * 获取哈希 keys
+ *
+ * @param key
+ * @return
+ */
+ public Set hmGetKeys(String key) {
+ HashOperations hash = redisTemplate.opsForHash();
+ return hash.keys(key);
+ }
+
+ /**
+ * 删除集合中的key
+ *
+ * @param key
+ * @param hashKey
+ */
+ public void hmDelete(String key, Object hashKey) {
+ HashOperations hash = redisTemplate.opsForHash();
+ hash.delete(key, hashKey);
+ }
+
+ /**
+ * 列表添加
+ *
+ * @param k
+ * @param v
+ */
+ public void lPush(String k, Object v) {
+ ListOperations list = redisTemplate.opsForList();
+ list.rightPush(k, v);
+ }
+
+ /**
+ * 列表获取
+ *
+ * @param k
+ * @param l
+ * @param l1
+ * @return
+ */
+ public List