From 09b8e33a1b2a1f3759b08ae1e37da9769a1aaabf Mon Sep 17 00:00:00 2001
From: jiangping <jp@doumee.com>
Date: 星期三, 06 十二月 2023 10:43:10 +0800
Subject: [PATCH] 海康接口对接开发

---
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionDAO.java         |    4 
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroConfig.java             |   43 +++++++-
 .idea/libraries/Maven__commons_net_commons_net_3_8_0.xml                                |   13 ++
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionManager.java     |    3 
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroAuthFilter.java         |    2 
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCredentialsMatcher.java |    3 
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCache.java              |   72 +++++++++++--
 server/pom.xml                                                                          |    4 
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroToken.java              |   80 ++++++++++++++++
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCacheManager.java       |    2 
 server/dmvisit_admin/src/main/java/com/doumee/api/business/HkSyncController.java        |   18 ++-
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroTokenManager.java       |    2 
 server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionSerializer.java  |   36 +++++++
 13 files changed, 248 insertions(+), 34 deletions(-)

diff --git a/.idea/libraries/Maven__commons_net_commons_net_3_8_0.xml b/.idea/libraries/Maven__commons_net_commons_net_3_8_0.xml
new file mode 100644
index 0000000..d338100
--- /dev/null
+++ b/.idea/libraries/Maven__commons_net_commons_net_3_8_0.xml
@@ -0,0 +1,13 @@
+<component name="libraryTable">
+  <library name="Maven: commons-net:commons-net:3.8.0">
+    <CLASSES>
+      <root url="jar://$MAVEN_REPOSITORY$/commons-net/commons-net/3.8.0/commons-net-3.8.0.jar!/" />
+    </CLASSES>
+    <JAVADOC>
+      <root url="jar://$MAVEN_REPOSITORY$/commons-net/commons-net/3.8.0/commons-net-3.8.0-javadoc.jar!/" />
+    </JAVADOC>
+    <SOURCES>
+      <root url="jar://$MAVEN_REPOSITORY$/commons-net/commons-net/3.8.0/commons-net-3.8.0-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>
\ No newline at end of file
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/api/business/HkSyncController.java b/server/dmvisit_admin/src/main/java/com/doumee/api/business/HkSyncController.java
index 3785a27..d5af113 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/api/business/HkSyncController.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/api/business/HkSyncController.java
@@ -12,6 +12,8 @@
 import com.doumee.dao.business.model.Device;
 import com.doumee.service.business.DeviceService;
 import com.doumee.service.business.HkSyncService;
+import com.doumee.service.business.impl.hksync.HkSyncDeviceServiceImpl;
+import com.doumee.service.business.impl.hksync.HkSyncParkServiceImpl;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -32,22 +34,24 @@
 public class HkSyncController extends BaseController {
 
     @Autowired
-    private HkSyncService hkSyncService;
+    private HkSyncDeviceServiceImpl hkSyncDeviceService;
+    @Autowired
+    private HkSyncParkServiceImpl hkSyncParkService;
 
     @PreventRepeat
     @ApiOperation("銆愭捣搴枫�戝叏閲忓悓姝ラ棬绂佽澶囨帴鍙�")
     @PostMapping("/getDevices")
-    @RequiresPermissions("business:hksync:device")
+//    @RequiresPermissions("business:hksync:device")
     public ApiResponse getDevices(@RequestBody AcsDeviceListRequest param) {
-        String result = hkSyncService.syncHkDevices(param);
+        String result = hkSyncDeviceService.syncHkDevices(param);
         return ApiResponse.success(result);
     }
     @PreventRepeat
     @ApiOperation("銆愭捣搴枫�戝叏閲忓悓姝ュ仠杞﹀簱鎺ュ彛")
-    @PostMapping("/getDevices")
-    @RequiresPermissions("business:hksync:park")
-    public ApiResponse getDevices(@RequestBody ParkListRequest param) {
-        String result = hkSyncService.syncHkParks(param);
+    @PostMapping("/getParks")
+//    @RequiresPermissions("business:hksync:park")
+    public ApiResponse getParks(@RequestBody ParkListRequest param) {
+        String result = hkSyncParkService.syncHkParks(param);
         return ApiResponse.success(result);
     }
 
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroAuthFilter.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroAuthFilter.java
index f978edf..30d7dc0 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroAuthFilter.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroAuthFilter.java
@@ -12,7 +12,7 @@
 /**
  * Shiro璁よ瘉杩囨护鍣紝澶勭悊鏈璇佹儏鍐电殑鍝嶅簲
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 public class ShiroAuthFilter extends FormAuthenticationFilter {
 
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCache.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCache.java
index 36cd7af..4e61661 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCache.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCache.java
@@ -1,24 +1,28 @@
 package com.doumee.config.shiro;
 
-import com.doumee.service.proxy.CacheProxy;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.cache.Cache;
 import org.apache.shiro.cache.CacheException;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.CollectionUtils;
 import org.springframework.context.annotation.Scope;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.SerializationException;
 import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
 
+import javax.annotation.Resource;
 import java.io.Serializable;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Shiro缂撳瓨
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 @Scope(value = "prototype")
 @Slf4j
@@ -27,8 +31,8 @@
 
     private String keyPrefix = "";
 
-    @Autowired
-    private CacheProxy<Object, Serializable> cacheProxy;
+    @Resource(name="sessionRedisTemplate")
+    private RedisTemplate<Object, Serializable> redisTemplate;
 
     public ShiroCache () {
         log.debug("ShiroCache: new, keyPrefix = [" + keyPrefix + "]");
@@ -44,7 +48,7 @@
         if (key == null) {
             return null;
         }
-        return cacheProxy.get(getKey(key));
+        return redisTemplate.opsForValue().get(getKey(key));
     }
 
     @Override
@@ -52,7 +56,7 @@
         if (key == null) {
             return null;
         }
-        cacheProxy.put(getKey(key), value);
+        redisTemplate.opsForValue().set(getKey(key), value);
         return value;
     }
 
@@ -60,14 +64,14 @@
         if (key == null) {
             return null;
         }
-        cacheProxy.put(getKey(key), value, timeout);
+        redisTemplate.opsForValue().set(getKey(key), value, timeout, TimeUnit.SECONDS);
         return value;
     }
 
     @Override
     public void clear() throws CacheException {
         Set<Object> keys = this.keys();
-        cacheProxy.remove(keys);
+        redisTemplate.delete(keys);
     }
 
     @Override
@@ -77,7 +81,7 @@
 
     @Override
     public Set<Object> keys() {
-        Set<Object> keys = cacheProxy.keys(keyPrefix + "*");
+        Set<Object> keys = redisTemplate.keys(keyPrefix + "*");
         if (CollectionUtils.isEmpty(keys)) {
             return Collections.emptySet();
         }
@@ -92,7 +96,7 @@
             return values;
         }
         for (Object k : keys) {
-            values.add(cacheProxy.get(k));
+            values.add(redisTemplate.opsForValue().get(k));
         }
         return values;
     }
@@ -103,11 +107,53 @@
             return null;
         }
         Serializable value = this.get(getKey(key));
-        cacheProxy.remove(getKey(key));
+        redisTemplate.delete(getKey(key));
         return value;
     }
 
     private Object getKey (Object key) {
+        if (key instanceof PrincipalCollection) {
+            return this.keyPrefix + getRedisKeyFromPrincipalIdField((PrincipalCollection)key);
+        }
         return (key instanceof String ? (this.keyPrefix + key) : key);
     }
+
+    /**
+     * 鑾峰彇redis cache key
+     */
+    private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) {
+        Object principalObject = key.getPrimaryPrincipal();
+        if (principalObject instanceof String) {
+            return principalObject.toString();
+        } else {
+            Method pincipalIdGetter = this.getPrincipalIdGetter(principalObject);
+            return this.getIdObj(principalObject, pincipalIdGetter);
+        }
+    }
+
+    private Method getPrincipalIdGetter(Object principalObject) {
+        Method pincipalIdGetter;
+        String principalIdMethodName = this.getPrincipalIdMethodName();
+
+        try {
+            pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName);
+            return pincipalIdGetter;
+        } catch (NoSuchMethodException e) {
+            throw new SerializationException(e.getMessage(), e);
+        }
+    }
+
+    private String getIdObj(Object principalObject, Method pincipalIdGetter) {
+        try {
+            Object idObj = pincipalIdGetter.invoke(principalObject);
+            String redisKey = idObj.toString();
+            return redisKey;
+        } catch (Exception e) {
+            throw new SerializationException(e.getMessage(), e);
+        }
+    }
+
+    private String getPrincipalIdMethodName() {
+        return "getId";
+    }
 }
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCacheManager.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCacheManager.java
index fedcb98..4c11155 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCacheManager.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCacheManager.java
@@ -14,7 +14,7 @@
 /**
  * 鑷畾涔塖hiro CacheManager
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 @Slf4j
 @Component
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroConfig.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroConfig.java
index edfd770..60dcdcc 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroConfig.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroConfig.java
@@ -10,8 +10,12 @@
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 import javax.servlet.Filter;
+import java.io.Serializable;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -39,6 +43,20 @@
     @Autowired
     private ShiroRealm shiroRealm;
 
+    @Bean("sessionRedisTemplate")
+    public RedisTemplate<Object, Serializable> sessionRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        RedisTemplate<Object, Serializable> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        // 榛樿搴忓垪鍖栨柟寮�
+        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
+        // 鍊煎簭鍒楀寲鏂瑰紡
+        ShiroSessionSerializer serializer = new ShiroSessionSerializer();
+        redisTemplate.setValueSerializer(serializer);
+        redisTemplate.setHashValueSerializer(serializer);
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+
     @Bean
     public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
         DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
@@ -50,6 +68,9 @@
     public SessionManager sessionManager() {
         ShiroSessionManager sessionManager = new ShiroSessionManager();
         sessionManager.setSessionDAO(shiroSessionDAO);
+        sessionManager.setGlobalSessionTimeout(sessionExpireTime*1000);
+        // 鍒犻櫎澶辨晥鐨剆ession
+        sessionManager.setDeleteInvalidSessions(true);
         return sessionManager;
     }
 
@@ -66,20 +87,32 @@
     public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
         shiroFilterFactoryBean.setSecurityManager(securityManager);
-        Map<String, String> map = new HashMap<>();
+        Map<String, String> map = new LinkedHashMap<>();
         // 璺緞鎷︽埅閰嶇疆
         map.put("/system/login", "anon");
+        map.put("/system/syncLingCountData", "anon");
+        map.put("/system/wxLogin", "anon");
+        map.put("/system/wxProgramLogin", "anon");
+        map.put("/system/wxAccountLogin", "anon");
+        map.put("/system/initCompany", "anon");
         map.put("/system/logout", "anon");
         map.put("/common/captcha", "anon");
-        //鏂囦欢涓婁紶鍙栨秷鎷︽埅
-        map.put("/public/**", "anon");
-
+        map.put("/statistics/**", "anon");
+        map.put("/dingding/push", "anon");
+//        map.put("/ext/workorderExt/freshStatistics", "anon");
+        map.put("/dingding/jsapiTicket", "anon");
+        map.put("/dingding/ddLogin", "anon");
+        map.put("/dingding/getDingdingCorpId", "anon");
+        map.put("/lingyang/login", "anon");
+        map.put("/lingyang/loginDemo", "anon");
+        map.put("/lingyang/importBatch", "anon");
+        map.put("/edgp/**", "anon");
         // - 鏀捐swagger
         map.put("/doc.html", "anon");
         map.put("/webjars/**", "anon");
+        map.put("/template/**", "anon");
         map.put("/swagger-resources/**", "anon");
         map.put("/v2/api-docs/**", "anon");
-        map.put("/wgListener/**", "anon");
         // - 鍏朵粬鎺ュ彛缁熶竴鎷︽埅
         map.put("/**", "authc");
         shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCredentialsMatcher.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCredentialsMatcher.java
index 75c5280..09156e0 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCredentialsMatcher.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroCredentialsMatcher.java
@@ -14,11 +14,10 @@
 /**
  * Shiro瀵嗙爜姣斿澶勭悊
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 @Component
 public class ShiroCredentialsMatcher extends HashedCredentialsMatcher {
-
     @Lazy
     @Autowired
     private SystemUserService systemUserService;
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionDAO.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionDAO.java
index 2cc6a11..1fe90bf 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionDAO.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionDAO.java
@@ -18,7 +18,7 @@
 /**
  * 鑷畾涔塖hiro SessionDAO锛屽皢浼氳瘽淇℃伅瀛樺叆缂撳瓨涓�
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 @Data
 @Slf4j
@@ -30,7 +30,7 @@
     @Autowired
     private ShiroCache shiroCache;
 
-    private int expireTime = 1800;
+    private int expireTime = 60 * 60 * 24;
 
     @Autowired
     private ShiroTokenManager shiroTokenManager;
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionManager.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionManager.java
index ef159a7..32b0379 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionManager.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionManager.java
@@ -19,7 +19,7 @@
 /**
  * 鑷畾涔変細璇濈鐞嗗櫒
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 @Slf4j
 public class ShiroSessionManager extends DefaultSessionManager implements WebSessionManager {
@@ -65,7 +65,6 @@
         }
         return sessionId;
     }
-
     @Override
     public boolean isServletContainerSessions() {
         return false;
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionSerializer.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionSerializer.java
new file mode 100644
index 0000000..d334adf
--- /dev/null
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroSessionSerializer.java
@@ -0,0 +1,36 @@
+package com.doumee.config.shiro;
+
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.shiro.codec.Base64;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Session搴忓垪鍖�
+ * @author Eva.Caesar Liu
+ * @date 2023/04/17 12:11
+ */
+public class ShiroSessionSerializer implements RedisSerializer<Serializable> {
+
+    @Override
+    public byte[] serialize(Serializable obj) throws SerializationException {
+        if (obj == null) {
+            return new byte[0];
+        }
+        String sessionBase64 = Base64.encodeToString(SerializationUtils.serialize(obj));
+        return sessionBase64.getBytes(StandardCharsets.UTF_8);
+    }
+
+    @Override
+    public Serializable deserialize(byte[] bytes) throws SerializationException {
+        if (bytes == null || bytes.length == 0) {
+            return null;
+        }
+        String sessionString = new String(bytes, StandardCharsets.UTF_8);
+        byte[] sessionBytes = Base64.decode(sessionString);
+        return SerializationUtils.deserialize(sessionBytes);
+    }
+}
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroToken.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroToken.java
new file mode 100644
index 0000000..4a27415
--- /dev/null
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroToken.java
@@ -0,0 +1,80 @@
+package com.doumee.config.shiro;
+
+import com.doumee.core.model.LoginUserInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鑷畾涔塗oken 锛屽鐞嗚璇佸拰鏉冮檺
+ * @author Eva.Caesar Liu
+ * @date 2022/04/18 18:12
+ */
+@Component
+public class ShiroToken extends UsernamePasswordToken {
+
+    /**
+     * 鍏徃ID
+     */
+    Integer companyId;
+    Boolean isDdLogin;
+    Boolean isWxLogin;
+    LoginUserInfo updateUser;
+
+    int updateFlag;
+
+    public ShiroToken() {
+    }
+    public ShiroToken(Integer companyId, String username, String password, boolean isDdLogin, boolean isWxLogin) {
+        super(username,  password, false, (String)null);
+        this.companyId = companyId;
+        this.isDdLogin = isDdLogin;
+        this.isWxLogin = isWxLogin;
+    }
+    public ShiroToken(LoginUserInfo user,int updateFlag) {
+        super(user.getUsername(), "", false, (String)null);
+        this.updateUser = user;
+        this.updateFlag = updateFlag;
+        this.isDdLogin = true;
+    }
+
+    public Boolean getDdLogin() {
+        return isDdLogin;
+    }
+
+    public void setDdLogin(Boolean ddLogin) {
+        isDdLogin = ddLogin;
+    }
+
+
+    public Boolean getWxLogin() {
+        return isWxLogin;
+    }
+
+    public void setWxLogin(Boolean wxLogin) {
+        isWxLogin = wxLogin;
+    }
+
+    public Integer getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Integer companyId) {
+        this.companyId = companyId;
+    }
+
+    public LoginUserInfo getUpdateUser() {
+        return updateUser;
+    }
+
+    public void setUpdateUser(LoginUserInfo updateUser) {
+        this.updateUser = updateUser;
+    }
+
+    public int getUpdateFlag() {
+        return updateFlag;
+    }
+
+    public void setUpdateFlag(int updateFlag) {
+        this.updateFlag = updateFlag;
+    }
+}
diff --git a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroTokenManager.java b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroTokenManager.java
index 1ba1679..ba35da6 100644
--- a/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroTokenManager.java
+++ b/server/dmvisit_admin/src/main/java/com/doumee/config/shiro/ShiroTokenManager.java
@@ -8,7 +8,7 @@
 /**
  * 榛樿Token绠$悊鍣�
  * @author Eva.Caesar Liu
- * @date 2023/03/21 14:49
+ * @date 2023/04/17 12:11
  */
 @Component
 public class ShiroTokenManager {
diff --git a/server/pom.xml b/server/pom.xml
index 034ad1c..172d776 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -276,6 +276,10 @@
       <artifactId>commons-net</artifactId>
       <version>3.8.0</version>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-data-redis</artifactId>
+    </dependency>
   </dependencies>
   <build>
     <plugins>

--
Gitblit v1.9.3