Browse Source

Merge branch 'cpq-dev' of wangfan/adweb3-server into master

chenpeiqing 4 months ago
parent
commit
4e25f64f30
29 changed files with 2930 additions and 379 deletions
  1. 5 0
      jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/WebsocketConst.java
  2. 8 4
      jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java
  3. 93 87
      jeecg-module-system/jeecg-system-biz/pom.xml
  4. 82 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/ShellConstans.java
  5. 12 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/mapper/CommonMapper.java
  6. 26 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/service/FeishuService.java
  7. 325 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/service/ShellService.java
  8. 65 52
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/AdwebRedisUtil.java
  9. 46 10
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/DateUtil.java
  10. 375 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/ShellSSH2Util.java
  11. 18 15
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicBlackEmailMapper.xml
  12. 20 20
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryServiceImpl.java
  13. 22 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/ISeoPlanSubscriptionService.java
  14. 129 2
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/impl/SeoPlanSubscriptionServiceImpl.java
  15. 1 1
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/constant/WordPressConstants.java
  16. 18 8
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/controller/AdwebSiteManageController.java
  17. 246 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/controller/wpSiteController.java
  18. 3 3
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/mapper/SiteUserPermissionMapper.java
  19. 5 3
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/ISiteUserPermissionService.java
  20. 943 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/SelfWebSiteService.java
  21. 162 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/SelfWebSiteServiceCommon.java
  22. 41 0
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/SiteManageService.java
  23. 7 3
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/impl/AdwebSiteServiceImpl.java
  24. 52 97
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/impl/SiteUserPermissionServiceImpl.java
  25. 65 41
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/theme/entity/AdwebTheme.java
  26. 23 21
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java
  27. 10 6
      jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/redis/CacheConfig.java
  28. 69 2
      jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml
  29. 59 1
      jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml

+ 5 - 0
jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/WebsocketConst.java

@@ -44,6 +44,11 @@ public class WebsocketConst {
     public static final String CMD_USER = "user";
 
     /**
+     * 消息类型 user 用户消息
+     */
+    public static final String CMD_ENQUIRY = "enquiry";
+
+    /**
      * 消息类型 topic 系统通知
      */
     public static final String CMD_TOPIC = "topic";

+ 8 - 4
jeecg-boot-base-core/src/main/java/org/jeecg/common/util/filter/SsrfFileTypeFilter.java

@@ -23,8 +23,11 @@ public class SsrfFileTypeFilter {
      * 允许操作文件类型白名单
      */
     private final static List<String> FILE_TYPE_WHITE_LIST = new ArrayList<>();
-    /**初始化文件头类型,不够的自行补充*/
+    /**
+     * 初始化文件头类型,不够的自行补充
+     */
     final static HashMap<String, String> FILE_TYPE_MAP = new HashMap<>();
+
     static {
         //图片文件
         FILE_TYPE_WHITE_LIST.add("jpg");
@@ -34,6 +37,7 @@ public class SsrfFileTypeFilter {
         FILE_TYPE_WHITE_LIST.add("bmp");
         FILE_TYPE_WHITE_LIST.add("svg");
         FILE_TYPE_WHITE_LIST.add("ico");
+        FILE_TYPE_WHITE_LIST.add("webp");
 
         //文本文件
         FILE_TYPE_WHITE_LIST.add("txt");
@@ -197,7 +201,7 @@ public class SsrfFileTypeFilter {
                     break;
                 }
             }
-            log.info("-----获取到的指定文件类型------"+fileExtendName);
+            log.info("-----获取到的指定文件类型------" + fileExtendName);
             // 如果不是上述类型,则判断扩展名
             if (StringUtils.isBlank(fileExtendName)) {
                 String fileName = file.getOriginalFilename();
@@ -208,13 +212,13 @@ public class SsrfFileTypeFilter {
                 // 如果有扩展名,则返回扩展名
                 return getFileTypeBySuffix(fileName);
             }
-            log.info("-----最終的文件类型------"+fileExtendName);
+            log.info("-----最終的文件类型------" + fileExtendName);
             is.close();
             return fileExtendName;
         } catch (Exception e) {
             log.error(e.getMessage(), e);
             return "";
-        }finally {
+        } finally {
             if (is != null) {
                 is.close();
             }

+ 93 - 87
jeecg-module-system/jeecg-system-biz/pom.xml

@@ -1,87 +1,87 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0"
-		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-	<parent>
-		<groupId>org.jeecgframework.boot</groupId>
-		<artifactId>jeecg-module-system</artifactId>
-		<version>3.7.0</version>
-	</parent>
-	<modelVersion>4.0.0</modelVersion>
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.jeecgframework.boot</groupId>
+        <artifactId>jeecg-module-system</artifactId>
+        <version>3.7.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
 
-	<artifactId>jeecg-system-biz</artifactId>
+    <artifactId>jeecg-system-biz</artifactId>
 
-	<dependencies>
-		<dependency>
-			<groupId>org.jeecgframework.boot</groupId>
-			<artifactId>jeecg-system-local-api</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.hibernate</groupId>
-			<artifactId>hibernate-core</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.jeecgframework.boot3</groupId>
-			<artifactId>hibernate-re</artifactId>
-		</dependency>
+    <dependencies>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-system-local-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jeecgframework.boot3</groupId>
+            <artifactId>hibernate-re</artifactId>
+        </dependency>
 
-		<!-- 企业微信/钉钉 api -->
-		<dependency>
-			<groupId>org.jeecgframework</groupId>
-			<artifactId>jeewx-api</artifactId>
-		</dependency>
-		<!-- 积木报表 -->
-		<dependency>
-			<groupId>org.jeecgframework.jimureport</groupId>
-			<artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
-		</dependency>
-		<dependency>
-			<groupId>org.jeecgframework.jimureport</groupId>
-			<artifactId>drag-free-springboot3</artifactId>
-			<version>1.1.2</version>
-		</dependency>
-		<dependency>
-			<groupId>cn.hutool</groupId>
-			<artifactId>hutool-all</artifactId>
-			<version>5.8.25</version>
-		</dependency>
+        <!-- 企业微信/钉钉 api -->
+        <dependency>
+            <groupId>org.jeecgframework</groupId>
+            <artifactId>jeewx-api</artifactId>
+        </dependency>
+        <!-- 积木报表 -->
+        <dependency>
+            <groupId>org.jeecgframework.jimureport</groupId>
+            <artifactId>jimureport-spring-boot3-starter-fastjson2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jeecgframework.jimureport</groupId>
+            <artifactId>drag-free-springboot3</artifactId>
+            <version>1.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.25</version>
+        </dependency>
 
-		<dependency>
-			<groupId>com.maxmind.geoip2</groupId>
-			<artifactId>geoip2</artifactId>
-			<version>2.12.0</version>
-			<scope>compile</scope>
-		</dependency>
+        <dependency>
+            <groupId>com.maxmind.geoip2</groupId>
+            <artifactId>geoip2</artifactId>
+            <version>2.12.0</version>
+            <scope>compile</scope>
+        </dependency>
 
-		<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core -->
-		<dependency>
-			<groupId>org.apache.lucene</groupId>
-			<artifactId>lucene-core</artifactId>
-			<version>7.7.3</version>
-		</dependency>
-		<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-common -->
-		<dependency>
-			<groupId>org.apache.lucene</groupId>
-			<artifactId>lucene-analyzers-common</artifactId>
-			<version>7.7.3</version>
-		</dependency>
-		<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-queryparser -->
-		<dependency>
-			<groupId>org.apache.lucene</groupId>
-			<artifactId>lucene-queryparser</artifactId>
-			<version>7.7.3</version>
-		</dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-core -->
+        <dependency>
+            <groupId>org.apache.lucene</groupId>
+            <artifactId>lucene-core</artifactId>
+            <version>7.7.3</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-analyzers-common -->
+        <dependency>
+            <groupId>org.apache.lucene</groupId>
+            <artifactId>lucene-analyzers-common</artifactId>
+            <version>7.7.3</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-queryparser -->
+        <dependency>
+            <groupId>org.apache.lucene</groupId>
+            <artifactId>lucene-queryparser</artifactId>
+            <version>7.7.3</version>
+        </dependency>
 
-		<dependency>
-			<groupId>redis.clients</groupId>
-			<artifactId>jedis</artifactId>
-			<version>2.9.0</version>
-		</dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+            <version>2.9.0</version>
+        </dependency>
 
-	<!-- 积木报表 mongo redis 支持包
-		<dependency>
-			<groupId>org.jeecgframework.jimureport</groupId>
-			<artifactId>jimureport-nosql-starter</artifactId>
-		</dependency>-->
+        <!-- 积木报表 mongo redis 支持包
+            <dependency>
+                <groupId>org.jeecgframework.jimureport</groupId>
+                <artifactId>jimureport-nosql-starter</artifactId>
+            </dependency>-->
 
         <!--xxl-job定时任务-->
         <dependency>
@@ -100,18 +100,24 @@
             <version>5.8.25</version>
             <scope>compile</scope>
         </dependency>
-		<!--dataforseo client https://docs.dataforseo.com/v3/-->
-		<dependency>
-			<groupId>io.github.dataforseo</groupId>
-			<artifactId>dataforseo-client</artifactId>
-			<version>1.0.19</version>
-		</dependency>
+        <!--dataforseo client https://docs.dataforseo.com/v3/-->
+        <dependency>
+            <groupId>io.github.dataforseo</groupId>
+            <artifactId>dataforseo-client</artifactId>
+            <version>1.0.19</version>
+        </dependency>
 
-		<dependency>
-			<groupId>com.amazonaws</groupId>
-			<artifactId>aws-java-sdk</artifactId>
-			<version>1.11.1000</version>
-		</dependency>
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk</artifactId>
+            <version>1.11.1000</version>
+        </dependency>
+
+        <dependency>
+            <groupId>ch.ethz.ganymed</groupId>
+            <artifactId>ganymed-ssh2</artifactId>
+            <version>262</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 82 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/ShellConstans.java

@@ -0,0 +1,82 @@
+package org.jeecg.modules.adweb.common.constant;
+
+/**
+ * class
+ *
+ * @author 马娟娟
+ * @date 2019/8/26 0026 17:29
+ * @Description
+ */
+public class ShellConstans {
+
+    /**
+     * 站点备份shell脚本常量
+     */
+    public interface BackupSite {
+
+        public final static String ERROR = "[ERROR]";
+
+        public final static String BACKUPCOMPLETE = "[BACKUPCOMPLETE]";
+
+        public final static String BACKUP_PATH = "[BACKUP_PATH]";
+
+        public final static String BACKUP_SIZE = "[BACKUP_SIZE]";
+
+        public final static String BACKUP_RESULT = "[BACKUP_RESULT]";
+
+    }
+
+    /**
+     * 站点内存空间监控
+     */
+    public interface SiteSize {
+
+        public final static String WEBSITE_DISK = "**website_disk**";
+
+    }
+
+    /**
+     * 服务内存空间监控
+     */
+    public interface ServerSize {
+
+        public final static String SERVER_DISK = "**server_disk**";
+
+        public final static String SERVER_MEM = "**server_mem**";
+
+        public final static String SERVER_CPU = "**server_cpu**";
+
+    }
+
+    /**
+     * 磁盘常量
+     */
+    public final static Integer DISK_NUM = 70;
+    /**
+     * CPU常量
+     */
+    public final static Integer CPU_NUM = 80;
+    /**
+     * 内存常量
+     */
+    public final static Integer MEMORY_NUM = 80;
+
+    public final static String SUCCESS_INFO = "[UPDATECOMPLETE]";
+
+    /**
+     * 自动添加SSL
+     */
+    public interface addSsl {
+        public final static String START_CERT = "[start cert.pem]";
+        public final static String END_CERT = "[end cert.pem]";
+        public final static String START_PRIVKEY = "[start privkey.pem]";
+        public final static String END_PRIVKEY = "[end privkey.pem]";
+        public final static String START_CHAIN = "[start chain.pem]";
+        public final static String END_CHAIN = "[end chain.pem]";
+        public final static String IS_ERROR_INFO = "[EXIST]";
+        public final static String NULL_ERROR_INFO = "[NONEXIST]";
+        public final static String DATE_TIME = "[LASTMTIME]";
+    }
+
+
+}

+ 12 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/mapper/CommonMapper.java

@@ -1,6 +1,10 @@
 package org.jeecg.modules.adweb.common.mapper;
 
+import org.apache.ibatis.annotations.Select;
+import org.jeecg.modules.system.entity.SysUser;
+
 import java.util.Date;
+import java.util.List;
 
 /**
  * 通用MyBatis mapper工具
@@ -18,4 +22,12 @@ public interface CommonMapper {
      * @return
      */
     Date getMaxDate(String tableName, String fieldName, String filter);
+
+    @Select("SELECT t1.id id,t1.realname realName\n" +
+            "FROM sys_user t1 Left JOIN sys_user_role t2\n" +
+            "ON t1.id = t2.user_id\n" +
+            "Left JOIN sys_role t3\n" +
+            "ON t3.id = t2.role_id\n" +
+            "WHERE t3.role_code = 'adweb_vip' AND t1.del_flag = 0 AND t1.username != ''")
+    List<SysUser> getAdwebVip();
 }

+ 26 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/service/FeishuService.java

@@ -6,6 +6,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.xkcoding.http.util.StringUtil;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.jeecg.modules.adweb.common.constant.RobotMsgTemplate;
 import org.jeecg.modules.adweb.common.dto.RobotDto;
 import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
@@ -14,6 +15,8 @@ import org.jeecg.modules.system.service.ISysDictService;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
@@ -49,7 +52,6 @@ public class FeishuService {
     private String gtmUrl;
 
 
-
     /**
      * 本地属性
      */
@@ -119,4 +121,27 @@ public class FeishuService {
         HttpRequest.post(enquiryUrl).body(object.toJSONString()).execute(true);
     }
 
+    /**
+     * @return
+     */
+    public void sendAdWebV2FeiShuMsg(String msgTitle, String message) throws NoSuchAlgorithmException, InvalidKeyException {
+//        String secretSign = "Irf26L7VJCbXPH0HOLJEkf";
+//        int timestamp = Integer.parseInt((System.currentTimeMillis() / 1000) + "");
+//        int timestamp=Integer.parseInt(String.valueOf(System.currentTimeMillis()).substring(0,10));
+//        log.info("timestamp:{}", timestamp);
+
+        String param = "{\"msg_type\":\"interactive\",\"card\":{\"header\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"msgTitle\"},\"template\":\"blue\"},\"elements\":[{\"tag\":\"div\",\"text\":{\"tag\":\"lark_md\",\"content\":\"message\"}}]}}";
+        if (StringUtils.isNotBlank(message)) {
+            param = param.replace("message", message);
+        }
+        if (StringUtils.isNotBlank(msgTitle)) {
+            param = param.replace("msgTitle", msgTitle);
+        }
+
+        JSONObject object = JSONObject.parseObject(param);
+//        object.replace("timestamp", timestamp);
+//        object.replace("sign", genSign(secretSign, timestamp));
+        HttpRequest.post(gtmUrl).body(object.toJSONString()).execute(true);
+    }
+
 }

+ 325 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/service/ShellService.java

@@ -0,0 +1,325 @@
+package org.jeecg.modules.adweb.common.service;
+
+
+import org.jeecg.modules.adweb.common.util.ShellSSH2Util;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+/**
+ * shell脚本调用
+ *
+ * @author jerry-
+ */
+@Service
+public class ShellService {
+    /**
+     * 日志
+     */
+    private static Logger logger = LoggerFactory.getLogger(ShellService.class);
+
+    @Value("${adcloud.file.rootpath}")
+    String rootPath;
+    @Value("${admp.shell.path}")
+    private String shellPath;
+    @Value("${jumpServer.pulicIp}")
+    private String pulicIp;
+    @Value("${jumpServer.username}")
+    private String jumpServerUserName;
+    @Value("${jumpServer.pem}")
+    private String jumpServerPem;
+
+    @Value("${usWest118Server.ip}")
+    private String usWest118ServerIp;
+
+    @Value("${usWest118Server.username}")
+    private String usWest118ServerUsername;
+
+    @Value("${usWest118Server.pem}")
+    private String usWest118ServerPem;
+
+    @Value("${usWest118Server.port}")
+    private Integer usWest118ServerPort;
+
+    @Value("${usWest118Server.shellpath}")
+    private String usWest118ServerShellPath;
+
+    @Value("${v2.projectPath}")
+    private String v2ProjectPath;
+
+    /**
+     * 创建共享站点  命令
+     *
+     * @param cmd            控制台返回监听器
+     * @param host           建站连接测试环境配置 域名
+     * @param port           端口
+     * @param username
+     * @param password
+     * @param stdoutListener
+     */
+    public void createShareSiteByPwd(String cmd
+            , String host
+            , int port
+            , String username
+            , String password
+            , ShellSSH2Util.StdoutListener stdoutListener) {
+        exceShellByPwd(cmd, host, port, username, password, stdoutListener);
+    }
+
+
+    /**
+     * 执行远程Shell脚本 (通过用户名和密码)
+     *
+     * @param cmd            命令
+     * @param host           建站连接测试环境配置 域名
+     * @param port           端口
+     * @param username
+     * @param password
+     * @param stdoutListener
+     * @param stdoutListener 控制台输出监听器
+     */
+    public void exceShellByPwd(String cmd
+            , String host
+            , int port
+            , String username
+            , String password
+            , ShellSSH2Util.StdoutListener stdoutListener) {
+        long currentTimeMillis = System.currentTimeMillis();
+        ShellSSH2Util.execmdByPwd(host, port, username, password, cmd, stdoutListener);
+        long currentTimeMillis1 = System.currentTimeMillis();
+        logger.info("花费时间:" + (currentTimeMillis1 - currentTimeMillis));
+    }
+
+    /**
+     * 站点发布
+     *
+     * @param domain
+     * @param code
+     * @return
+     */
+    public Integer publishSiteShell(String domain, String code) {
+        logger.info("发布域名:{},站点code:{}", domain, code);
+        String cmd = shellPath + "adweb2.0-website.sh " + domain + " " + code;
+        logger.info("脚本命令:{}", cmd);
+        Process p;
+        int res = 0;
+        try {
+            p = Runtime.getRuntime().exec(cmd);
+            InputStream fis = p.getInputStream();
+            InputStreamReader isr = new InputStreamReader(fis);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                if ("finished".equals(line)) {
+                    res = 1;
+                }
+                logger.info(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            res = 0;
+        }
+        return res;
+    }
+
+    /**
+     * 子站点发布
+     *
+     * @param sourcePath
+     * @param targetPath
+     * @return
+     */
+    public Integer publishChildrenSiteShell(String sourcePath, String targetPath) {
+        logger.info("源站点:{},目标位置:{}", sourcePath, targetPath);
+        String cmd = shellPath + "createChildSiteLink.sh " + sourcePath + " " + targetPath;
+        logger.info("脚本命令:{}", cmd);
+        Process p = null;
+        int res = 0;
+        try {
+            p = Runtime.getRuntime().exec(cmd);
+            InputStream fis = p.getInputStream();
+            InputStreamReader isr = new InputStreamReader(fis);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                if ("finished".equals(line)) {
+                    res = 1;
+                }
+                logger.info(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            res = 0;
+        }
+        return res;
+    }
+
+    /**
+     * @param targetPath
+     * @return
+     */
+    public Integer rmChildrenSiteShell(String targetPath) {
+        logger.info("目标位置:{}", targetPath);
+        String cmd = shellPath + "rmChildSiteLink.sh " + targetPath;
+        logger.info("脚本命令:{}", cmd);
+        Process p = null;
+        int res = 0;
+        try {
+            p = Runtime.getRuntime().exec(cmd);
+            InputStream fis = p.getInputStream();
+            InputStreamReader isr = new InputStreamReader(fis);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                if ("finished".equals(line)) {
+                    res = 1;
+                }
+                logger.info(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            res = 0;
+        }
+        return res;
+    }
+
+    /**
+     * @param domain
+     * @return
+     */
+    public Integer stopSiteShell(String domain) {
+        logger.info("源站点:{}", domain);
+        String cmd = shellPath + "stop_site.sh " + domain;
+        logger.info("脚本命令:{}", cmd);
+        Process p = null;
+        int res = 0;
+        try {
+            p = Runtime.getRuntime().exec(cmd);
+            InputStream fis = p.getInputStream();
+            InputStreamReader isr = new InputStreamReader(fis);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                if ("finished".equals(line)) {
+                    res = 1;
+                }
+                logger.info(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            res = 0;
+        }
+        return res;
+    }
+
+    /**
+     * @param domain
+     * @return
+     */
+    public Integer startSiteShell(String domain) {
+        logger.info("源站点:{}", domain);
+        String cmd = shellPath + "start_site.sh " + domain;
+        logger.info("脚本命令:{}", cmd);
+        Process p = null;
+        int res = 0;
+        try {
+            p = Runtime.getRuntime().exec(cmd);
+            InputStream fis = p.getInputStream();
+            InputStreamReader isr = new InputStreamReader(fis);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                if ("finished".equals(line)) {
+                    res = 1;
+                }
+                logger.info(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            res = 0;
+        }
+        return res;
+    }
+
+    /**
+     * @param siteCode
+     * @return
+     */
+    public Integer createSiteSsl(String siteCode) {
+        logger.info("源站点:{}", siteCode);
+        String cmd = shellPath + "stopSite.sh " + siteCode;
+        logger.info("脚本命令:{}", cmd);
+        Process p = null;
+        int res = 0;
+        try {
+            p = Runtime.getRuntime().exec(cmd);
+            InputStream fis = p.getInputStream();
+            InputStreamReader isr = new InputStreamReader(fis);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                if ("finished".equals(line)) {
+                    res = 1;
+                }
+                logger.info(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            res = 0;
+        }
+        return res;
+    }
+
+
+    /**
+     * 执行远程Shell脚本
+     *
+     * @param cmd            命令
+     * @param stdoutListener 控制台输出监听器
+     */
+    public void exceShell(String cmd, ShellSSH2Util.StdoutListener stdoutListener) {
+        long currentTimeMillis = System.currentTimeMillis();
+        File pemFile = new File(jumpServerPem);
+        ShellSSH2Util.execmd(pulicIp, jumpServerUserName, pemFile, cmd, stdoutListener);
+        long currentTimeMillis1 = System.currentTimeMillis();
+        System.out.println("花费时间:" + (currentTimeMillis1 - currentTimeMillis));
+    }
+
+    /**
+     * 执行远程Shell脚本
+     *
+     * @param cmd            命令
+     * @param stdoutListener 控制台输出监听器
+     */
+    public void exceShellByUsWest118(String cmd, ShellSSH2Util.StdoutListener stdoutListener) {
+        long currentTimeMillis = System.currentTimeMillis();
+        File pemFile = new File(usWest118ServerPem);
+        ShellSSH2Util.execmd(usWest118ServerIp, usWest118ServerPort, usWest118ServerUsername, pemFile, cmd, stdoutListener);
+        long currentTimeMillis1 = System.currentTimeMillis();
+        System.out.println("花费时间:" + (currentTimeMillis1 - currentTimeMillis));
+    }
+
+    /**
+     * 执行远程Shell脚本
+     *
+     * @param cmd            命令
+     * @param stdoutListener 控制台输出监听器
+     */
+    public void exceShellByServerInfo(String cmd, String ip, Integer port, String username, String password, ShellSSH2Util.StdoutListener stdoutListener) {
+        long currentTimeMillis = System.currentTimeMillis();
+        if (password.contains(".cer") || password.contains(".pem")) {
+            File pemFile = new File(v2ProjectPath + "/" + password);
+            ShellSSH2Util.execmd(ip, port, username, pemFile, cmd, stdoutListener);
+        } else {
+            ShellSSH2Util.execmdByPwd(ip, port, username, password, cmd, stdoutListener);
+        }
+        long currentTimeMillis1 = System.currentTimeMillis();
+        System.out.println("花费时间:" + (currentTimeMillis1 - currentTimeMillis));
+    }
+}

+ 65 - 52
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/AdwebRedisUtil.java

@@ -2,11 +2,13 @@ package org.jeecg.modules.adweb.common.util;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
-
+import com.fasterxml.jackson.databind.json.JsonMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
-
-import org.springframework.beans.factory.annotation.Autowired;
+import org.jeecg.common.base.BaseMap;
 import org.springframework.data.redis.core.RedisCallback;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
@@ -27,12 +29,13 @@ import java.util.concurrent.TimeUnit;
 @Slf4j
 public class AdwebRedisUtil {
 
-    @Autowired private RedisTemplate<String, Object> redisTemplate;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
 
-    @Autowired(required = false)
-    public void setRedisTemplate(RedisTemplate redisTemplate) {
+    @Resource
+    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
         Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = jacksonSerializer();
-        RedisSerializer stringSerializer = new StringRedisSerializer();
+        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
         redisTemplate.setKeySerializer(stringSerializer);
         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
         redisTemplate.setHashKeySerializer(stringSerializer);
@@ -40,20 +43,30 @@ public class AdwebRedisUtil {
         this.redisTemplate = redisTemplate;
     }
 
-    private Jackson2JsonRedisSerializer jacksonSerializer() {
-        ObjectMapper objectMapper = new ObjectMapper();
-        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =
-                new Jackson2JsonRedisSerializer(objectMapper, Object.class);
-        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+    private Jackson2JsonRedisSerializer<Object> jacksonSerializer() {
+        JsonMapper jsonMapper =
+                JsonMapper.builder()
+                        .visibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
+                        .activateDefaultTyping(
+                                LaissezFaireSubTypeValidator.instance,
+                                ObjectMapper.DefaultTyping.NON_FINAL)
+                        .configure(MapperFeature.USE_ANNOTATIONS, false) // 忽略@JsonIgnore注解,缓存所有字段
+                        .build();
+
+
+        return new Jackson2JsonRedisSerializer<>(jsonMapper, Object.class);
+    }
 
-        return jackson2JsonRedisSerializer;
+    public void sendMessage(String handlerName, BaseMap params) {
+        params.put("handlerName", handlerName);
+        this.setRedisTemplate(this.redisTemplate);
+        this.redisTemplate.convertAndSend("jeecg_redis_topic", params);
     }
 
     /**
      * 指定缓存失效时间
      *
-     * @param key 键
+     * @param key  
      * @param time 时间(秒)
      * @return
      */
@@ -146,7 +159,7 @@ public class AdwebRedisUtil {
     /**
      * 普通缓存放入
      *
-     * @param key 键
+     * @param key   
      * @param value 值
      * @return true成功 false失败
      */
@@ -163,9 +176,9 @@ public class AdwebRedisUtil {
     /**
      * 普通缓存放入并设置时间
      *
-     * @param key 键
+     * @param key   
      * @param value 值
-     * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
      * @return true成功 false 失败
      */
     public boolean set(String key, Object value, long time) {
@@ -185,7 +198,7 @@ public class AdwebRedisUtil {
     /**
      * 递增
      *
-     * @param key 键
+     * @param key   
      * @param delta 要增加几(大于0)
      * @return
      */
@@ -199,7 +212,7 @@ public class AdwebRedisUtil {
     /**
      * 递减
      *
-     * @param key 键
+     * @param key   
      * @param delta 要减少几(小于0)
      * @return
      */
@@ -215,7 +228,7 @@ public class AdwebRedisUtil {
     /**
      * HashGet
      *
-     * @param key 键 不能为null
+     * @param key  键 不能为null
      * @param item 项 不能为null
      * @return 值
      */
@@ -253,8 +266,8 @@ public class AdwebRedisUtil {
     /**
      * HashSet 并设置时间
      *
-     * @param key 键
-     * @param map 对应多个键值
+     * @param key  
+     * @param map  对应多个键值
      * @param time 时间(秒)
      * @return true成功 false失败
      */
@@ -274,8 +287,8 @@ public class AdwebRedisUtil {
     /**
      * 向一张hash表中放入数据,如果不存在将创建
      *
-     * @param key 键
-     * @param item 项
+     * @param key   
+     * @param item  
      * @param value 值
      * @return true 成功 false失败
      */
@@ -292,10 +305,10 @@ public class AdwebRedisUtil {
     /**
      * 向一张hash表中放入数据,如果不存在将创建
      *
-     * @param key 键
-     * @param item 项
+     * @param key   
+     * @param item  
      * @param value 值
-     * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
      * @return true 成功 false失败
      */
     public boolean hset(String key, String item, Object value, long time) {
@@ -314,7 +327,7 @@ public class AdwebRedisUtil {
     /**
      * 删除hash表中的值
      *
-     * @param key 键 不能为null
+     * @param key  键 不能为null
      * @param item 项 可以使多个 不能为null
      */
     public void hdel(String key, Object... item) {
@@ -324,7 +337,7 @@ public class AdwebRedisUtil {
     /**
      * 判断hash表中是否有该项的值
      *
-     * @param key 键 不能为null
+     * @param key  键 不能为null
      * @param item 项 不能为null
      * @return true 存在 false不存在
      */
@@ -335,9 +348,9 @@ public class AdwebRedisUtil {
     /**
      * hash递增 如果不存在,就会创建一个 并把新增后的值返回
      *
-     * @param key 键
+     * @param key  
      * @param item 项
-     * @param by 要增加几(大于0)
+     * @param by   要增加几(大于0)
      * @return
      */
     public double hincr(String key, String item, double by) {
@@ -347,9 +360,9 @@ public class AdwebRedisUtil {
     /**
      * hash递减
      *
-     * @param key 键
+     * @param key  
      * @param item 项
-     * @param by 要减少记(小于0)
+     * @param by   要减少记(小于0)
      * @return
      */
     public double hdecr(String key, String item, double by) {
@@ -376,7 +389,7 @@ public class AdwebRedisUtil {
     /**
      * 根据value从一个set中查询,是否存在
      *
-     * @param key 键
+     * @param key   
      * @param value 值
      * @return true 存在 false不存在
      */
@@ -392,7 +405,7 @@ public class AdwebRedisUtil {
     /**
      * 将数据放入set缓存
      *
-     * @param key 键
+     * @param key    
      * @param values 值 可以是多个
      * @return 成功个数
      */
@@ -408,8 +421,8 @@ public class AdwebRedisUtil {
     /**
      * 将set数据放入缓存
      *
-     * @param key 键
-     * @param time 时间(秒)
+     * @param key    
+     * @param time   时间(秒)
      * @param values 值 可以是多个
      * @return 成功个数
      */
@@ -444,7 +457,7 @@ public class AdwebRedisUtil {
     /**
      * 移除值为value的
      *
-     * @param key 键
+     * @param key    
      * @param values 值 可以是多个
      * @return 移除的个数
      */
@@ -463,9 +476,9 @@ public class AdwebRedisUtil {
     /**
      * 获取list缓存的内容
      *
-     * @param key 键
+     * @param key   
      * @param start 开始
-     * @param end 结束 0 到 -1代表所有值
+     * @param end   结束 0 到 -1代表所有值
      * @return
      */
     public List<Object> lGet(String key, long start, long end) {
@@ -495,7 +508,7 @@ public class AdwebRedisUtil {
     /**
      * 通过索引 获取list中的值
      *
-     * @param key 键
+     * @param key   
      * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
      * @return
      */
@@ -511,7 +524,7 @@ public class AdwebRedisUtil {
     /**
      * 将list放入缓存
      *
-     * @param key 键
+     * @param key   
      * @param value 值
      * @return
      */
@@ -528,9 +541,9 @@ public class AdwebRedisUtil {
     /**
      * 将list放入缓存
      *
-     * @param key 键
+     * @param key   
      * @param value 值
-     * @param time 时间(秒)
+     * @param time  时间(秒)
      * @return
      */
     public boolean lSet(String key, Object value, long time) {
@@ -549,7 +562,7 @@ public class AdwebRedisUtil {
     /**
      * 将list放入缓存
      *
-     * @param key 键
+     * @param key   
      * @param value 值
      * @return
      */
@@ -566,9 +579,9 @@ public class AdwebRedisUtil {
     /**
      * 将list放入缓存
      *
-     * @param key 键
+     * @param key   
      * @param value 值
-     * @param time 时间(秒)
+     * @param time  时间(秒)
      * @return
      */
     public boolean lSet(String key, List<Object> value, long time) {
@@ -587,7 +600,7 @@ public class AdwebRedisUtil {
     /**
      * 根据索引修改list中的某条数据
      *
-     * @param key 键
+     * @param key   
      * @param index 索引
      * @param value 值
      * @return
@@ -605,7 +618,7 @@ public class AdwebRedisUtil {
     /**
      * 移除N个值为value
      *
-     * @param key 键
+     * @param key   
      * @param count 移除多少个
      * @param value 值
      * @return 移除的个数
@@ -623,7 +636,7 @@ public class AdwebRedisUtil {
     /**
      * 获取锁
      *
-     * @param lockKey 锁的键
+     * @param lockKey        锁的键
      * @param lockExpireMils 获取锁的时间
      * @return 是否获取到锁
      */
@@ -658,7 +671,7 @@ public class AdwebRedisUtil {
                                                 return oldValue == null
                                                         ? false
                                                         : Long.parseLong(new String(oldValue))
-                                                                < nowTime;
+                                                        < nowTime;
                                             }
                                         }
                                     }

+ 46 - 10
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/DateUtil.java

@@ -1,7 +1,6 @@
 package org.jeecg.modules.adweb.common.util;
 
 import lombok.extern.slf4j.Slf4j;
-
 import org.apache.commons.lang3.tuple.Pair;
 
 import java.text.ParseException;
@@ -9,7 +8,9 @@ import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.ZoneId;
 import java.time.temporal.ChronoUnit;
-import java.util.*;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
 import java.util.stream.IntStream;
 
 /**
@@ -22,27 +23,46 @@ import java.util.stream.IntStream;
 @Slf4j
 public class DateUtil {
 
-    /** 标准日期格式(yyyy-MM-dd) */
+    /**
+     * 标准日期格式(yyyy-MM-dd)
+     */
     public static final String DATE_FORMAT = "yyyy-MM-dd";
 
-    /** 标准时间格式(yyyy-MM-dd HH:mm:ss) */
+    /**
+     * 标准时间格式(yyyy-MM-dd HH:mm:ss)
+     */
     public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
 
-    /** 带时区的时间格式(yyyy-MM-dd HH:mm:ss +00:00) */
+    /**
+     * 带时区的时间格式(yyyy-MM-dd HH:mm:ss +00:00)
+     */
     public static final String ZONED_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss X";
 
-    /** 时间格式(yyyy/MM/dd) */
+    /**
+     * 时间格式(yyyy/MM/dd)
+     */
     public static final String SUBJECT_DATE_FORMAT = "yyyy/MM/dd";
 
-    /** 时间格式(yyyyMMdd) */
+    /**
+     * 时间格式(yyyyMMdd)
+     */
     public static final String COMPACT_DATE_FORMAT = "yyyyMMdd";
 
-    /** 时间格式(yyyyMMddHHmmss) */
+    /**
+     * 时间格式(yyyyMMddHHmmss)
+     */
     public static final String COMPACT_DATE_TIME_FORMAT = "yyyyMMddHHmmss";
 
     public static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("Asia/Shanghai");
 
     /**
+     * 取得系统当前日期
+     */
+    public static Date getDate() {
+        return new Date();
+    }
+
+    /**
      * 根据日期类型返回日期区间
      *
      * @param dateType 日期类型
@@ -110,7 +130,7 @@ public class DateUtil {
     /**
      * 在当前日期上追加N天
      *
-     * @param date 当前日期
+     * @param date      当前日期
      * @param daysToAdd 添加天数
      * @return 日期字符串形式
      */
@@ -122,6 +142,20 @@ public class DateUtil {
     }
 
     /**
+     * 在当前日期上追加N年
+     *
+     * @param date 当前日期
+     * @param num  添加年数
+     * @return 日期字符串形式
+     */
+    public static Date addYear(Date date, int num) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        c.add(Calendar.YEAR, num);
+        return c.getTime();
+    }
+
+    /**
      * 计算两个Date的日期差
      *
      * @param start
@@ -135,7 +169,9 @@ public class DateUtil {
                         LocalDate.ofInstant(end.toInstant(), DEFAULT_ZONE_ID));
     }
 
-    /** 获取start和end之间所有的日期,包含起止两端 */
+    /**
+     * 获取start和end之间所有的日期,包含起止两端
+     */
     public static List<Date> getAllDaysBetween(Date start, Date end) {
         return IntStream.rangeClosed(0, diffDays(start, end))
                 .mapToObj(diff -> addDays(start, diff))

+ 375 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/util/ShellSSH2Util.java

@@ -0,0 +1,375 @@
+package org.jeecg.modules.adweb.common.util;
+
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+import ch.ethz.ssh2.StreamGobbler;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+
+/**
+ * 远程Shell执行工具类
+ *
+ * @author liyl
+ * @date 2019-08-13
+ */
+@Slf4j
+public class ShellSSH2Util {
+
+    /**
+     * 日志
+     */
+    protected static Logger logger = LoggerFactory.getLogger(ShellSSH2Util.class);
+
+
+    /**
+     * 默认字符编码
+     */
+    private static String DEFAULT_CHART = "UTF-8";
+
+    /**
+     * 登录远程服务器
+     *
+     * @param host     远程主机
+     * @param username 远程主机登录用户名
+     * @param password 远程主机登录密码
+     * @return Connection
+     */
+    public static Connection login(String host, int port, String username, String password, StdoutListener listener) {
+        Connection connection = null;
+        listener.stdout("开始连接:" + username + "@" + host);
+        try {
+            connection = new Connection(host, port);
+            connection.connect();// 连接
+            boolean login = connection.authenticateWithPassword(username, password);// 认证
+            if (login) {
+                listener.stdout(username + "@" + host + "; 登录成功");
+            } else {
+                listener.stderr(username + "@" + host + "; 登录失败");
+                connection.close();
+            }
+        } catch (IOException e) {
+            listener.stderr(username + "@" + host + "; 登录失败");
+            log.error("服务器host:{},连接失败:{}", host, e.getMessage());
+            connection.close();
+        }
+        return connection;
+    }
+
+    /**
+     * 登录远程服务器
+     *
+     * @param host     远程主机
+     * @param username 远程主机登录用户名
+     * @param pemFile  登录密钥
+     * @param listener 执行过程监听器
+     * @return Connection
+     */
+    public static Connection login(String host, int port, String username, File pemFile, StdoutListener listener) {
+        Connection connection = null;
+        listener.stdout("开始连接:" + username + "@" + host);
+        try {
+            connection = new Connection(host, port);
+            connection.connect();// 连接
+            boolean login = connection.authenticateWithPublicKey(username, pemFile, null);// 认证
+            if (login) {
+                listener.stdout(username + "@" + host + "; 登录成功");
+            } else {
+                listener.stderr(username + "@" + host + "; 登录失败");
+                connection.close();
+            }
+        } catch (IOException e) {
+            listener.stderr(username + "@" + host + "; 登录失败");
+            log.error("服务器host:{},连接失败:{}", host, e.getMessage());
+            connection.close();
+        }
+        return connection;
+    }
+
+    /**
+     * 检验是否能够连接服务器
+     *
+     * @param host     远程主机
+     * @param port     端口
+     * @param username 远程主机登录用户名
+     * @param password 远程主机登录密码
+     * @return true:可以连接  false:无法连接
+     * @author Cyan -- 2020/4/26 10:56
+     */
+    public static Boolean loginCheck(String host, int port, String username, String password, StdoutListener listener) {
+        Boolean result = true;
+        Connection connection = null;
+        listener.stdout("开始连接:" + username + "@" + host);
+        try {
+            connection = new Connection(host, port);
+            connection.connect();// 连接
+            boolean login = connection.authenticateWithPassword(username, password);// 认证
+            if (login) {
+                listener.stdout(username + "@" + host + "; 登录成功");
+            } else {
+                result = false;
+                listener.stderr(username + "@" + host + "; 登录失败");
+                if (connection != null) {
+                    connection.close();
+                }
+            }
+        } catch (IOException e) {
+            result = false;
+            listener.stderr(username + "@" + host + "; 登录失败");
+            if (connection != null) {
+                connection.close();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 登录远程服务器
+     *
+     * @param host     远程主机
+     * @param username 远程主机登录用户名
+     * @param pemFile  登录密钥
+     * @param listener 执行过程监听器
+     * @return Connection
+     */
+    private static Connection login(String host, String username, File pemFile, StdoutListener listener) {
+        Connection connection = null;
+        listener.stdout("开始连接:" + username + "@" + host);
+        try {
+            connection = new Connection(host);
+            connection.connect();// 连接
+            boolean login = connection.authenticateWithPublicKey(username, pemFile, null);// 认证
+            if (login) {
+                listener.stdout(username + "@" + host + "; 登录成功");
+            } else {
+                listener.stderr(username + "@" + host + "; 登录失败");
+                if (connection != null) {
+                    connection.close();
+                }
+            }
+        } catch (IOException e) {
+            listener.stderr(username + "@" + host + "; 登录失败");
+            if (connection != null) {
+                connection.close();
+            }
+        }
+        return connection;
+    }
+
+    /**
+     * 登录远程服务器
+     *
+     * @param host     远程主机
+     * @param username 远程主机登录用户名
+     * @param pemFile  登录密钥
+     * @param listener 执行过程监听器
+     * @return Connection
+     */
+    public static Boolean loginCheck(String host, String username, File pemFile, StdoutListener listener) {
+        Boolean result = true;
+        Connection connection = null;
+        listener.stdout("开始连接:" + username + "@" + host);
+        try {
+            connection = new Connection(host);
+            connection.connect();// 连接
+            boolean login = connection.authenticateWithPublicKey(username, pemFile, null);// 认证
+            if (login) {
+                listener.stdout(username + "@" + host + "; 登录成功");
+            } else {
+                result = false;
+                listener.stderr(username + "@" + host + "; 登录失败");
+                if (connection != null) {
+                    connection.close();
+                }
+            }
+        } catch (IOException e) {
+            result = false;
+            listener.stderr(username + "@" + host + "; 登录失败");
+            if (connection != null) {
+                connection.close();
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * 执行远程Shell命令
+     *
+     * @param host        远程主机地址
+     * @param username    远程主机用户名
+     * @param pemFilePath 远程主机登录密钥路径
+     * @param cmd         执行的命令
+     * @param listener    标准输出监听器
+     * @return String               执行结果
+     */
+    public static String execmd(String host, String username, String pemFilePath, String cmd, StdoutListener listener) {
+        File pemFile = new File(pemFilePath);
+        Connection connection = login(host, username, pemFile, listener);
+        return execmd(connection, cmd, listener);
+    }
+
+    /**
+     * 执行远程Shell命令
+     *
+     * @param host     远程主机地址
+     * @param username 远程主机用户名
+     * @param password 远程主机密码
+     * @param cmd      执行的命令
+     * @param listener 标准输出监听器
+     * @return String               执行结果
+     */
+    public static String execmdByPwd(String host, int port, String username, String password, String cmd, StdoutListener listener) {
+        Connection connection = login(host, port, username, password, listener);
+        return execmd(connection, cmd, listener);
+    }
+
+
+    /**
+     * 执行远程Shell命令
+     *
+     * @param host     远程主机地址
+     * @param username 远程主机用户名
+     * @param pemFile  远程主机登录密钥
+     * @param cmd      执行的命令
+     * @param listener 标准输出监听器
+     * @return String               执行结果
+     */
+    public static String execmd(String host, String username, File pemFile, String cmd, StdoutListener listener) {
+        Connection connection = login(host, username, pemFile, listener);
+        return execmd(connection, cmd, listener);
+    }
+
+    /**
+     * @param host
+     * @param port
+     * @param username
+     * @param pemFile
+     * @param cmd
+     * @param listener
+     * @return
+     */
+    public static String execmd(String host, int port, String username, File pemFile, String cmd, StdoutListener listener) {
+        Connection connection = login(host, port, username, pemFile, listener);
+        return execmd(connection, cmd, listener);
+    }
+
+    /**
+     * 远程执行shll脚本或者命令
+     *
+     * @param cmd 即将执行的命令
+     * @return 命令执行完后返回的结果值
+     */
+    private static String execmd(Connection connection, String cmd, StdoutListener listener) {
+        String result = "";
+        try {
+            if (connection != null) {
+                Session session = connection.openSession();// 打开一个会话
+                session.execCommand(cmd);// 执行命令
+                result = processStdout(session.getStdout(), DEFAULT_CHART, listener);
+                listener.stdout("命令标准输出结果:\n");
+                listener.stdout(result);
+                // 如果为得到标准输出为空,说明脚本执行出错了
+                if (StringUtils.isBlank(result)) {
+                    listener.stdout("得到标准输出为空,链接conn:" + connection + ",执行的命令:" + cmd);
+                    result = processStdout(session.getStderr(), DEFAULT_CHART, listener);
+                    listener.stdout("得到标准输出为空,链接conn:" + connection + ",执行的命令:" + cmd + "; 错误信息:" + result);
+                } else {
+                    listener.stdout("执行命令成功,链接conn:" + connection + ",执行的命令:" + cmd);
+                }
+                session.close();
+                connection.close();
+            }
+        } catch (IOException e) {
+            listener.stderr("执行命令失败,链接conn:" + connection + ",执行的命令:" + cmd + " " + e);
+            e.printStackTrace();
+        }
+        return result;
+
+    }
+
+    /**
+     * 解析脚本执行返回的结果集
+     *
+     * @param in      输入流对象
+     * @param charset 编码
+     * @return 以纯文本的格式返回
+     */
+    private static String processStdout(InputStream in, String charset, StdoutListener listener) {
+        InputStream stdout = new StreamGobbler(in);
+        StringBuffer buffer = new StringBuffer();
+        try {
+            BufferedReader br = new BufferedReader(new InputStreamReader(stdout, charset));
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                buffer.append(line + "\n");
+                listener.stdout(line);
+            }
+            br.close();
+        } catch (UnsupportedEncodingException e) {
+            buffer.append("解析脚本出错:" + e.getMessage() + "\n");
+            listener.stderr("解析脚本出错:" + e.getMessage());
+            e.printStackTrace();
+        } catch (IOException e) {
+            buffer.append("解析脚本出错:" + e.getMessage() + "\n");
+            listener.stderr("解析脚本出错:" + e.getMessage());
+            e.printStackTrace();
+        }
+        return buffer.toString();
+    }
+
+    public static void main(String[] args) {
+        long currentTimeMillis = System.currentTimeMillis();
+        String host = "52.33.206.188";
+        String username = "ubuntu";
+        File pemFile = new File("/Users/liyl/Desktop/jumpserver.pem");
+        String cmd = "./sb abc T000 test37.advichcloud.com";
+        cmd = "mysql -h advich-wp-product-db.cqhn3c5h2mcz.us-west-2.rds.amazonaws.com -u admin -p Ew7MEm1EmJpDVvdK";
+//        cmd = "uname -a";
+        execmd(host, username, pemFile, cmd, new StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                System.out.println("标准:" + line);
+                if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+                    // TODO 已存在,退出
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                System.out.println("错误:" + line);
+            }
+        });
+        long currentTimeMillis1 = System.currentTimeMillis();
+        System.out.println("花费时间:" + (currentTimeMillis1 - currentTimeMillis));
+    }
+
+    /**
+     * 标准输出监听器
+     *
+     * @author liyl
+     * @date 2019-08-13
+     */
+    public interface StdoutListener {
+
+        /**
+         * 控制台标准输出
+         *
+         * @param line 每行输出内容
+         */
+        void stdout(String line);
+
+        /**
+         * 控制台错误输出
+         *
+         * @param line 每行输出内容
+         */
+        void stderr(String line);
+
+    }
+
+
+}

+ 18 - 15
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/mapper/xml/AdwebPublicBlackEmailMapper.xml

@@ -4,13 +4,13 @@
     <select id="pageList" resultType="org.jeecg.modules.adweb.enquiry.entity.AdwebPublicBlackEmail">
         SELECT t1.*, t2.num wasteEnquiryNum
         FROM `adweb_public_black_email` t1
-                 LEFT JOIN (SELECT COUNT(*) num, from_email
-                            FROM adweb_enquiry
-                            WHERE `status` = 1
-                              AND user_effective = 0
-                              AND sys_effective = 1
-                              AND waste_enquiry_type = 'email'
-                            GROUP BY from_email) t2 ON t1.email = t2.from_email
+        LEFT JOIN (SELECT COUNT(*) num, from_email
+        FROM adweb_enquiry
+        WHERE `status` = 1
+        AND user_effective = 0
+        AND sys_effective = 1
+        AND waste_enquiry_type = 'email'
+        GROUP BY from_email) t2 ON t1.email = t2.from_email
         WHERE t1.`status` != 0
         <if test="email != null and email != ''">
             AND t1.email like CONCAT('%', #{email}, '%')
@@ -18,14 +18,17 @@
         <if test="blackOrWhite != null">
             AND t1.black_or_white = #{blackOrWhite}
         </if>
-        <if test = "column != null and column != ''">
-          ORDER BY
-          <if test = "column == 'createTime'">
-            t1.create_time ${order}
-          </if>
-           <if test = "column == 'email'">
-            t1.email ${order}
-          </if>
+        <if test="column != null and column != ''">
+            ORDER BY
+            <if test="column == 'createTime'">
+                t1.create_time ${order}
+            </if>
+            <if test="column == 'email'">
+                t1.email ${order}
+            </if>
+            <if test="column == 'wasteEnquiryNum'">
+                wasteEnquiryNum ${order}
+            </if>
         </if>
     </select>
 </mapper>

+ 20 - 20
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/enquiry/service/impl/AdwebEnquiryServiceImpl.java

@@ -9,14 +9,12 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.xkcoding.http.util.StringUtil;
-
 import jakarta.annotation.Resource;
-
 import lombok.extern.slf4j.Slf4j;
-
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
 import org.jeecg.common.constant.CacheConstant;
+import org.jeecg.common.constant.WebsocketConst;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.DictPropertyModel;
 import org.jeecg.common.util.FastJsonUtil;
@@ -43,7 +41,6 @@ import org.jeecg.modules.system.entity.SysDictItem;
 import org.jeecg.modules.system.entity.SysUser;
 import org.jeecg.modules.system.service.ISysDictService;
 import org.jeecg.modules.system.service.ISysUserService;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.http.HttpEntity;
@@ -264,13 +261,16 @@ public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, Adw
                 this.save(target);
                 adwebEnquiryFormService.save(form);
 
-                //创建业务消息信息
+
+                // 给该站点所属的用户发送消息
+                AdwebSite targetSite = adwebSiteService.getSiteByCode(target.getSiteCode());
+                String[] userIds = targetSite.getUid().split(",");
+                // TODO 之后仅对有效询盘进行发送消息通知
                 JSONObject obj = new JSONObject();
-                obj.put("cmd", "user");//业务类型
-                obj.put("msgId", target.getId());//消息id
-                obj.put("msgTxt",  target.getEmail());//消息内容
-                //单个用户发送 (userId为用户id)
-                webSocket.sendMessage("e9ca23d68d884d4ebb19d07889727dae", obj.toJSONString());
+                obj.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_ENQUIRY);
+                obj.put(WebsocketConst.MSG_TXT, "您已经收到询盘,请尽快处理");
+                webSocket.sendMessage(userIds, obj.toJSONString());
+
             } catch (Exception e) {
                 log.error("站点为:{},  recordId为:{} 保存询盘到数据库失败,原因是:{}", adwebSite.getName(), enquiryDto.getRecordId(), e.getMessage());
             }
@@ -661,7 +661,7 @@ public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, Adw
         // 外部编号暂无作用,且多查询一次数据库,暂时注释
 //        adwebEnquiry.setNoOut(DateUtil.dateToString(new Date(), DateUtil.DATE_FORMAT_THREE) + adwebOpenApiService.loadOutNoByUser(adwebSite.getUid()));
         adwebEnquiry.setWasteEnquiry(0);
-        adwebEnquiry.setRequestTime( new Date());
+        adwebEnquiry.setRequestTime(new Date());
         adwebEnquiry.setAcquireMessageTime(adwebSite.getEnquiryMessageTime());
         adwebEnquiry.setIsEnquirySync("enquirySync");
 
@@ -1752,16 +1752,16 @@ public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, Adw
     }
 
     @Override
-    public void returnSalesperson(String siteCode,String inquiryId,String sales) {
+    public void returnSalesperson(String siteCode, String inquiryId, String sales) {
         log.info("返回跟进人名称开始");
         //获取站点
         QueryWrapper<AdwebSite> queryWrapper = new QueryWrapper<>();
-        queryWrapper.eq("code",siteCode);
+        queryWrapper.eq("code", siteCode);
         AdwebSite adwebSite = adwebSiteService.getOne(queryWrapper);
 
         RestTemplate restTemplate = new RestTemplate();
         String url = adwebSite.getDomain() + "/wp-json/inquiry/v1/add-sales";
-        log.info("请求地址{}",url);
+        log.info("请求地址{}", url);
         // 如果需要传递参数
         HttpHeaders headers = new HttpHeaders();
         headers.set("Content-Type", "application/json");
@@ -1814,19 +1814,19 @@ public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, Adw
             updateWrapper.set("waste_enquiry_type", wasteEnquiryType);
 
             //特殊处理垃圾询盘是邮箱或者ip
-            if(wasteEnquiryType.equals("ip")){
+            if (wasteEnquiryType.equals("ip")) {
                 updateWrapper.set("effective_reason", "人工操作-ip-" + wasteEnquirySeason);
                 adwebSiteBlackIpService.addBlackIpByContent(effectiveEnquiryParamDto);
             }
-            if(wasteEnquiryType.equals("email")){
+            if (wasteEnquiryType.equals("email")) {
                 updateWrapper.set("effective_reason", "人工操作-邮箱-" + wasteEnquirySeason);
                 enquirySiteBlackEmailService.addBlackEmailByContent(effectiveEnquiryParamDto);
             }
-            if(wasteEnquiryType.equals("keyword")){
+            if (wasteEnquiryType.equals("keyword")) {
                 updateWrapper.set("effective_reason", "人工操作-关键词-" + wasteEnquirySeason);
                 adwebSiteEnquiryRuleService.addBlackKeywordByContent(effectiveEnquiryParamDto);
             }
-            if(wasteEnquiryType.equals("other")){
+            if (wasteEnquiryType.equals("other")) {
                 updateWrapper.set("effective_reason", "人工操作-其他-" + wasteEnquirySeason);
             }
         } else {  // 有效询盘
@@ -1851,7 +1851,7 @@ public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, Adw
 
                     //判断是否为产品询盘
                     for (AdwebEnquiry adwebEnquiry : enquiryList) {
-                        if(StringUtils.isNotBlank(adwebEnquiry.getCartItems())){
+                        if (StringUtils.isNotBlank(adwebEnquiry.getCartItems())) {
                             adwebEnquiry.setExistProductEnquiry(1);  // 产品询盘
                         }
                     }
@@ -1872,7 +1872,7 @@ public class AdwebEnquiryServiceImpl extends ServiceImpl<AdwebEnquiryMapper, Adw
                     log.info("获取的子账户id:{}", FastJsonUtil.toJSONString(subAccountIdList));
                     if (CollectionUtils.isNotEmpty(subAccountIdList)) {
                         subAccountIdList.add(String.valueOf(adwebSite.getUid()));
-                        List<SysUser> principalEmailList = sysUserService.list(new QueryWrapper<SysUser>().in("id", subAccountIdList).eq("del_flag", 0).isNotNull("email").ne("email","").select("id", "email"));
+                        List<SysUser> principalEmailList = sysUserService.list(new QueryWrapper<SysUser>().in("id", subAccountIdList).eq("del_flag", 0).isNotNull("email").ne("email", "").select("id", "email"));
                         if (CollectionUtils.isNotEmpty(principalEmailList)) {
                             principalEmailMap = principalEmailList.stream().collect(Collectors.toMap(SysUser::getId, SysUser::getEmail));
 

+ 22 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/ISeoPlanSubscriptionService.java

@@ -1,14 +1,34 @@
 package org.jeecg.modules.adweb.seo.service;
 
-import org.jeecg.modules.adweb.seo.entity.SeoPlanSubscription;
 import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.adweb.seo.entity.SeoPlanSubscription;
+import org.jeecg.modules.adweb.subscribePlan.entity.SubscribePlan;
 
 /**
  * @Description: seo套餐订购
  * @Author: jeecg-boot
- * @Date:   2024-10-15
+ * @Date: 2024-10-15
  * @Version: V1.0
  */
 public interface ISeoPlanSubscriptionService extends IService<SeoPlanSubscription> {
 
+    /**
+     * 绑定SEO套餐
+     *
+     * @param seoPlanSubscription
+     * @param sysUser
+     * @return
+     */
+    Result<?> addSeoPlanSubscription(SeoPlanSubscription seoPlanSubscription, LoginUser sysUser);
+
+    /**
+     * 新增套餐订阅记录
+     *
+     * @param seoPlanSubscription
+     * @param marketPlan
+     * @return
+     */
+    boolean addNewSubscription(SeoPlanSubscription seoPlanSubscription, SubscribePlan marketPlan);
 }

+ 129 - 2
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/seo/service/impl/SeoPlanSubscriptionServiceImpl.java

@@ -1,19 +1,146 @@
 package org.jeecg.modules.adweb.seo.service.impl;
 
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUnit;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.modules.adweb.seo.entity.SeoPlanSubscription;
 import org.jeecg.modules.adweb.seo.mapper.SeoPlanSubscriptionMapper;
 import org.jeecg.modules.adweb.seo.service.ISeoPlanSubscriptionService;
+import org.jeecg.modules.adweb.subscribePlan.entity.SubscribePlan;
+import org.jeecg.modules.adweb.subscribePlan.service.ISubscribePlanService;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import java.util.Date;
+import java.util.List;
 
 /**
  * @Description: seo套餐订购
  * @Author: jeecg-boot
- * @Date:   2024-10-15
+ * @Date: 2024-10-15
  * @Version: V1.0
  */
 @Service
 public class SeoPlanSubscriptionServiceImpl extends ServiceImpl<SeoPlanSubscriptionMapper, SeoPlanSubscription> implements ISeoPlanSubscriptionService {
 
+    @Resource
+    private ISubscribePlanService subscribePlanService;
+
+    @Override
+    public Result<?> addSeoPlanSubscription(SeoPlanSubscription seoPurchaseHistory, LoginUser sysUser) {
+        boolean result = false;
+
+        SubscribePlan marketPlan = subscribePlanService.getById(seoPurchaseHistory.getPlanId());
+        if (marketPlan == null) {
+            return Result.error("此套餐不存在");
+        }
+
+        if (sysUser != null) {
+            seoPurchaseHistory.setCreateBy(sysUser.getId());
+        } else {
+            seoPurchaseHistory.setCreateBy("system_auto");
+        }
+
+        //如果不是续费客户(就是新客户)的话,直接入库,套餐开启时间即是现在
+        if (seoPurchaseHistory.getIsRenew() == null || seoPurchaseHistory.getIsRenew() == 0) {
+            QueryWrapper<SeoPlanSubscription> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("site_id", seoPurchaseHistory.getSiteId());
+            queryWrapper.eq("status", 1);
+            List<SeoPlanSubscription> seoPurchaseHistoryList = this.list(queryWrapper);
+            if (!CollectionUtils.isEmpty(seoPurchaseHistoryList)) {
+                return Result.error("站点存在使用中套餐,请到期后绑定!");
+            }
+            result = this.addNewSubscription(seoPurchaseHistory, marketPlan);
+        } else {//续费
+            //判断是否有正在使用的套餐,如果没有,新建status为1的套餐
+            QueryWrapper<SeoPlanSubscription> oldQueryWrapper = new QueryWrapper<>();
+            oldQueryWrapper.eq("site_id", seoPurchaseHistory.getSiteId());
+            oldQueryWrapper.eq("status", 1);
+            List<SeoPlanSubscription> oldHistoryList = this.list(oldQueryWrapper);
+            if (CollectionUtils.isEmpty(oldHistoryList)) {
+                return Result.error("站点不存在使用中套餐,请先新增套餐");
+            } else {
+                QueryWrapper<SeoPlanSubscription> queryWrapper = new QueryWrapper<>();
+                queryWrapper.eq("site_id", seoPurchaseHistory.getSiteId());
+                queryWrapper.eq("status", 2);
+                List<SeoPlanSubscription> seoPurchaseHistoryList = this.list(queryWrapper);
+                if (!CollectionUtils.isEmpty(seoPurchaseHistoryList)) {
+                    return Result.error("同一站点不能同时续费多个相同类型的套餐!");
+                }
+
+                if (seoPurchaseHistory.getIsCustom() == 0) {
+                    // ->不是自定义服务开启时间 需找到多个套餐服务结束时间最大的那个
+                    //此站点所有对应的套餐的最大服务结束时间
+                    SeoPlanSubscription history = this.getOne(new LambdaQueryWrapper<SeoPlanSubscription>()
+                            .eq(SeoPlanSubscription::getSiteId, seoPurchaseHistory.getSiteId())
+                            .and(wrapper -> wrapper.eq(SeoPlanSubscription::getStatus, 1)
+                                    .or().eq(SeoPlanSubscription::getStatus, 2))
+                            .orderByDesc(SeoPlanSubscription::getServiceEndTime).last("limit 1"));
+                    Date maxEndTime = null;
+                    if (history == null || history.getServiceEndTime() == null) {
+                        maxEndTime = new Date();
+                    } else {
+                        maxEndTime = history.getServiceEndTime();
+                    }
+                    seoPurchaseHistory.setCreateTime(new Date());
+                    seoPurchaseHistory.setPlanStartTime(maxEndTime);
+                    seoPurchaseHistory.setStatus(2);
+                    seoPurchaseHistory.setPlanName(marketPlan.getPlanName());
+                    seoPurchaseHistory.setPlanCode(marketPlan.getPlanCode());
+                    seoPurchaseHistory.setPlanPrice(marketPlan.getPrice());
+                    seoPurchaseHistory.setPlanType(marketPlan.getMarketType());
+                    seoPurchaseHistory.setServiceMonth(marketPlan.getServiceTime());
+                    result = this.save(seoPurchaseHistory);
+                } else if (seoPurchaseHistory.getIsCustom() == 1) {//是自定义套餐开启时间
+                    seoPurchaseHistory.setCreateTime(new Date());
+                    seoPurchaseHistory.setPlanName(marketPlan.getPlanName());
+                    seoPurchaseHistory.setPlanCode(marketPlan.getPlanCode());
+                    seoPurchaseHistory.setPlanPrice(marketPlan.getPrice());
+                    seoPurchaseHistory.setPlanType(marketPlan.getMarketType());
+                    DateTime today = cn.hutool.core.date.DateUtil.date();
+                    long betweenTime = cn.hutool.core.date.DateUtil.between(seoPurchaseHistory.getPlanStartTime(), today, DateUnit.DAY, false);
+                    if (betweenTime > 0) {
+                        return Result.error("自定义时间请选择于今天之后!");
+                    } else {
+                        //如果有正在使用的套餐,才能设置为2,否则设置为1
+                        seoPurchaseHistory.setStatus(2);
+                    }
+                    seoPurchaseHistory.setServiceMonth(marketPlan.getServiceTime());
+                    result = this.save(seoPurchaseHistory);
+                }
+            }
+        }
+
+        if (result) {
+
+            return Result.OK("添加成功!");
+        }
+
+        return Result.error("添加失败!");
+    }
+
+    @Override
+    public boolean addNewSubscription(SeoPlanSubscription seoPurchaseHistory, SubscribePlan marketPlan) {
+        boolean result = false;
+        try {
+            Date startTime = new Date();
+            seoPurchaseHistory.setCreateTime(startTime);
+            seoPurchaseHistory.setPlanStartTime(startTime);
+            seoPurchaseHistory.setStatus(1);//使用中
+            seoPurchaseHistory.setPlanName(marketPlan.getPlanName());
+            seoPurchaseHistory.setPlanCode(marketPlan.getPlanCode());
+            seoPurchaseHistory.setPlanPrice(marketPlan.getPrice());
+            seoPurchaseHistory.setPlanType(marketPlan.getMarketType());
+            seoPurchaseHistory.setServiceMonth(marketPlan.getServiceTime());
+            result = this.save(seoPurchaseHistory);
+        } catch (Exception e) {
+            log.error("站点新绑定套餐失败", e);
+        }
+        return result;
+    }
 }

+ 1 - 1
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/common/constant/WordPressConstants.java → jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/constant/WordPressConstants.java

@@ -1,4 +1,4 @@
-package org.jeecg.modules.adweb.common.constant;
+package org.jeecg.modules.adweb.site.constant;
 
 public class WordPressConstants {
     public static final String SSO_RES_KEY_NAME = "Adweb_Wordpress_ssoResKey";

+ 18 - 8
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/controller/AdwebSiteManageController.java

@@ -2,17 +2,18 @@ package org.jeecg.modules.adweb.site.controller;
 
 
 import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.api.vo.Result;
-import org.jeecg.modules.adweb.site.dto.WordPressConfig;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.modules.adweb.common.mapper.CommonMapper;
+import org.jeecg.modules.adweb.site.dto.WordPressConfig;
 import org.jeecg.modules.adweb.site.entity.AdwebSite;
 import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.jeecg.modules.system.entity.SysUser;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * @Description: adweb_site
@@ -20,18 +21,21 @@ import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
  * @Date: 2020-12-24
  * @Version: V1.0
  */
-@Tag(name="adweb站点配置表单")
+@Tag(name = "adweb站点配置表单")
 @RestController
 @RequestMapping("/adweb/adwebSiteManage")
 @Slf4j
 public class AdwebSiteManageController extends JeecgController<AdwebSite, IAdwebSiteService> {
 
-    @Autowired
+    @Resource
     private IAdwebSiteService adwebSiteManageService;
 
+    @Resource
+    private CommonMapper commonMapper;
 
     /**
      * 查询wordpress站点配置
+     *
      * @param wordPressConfig
      * @return
      */
@@ -40,4 +44,10 @@ public class AdwebSiteManageController extends JeecgController<AdwebSite, IAdweb
         WordPressConfig config = this.adwebSiteManageService.queryWordPressConfig(wordPressConfig.getSiteCode());
         return Result.OK(config);
     }
+
+    @GetMapping(value = "/getAdwebVip")
+    public Result getAdwebVip() {
+        List<SysUser> userList = commonMapper.getAdwebVip();
+        return Result.OK(userList);
+    }
 }

+ 246 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/controller/wpSiteController.java

@@ -0,0 +1,246 @@
+package org.jeecg.modules.adweb.site.controller;
+
+
+import com.alibaba.fastjson.JSONObject;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.shiro.SecurityUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.adweb.common.util.AdwebRedisUtil;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.service.IAdwebSiteService;
+import org.jeecg.modules.adweb.site.service.SelfWebSiteService;
+import org.jeecg.modules.adweb.site.service.SelfWebSiteServiceCommon;
+import org.jeecg.modules.message.websocket.WebSocket;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * @autor jerry
+ * @date: 2022/1/11 20:45
+ */
+@Slf4j
+@RestController
+@RequestMapping("/wpWebSite")
+public class wpSiteController {
+
+    @Value("${jeecg.path.upload}")
+    private String uploadUrl;
+
+    @Value("${pemFileDownLoad.prefix}")
+    private String pemFileDownLoadUrl;
+
+    @Resource
+    private SelfWebSiteService selfWebSiteService;
+
+    @Resource
+    private IAdwebSiteService siteService;
+
+    @Resource
+    private SelfWebSiteServiceCommon selfWebSiteServiceCommon;
+
+    @Resource
+    private AdwebRedisUtil adwebRedisUtil;
+
+    @Resource
+    private WebSocket webSocket;
+
+    /**
+     * 创建站点
+     *
+     * @param templateId 模板id
+     * @param planId     域名
+     * @param name       站点名称
+     * @param uid        站点所属用户名称
+     * @param request    请求信息
+     * @return 创建的站点信息
+     */
+    @RequestMapping("addWebsite")
+    public Result<?> createWebSiteByTempId(HttpServletRequest request, Long templateId, String planId, String name, String uid, Integer giveDay, Integer compensateDay) {
+        log.info("新建站点模板:" + templateId + "; 站点名称:" + name + "; 套餐id:" + planId);
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        // 如果2分钟内有创建过站点,则不允许再次创建站点
+        String flag = adwebRedisUtil.getString(templateId + "_" + uid);
+        if (StringUtils.isNotBlank(flag)) {
+            log.info("2分钟内重复拉站点");
+            try {
+                Thread.sleep(5 * 60 * 1000);
+            } catch (InterruptedException e) {
+                log.info("重复拉站点的睡眠出现异常");
+            }
+            return Result.OK("ignore");
+        }
+        adwebRedisUtil.set(templateId + "_" + uid, "flag", 2 * 60);
+
+        AdwebSite adwebSite = null;
+        try {
+            // 建站服务
+            adwebSite = selfWebSiteService.createSite(request, templateId, uid, name, planId, sysUser, giveDay, compensateDay);
+            if (null != adwebSite) {
+                log.info("创建站点成功");
+                //创建业务消息信息
+                JSONObject obj = new JSONObject();
+                obj.put("cmd", "user");//业务类型
+                obj.put("msgId", "test");//消息id
+                obj.put("msgTxt", "站点创建成功");//消息内容
+                //单个用户发送 (userId为用户id)
+                webSocket.sendMessage("e9ca23d68d884d4ebb19d07889727dae", obj.toJSONString());
+                return Result.OK(adwebSite.getDomainDev());
+            }
+        } catch (Exception e) {
+            log.error("创建站点失败", e);
+        }
+        return Result.error("创建站点失败!");
+    }
+
+    /**
+     * 发布站点
+     *
+     * @param domain 域名
+     * @param siteId 站点ID
+     * @return
+     */
+    @RequestMapping("releaseWebsite")
+    public Result<?> releaseWebsite(HttpServletRequest request, String domain, Integer siteId) {
+        return selfWebSiteService.releaseSite(request, domain, siteId);
+    }
+
+    /**
+     * 重新发布站点
+     *
+     * @param domain 域名
+     * @param siteId 站点ID
+     * @return
+     */
+    @RequestMapping("delReleaseWebsite")
+    public Result<?> delReleaseWebsite(String domain, Integer siteId) {
+        return selfWebSiteService.delReleaseWebsite(domain, siteId);
+    }
+
+
+    /**
+     * 站点 启动/停止
+     *
+     * @param siteId 站点Id
+     * @param status 站点启动(local):1;停止:2; 站点启动(prod):3;停止:4;
+     * @return
+     */
+    @RequestMapping("siteStartOrStop")
+    public Result<?> siteStartOrStop(Integer siteId, Integer status) {
+        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        boolean flag = selfWebSiteService.siteStartOrStop(sysUser, siteId, status);
+        String result = "";
+        if (flag) {
+            if (status.equals(1) || status.equals(3)) {
+                result = "站点启动成功!";
+            }
+            if (status.equals(2) || status.equals(4)) {
+                result = "站点停止成功!";
+            }
+        } else {
+            if (status.equals(1) || status.equals(3)) {
+                result = "站点启动失败!";
+            }
+            if (status.equals(2) || status.equals(4)) {
+                result = "站点停止失败!";
+            }
+        }
+        return Result.OK(result);
+    }
+
+
+    /**
+     * 手动添加SSL
+     *
+     * @param adwebSite
+     * @return
+     */
+    @RequestMapping(value = "munualAddSSL", method = RequestMethod.POST)
+    @ResponseBody
+    public Result<?> munualAddSSL(AdwebSite adwebSite) {
+        //开始校验证书格式是否正确
+        String cert = adwebSite.getSiteCert();
+        String chain = adwebSite.getSiteChain();
+        String privateKey = adwebSite.getSitePrivkey();
+        if (!cert.startsWith("-----BEGIN CERTIFICATE-----") || !cert.endsWith("-----END CERTIFICATE-----")
+                || !chain.startsWith("-----BEGIN CERTIFICATE-----") || !chain.endsWith("-----END CERTIFICATE-----")
+                || !privateKey.startsWith("-----BEGIN PRIVATE KEY-----") || !privateKey.endsWith("-----END PRIVATE KEY-----")) {
+            return Result.error("ssl证书错误,请检查证书格式!");
+        }
+        String fullchain = cert.concat("\n").concat(chain);
+        String uploadPemUrl = uploadUrl + "keys/";
+        File newFile = new File(uploadPemUrl + adwebSite.getCode());
+        if (!newFile.exists()) {
+            newFile.mkdirs();
+        }
+        File file = new File(uploadPemUrl + adwebSite.getCode() + "/fullchain.pem");
+        File file2 = new File(uploadPemUrl + adwebSite.getCode() + "/privkey.pem");
+        try {
+            FileOutputStream out = new FileOutputStream(file);
+            FileOutputStream out2 = new FileOutputStream(file2);
+            if (!file.exists()) {
+                file.createNewFile();
+            }
+            if (!file2.exists()) {
+                file2.createNewFile();
+            }
+            byte[] content = fullchain.getBytes();
+            byte[] content2 = privateKey.getBytes();
+            out.write(content);
+            out2.write(content2);
+            out.flush();
+            out2.flush();
+            out.close();
+            out2.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        selfWebSiteService.munualAddSSL(adwebSite,
+                pemFileDownLoadUrl + adwebSite.getCode() + "/fullchain.pem",
+                pemFileDownLoadUrl + adwebSite.getCode() + "/privkey.pem");
+        boolean flag = siteService.updateById(adwebSite);
+        if (!flag) {
+            return Result.error("添加失败");
+        }
+        return Result.OK();
+    }
+
+
+    /**
+     * 自动添加SSL(脚本执行)
+     *
+     * @param adwebSite
+     */
+    @RequestMapping(value = "autoAddSsl")
+    @ResponseBody
+    public Result<?> autoAddSsl(AdwebSite adwebSite) {
+        AdwebSite adwebSite1 = selfWebSiteService.autoAddSsl(adwebSite);
+        if (StringUtils.isEmpty(adwebSite1.getSiteCert()) || StringUtils.isEmpty(adwebSite1.getSiteChain()) || StringUtils.isEmpty(adwebSite1.getSitePrivkey())) {
+            return Result.error("证书添加失败!");
+        }
+        adwebSite1.setId(adwebSite.getId());
+        return Result.OK(siteService.updateById(adwebSite1));
+    }
+
+    /**
+     * 自动添加SSL
+     *
+     * @param adwebSite
+     */
+    @RequestMapping(value = "autoAddSsl/v2")
+    @ResponseBody
+    public Result<?> autoAddSslV2(AdwebSite adwebSite) {
+        return selfWebSiteService.autoAddSslV2(adwebSite);
+    }
+
+}

+ 3 - 3
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/mapper/SiteUserPermissionMapper.java

@@ -1,14 +1,14 @@
 package org.jeecg.modules.adweb.site.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import org.jeecg.modules.adweb.site.entity.AdwebSitePermission;
+import org.jeecg.modules.adweb.site.entity.AdwebSiteUserPermission;
 
 /**
  * @Description: 站点和用户的中间表
  * @Author: jeecg-boot
- * @Date:   2021-04-06
+ * @Date: 2021-04-06
  * @Version: V1.0
  */
-public interface SiteUserPermissionMapper extends BaseMapper<AdwebSitePermission> {
+public interface SiteUserPermissionMapper extends BaseMapper<AdwebSiteUserPermission> {
 
 }

+ 5 - 3
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/ISiteUserPermissionService.java

@@ -8,13 +8,15 @@ import java.util.List;
 /**
  * @Description: 站点权限表
  * @Author: liang
- * @Date:   2022-08-09
+ * @Date: 2022-08-09
  * @Version: V1.0
  */
 public interface ISiteUserPermissionService extends IService<AdwebSiteUserPermission> {
 
-    public List<String> getSiteCodeList(String uid);
+    List<String> getSiteCodeList(String uid);
 
-    public List<String> getSiteCodeListByUids(List<String> list);
+    List<String> getSiteCodeListByUids(List<String> list);
+
+    void insertSiteUserPermission(String uid, String siteCode, String siteName);
 
 }

+ 943 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/SelfWebSiteService.java

@@ -0,0 +1,943 @@
+package org.jeecg.modules.adweb.site.service;
+
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpSession;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.UUIDGenerator;
+import org.jeecg.modules.adweb.common.constant.ShellConstans;
+import org.jeecg.modules.adweb.common.service.FeishuService;
+import org.jeecg.modules.adweb.common.service.ShellService;
+import org.jeecg.modules.adweb.common.util.ShellSSH2Util;
+import org.jeecg.modules.adweb.site.constant.WordPressConstants;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.system.mapper.SysDictItemMapper;
+import org.jeecg.modules.system.mapper.SysDictMapper;
+import org.jeecg.modules.system.service.ISysDictService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author jerry
+ */
+@Slf4j
+@Service
+public class SelfWebSiteService {
+
+    @Resource
+    private IAdwebSiteService siteService;
+
+    /**
+     * 远程脚本执行服务类
+     */
+    @Resource
+    private ShellService shellService;
+
+
+    @Resource
+    private SelfWebSiteServiceCommon selfWebSiteServiceCommon;
+
+
+    @Value(value = "${jeecg.minio.dataPrefix}")
+    private String dataPrefix;
+
+    @Value(value = "${jeecg.minio_us.dataPrefix}")
+    private String usDataPrefix;
+
+    @Value("${AdwebSiteConnect.host}")
+    private String host;
+    @Value("${AdwebSiteConnect.port}")
+    private int port;
+    @Value("${AdwebSiteConnect.username}")
+    private String username;
+    @Value("${AdwebSiteConnect.password}")
+    private String password;
+    @Value("${AdwebSiteConnect.tempDomain}")
+    private String tempDomain;
+    @Value("${AdwebSiteConnect.tempCname}")
+    private String tempCname;
+    @Value("${AdwebSiteProdConnect.privateIp}")
+    private String wpSiteReleasePrivateIp;
+    @Value("${usWest118Server.shellpath}")
+    private String usWest118ServerShellPath;
+    @Resource
+    private FeishuService openFeishuMsgService;
+
+    @Autowired
+    private ISysDictService dictService;
+
+    @Resource
+    private SysDictItemMapper sysDictItemMapper;
+
+    @Resource
+    private SysDictMapper sysDictMapper;
+
+    /**
+     * @param tempId 模板ID
+     * @param uid    系统用户信息
+     * @param name   站点名称
+     * @param planId 新建站点绑定的套餐
+     * @return
+     */
+    public AdwebSite createSite(HttpServletRequest request, Long tempId, String uid, String name, String planId, LoginUser sysUser, Integer giveDay, Integer compensateDay) {
+        // 创建站点信息,生成code,拼接域名等,并将站点信息写入数据库
+
+        AdwebSite adwebSite = null;
+        try {
+            adwebSite = selfWebSiteServiceCommon.saveNewSiteInfo(tempId, uid, name, planId, sysUser, giveDay, compensateDay);
+            if (adwebSite == null) {
+                return null;
+            }
+        } catch (Exception e) {
+            log.error("新建站点时保存站点信息失败", e);
+            return null;
+        }
+
+        try {
+            if (request != null) {
+                HttpSession session = request.getSession();
+                session.setAttribute("shellLineModular", "");
+            }
+
+            // 执行临时服务器shell脚本,生成临时站点
+            String cmd = "/opt/adweb3/shell/auto-website " + adwebSite.getCode() + " " + adwebSite.getParentCode();
+
+            shellService.createShareSiteByPwd(cmd, host, port, username, password, new ShellSSH2Util.StdoutListener() {
+                @Override
+                public void stdout(String line) {
+                    log.info("标准 :{}", line);
+                    if (request != null) {
+                        msgSetInSession(request, line);
+                    }
+                    if (line.startsWith("执行命令成功")) {
+                        log.info("站点创建成功!更新站点状态");
+                    }
+                }
+
+                @Override
+                public void stderr(String line) {
+                    log.info("错误 :{}", line);
+                }
+            });
+        } catch (Exception e) {
+            log.error("在wp服务器上生成站点文件失败");
+            adwebSite.setStatus(0);
+            siteService.updateById(adwebSite);
+            return null;
+        }
+        return adwebSite;
+    }
+
+    private void msgSetInSession(HttpServletRequest request, String line) {
+        HttpSession session = request.getSession();
+        if ("CP_TAR_GZ_START".equals(line)) {
+            session.setAttribute("testSiteProcess", "CP_TAR_GZ");
+        }
+        if ("SQL_DUMP_IMPORT_START".equals(line)) {
+            session.setAttribute("testSiteProcess", "SQL_DUMP_IMPORT");
+        }
+        if ("WP_UDONM_START".equals(line)) {
+            session.setAttribute("testSiteProcess", "WP_UDONM");
+        }
+        if ("WP_UDONM_END".equals(line)) {
+            session.setAttribute("testSiteProcess", "SUCCESS");
+        }
+    }
+
+    private void msgSetInSessionProd(HttpServletRequest request, String line) {
+        HttpSession session = request.getSession();
+        if ("wget_tar_start".equals(line)) {
+            session.setAttribute("prodSiteProcess", "wget_tar_start");
+        }
+        if ("wget_sql_start".equals(line)) {
+            session.setAttribute("prodSiteProcess", "wget_sql_start");
+        }
+        if ("start tar zxf".equals(line)) {
+            session.setAttribute("prodSiteProcess", "start tar zxf");
+        }
+        if ("wp_udomain_start".equals(line)) {
+            session.setAttribute("prodSiteProcess", "wp_udomain_start");
+        }
+        if ("wp_udomain_end".equals(line)) {
+            session.setAttribute("prodSiteProcess", "success");
+        }
+    }
+
+
+    /**
+     * 站点启动/停止
+     *
+     * @param sysUser
+     * @param siteId
+     * @param status
+     * @return
+     */
+    public boolean siteStartOrStop(LoginUser sysUser, Integer siteId, Integer status) {
+        AdwebSite adwebSite = siteService.getById(siteId);
+        boolean flag = false;
+        switch (status) {
+            case 1:
+                flag = startSiteLocal(sysUser, adwebSite);
+                break;
+            case 2:
+                flag = stopSiteLocal(sysUser, adwebSite);
+                break;
+            case 3:
+                flag = startSite(sysUser, adwebSite);
+                break;
+            case 4:
+                flag = stopSite(sysUser, adwebSite);
+                break;
+        }
+        return flag;
+    }
+
+    /**
+     * 站点启动脚本调用(未发布)
+     *
+     * @param sysUser
+     * @param adwebSite
+     * @return
+     */
+    private boolean startSiteLocal(LoginUser sysUser, AdwebSite adwebSite) {
+        //站点启动
+        String cmd = "/home/ci-user/shell/start_site " + adwebSite.getCode() + " ";
+        shellService.exceShellByPwd(cmd, host, port, username, password, new ShellSSH2Util.StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                log.info("标准 :" + line);
+                if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+                    // TODO ----
+                    log.error("恢复测试站点异常:" + line);
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                log.info("错误 :" + line);
+            }
+        });
+        return siteStatusUpdate(sysUser, adwebSite, 0);
+    }
+
+    /**
+     * 站点停止脚本调用(未发布)
+     *
+     * @param sysUser
+     * @param adwebSite
+     * @return
+     */
+    private boolean stopSiteLocal(LoginUser sysUser, AdwebSite adwebSite) {
+        String cmd = "/home/ci-user/shell/stop_site " + adwebSite.getCode() + " ";
+        shellService.exceShellByPwd(cmd, host, port, username, password, new ShellSSH2Util.StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                log.info("标准 :" + line);
+                if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+                    // TODO ----
+                    log.error("停止测试站点异常:" + line);
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                log.info("错误 :" + line);
+            }
+        });
+        return siteStatusUpdate(sysUser, adwebSite, 3);
+    }
+
+    /**
+     * 站点启动脚本调用(生产环境)
+     *
+     * @param sysUser
+     * @param adwebSite
+     * @return
+     */
+    private boolean startSite(LoginUser sysUser, AdwebSite adwebSite) {
+        //站点启动
+        String cmd = "./shell/start_site " + wpSiteReleasePrivateIp + " " + adwebSite.getCode() + " ";
+        shellService.exceShell(cmd, new ShellSSH2Util.StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                log.info("MJJ控制台 :" + line);
+                if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+                    // TODO ----
+                    log.error("恢复站点异常:" + line);
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                log.info("错误 :" + line);
+            }
+        });
+        return siteStatusUpdate(sysUser, adwebSite, 0);
+    }
+
+    /**
+     * 站点停止脚本调用(生产环境)
+     *
+     * @param sysUser
+     * @param adwebSite
+     * @return
+     */
+    private boolean stopSite(LoginUser sysUser, AdwebSite adwebSite) {
+        String cmd = "./shell/stop_site " + wpSiteReleasePrivateIp + " " + adwebSite.getCode() + " ";
+        shellService.exceShell(cmd, new ShellSSH2Util.StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                log.info("MJJ控制台 :" + line);
+                if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+                    // TODO ----
+                    log.error("停止站点异常:" + line);
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                log.info("错误 :" + line);
+            }
+        });
+        return siteStatusUpdate(sysUser, adwebSite, 3);
+    }
+
+
+    /**
+     * 站点状态更改
+     *
+     * @param sysUser
+     * @param adwebSite
+     * @param runStatus
+     * @return
+     */
+    private boolean siteStatusUpdate(LoginUser sysUser, AdwebSite adwebSite, Integer runStatus) {
+        if (runStatus.equals(3)) {
+            adwebSite.setStopTime(new Date());
+            adwebSite.setStopUid(sysUser.getId());
+        }
+        adwebSite.setRunStatus(runStatus);
+        return siteService.updateById(adwebSite);
+    }
+
+
+    /**
+     * 发布站点(生产环境)
+     *
+     * @param domain 新域名
+     * @param siteId 站点ID
+     */
+    public Result<?> releaseSite(HttpServletRequest request, String domain, Integer siteId) {
+        log.info("===== releaseSite domain:{},siteId:{} ====", domain, siteId);
+        StringBuilder statusSuccess = new StringBuilder();
+        StringBuilder statusFail = new StringBuilder();
+        AdwebSite adwebSite = siteService.getById(siteId);
+        String siteToken = UUIDGenerator.generate().toUpperCase();
+        HttpSession session = request.getSession();
+//        String cmd = " ./shell/auto_website " + wpSiteReleasePrivateIp + " " + adwebSite.getCode() + " " + adwebSite.getInCode() + " " + domain + " " + siteToken + " " + tempDomain;
+        if (StringUtils.isEmpty(adwebSite.getDevServerIp())) {
+            return Result.error("该站点的服务器IP没有设置,请设置后在发布上线!");
+        }
+        log.info("===== releaseSite domain:{},siteId:{},getDevServerIp:{} ====", domain, siteId, adwebSite.getDevServerIp());
+        if ((!WordPressConstants.DEV_CI1.equals(adwebSite.getDevServerIp())) && (!WordPressConstants.DEV_CI2.equals(adwebSite.getDevServerIp()))) {
+            return Result.error("该站点的服务器IP设置不正确,请重试!");
+        }
+
+        //原始域名
+        String originDomain = domain;
+        //检验域名是否以www开头
+        if (domain.startsWith("www.")) {
+            domain = domain.replace("www.", "");
+        }
+        String dbName = domain.replaceAll("[^a-zA-Z0-9]", "") + "_" + adwebSite.getCode();
+        log.info("===== releaseSite domain:{},siteId:{},originDomain:{},domain:{},dbName:{} ====", domain, siteId, originDomain, domain, dbName);
+
+        String cmd = "";
+        if (WordPressConstants.DEV_CI1.equals(adwebSite.getDevServerIp())) {
+            cmd = "sudo sh " + usWest118ServerShellPath + "/adweb-publish_http.sh " + adwebSite.getCode() + " " + domain + " " + dbName;
+        }
+        if (WordPressConstants.DEV_CI2.equals(adwebSite.getDevServerIp())) {
+            cmd = "sudo sh " + usWest118ServerShellPath + "/adweb-publish-devci2_http.sh " + adwebSite.getCode() + " " + domain + " " + dbName;
+        }
+        log.info("===== releaseSite originDomain:{},domain:{},siteId:{},cmd:{} ====", originDomain, domain, siteId, cmd);
+
+        if (StringUtils.isEmpty(cmd)) {
+            String errorMsg = "网站上线脚本命令获取失败!";
+            String title = "网站域名:" + originDomain + " 站点发布失败";
+            String message = "**站点ID:** " + siteId + "\n";
+            message += "**临时域名:** " + adwebSite.getDomainDev() + "\n";
+            message += "**服务器IP:** " + adwebSite.getDevServerIp() + "\n";
+            message += "**错误原因:** " + errorMsg + "\n";
+            sendAdWebV2FeiShuMsg(title, message);
+            return Result.error("该站点的发布上线命令执行失败,请重试!");
+        }
+
+//        return false;
+        try {
+//            modifyMaterialImgToUs(adwebSite.getCode());
+            shellService.exceShellByUsWest118(cmd, new ShellSSH2Util.StdoutListener() {
+                @Override
+                public void stdout(String line) {
+                    log.info("标准 :" + line);
+                    msgSetInSessionProd(request, line);
+                    if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+                        // TODO ----
+                    }
+                    if ("[Creationcompleted]".equals(line)) {
+                        log.info("======网站上线成功======");
+                        statusSuccess.append("ok");
+                    }
+                }
+
+                @Override
+                public void stderr(String line) {
+                    log.info("错误 :" + line);
+                    statusFail.append(line);
+                }
+            });
+//            //发布完成后,调用脚本,停止测试站点的访问
+//            try {
+//                String delCmd = "/home/ci-user/shell/deldns " + adwebSite.getCode();
+//                log.info("/***************开始停止测试站点*****************/");
+//                shellService.createShareSiteByPwd(delCmd, host, port, username, password, new ShellSSH2Util.StdoutListener() {
+//                    @Override
+//                    public void stdout(String line) {
+//                        log.info("停止测试站,标准 :" + line);
+//                        //信息存入session
+//                        if ("ERROR:FILE_NAME IS EXISTS".equals(line)) {
+//                            // TODO ----
+//                        }
+//                    }
+//
+//                    @Override
+//                    public void stderr(String line) {
+//                        log.info(line);
+//                    }
+//                });
+//                log.info("/***************停止测试站点结束,成功*****************/");
+//            } catch (Exception e) {
+//                log.info("停止测试站异常", e);
+//                e.printStackTrace();
+//            }
+            //正式域名
+
+            log.info("===== releaseSite originDomain:{},domain:{},siteId:{},statusSuccess:{} ====", originDomain, domain, siteId, statusSuccess);
+            log.info("===== releaseSite originDomain:{},domain:{},siteId:{},statusFail:{} ====", originDomain, domain, siteId, statusFail);
+            if (StringUtils.isNotEmpty(statusFail.toString())) {
+                String title = "网站域名:" + originDomain + " 站点发布失败";
+                String message = "**站点ID:** " + siteId + "\n";
+                message += "**临时域名:** " + adwebSite.getDomainDev() + "\n";
+                message += "**服务器IP:** " + adwebSite.getDevServerIp() + "\n";
+                message += "**错误信息:** " + statusFail.toString() + "\n";
+                sendAdWebV2FeiShuMsg(title, message);
+
+                // 站点发布失败
+                adwebSite.setStatus(5);
+                siteService.updateById(adwebSite);
+                return Result.error("网站发布上线失败!");
+            } else {
+                String title = "网站域名:" + originDomain + " 站点发布成功";
+                String message = "**站点ID:** " + siteId + "\n";
+                message += "**临时域名:** " + adwebSite.getDomainDev() + "\n";
+                message += "**服务器IP:** " + adwebSite.getDevServerIp() + "\n";
+                sendAdWebV2FeiShuMsg(title, message);
+
+                // 创建站点完成-操作
+                adwebSite.setDomain(originDomain);
+                adwebSite.setIsDomain(1);
+                adwebSite.setSiteType(2);
+                //添加发布时间
+                adwebSite.setIssueTime(new Date());
+                //发布成功后修改状态为发布成功状态 :1
+                adwebSite.setStatus(1);
+                adwebSite.setProdServerIp(WordPressConstants.PROD_WP_SERVER_IP);
+                siteService.updateById(adwebSite);
+                // 将数据库中关键词的域名修改一致
+                // UpdateWrapper<SeoKeywords> updateWrapper = new UpdateWrapper<>();
+                // updateWrapper.eq("user_flag", adwebSite.getCode());
+                // updateWrapper.set("domain", domain);
+                // seoKeywordsService.update(updateWrapper);
+                session.setAttribute("shellLineModular", "");
+                return Result.OK("网站发布上线成功!");
+            }
+        } catch (Exception e) {
+            log.error("站点发布失败,退出执行;" + e.getMessage(), e);
+            // 站点发布失败
+            adwebSite.setStatus(5);
+            siteService.updateById(adwebSite);
+            return Result.error("网站发布上线失败!");
+        }
+    }
+
+    /**
+     * 删除发布失败的站点(生产环境)
+     *
+     * @param domain 新域名
+     * @param siteId 站点ID
+     */
+    public Result<?> delReleaseWebsite(String domain, Integer siteId) {
+        log.info("===== delReleaseWebsite domain:{},siteId:{} ====", domain, siteId);
+        StringBuilder delSuccess = new StringBuilder();
+        StringBuilder delFail = new StringBuilder();
+        AdwebSite adwebSite = siteService.getById(siteId);
+        //检验域名是否以www开头
+        if (domain.startsWith("www.")) {
+            domain = domain.replace("www.", "");
+        }
+        // 删除已发布的站点,重新发布
+        if (adwebSite.getStatus() == 5) {
+            String cmd = "sudo sh " + usWest118ServerShellPath + "/adweb-remove_prod_site.sh " + domain;
+            log.info("===== delReleaseWebsite domain:{},siteId:{},cmd:{} ====", domain, siteId, cmd);
+            try {
+                String finalDomain = domain;
+                shellService.exceShellByUsWest118(cmd, new ShellSSH2Util.StdoutListener() {
+                    @Override
+                    public void stdout(String line) {
+                        log.info("标准 :" + line);
+                        if ("remove site success".equals(line) || "remove site nginx success".equals(line)) {
+                            log.info("======执行删除旧站点,成功通知======");
+                            String title = "网站域名:" + finalDomain + " 删除发布失败的旧站点成功";
+                            String message = "**站点ID:** " + siteId + "\n";
+                            message += "**临时域名:** " + adwebSite.getDomainDev() + "\n";
+                            message += "**服务器IP:** " + adwebSite.getDevServerIp() + "\n";
+                            sendAdWebV2FeiShuMsg(title, message);
+
+                            delSuccess.append(line);
+                        }
+
+                        if ("remove site failed".equals(line) || "remove site nginx failed".equals(line)) {
+                            log.info("======执行删除旧站点,失败通知======");
+                            String title = "网站域名:" + finalDomain + " 删除发布失败的旧站点失败";
+                            String message = "**站点ID:** " + siteId + "\n";
+                            message += "**临时域名:** " + adwebSite.getDomainDev() + "\n";
+                            message += "**服务器IP:** " + adwebSite.getDevServerIp() + "\n";
+                            message += "**错误信息:** " + line + "\n";
+                            sendAdWebV2FeiShuMsg(title, message);
+
+                            delFail.append(line);
+                        }
+                    }
+
+                    @Override
+                    public void stderr(String line) {
+                        log.info("错误 :" + line);
+                        String title = "网站域名:" + finalDomain + " 删除发布失败的旧站点失败";
+                        String message = "**站点ID:** " + siteId + "\n";
+                        message += "**临时域名:** " + adwebSite.getDomainDev() + "\n";
+                        message += "**服务器IP:** " + adwebSite.getDevServerIp() + "\n";
+                        message += "**错误信息:** " + line + "\n";
+                        sendAdWebV2FeiShuMsg(title, message);
+
+                        delFail.append(line);
+                    }
+                });
+            } catch (Exception e) {
+                log.error("删除发布失败的旧站点失败,退出执行;" + e.getMessage(), e);
+                delFail.append(e.getMessage());
+            }
+
+            if (StringUtils.isNotBlank(delFail.toString())) {
+                return Result.error("旧站点删除失败,请重试!");
+            } else {
+                return Result.OK("旧站点删除成功!");
+            }
+        } else {
+            return Result.error("该站点状态不是发布失败,执行失败!");
+        }
+    }
+
+
+    /**
+     * 自动添加SSL(脚本执行)
+     *
+     * @param adwebSite
+     */
+    public AdwebSite autoAddSsl(AdwebSite adwebSite) {
+        String cmd;
+        StringBuilder isExists = new StringBuilder();
+        StringBuilder notExists = new StringBuilder();
+        cmd = "./shell/read_cert " + wpSiteReleasePrivateIp + " " + adwebSite.getDomain();
+        shellService.exceShell(cmd, new ShellSSH2Util.StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                log.info("控制台:" + line);
+                //存在
+                if (line.startsWith(ShellConstans.addSsl.IS_ERROR_INFO)) {
+                    isExists.append(line);
+                }
+                //不存在
+                if (line.startsWith(ShellConstans.addSsl.NULL_ERROR_INFO)) {
+                    notExists.append(line);
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                log.info("错误:" + line);
+            }
+        });
+
+        if (StringUtils.isNotBlank(isExists.toString())) {
+            StringBuilder privekeySb = new StringBuilder();
+            StringBuilder cert = new StringBuilder();
+            StringBuilder chain = new StringBuilder();
+            StringBuilder dataTime = new StringBuilder();
+            final Map<String, Boolean> certWriteMap = new HashMap<>();
+            certWriteMap.put("isCertWrite", false);
+            certWriteMap.put("isPrivateKeyWrite", false);
+            certWriteMap.put("isChainWrite", false);
+            cmd = "./shell/update_cert " + wpSiteReleasePrivateIp + " " + adwebSite.getDomain();
+            shellService.exceShell(cmd, new ShellSSH2Util.StdoutListener() {
+                @Override
+                public void stdout(String line) {
+                    log.info("控制台:" + line);
+                    if (line.startsWith(ShellConstans.addSsl.DATE_TIME)) {
+                        dataTime.append(line);
+                    }
+                    //cert
+                    if (line.startsWith(ShellConstans.addSsl.START_CERT)) {
+                        certWriteMap.put("isCertWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_CERT)) {
+                        certWriteMap.put("isCertWrite", false);
+                    }
+                    // 私有key可写
+                    if (certWriteMap.get("isCertWrite") && !line.startsWith(ShellConstans.addSsl.START_CERT)) {
+                        cert.append(line);
+                        cert.append('\n');
+                    }
+                    //privkey
+                    if (line.startsWith(ShellConstans.addSsl.START_PRIVKEY)) {
+                        certWriteMap.put("isPrivateKeyWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_PRIVKEY)) {
+                        certWriteMap.put("isPrivateKeyWrite", false);
+                    }
+                    // 私有key可写
+                    if (certWriteMap.get("isPrivateKeyWrite") && !line.startsWith(ShellConstans.addSsl.START_PRIVKEY)) {
+                        privekeySb.append(line);
+                        privekeySb.append('\n');
+                    }
+                    //chain
+                    if (line.startsWith(ShellConstans.addSsl.START_CHAIN)) {
+                        certWriteMap.put("isChainWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_CHAIN)) {
+                        certWriteMap.put("isChainWrite", false);
+                    }
+                    // 私有key可写
+                    if (certWriteMap.get("isChainWrite") && !line.startsWith(ShellConstans.addSsl.START_CHAIN)) {
+                        chain.append(line);
+                        chain.append('\n');
+                    }
+                }
+
+                @Override
+                public void stderr(String line) {
+                    log.info("错误:" + line);
+                }
+            });
+            adwebSite.setSiteCert(cert.toString());
+            adwebSite.setSiteChain(chain.toString());
+            adwebSite.setSitePrivkey(privekeySb.toString());
+        } else if (StringUtils.isNotBlank(notExists.toString())) {
+            StringBuilder privekeySb = new StringBuilder();
+            StringBuilder cert = new StringBuilder();
+            StringBuilder chain = new StringBuilder();
+            StringBuilder dataTime = new StringBuilder();
+            final Map<String, Boolean> certWriteMap = new HashMap<>();
+            certWriteMap.put("isCertWrite", false);
+            certWriteMap.put("isPrivateKeyWrite", false);
+            certWriteMap.put("isChainWrite", false);
+            cmd = "./shell/make_cert " + wpSiteReleasePrivateIp + " " + adwebSite.getCode() + " " + adwebSite.getInCode() + " " + adwebSite.getDomain();
+            shellService.exceShell(cmd, new ShellSSH2Util.StdoutListener() {
+                @Override
+                public void stdout(String line) {
+                    log.info("控制台:" + line);
+                    if (line.startsWith(ShellConstans.addSsl.DATE_TIME)) {
+                        dataTime.append(line);
+                    }
+                    //cert
+                    if (line.startsWith(ShellConstans.addSsl.START_CERT)) {
+                        certWriteMap.put("isCertWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_CERT)) {
+                        certWriteMap.put("isCertWrite", false);
+                    }
+                    // 私有key可写
+                    if (certWriteMap.get("isCertWrite") && !line.startsWith(ShellConstans.addSsl.START_CERT)) {
+                        cert.append(line);
+                        cert.append('\n');
+                    }
+                    //privkey
+                    if (line.startsWith(ShellConstans.addSsl.START_PRIVKEY)) {
+                        certWriteMap.put("isPrivateKeyWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_PRIVKEY)) {
+                        certWriteMap.put("isPrivateKeyWrite", false);
+                    }
+                    // 私有key可写
+                    if (certWriteMap.get("isPrivateKeyWrite") && !line.startsWith(ShellConstans.addSsl.START_PRIVKEY)) {
+                        privekeySb.append(line);
+                        privekeySb.append('\n');
+                    }
+                    //chain
+                    if (line.startsWith(ShellConstans.addSsl.START_CHAIN)) {
+                        certWriteMap.put("isChainWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_CHAIN)) {
+                        certWriteMap.put("isChainWrite", false);
+                    }
+                    // 私有key可写
+                    if (certWriteMap.get("isChainWrite") && !line.startsWith(ShellConstans.addSsl.START_CHAIN)) {
+                        chain.append(line);
+                        chain.append('\n');
+                    }
+                }
+
+                @Override
+                public void stderr(String line) {
+                    log.info("错误:" + line);
+                }
+            });
+            adwebSite.setSiteCert(cert.toString());
+            adwebSite.setSiteChain(chain.toString());
+            adwebSite.setSitePrivkey(privekeySb.toString());
+        }
+        return adwebSite;
+    }
+
+    /**
+     * @param adwebSite
+     * @return
+     */
+    public Result<?> autoAddSslV2(AdwebSite adwebSite) {
+        log.info("===== autoAddSslV2 ==> 开始生成SSL证书 domain:{},code:{},siteId:{} =====", adwebSite.getDomain(), adwebSite.getCode(), adwebSite.getId());
+        String domainNew = adwebSite.getDomain().replace("http://", "").replace("https://", "").replace("www.", "");
+        log.info("===== autoAddSslV2 ==> 开始生成SSL证书 domain:{},code:{},siteId:{},domainNew:{} =====", adwebSite.getDomain(), adwebSite.getCode(), adwebSite.getId(), domainNew);
+//        domainNew = "xyexcavator.com";
+//        String cmd = "sudo sh " + usWest118ServerShellPath + "/test_check_site_ssl_exist.sh " + adwebSite.getCode() + " " + domainNew;
+//        String cmd = "sudo sh " + usWest118ServerShellPath + "/generate_site_ssl.sh " + adwebSite.getCode() + " " + domainNew;
+        String cmd = "sudo sh " + usWest118ServerShellPath + "/switch_root_user.sh " + adwebSite.getCode() + " " + domainNew;
+        log.info("===== autoAddSslV2 ==> 开始生成SSL证书 domain:{},code:{},siteId:{},domainNew:{},cmd:{} =====", adwebSite.getDomain(), adwebSite.getCode(), adwebSite.getId(), domainNew, cmd);
+        try {
+            String finalDomainNew = domainNew;
+            final Map<String, Boolean> certWriteMap = new HashMap<>();
+            certWriteMap.put("isCertWrite", false);
+            certWriteMap.put("isPrivateKeyWrite", false);
+            certWriteMap.put("isChainWrite", false);
+            StringBuilder privateKey = new StringBuilder();
+            StringBuilder cert = new StringBuilder();
+            StringBuilder chain = new StringBuilder();
+            shellService.exceShellByUsWest118(cmd, new ShellSSH2Util.StdoutListener() {
+                @Override
+                public void stdout(String line) {
+                    log.info("标准 :" + line);
+                    //cert
+                    if (line.startsWith(ShellConstans.addSsl.START_CERT)) {
+                        certWriteMap.put("isCertWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_CERT)) {
+                        certWriteMap.put("isCertWrite", false);
+                    }
+                    if (certWriteMap.get("isCertWrite") && !line.startsWith(ShellConstans.addSsl.START_CERT)) {
+                        cert.append(line);
+                        cert.append('\n');
+                    }
+
+                    //privkey
+                    if (line.startsWith(ShellConstans.addSsl.START_PRIVKEY)) {
+                        certWriteMap.put("isPrivateKeyWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_PRIVKEY)) {
+                        certWriteMap.put("isPrivateKeyWrite", false);
+                    }
+                    if (certWriteMap.get("isPrivateKeyWrite") && !line.startsWith(ShellConstans.addSsl.START_PRIVKEY)) {
+                        privateKey.append(line);
+                        privateKey.append('\n');
+                    }
+
+                    //chain
+                    if (line.startsWith(ShellConstans.addSsl.START_CHAIN)) {
+                        certWriteMap.put("isChainWrite", true);
+                    } else if (line.startsWith(ShellConstans.addSsl.END_CHAIN)) {
+                        certWriteMap.put("isChainWrite", false);
+                    }
+                    if (certWriteMap.get("isChainWrite") && !line.startsWith(ShellConstans.addSsl.START_CHAIN)) {
+                        chain.append(line);
+                        chain.append('\n');
+                    }
+
+                    if ("SSL Certificate generation failed".equals(line)) {
+                        log.info("======网站SSL证书生成失败======");
+                        String title = "网站域名:" + finalDomainNew + " 站点SSL证书创建失败";
+                        String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                        message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                        message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                        message += "**错误信息:** " + line + "\n";
+                        sendAdWebV2FeiShuMsg(title, message);
+                    }
+                }
+
+                @Override
+                public void stderr(String line) {
+                    log.info("错误 :" + line);
+                    String title = "网站域名:" + finalDomainNew + " 站点SSL证书创建失败";
+                    String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                    message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                    message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                    message += "**错误信息:** " + line + "\n";
+                    sendAdWebV2FeiShuMsg(title, message);
+                }
+            });
+
+            if (StringUtils.isNotBlank(privateKey.toString()) && StringUtils.isNotBlank(cert.toString()) && StringUtils.isNotBlank(chain.toString())) {
+                log.info("======= SSL证书获取成功 =======");
+                log.info("privateKey:{}", privateKey);
+                log.info("cert:{}", cert);
+                log.info("chain:{}", chain);
+
+                String certStr = cert.toString();
+                boolean certStatus = certStr.contains("-----END CERTIFICATE-----");
+                if (certStatus) {
+                    int index = certStr.lastIndexOf("-----END CERTIFICATE-----");
+                    certStr = certStr.substring(0, index + 25);
+                }
+                log.info("certStr:{}", certStr);
+
+                // 站点SSL证书创建成功-操作
+                log.info("======= 将证书信息保存至站点 =======");
+                AdwebSite adwebSiteSSL = new AdwebSite();
+                adwebSiteSSL.setId(adwebSite.getId());
+                adwebSiteSSL.setSslOrigin(1);
+                adwebSiteSSL.setSitePrivkey(privateKey.toString());
+                adwebSiteSSL.setSiteCert(certStr);
+                adwebSiteSSL.setSiteChain(chain.toString());
+                adwebSiteSSL.setCretModifyTime(new Date());
+                adwebSiteSSL.setUtime(new Date());
+                siteService.updateById(adwebSiteSSL);
+
+                //发送飞书消息
+                String title = "网站域名:" + finalDomainNew + " 站点SSL证书创建成功";
+                String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                sendAdWebV2FeiShuMsg(title, message);
+//                return Result.OK("该站点SSL证书创建成功!");
+                return domainHttpToHttps(adwebSite);
+            } else {
+                //发送飞书消息
+                String title = "网站域名:" + finalDomainNew + " 站点SSL证书获取失败";
+                String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                sendAdWebV2FeiShuMsg(title, message);
+                return Result.error("该站点SSL证书获取失败!");
+            }
+        } catch (Exception e) {
+            log.error("网站SSL证书创建失败退出执行;" + e.getMessage(), e);
+            return Result.error("该站点SSL证书创建失败,请重试!");
+        }
+    }
+
+    /**
+     * 网站 http升级为https
+     *
+     * @param adwebSite
+     * @return
+     */
+    public Result<?> domainHttpToHttps(AdwebSite adwebSite) {
+        log.info("===== domainHttpToHttps ==> 开始执行将站点由http升级为https操作 domain:{},code:{},siteId:{} =====", adwebSite.getDomain(), adwebSite.getCode(), adwebSite.getId());
+        String domainNew = adwebSite.getDomain().replace("http://", "").replace("https://", "").replace("www.", "");
+        log.info("===== domainHttpToHttps ==> 开始执行将站点由http升级为https操作 domain:{},code:{},siteId:{},domainNew:{} =====", adwebSite.getDomain(), adwebSite.getCode(), adwebSite.getId(), domainNew);
+        String cmd = "sudo sh " + usWest118ServerShellPath + "/adweb-publish_https.sh " + adwebSite.getCode() + " " + domainNew;
+        log.info("===== domainHttpToHttps ==> 开始执行将站点由http升级为https操作 domain:{},code:{},siteId:{},domainNew:{},cmd:{} =====", adwebSite.getDomain(), adwebSite.getCode(), adwebSite.getId(), domainNew, cmd);
+        try {
+            shellService.exceShellByUsWest118(cmd, new ShellSSH2Util.StdoutListener() {
+                @Override
+                public void stdout(String line) {
+                    log.info("标准 :" + line);
+                    if ("Site Https Created successfully".equals(line)) {
+                        log.info("======网站http升级为https成功======");
+                        String title = "网站域名:" + domainNew + " 站点http升级为https成功";
+                        String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                        message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                        message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                        message += "**成功信息:** " + line + "\n";
+                        sendAdWebV2FeiShuMsg(title, message);
+
+                        log.info("======网站http升级为https成功,开始更新站点信息======");
+                        adwebSite.setDomain("https://" + domainNew);
+                        siteService.updateById(adwebSite);
+                    }
+
+                    if ("test nginx failed".equals(line) || "SSL Certificate not found".equals(line)) {
+                        log.info("======网站http升级为https失败======");
+                        String title = "网站域名:" + domainNew + " 站点http升级为https失败";
+                        String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                        message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                        message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                        message += "**错误信息:** " + line + "\n";
+                        sendAdWebV2FeiShuMsg(title, message);
+                    }
+                }
+
+                @Override
+                public void stderr(String line) {
+                    log.info("错误 :" + line);
+                    String title = "网站域名:" + domainNew + " 站点http升级为https失败";
+                    String message = "**站点ID:** " + adwebSite.getId() + "\n";
+                    message += "**站点Code:** " + adwebSite.getCode() + "\n";
+//                    message += "**服务器IP:** " + adwebSite.getProdServerIp() + "\n";
+                    message += "**错误信息:** " + line + "\n";
+                    sendAdWebV2FeiShuMsg(title, message);
+                }
+            });
+            return Result.OK();
+        } catch (Exception e) {
+            log.error("网站http升级为https失败退出执行;" + e.getMessage(), e);
+            return Result.error("该站点http升级为https失败,请重试!");
+        }
+    }
+
+
+    /**
+     * 手动添加SSL
+     *
+     * @param adwebSite
+     * @return
+     */
+    public void munualAddSSL(AdwebSite adwebSite, String fullchainUrl, String privkeyUrl) {
+        String cmd = "./shell/add_ssl " + wpSiteReleasePrivateIp + " " + adwebSite.getCode() + " " + adwebSite.getInCode() + " " + adwebSite.getDomain() + " " + fullchainUrl + " " + privkeyUrl;
+        shellService.exceShell(cmd, new ShellSSH2Util.StdoutListener() {
+            @Override
+            public void stdout(String line) {
+                log.info("控制台:" + line);
+                if (line.contains("EXIST!")) {
+                    log.info("更新!");
+                }
+            }
+
+            @Override
+            public void stderr(String line) {
+                log.info("错误 :" + line);
+            }
+            //TODO 脚本异常处理
+        });
+    }
+
+
+    /**
+     * @param msgTitle
+     * @param message
+     */
+    public void sendAdWebV2FeiShuMsg(String msgTitle, String message) {
+        try {
+            openFeishuMsgService.sendAdWebV2FeiShuMsg(msgTitle, message);
+        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

+ 162 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/SelfWebSiteServiceCommon.java

@@ -0,0 +1,162 @@
+package org.jeecg.modules.adweb.site.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.FastJsonUtil;
+import org.jeecg.modules.adweb.common.constant.AdwebConstant;
+import org.jeecg.modules.adweb.common.util.DateUtil;
+import org.jeecg.modules.adweb.enquiry.constant.EnquiryDistributeTypeConstant;
+import org.jeecg.modules.adweb.seo.entity.SeoPlanSubscription;
+import org.jeecg.modules.adweb.seo.service.ISeoPlanSubscriptionService;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.subscribePlan.entity.SubscribePlan;
+import org.jeecg.modules.adweb.subscribePlan.service.ISubscribePlanService;
+import org.jeecg.modules.adweb.theme.entity.AdwebTheme;
+import org.jeecg.modules.adweb.theme.service.IAdwebThemeService;
+import org.jeecg.modules.system.entity.SysUser;
+import org.jeecg.modules.system.service.ISysUserService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.util.Date;
+import java.util.List;
+
+@Service
+@Slf4j
+public class SelfWebSiteServiceCommon {
+
+    @Value("${AdwebSiteConnect.tempDomain}")
+    private String tempDomain;
+
+    @Value("${AdwebSiteConnect.tempCname}")
+    private String tempCname;
+
+    @Value("${serverIp.new}")
+    private String newServerIp;
+
+    @Resource
+    private ISiteUserPermissionService siteUserPermissionService;
+
+    @Resource
+    private ISysUserService sysUserService;
+
+    @Resource
+    private IAdwebSiteService adwebSiteService;
+
+    @Resource
+    private SiteManageService siteManageService;
+
+    @Resource
+    private IAdwebSiteService siteService;
+
+    @Resource
+    private IAdwebThemeService adwebThemeService;
+
+    @Resource
+    private ISeoPlanSubscriptionService seoPlanSubscriptionService;
+
+    @Resource
+    private ISubscribePlanService subscribePlanService;
+
+    @Transactional
+    public AdwebSite saveNewSiteInfo(Long tempId, String uid, String name, String planId, LoginUser sysUser, Integer giveDay, Integer compensateDay) {
+        AdwebSite adwebTemplate = siteService.getById(tempId);
+        AdwebTheme adwebTheme = adwebThemeService.getById(tempId);
+        if (adwebTemplate == null) {
+            log.error("未查询到模板数据退出执行,模板ID=" + tempId);
+            return null;
+        }
+        // 站点CODE
+        String siteCode = siteManageService.getSiteCode(null); // 自动生成临时站点code
+        String domain = siteCode + "." + tempDomain;
+        //站点对象
+        AdwebSite adwebSite = new AdwebSite();
+        // 有效期  默认当前时间加1年
+        Date endTime = DateUtil.addYear(DateUtil.getDate(), 1);
+        //TODO 改为NLB  cName
+        adwebSite.setCname(tempCname);
+        adwebSite.setUid(uid);
+        //站点名称改为创建站点时必填字段
+        adwebSite.setSiteType(AdwebConstant.SITE);
+        adwebSite.setEtime(endTime);
+        adwebSite.setManageUrl("https://" + domain + "/adweb-admin/");
+        adwebSite.setRunStatus(1);
+        adwebSite.setParentCode(adwebTheme.getCode());
+        adwebSite.setCreateType("wp");
+        adwebSite.setName(name);
+        //域名
+        adwebSite.setDomain("https://" + domain);
+        adwebSite.setDomainDev(domain);
+        //站点code,此处保存
+        adwebSite.setCode(siteCode);
+        adwebSite.setInCode(adwebTemplate.getInCode());
+        adwebSite.setIsDomain(0);
+        adwebSite.setCtime(new Date());
+        adwebSite.setStatus(2);
+        adwebSite.setEnquiryDistributeType(EnquiryDistributeTypeConstant.MASTER);
+        adwebSite.setDevServerIp(newServerIp);
+        adwebSite.setEnquirySendEmailType("ALL");
+
+        //设置seo_job_status默认值为1(可见)
+        adwebSite.setSeoJobStatus(1);
+        SysUser user = sysUserService.getById(uid);
+        String oemCode = user.getOemCode();
+        if (StringUtils.isNotBlank(oemCode)) {
+            adwebSite.setChannelProviderId(oemCode);//渠道商信息入库
+            SysUser sUser = sysUserService.getOne(new QueryWrapper<SysUser>().eq("work_no", oemCode));
+            if (sUser != null) {
+                adwebSite.setChannelProviderName(sUser.getUsername());
+            }
+        }
+        siteService.save(adwebSite);
+
+        log.info("===================绑定套餐,套餐id:{}==========================", planId);
+        log.info(FastJsonUtil.toJSONString(adwebSite));
+        if (StringUtils.isNotBlank(planId)) {
+            SubscribePlan seoMarketPlan = subscribePlanService.getById(planId);
+            if (!"SEO".equals(seoMarketPlan.getMarketType())) {
+                giveDay = 0;
+                compensateDay = 0;
+            }
+            SeoPlanSubscription history = new SeoPlanSubscription();
+            history.setPlanId(planId);
+            history.setSiteId(adwebSite.getId() + "");
+            history.setIsRenew(0);
+
+            if (giveDay != null) {
+                history.setGiveDay(giveDay);
+            } else {
+                history.setGiveDay(0);
+            }
+            if (compensateDay != null) {
+                history.setCompensateDay(compensateDay);
+            } else {
+                history.setCompensateDay(0);
+            }
+            seoPlanSubscriptionService.addSeoPlanSubscription(history, sysUser);
+        }
+
+        log.info("================新站点授权===============");
+
+        String siteName = "";
+        QueryWrapper<AdwebSite> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("code", siteCode);
+        queryWrapper.ne("status", AdwebConstant.SITE_DEL);
+        List<AdwebSite> list = adwebSiteService.list(queryWrapper);
+        if (CollectionUtils.isNotEmpty(list)) {
+            siteName = list.get(0).getName();
+            siteUserPermissionService.insertSiteUserPermission(adwebSite.getUid(), adwebSite.getCode(), siteName);
+        } else {
+            log.error("更新站点权限失败,该站点不存在,站点code为 {}", siteCode);
+        }
+
+
+        return adwebSite;
+    }
+
+}

+ 41 - 0
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/SiteManageService.java

@@ -0,0 +1,41 @@
+package org.jeecg.modules.adweb.site.service;
+
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import jakarta.annotation.Resource;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.adweb.common.util.DateUtil;
+import org.jeecg.modules.adweb.site.entity.AdwebSite;
+import org.jeecg.modules.adweb.site.mapper.AdwebSiteMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 站点管理服务类
+ */
+@Service
+public class SiteManageService {
+
+    protected Logger logger = LoggerFactory.getLogger(SiteManageService.class);
+    @Resource
+    private AdwebSiteMapper adwebSiteMapper;
+
+
+    public String getSiteCode(String siteCode) {
+        if (StringUtils.isEmpty(siteCode)) {
+            String currDate = DateUtil.formatDate(DateUtil.getDate(), DateUtil.COMPACT_DATE_FORMAT);
+            siteCode = currDate + RandomUtil.randomStringUpper(6).toLowerCase();
+
+            LambdaQueryWrapper<AdwebSite> queryWrapper = new LambdaQueryWrapper<>();
+            queryWrapper.eq(AdwebSite::getCode, siteCode);
+            List<AdwebSite> list = adwebSiteMapper.selectList(queryWrapper);
+            if (!list.isEmpty()) {
+                siteCode = getSiteCode(null);
+            }
+        }
+        return siteCode;
+    }
+}

+ 7 - 3
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/impl/AdwebSiteServiceImpl.java

@@ -12,7 +12,7 @@ import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.FastJsonUtil;
 import org.jeecg.common.util.RedisUtil;
 import org.jeecg.modules.adweb.common.constant.NumConstant;
-import org.jeecg.modules.adweb.common.constant.WordPressConstants;
+import org.jeecg.modules.adweb.site.constant.WordPressConstants;
 import org.jeecg.modules.adweb.site.dto.WordPressConfig;
 import org.jeecg.modules.adweb.site.entity.AdwebSite;
 import org.jeecg.modules.adweb.site.entity.AdwebUserWpsite;
@@ -32,7 +32,7 @@ import java.util.Map;
 /**
  * @Description: adweb站点配置表单
  * @Author: jeecg-boot
- * @Date:   2024-09-29
+ * @Date: 2024-09-29
  * @Version: V1.0
  */
 @Service
@@ -188,6 +188,7 @@ public class AdwebSiteServiceImpl extends ServiceImpl<AdwebSiteMapper, AdwebSite
 
     /**
      * 根据siteCode返回站点信息
+     *
      * @param siteCode
      * @return
      */
@@ -205,6 +206,7 @@ public class AdwebSiteServiceImpl extends ServiceImpl<AdwebSiteMapper, AdwebSite
         }
         return null;
     }
+
     /**
      * 根据用户id查询所有未删除的站点
      *
@@ -229,7 +231,9 @@ public class AdwebSiteServiceImpl extends ServiceImpl<AdwebSiteMapper, AdwebSite
         return siteIds;
     }
 
-    /** 查询全部有效的站点code */
+    /**
+     * 查询全部有效的站点code
+     */
     @Override
     public List<String> getAllActiveSiteCodes() {
         return this.list(

+ 52 - 97
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/site/service/impl/SiteUserPermissionServiceImpl.java

@@ -1,21 +1,22 @@
 package org.jeecg.modules.adweb.site.service.impl;
 
 
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
-
 import org.apache.commons.collections4.CollectionUtils;
+import org.jeecg.modules.adweb.common.util.SnowflakeIdUtil;
 import org.jeecg.modules.adweb.site.entity.AdwebSitePermission;
 import org.jeecg.modules.adweb.site.entity.AdwebSiteUserPermission;
+import org.jeecg.modules.adweb.site.mapper.SiteUserPermissionMapper;
 import org.jeecg.modules.adweb.site.service.ISitePermissionService;
 import org.jeecg.modules.adweb.site.service.ISiteUserPermissionService;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.*;
-import java.util.function.Function;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
@@ -26,11 +27,15 @@ import java.util.stream.Collectors;
  */
 @Service
 @Slf4j
-public class SiteUserPermissionServiceImpl implements ISiteUserPermissionService {
+public class SiteUserPermissionServiceImpl extends ServiceImpl<SiteUserPermissionMapper, AdwebSiteUserPermission> implements ISiteUserPermissionService {
 
-    @Autowired
+    @Resource
     private ISitePermissionService sitePermissionService;
 
+
+    @Resource
+    private SnowflakeIdUtil snowflakeIdUtil;
+
     @Override
     public List<String> getSiteCodeList(String uid) {
         List<String> codeList = new ArrayList<>();
@@ -95,97 +100,47 @@ public class SiteUserPermissionServiceImpl implements ISiteUserPermissionService
     }
 
     /**
-     * @param entityList
-     * @param batchSize
-     * @return
-     */
-    @Override
-    public boolean saveBatch(Collection<AdwebSiteUserPermission> entityList, int batchSize) {
-        return false;
-    }
-
-    /**
-     * @param entityList
-     * @param batchSize
-     * @return
-     */
-    @Override
-    public boolean saveOrUpdateBatch(Collection<AdwebSiteUserPermission> entityList, int batchSize) {
-        return false;
-    }
-
-    /**
-     * @param entityList
-     * @param batchSize
-     * @return
-     */
-    @Override
-    public boolean updateBatchById(Collection<AdwebSiteUserPermission> entityList, int batchSize) {
-        return false;
-    }
-
-    /**
-     * @param entity
-     * @return
-     */
-    @Override
-    public boolean saveOrUpdate(AdwebSiteUserPermission entity) {
-        return false;
-    }
-
-    /**
-     * @param queryWrapper
-     * @param throwEx
-     * @return
-     */
-    @Override
-    public AdwebSiteUserPermission getOne(Wrapper<AdwebSiteUserPermission> queryWrapper, boolean throwEx) {
-        return null;
-    }
-
-    /**
-     * @param queryWrapper
-     * @param throwEx
-     * @return
+     * 根据uid和siteCode向site_user_permission表中插入一条记录
+     *
+     * @return:
+     * @Author: luxiaoxiao
+     * @Date: 2021/4/22
      */
     @Override
-    public Optional<AdwebSiteUserPermission> getOneOpt(Wrapper<AdwebSiteUserPermission> queryWrapper, boolean throwEx) {
-        return Optional.empty();
-    }
+    public void insertSiteUserPermission(String uid, String siteCode, String siteName) {
 
-    /**
-     * @param queryWrapper
-     * @return
-     */
-    @Override
-    public Map<String, Object> getMap(Wrapper<AdwebSiteUserPermission> queryWrapper) {
-        return Map.of();
-    }
-
-    /**
-     * @param queryWrapper
-     * @param mapper
-     * @param <V>
-     * @return
-     */
-    @Override
-    public <V> V getObj(Wrapper<AdwebSiteUserPermission> queryWrapper, Function<? super Object, V> mapper) {
-        return null;
-    }
-
-    /**
-     * @return
-     */
-    @Override
-    public BaseMapper<AdwebSiteUserPermission> getBaseMapper() {
-        return null;
-    }
-
-    /**
-     * @return
-     */
-    @Override
-    public Class<AdwebSiteUserPermission> getEntityClass() {
-        return null;
+        List<AdwebSiteUserPermission> siteUserPermissionList = null;
+        try {
+            LambdaQueryWrapper<AdwebSiteUserPermission> queryWrapper = new LambdaQueryWrapper<>();
+
+            queryWrapper.eq(AdwebSiteUserPermission::getUid, uid)
+                    .eq(AdwebSiteUserPermission::getStatus, 1);
+
+            siteUserPermissionList = this.list(queryWrapper);
+
+            AdwebSiteUserPermission siteUserPermission = new AdwebSiteUserPermission();
+            String permissionCode = "";
+            if (CollectionUtils.isNotEmpty(siteUserPermissionList)) {
+                siteUserPermission = siteUserPermissionList.get(0);
+                permissionCode = siteUserPermission.getPermissionCode();
+            } else {
+                permissionCode = String.valueOf(snowflakeIdUtil.nextId());
+                siteUserPermission.setUid(uid);
+                siteUserPermission.setPermissionCode(permissionCode);
+                siteUserPermission.setStatus(1);
+                siteUserPermission.setCreateTime(new Date());
+                this.save(siteUserPermission);
+            }
+
+            AdwebSitePermission sitePermission = new AdwebSitePermission();
+            sitePermission.setSiteCode(siteCode);
+            sitePermission.setSiteName(siteName);
+            sitePermission.setPermissionCode(permissionCode);
+            sitePermission.setStatus(1);
+            sitePermission.setCreateTime(new Date());
+            sitePermissionService.save(sitePermission);
+        } catch (Exception e) {
+            log.error("添加站点权限失败", e);
+        }
     }
 }

+ 65 - 41
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/theme/entity/AdwebTheme.java

@@ -1,90 +1,114 @@
 package org.jeecg.modules.adweb.theme.entity;
 
-import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
-import java.util.Date;
-import java.math.BigDecimal;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.baomidou.mybatisplus.annotation.TableLogic;
-import lombok.Data;
 import com.fasterxml.jackson.annotation.JsonFormat;
-import org.springframework.format.annotation.DateTimeFormat;
-import org.jeecgframework.poi.excel.annotation.Excel;
-import org.jeecg.common.aspect.annotation.Dict;
 import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
 
 /**
  * @Description: adweb主题库
  * @Author: jeecg-boot
- * @Date:   2024-09-30
+ * @Date: 2024-09-30
  * @Version: V1.0
  */
 @Data
 @TableName("adweb_theme")
 @Accessors(chain = true)
 @EqualsAndHashCode(callSuper = false)
-@Schema(description="adweb主题库")
+@Schema(description = "adweb主题库")
 public class AdwebTheme implements Serializable {
     private static final long serialVersionUID = 1L;
 
-	/**主键*/
-	@TableId(type = IdType.ASSIGN_ID)
+    /**
+     * 主键
+     */
+    @TableId(type = IdType.ASSIGN_ID)
     @Schema(description = "主键")
     private java.lang.String id;
-	/**创建人*/
+    /**
+     * 创建人
+     */
     @Schema(description = "创建人")
     private java.lang.String createBy;
-	/**创建日期*/
-	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    /**
+     * 创建日期
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Schema(description = "创建日期")
     private java.util.Date createTime;
-	/**更新人*/
+    /**
+     * 更新人
+     */
     @Schema(description = "更新人")
     private java.lang.String updateBy;
-	/**更新日期*/
-	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    /**
+     * 更新日期
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @Schema(description = "更新日期")
     private java.util.Date updateTime;
-	/**模板名称*/
-	@Excel(name = "模板名称", width = 15)
+    /**
+     * 模板名称
+     */
+    @Excel(name = "模板名称", width = 15)
     @Schema(description = "模板名称")
     private java.lang.String name;
-	/**上架状态:0:未上架;1:已上架;默认0*/
-	@Excel(name = "上架状态:0:未上架;1:已上架;默认0", width = 15)
+    /**
+     * 上架状态:0:未上架;1:已上架;默认0
+     */
+    @Excel(name = "上架状态:0:未上架;1:已上架;默认0", width = 15)
     @Schema(description = "上架状态:0:未上架;1:已上架;默认0")
     private java.lang.Integer putaway;
-	/**图片路径*/
-	@Excel(name = "图片路径", width = 15)
+    /**
+     * 图片路径
+     */
+    @Excel(name = "图片路径", width = 15)
     @Schema(description = "图片路径")
     private java.lang.String images;
-	/**模板价格*/
-	@Excel(name = "模板价格", width = 15)
+    /**
+     * 模板价格
+     */
+    @Excel(name = "模板价格", width = 15)
     @Schema(description = "模板价格")
     private java.math.BigDecimal templatePrice;
-	/**模板标签*/
-	@Excel(name = "模板标签", width = 15)
+    /**
+     * 模板标签
+     */
+    @Excel(name = "模板标签", width = 15)
     @Schema(description = "模板标签")
     private java.lang.String templateTags;
-	/**主题颜色ID*/
-	@Excel(name = "主题颜色ID", width = 15)
+    /**
+     * 主题颜色ID
+     */
+    @Excel(name = "主题颜色ID", width = 15)
     @Schema(description = "主题颜色ID")
     private java.lang.Integer templateColorId;
-	/**站点域名*/
-	@Excel(name = "站点域名", width = 15)
+    /**
+     * 站点域名
+     */
+    @Excel(name = "站点域名", width = 15)
     @Schema(description = "站点域名")
     private java.lang.String domain;
-	/**站点备注*/
-	@Excel(name = "站点备注", width = 15)
+    /**
+     * 站点备注
+     */
+    @Excel(name = "站点备注", width = 15)
     @Schema(description = "站点备注")
     private java.lang.String descirbe;
-	/**站点状态:0:创建失败,1:正常运行,2:运行异常 3:站点停止*/
-	@Excel(name = "站点状态:0:创建失败,1:正常运行,2:运行异常 3:站点停止", width = 15)
-    @Schema(description = "站点状态:0:创建失败,1:正常运行,2:运行异常 3:站点停止")
-    private java.lang.Integer runStatus;
+    /**
+     * 站点code,生成6位长度随机码,取值范围[a-z0-9],保证系统唯一
+     */
+    @Excel(name = "站点code,生成6位长度随机码,取值范围[a-z0-9],保证系统唯一", width = 15)
+    @Schema(description = "站点code,生成6位长度随机码,取值范围[a-z0-9],保证系统唯一")
+    private java.lang.String code;
 }

+ 23 - 21
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/message/websocket/WebSocket.java

@@ -1,18 +1,17 @@
 package org.jeecg.modules.message.websocket;
 
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 import jakarta.websocket.*;
 import jakarta.websocket.server.PathParam;
 import jakarta.websocket.server.ServerEndpoint;
-
-import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.base.BaseMap;
 import org.jeecg.common.constant.WebsocketConst;
-import org.jeecg.common.modules.redis.client.JeecgRedisClient;
+import org.jeecg.modules.adweb.common.util.AdwebRedisUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
-import lombok.extern.slf4j.Slf4j;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * @Author scott
@@ -23,8 +22,10 @@ import lombok.extern.slf4j.Slf4j;
 @Slf4j
 @ServerEndpoint("/websocket/{userId}")
 public class WebSocket {
-    
-    /**线程安全Map*/
+
+    /**
+     * 线程安全Map
+     */
     private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();
 
     /**
@@ -32,11 +33,11 @@ public class WebSocket {
      */
     public static final String REDIS_TOPIC_NAME = "socketHandler";
 
-    //避免初次调用出现空指针的情况
-    private static JeecgRedisClient jeecgRedisClient;
+    private static AdwebRedisUtil adwebRedisUtil;
+
     @Autowired
-    private void setJeecgRedisClient(JeecgRedisClient jeecgRedisClient){
-        WebSocket.jeecgRedisClient = jeecgRedisClient;
+    private void setAdwebRedisUtil(AdwebRedisUtil adwebRedisUtil) {
+        WebSocket.adwebRedisUtil = adwebRedisUtil;
     }
 
 
@@ -74,13 +75,13 @@ public class WebSocket {
                 Session session = item.getValue();
                 try {
                     //update-begin-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
-                    synchronized (session){
+                    synchronized (session) {
                         log.debug("【系统 WebSocket】推送单人消息:" + message);
                         session.getBasicRemote().sendText(message);
                     }
                     //update-end-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
                 } catch (Exception e) {
-                    log.error(e.getMessage(),e);
+                    log.error(e.getMessage(), e);
                 }
             }
         }
@@ -110,15 +111,15 @@ public class WebSocket {
      */
     @OnMessage
     public void onMessage(String message, @PathParam(value = "userId") String userId) {
-        if(!"ping".equals(message) && !WebsocketConst.CMD_CHECK.equals(message)){
+        if (!"ping".equals(message) && !WebsocketConst.CMD_CHECK.equals(message)) {
             log.debug("【系统 WebSocket】收到客户端消息:" + message);
-        }else{
+        } else {
             log.debug("【系统 WebSocket】收到客户端消息:" + message);
             //update-begin---author:wangshuai---date:2024-05-07---for:【issues/1161】前端websocket因心跳导致监听不起作用---
             this.sendMessage(userId, "ping");
             //update-end---author:wangshuai---date:2024-05-07---for:【issues/1161】前端websocket因心跳导致监听不起作用---
         }
-        
+
 //        //------------------------------------------------------------------------------
 //        JSONObject obj = new JSONObject();
 //        //业务类型
@@ -141,9 +142,10 @@ public class WebSocket {
         t.printStackTrace();
     }
     //==========【系统 WebSocket接受、推送消息等方法 —— 具体服务节点推送ws消息】========================================================================================
-    
+
 
     //==========【采用redis发布订阅模式——推送消息】========================================================================================
+
     /**
      * 后台发送消息到redis
      *
@@ -154,7 +156,7 @@ public class WebSocket {
         BaseMap baseMap = new BaseMap();
         baseMap.put("userId", "");
         baseMap.put("message", message);
-        jeecgRedisClient.sendMessage(WebSocket.REDIS_TOPIC_NAME, baseMap);
+        adwebRedisUtil.sendMessage(WebSocket.REDIS_TOPIC_NAME, baseMap);
     }
 
     /**
@@ -167,7 +169,7 @@ public class WebSocket {
         BaseMap baseMap = new BaseMap();
         baseMap.put("userId", userId);
         baseMap.put("message", message);
-        jeecgRedisClient.sendMessage(WebSocket.REDIS_TOPIC_NAME, baseMap);
+        adwebRedisUtil.sendMessage(WebSocket.REDIS_TOPIC_NAME, baseMap);
     }
 
     /**
@@ -182,5 +184,5 @@ public class WebSocket {
         }
     }
     //=======【采用redis发布订阅模式——推送消息】==========================================================================================
-    
+
 }

+ 10 - 6
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/redis/CacheConfig.java

@@ -1,14 +1,11 @@
 package org.jeecg.modules.redis;
 
-import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
-
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.databind.MapperFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.json.JsonMapper;
 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
-
 import org.jeecg.common.modules.redis.config.RedisConfig;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cache.CacheManager;
@@ -28,6 +25,8 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 import java.time.Duration;
 
+import static org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
+
 /**
  * Redis cache配置
  *
@@ -43,8 +42,11 @@ public class CacheConfig {
 
     private static final int DEFAULT_TTL_HOURS = 5;
 
-    /** Jeecg默认Redis cache配置 */
-    @Autowired private RedisConfig redisConfig;
+    /**
+     * Jeecg默认Redis cache配置
+     */
+    @Autowired
+    private RedisConfig redisConfig;
 
     /**
      * Workaround - 重新注册Jeecg默认的{@link CacheManager},标识为Primary
@@ -61,7 +63,9 @@ public class CacheConfig {
         return redisConfig.cacheManager(connectionFactory);
     }
 
-    /** 注册{@link CacheManager},支持在{@link Cacheable#cacheNames()}中设置Redis TTL */
+    /**
+     * 注册{@link CacheManager},支持在{@link Cacheable#cacheNames()}中设置Redis TTL
+     */
     @Bean(name = TTL_CACHE_MANAGER)
     public CacheManager ttlCacheManager(RedisConnectionFactory connectionFactory) {
         // 解决缓存对象转换异常问题

+ 69 - 2
jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml

@@ -252,6 +252,15 @@ jeecg:
     minio_name: ??
     minio_pass: ??
     bucketName: otatest
+    dataPrefix: https://cutomer-static-bucket.s3.cn-northwest-1.amazonaws.com.cn/
+  minio_us:
+    minio_url: s3.amazonaws.com
+    minio_name: AKIA4NOAZAWYOT6RAF2F
+    minio_pass: IShWegPpmE3K0P1xbBv/qNJoWlPZMGxgueqyimcz
+    minio_region: us-east-1
+    bucketName: sync-adwebcloud-bucket
+    dataPrefix: https://data.adwebcloud.com/
+    originDataPrefix: https://advich-wordpress-static-resources.s3.us-west-2.amazonaws.com/
   #大屏报表参数设置
   jmreport:
     #多租户模式,默认值为空(created:按照创建人隔离、tenant:按照租户隔离) (v1.6.2+ 新增)
@@ -293,7 +302,8 @@ jeecg:
     apiHost: "https://api.openai.com"
     # 超时时间单位:s。默认 60s
     timeout: 60
-    # 本地代理地址
+
+  # 本地代理地址
 #    proxy:
 #      host: "http://127.0.0.1"
 #      port: "7890"
@@ -406,4 +416,61 @@ enquiry:
 aws:
   translate:
     accessKey: AKIAS37NJDKDETZ7PPEN
-    secretKey: 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
+    secretKey: b05X9U/zQ7jJwtIP8edIw1bZGk9p/L6iz9UxcBn5
+
+### 自定义 start, TODO 改位置配置将要再数据库中配置
+###配置测试文件上传路径
+adcloud:
+  file:
+    rootpath: /home/jiangning/adweb2.1/static/
+  picture:
+    ###图片压缩程度
+    size: 0.8
+
+#物料收集打包临时存放路径
+admp:
+  #脚本
+  shell:
+    path: /home/jiangning/adweb2.1/shell/
+
+#跳板机配置
+jumpServer:
+  pulicIp: 52.11.145.237
+  privateIp: 10.10.54.109
+  username: ubuntu
+  pem: /home/jiangning/adweb2.1/static/jumpserver.pem
+#建站链接生产环境配置
+AdwebSiteProdConnect:
+  privateIp: 10.10.182.222
+
+#118机器信息
+usWest118Server:
+  ip: 44.227.32.118
+  username: centos
+  pem: D:/Advich/pem/197529246342-oregon.cer
+  port: 50002
+  shellpath: /usr/local/adweb-v2/shell
+
+#v2项目路径
+v2:
+  projectPath: D:/Advich/pem
+  seoReportPath: /seopdf/report/
+  domainUrl: https://cyan.feishu.adwebcloud.com
+  pdfExportServiceUrl: https://puppeteer.advichcloud.com:7020
+
+#建站链接测试环境配置
+AdwebSiteConnect:
+  host: 35.87.155.71
+  port: 22
+  username: ubuntu
+  password: adweb123@2024
+  tempDomain: adweb3.topxuetang.com
+  tempCname: devci2.adwebcloud.com
+
+serverIp:
+  new: 52.83.132.56
+  old: 52.83.52.93
+#pem文件上传公网地址前缀
+pemFileDownLoad:
+  prefix: https://v2.adwebcloud.com/keys/
+### 自定义 end TODO 改位置配置将要再数据库中配置

+ 59 - 1
jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml

@@ -394,4 +394,62 @@ enquiry:
 aws:
   translate:
     accessKey: AKIAS37NJDKDETZ7PPEN
-    secretKey: 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
+    secretKey: b05X9U/zQ7jJwtIP8edIw1bZGk9p/L6iz9UxcBn5
+
+
+### 自定义 start, TODO 改位置配置将要再数据库中配置
+###配置测试文件上传路径
+adcloud:
+  file:
+    rootpath: /opt/adweb3/static/
+  picture:
+    ###图片压缩程度
+    size: 0.8
+
+#物料收集打包临时存放路径
+admp:
+  #脚本
+  shell:
+    path: /opt/adweb3/shell/
+
+#跳板机配置
+jumpServer:
+  pulicIp: 52.11.145.237
+  privateIp: 10.10.54.109
+  username: ubuntu
+  pem: /home/jiangning/adweb2.1/static/jumpserver.pem
+#建站链接生产环境配置
+AdwebSiteProdConnect:
+  privateIp: 10.10.182.222
+
+#118机器信息
+usWest118Server:
+  ip: 44.227.32.118
+  username: centos
+  pem: D:/Advich/pem/197529246342-oregon.cer
+  port: 50002
+  shellpath: /usr/local/adweb-v2/shell
+
+#v2项目路径
+v2:
+  projectPath: /opt/adweb3/pem
+  seoReportPath: /seopdf/report/
+  domainUrl: https://cyan.feishu.adwebcloud.com
+  pdfExportServiceUrl: https://puppeteer.advichcloud.com:7020
+
+#建站链接测试环境配置
+AdwebSiteConnect:
+  host: 52.83.163.165
+  port: 22
+  username: ubuntu
+  password: Admin@123.com
+  tempDomain: adweb3.topxuetang.com
+  tempCname: devci2.adwebcloud.com
+
+serverIp:
+  new: 52.83.132.56
+  old: 52.83.52.93
+#pem文件上传公网地址前缀
+pemFileDownLoad:
+  prefix: https://v2.adwebcloud.com/keys/
+### 自定义 end TODO 改位置配置将要再数据库中配置