Browse Source

基于companyId的数据库快照功能

yingp 6 years ago
parent
commit
9af1ce3f5c
35 changed files with 799 additions and 562 deletions
  1. 8 8
      base-servers/datacenter/datacenter-server/pom.xml
  2. 0 1
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/DatacenterApplication.java
  3. 0 27
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/BackupFailedEvent.java
  4. 0 22
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/BackupReadyEvent.java
  5. 0 28
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/BackupSuccessEvent.java
  6. 0 62
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/DumpContext.java
  7. 0 54
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/DumpFile.java
  8. 0 61
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/controller/BackupController.java
  9. 66 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/controller/SnapshotController.java
  10. 0 49
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/mapper/BackupMapper.java
  11. 24 29
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/Snapshot.java
  12. 82 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/SnapshotData.java
  13. 127 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/SnapshotUsage.java
  14. 19 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/repository/SnapshotDataRepository.java
  15. 23 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/repository/SnapshotRepository.java
  16. 25 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/repository/SnapshotUsageRepository.java
  17. 0 25
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/BackupService.java
  18. 30 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/SnapshotService.java
  19. 0 119
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/impl/BackupServiceImpl.java
  20. 52 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/impl/SnapshotServiceImpl.java
  21. 21 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/CreateFailedEvent.java
  22. 13 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/CreatedEvent.java
  23. 14 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/ReadyToCreateEvent.java
  24. 15 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/RemovedEvent.java
  25. 21 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/SnapshotEvent.java
  26. 108 0
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/SnapshotLifecycle.java
  27. 2 2
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/support/CompanyStrategy.java
  28. 15 10
      base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/support/MysqlStrategy.java
  29. 7 2
      base-servers/datacenter/datacenter-server/src/main/resources/application.yml
  30. 3 0
      base-servers/datacenter/datacenter-server/src/main/resources/config/application-docker-prod.yml
  31. 0 62
      base-servers/datacenter/datacenter-server/src/main/resources/mapper/BackupMapper.xml
  32. 66 0
      framework/commons-compress/src/main/java/com/usoftchina/saas/commons/compress/UnZip.java
  33. 4 0
      framework/commons-compress/src/test/java/com/usoftchina/saas/commons/compress/ZipTest.java
  34. 43 0
      framework/core/src/main/java/com/usoftchina/saas/page/StandardPage.java
  35. 11 1
      script/mysql/init/manage.sql

+ 8 - 8
base-servers/datacenter/datacenter-server/pom.xml

@@ -30,6 +30,14 @@
             <groupId>org.mybatis.spring.boot</groupId>
             <artifactId>mybatis-spring-boot-starter</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+        </dependency>
         <!-- sleuth -->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
@@ -62,14 +70,6 @@
             <groupId>com.usoftchina.saas</groupId>
             <artifactId>account-api</artifactId>
         </dependency>
-        <dependency>
-            <groupId>com.usoftchina.saas</groupId>
-            <artifactId>file-api</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.usoftchina.saas</groupId>
-            <artifactId>commons-compress</artifactId>
-        </dependency>
     </dependencies>
     <build>
         <plugins>

+ 0 - 1
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/DatacenterApplication.java

@@ -18,7 +18,6 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
 @MapperScan("com.usoftchina.saas.dc.mapper")
 @EnableDynamicDataSource
 @EnableFeignClients({
-        "com.usoftchina.saas.file.api",
         "com.usoftchina.saas.account.api"
 })
 public class DatacenterApplication {

+ 0 - 27
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/BackupFailedEvent.java

@@ -1,27 +0,0 @@
-package com.usoftchina.saas.dc.backup;
-
-import com.usoftchina.saas.dc.po.Backup;
-import org.springframework.context.ApplicationEvent;
-
-/**
- * @author yingp
- * @date 2019/1/21
- */
-public class BackupFailedEvent extends ApplicationEvent {
-    private Backup backup;
-    private Exception exception;
-
-    public BackupFailedEvent(Object source, Backup backup, Exception exception) {
-        super(source);
-        this.backup = backup;
-        this.exception = exception;
-    }
-
-    public Backup getBackup() {
-        return backup;
-    }
-
-    public Exception getException() {
-        return exception;
-    }
-}

+ 0 - 22
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/BackupReadyEvent.java

@@ -1,22 +0,0 @@
-package com.usoftchina.saas.dc.backup;
-
-import com.usoftchina.saas.dc.po.Backup;
-import com.usoftchina.saas.file.dto.FileInfoDTO;
-import org.springframework.context.ApplicationEvent;
-
-/**
- * @author yingp
- * @date 2019/1/21
- */
-public class BackupReadyEvent extends ApplicationEvent {
-    private Backup backup;
-
-    public BackupReadyEvent(Object source, Backup backup) {
-        super(source);
-        this.backup = backup;
-    }
-
-    public Backup getBackup() {
-        return backup;
-    }
-}

+ 0 - 28
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/BackupSuccessEvent.java

@@ -1,28 +0,0 @@
-package com.usoftchina.saas.dc.backup;
-
-import com.usoftchina.saas.dc.po.Backup;
-import com.usoftchina.saas.file.dto.FileInfoDTO;
-import org.springframework.context.ApplicationEvent;
-
-/**
- * @author yingp
- * @date 2019/1/21
- */
-public class BackupSuccessEvent extends ApplicationEvent {
-    private Backup backup;
-    private FileInfoDTO fileInfo;
-
-    public BackupSuccessEvent(Object source, Backup backup, FileInfoDTO fileInfo) {
-        super(source);
-        this.backup = backup;
-        this.fileInfo = fileInfo;
-    }
-
-    public Backup getBackup() {
-        return backup;
-    }
-
-    public FileInfoDTO getFileInfo() {
-        return fileInfo;
-    }
-}

+ 0 - 62
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/DumpContext.java

@@ -1,62 +0,0 @@
-package com.usoftchina.saas.dc.backup;
-
-import com.usoftchina.saas.commons.compress.Zip;
-import com.usoftchina.saas.dc.po.Backup;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-/**
- * @author yingp
- * @date 2019/1/21
- */
-public class DumpContext {
-    private Backup backup;
-    private final Path workspace;
-    private final Path zipPath;
-    private Zip zip;
-
-    public DumpContext(Backup backup) throws IOException{
-        this.backup = backup;
-        this.workspace = Files.createTempDirectory("backup");
-        this.zipPath = Files.createTempFile(backup.getCompanyId() + "-backup-", ".zip");
-        this.zip = Zip.out(zipPath);
-    }
-
-    public Path getWorkspace() {
-        return workspace;
-    }
-
-    public Backup getBackup() {
-        return backup;
-    }
-
-    public synchronized DumpContext append(DumpFile file) throws IOException{
-        if (zip.isClosed()) {
-            throw new IOException("zip file closed");
-        }
-        zip.append(file.getTempFile());
-        return this;
-    }
-
-    public File getZipFile() {
-        return zipPath.toFile();
-    }
-
-    public void close() {
-        try {
-            zip.close();
-        } catch (Exception e) {
-        };
-        try {
-            Files.delete(zipPath);
-        } catch (Exception e) {
-        };
-        try {
-            Files.delete(workspace);
-        } catch (Exception e) {
-        };
-    }
-}

+ 0 - 54
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/DumpFile.java

@@ -1,54 +0,0 @@
-package com.usoftchina.saas.dc.backup;
-
-import com.usoftchina.saas.dc.po.DataSourceInfo;
-import org.springframework.util.FileCopyUtils;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * @author yingp
- * @date 2019/1/21
- */
-public class DumpFile {
-    private final DumpContext context;
-    private final String dcName;
-    private final String dbName;
-    private final String tableName;
-    private final String data;
-    private File tempFile;
-
-    public DumpFile(DumpContext context, DataSourceInfo ds, String tableName, String data) {
-        this.context = context;
-        this.dcName = ds.getDcName();
-        this.dbName = ds.getDbName();
-        this.tableName = tableName;
-        this.data = data;
-    }
-
-    public String getDcName() {
-        return dcName;
-    }
-
-    public String getDbName() {
-        return dbName;
-    }
-
-    public String getTableName() {
-        return tableName;
-    }
-
-    public String getData() {
-        return data;
-    }
-
-    public File getTempFile() throws IOException{
-        if (null == tempFile && null != data) {
-            File file = new File(context.getWorkspace().toFile(),
-                    dcName + "-" + dbName + "-" + tableName + ".json");
-            file.createNewFile();
-            FileCopyUtils.copy(data.getBytes(), file);
-        }
-        return tempFile;
-    }
-}

+ 0 - 61
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/controller/BackupController.java

@@ -1,61 +0,0 @@
-package com.usoftchina.saas.dc.controller;
-
-import com.usoftchina.saas.base.Result;
-import com.usoftchina.saas.dc.service.BackupService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-
-/**
- * @author yingp
- * @date 2019/1/15
- */
-@RestController
-@RequestMapping("/backup")
-public class BackupController {
-
-    @Autowired
-    private BackupService backupService;
-
-    /**
-     * 备份
-     *
-     * @return
-     */
-    @PostMapping
-    public Result backup() {
-        backupService.newBackupTask();
-        return Result.success();
-    }
-
-    /**
-     * 查询列表
-     *
-     * @return
-     */
-    @GetMapping
-    public Result getBackups() {
-        return Result.success();
-    }
-
-    /**
-     * 删除单次备份
-     *
-     * @param id
-     * @return
-     */
-    @DeleteMapping
-    public Result deleteBackup(@RequestParam Long id) {
-        return Result.success();
-    }
-
-    /**
-     * 选择备份还原
-     *
-     * @param id
-     * @return
-     */
-    @PostMapping("/restore")
-    public Result restore(@RequestParam Long id) {
-        return Result.success();
-    }
-}

+ 66 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/controller/SnapshotController.java

@@ -0,0 +1,66 @@
+package com.usoftchina.saas.dc.controller;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.saas.base.Result;
+import com.usoftchina.saas.dc.po.Snapshot;
+import com.usoftchina.saas.dc.service.SnapshotService;
+import com.usoftchina.saas.page.PageDefault;
+import com.usoftchina.saas.page.PageRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+@RestController
+@RequestMapping("/snapshot")
+public class SnapshotController {
+
+    @Autowired
+    private SnapshotService snapshotService;
+
+    /**
+     * 生成快照
+     *
+     * @return
+     */
+    @PostMapping
+    public Result create() {
+        snapshotService.save();
+        return Result.success();
+    }
+
+    /**
+     * 查询列表
+     *
+     * @return
+     */
+    @GetMapping
+    public Result<PageInfo<Snapshot>> findAll(@PageDefault PageRequest pageRequest) {
+        return Result.success(snapshotService.selectByCompany(pageRequest));
+    }
+
+    /**
+     * 删除快照
+     *
+     * @param id
+     * @return
+     */
+    @DeleteMapping
+    public Result deleteSnapshot(@RequestParam String id) {
+        snapshotService.removeByPrimaryKey(id);
+        return Result.success();
+    }
+
+    /**
+     * 选择快照还原
+     *
+     * @param id
+     * @return
+     */
+    @PostMapping("/restore")
+    public Result restore(@RequestParam Long id) {
+        return Result.success();
+    }
+}

+ 0 - 49
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/mapper/BackupMapper.java

@@ -1,49 +0,0 @@
-package com.usoftchina.saas.dc.mapper;
-
-import com.usoftchina.saas.dc.po.Backup;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * @author yingp
- * @date 2019/1/15
- */
-public interface BackupMapper {
-
-    /**
-     * 按公司查找
-     *
-     * @param companyId
-     * @return
-     */
-    List<Backup> selectByCompanyId(@Param("companyId") Long companyId);
-
-    /**
-     * 新增
-     * @param backup
-     * @return
-     */
-    Long insert(Backup backup);
-
-    /**
-     * 更新
-     * @param backup
-     * @return
-     */
-    int updateByPrimaryKey(Backup backup);
-
-    /**
-     * 更新
-     * @param backup
-     * @return
-     */
-    int updateByPrimaryKeySelective(Backup backup);
-
-    /**
-     * 删除
-     * @param id
-     * @return
-     */
-    int deleteByPrimaryKey(@Param("id") Long id);
-}

+ 24 - 29
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/Backup.java → base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/Snapshot.java

@@ -1,21 +1,23 @@
 package com.usoftchina.saas.dc.po;
 
 import com.usoftchina.saas.context.BaseContextHolder;
-
-import java.io.Serializable;
-import java.util.Date;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
 
 /**
- * 数据备份记录
+ * 按公司生成数据快照
  *
  * @author yingp
- * @date 2019/1/15
+ * @date 2019/1/22
  */
-public class Backup implements Serializable {
-    private Long id;
-    private Long filePath;
-    private Date createTime;
+@Document(collection = "snapshot")
+public class Snapshot {
+    @Id
+    private String _id;
+    private Long createTime;
     private Long creatorId;
+    @Indexed(name = "snapshot_company_index")
     private Long companyId;
     /**
      * 0 - 未开始
@@ -24,43 +26,36 @@ public class Backup implements Serializable {
      * 2 - 完成备份
      */
     private short status;
+    private String remark;
     private String message;
 
-    public Backup() {
-        this.createTime = new Date();
+    public Snapshot() {
+        this.createTime = System.currentTimeMillis();
         this.creatorId = BaseContextHolder.getUserId();
         this.companyId = BaseContextHolder.getCompanyId();
         this.status = Status.NOT_READY;
     }
 
-    public Backup(long companyId) {
-        this.createTime = new Date();
+    public Snapshot(long companyId) {
+        this.createTime = System.currentTimeMillis();
         this.creatorId = BaseContextHolder.getUserId();
         this.companyId = companyId;
-        this.status = Status.NOT_READY;
-    }
-
-    public Long getId() {
-        return id;
-    }
-
-    public void setId(Long id) {
-        this.id = id;
+        this.status =Status.NOT_READY;
     }
 
-    public Long getFilePath() {
-        return filePath;
+    public String get_id() {
+        return _id;
     }
 
-    public void setFilePath(Long filePath) {
-        this.filePath = filePath;
+    public void set_id(String _id) {
+        this._id = _id;
     }
 
-    public Date getCreateTime() {
+    public Long getCreateTime() {
         return createTime;
     }
 
-    public void setCreateTime(Date createTime) {
+    public void setCreateTime(Long createTime) {
         this.createTime = createTime;
     }
 
@@ -98,7 +93,7 @@ public class Backup implements Serializable {
 
     public interface Status {
         short NOT_READY = 0;
-        short DUMPING = 1;
+        short CREATING = 1;
         short FAILED = -1;
         short SUCCESS = 2;
     }

+ 82 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/SnapshotData.java

@@ -0,0 +1,82 @@
+package com.usoftchina.saas.dc.po;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * 按公司生成数据快照 - 数据
+ *
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Document(collection = "snapshot_data")
+public class SnapshotData {
+    @Id
+    private String _id;
+    @Indexed(name = "snapshot_data_sid_index")
+    private String snapshotId;
+    private String dcName;
+    private String dbName;
+    private String tableName;
+    private Object data;
+
+    public SnapshotData() {
+    }
+
+    public SnapshotData(Snapshot snapshot, DataSourceInfo info, String tableName, Object data) {
+        this.snapshotId = snapshot.get_id();
+        this.dcName = info.getDcName();
+        this.dbName = info.getDbName();
+        this.tableName = tableName;
+        this.data = data;
+    }
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public String getSnapshotId() {
+        return snapshotId;
+    }
+
+    public void setSnapshotId(String snapshotId) {
+        this.snapshotId = snapshotId;
+    }
+
+    public String getDcName() {
+        return dcName;
+    }
+
+    public void setDcName(String dcName) {
+        this.dcName = dcName;
+    }
+
+    public String getDbName() {
+        return dbName;
+    }
+
+    public void setDbName(String dbName) {
+        this.dbName = dbName;
+    }
+
+    public String getTableName() {
+        return tableName;
+    }
+
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+}

+ 127 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/po/SnapshotUsage.java

@@ -0,0 +1,127 @@
+package com.usoftchina.saas.dc.po;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.index.Indexed;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * 快照使用记录
+ *
+ * TODO: 可以简单扩展一下,支持从一个公司的(快照)数据覆盖到另一个公司
+ *
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Document(collection = "snapshot_usage")
+public class SnapshotUsage implements Serializable {
+    @Id
+    private String _id;
+    /**
+     * 执行还原前,先将当前数据生成一份快照,这样在还原失败的情况下可以恢复
+     */
+    private String originSnapshotId;
+    /**
+     * 选择的快照文件
+     */
+    private String usedSnapshotId;
+    private Long createTime;
+    private Long creatorId;
+    @Indexed(name = "snapshot_usage_company_index")
+    private Long companyId;
+    /**
+     * 0 - 未开始
+     * 1 - 备份中
+     * -1 - 备份失败
+     * 2 - 完成备份
+     */
+    private short status;
+    private String message;
+
+    public String get_id() {
+        return _id;
+    }
+
+    public void set_id(String _id) {
+        this._id = _id;
+    }
+
+    public String getOriginSnapshotId() {
+        return originSnapshotId;
+    }
+
+    public void setOriginSnapshotId(String originSnapshotId) {
+        this.originSnapshotId = originSnapshotId;
+    }
+
+    public String getUsedSnapshotId() {
+        return usedSnapshotId;
+    }
+
+    public void setUsedSnapshotId(String usedSnapshotId) {
+        this.usedSnapshotId = usedSnapshotId;
+    }
+
+    public Long getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Long createTime) {
+        this.createTime = createTime;
+    }
+
+    public Long getCreatorId() {
+        return creatorId;
+    }
+
+    public void setCreatorId(Long creatorId) {
+        this.creatorId = creatorId;
+    }
+
+    public Long getCompanyId() {
+        return companyId;
+    }
+
+    public void setCompanyId(Long companyId) {
+        this.companyId = companyId;
+    }
+
+    public short getStatus() {
+        return status;
+    }
+
+    public void setStatus(short status) {
+        this.status = status;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public interface Status {
+        short NOT_READY = 0;
+        /**
+         * 导出当前数据
+         */
+        short DUMPING_ORIGIN = 1;
+        /**
+         * 读取备份文件
+         */
+        short READ_DUMPFILE = 1;
+        /**
+         * 还原中(删除旧数据,)
+         */
+        short RESTORE = 1;
+        /**
+         * 操作失败需要使用originData还原
+         */
+        short ROLLBACK = -1;
+        short FAILED = 2;
+        short SUCCESS = 2;
+    }
+}

+ 19 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/repository/SnapshotDataRepository.java

@@ -0,0 +1,19 @@
+package com.usoftchina.saas.dc.repository;
+
+import com.usoftchina.saas.dc.po.SnapshotData;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Repository
+public interface SnapshotDataRepository extends MongoRepository<SnapshotData, String> {
+    /**
+     * 删除
+     *
+     * @param snapshotId
+     */
+    void deleteBySnapshotId(String snapshotId);
+}

+ 23 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/repository/SnapshotRepository.java

@@ -0,0 +1,23 @@
+package com.usoftchina.saas.dc.repository;
+
+import com.usoftchina.saas.dc.po.Snapshot;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Repository
+public interface SnapshotRepository extends MongoRepository<Snapshot, String> {
+    /**
+     * 按公司分页查找
+     *
+     * @param companyId
+     * @param pageable
+     * @return
+     */
+    Page<Snapshot> findByCompanyIdOrderByCreateTimeDesc(Long companyId, Pageable pageable);
+}

+ 25 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/repository/SnapshotUsageRepository.java

@@ -0,0 +1,25 @@
+package com.usoftchina.saas.dc.repository;
+
+import com.usoftchina.saas.dc.po.SnapshotUsage;
+import org.springframework.data.mongodb.repository.MongoRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Repository
+public interface SnapshotUsageRepository extends MongoRepository<SnapshotUsage, String> {
+    /**
+     * 删除
+     *
+     * @param snapshotId
+     */
+    void deleteByUsedSnapshotId(String snapshotId);
+    /**
+     * 删除
+     *
+     * @param snapshotId
+     */
+    void deleteByOriginSnapshotId(String snapshotId);
+}

+ 0 - 25
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/BackupService.java

@@ -1,25 +0,0 @@
-package com.usoftchina.saas.dc.service;
-
-import com.usoftchina.saas.dc.po.Backup;
-
-/**
- * @author yingp
- * @date 2019/1/15
- */
-public interface BackupService {
-
-    /**
-     * 新增
-     *
-     * @return
-     */
-    Backup newBackupTask();
-
-    /**
-     * 删除
-     *
-     * @param id
-     * @return
-     */
-    boolean removeByPrimaryKey(Long id);
-}

+ 30 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/SnapshotService.java

@@ -0,0 +1,30 @@
+package com.usoftchina.saas.dc.service;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.saas.dc.po.Snapshot;
+import com.usoftchina.saas.page.PageRequest;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public interface SnapshotService {
+    /**
+     * 创建快照
+     * @return
+     */
+    Snapshot save();
+
+    /**
+     * 查找
+     * @param page
+     * @return
+     */
+    PageInfo<Snapshot> selectByCompany(PageRequest page);
+
+    /**
+     * 删除
+     * @param id
+     */
+    void removeByPrimaryKey(String id);
+}

+ 0 - 119
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/impl/BackupServiceImpl.java

@@ -1,119 +0,0 @@
-package com.usoftchina.saas.dc.service.impl;
-
-import com.usoftchina.saas.account.cache.CompanyCache;
-import com.usoftchina.saas.account.cache.CompanyLockCache;
-import com.usoftchina.saas.context.SpringContextHolder;
-import com.usoftchina.saas.dc.backup.*;
-import com.usoftchina.saas.dc.mapper.BackupMapper;
-import com.usoftchina.saas.dc.po.Backup;
-import com.usoftchina.saas.dc.po.DataSourceInfo;
-import com.usoftchina.saas.dc.service.BackupService;
-import com.usoftchina.saas.dc.service.DataSourceInfoService;
-import com.usoftchina.saas.exception.Try;
-import com.usoftchina.saas.file.api.FileApi;
-import com.usoftchina.saas.file.dto.FileInfoDTO;
-import com.usoftchina.saas.file.util.FileUploadUtils;
-import com.usoftchina.saas.utils.CollectionUtils;
-import com.usoftchina.saas.utils.StringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.event.EventListener;
-import org.springframework.scheduling.annotation.Async;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
- * @author yingp
- * @date 2019/1/15
- */
-@Service
-public class BackupServiceImpl implements BackupService {
-
-    @Autowired
-    private BackupMapper backupMapper;
-
-    @Autowired
-    private DataSourceInfoService dataSourceInfoService;
-
-    @Autowired
-    private FileApi fileApi;
-
-    @Autowired
-    private MysqlStrategy mysqlStrategy;
-
-    @Override
-    public Backup newBackupTask() {
-        Backup backup = new Backup();
-        backupMapper.insert(backup);
-        SpringContextHolder.getContext().publishEvent(new BackupReadyEvent(this, backup));
-        return backup;
-    }
-
-    public void dump(long companyId) throws Exception {
-        dump(new Backup(companyId));
-    }
-
-    public void dump(Backup backup) throws Exception {
-        String dcName = StringUtils.nullIf(CompanyCache.current().getCompany().getDcName(), "default");
-        List<DataSourceInfo> dss = dataSourceInfoService.findByDcNameUseDefault(dcName);
-        if (!CollectionUtils.isEmpty(dss)) {
-            DumpContext context = new DumpContext(backup);
-            try {
-                dss.parallelStream().forEach(Try.accept(ds -> {
-                    if ("mysql".equals(ds.getDbType())) {
-                        mysqlStrategy.exp(context, ds);
-                    }
-                }));
-                FileInfoDTO fileInfoDTO = FileUploadUtils.upload(context.getZipFile());
-                SpringContextHolder.getContext().publishEvent(
-                        new BackupSuccessEvent(this, backup, fileInfoDTO));
-            } finally {
-                context.close();
-            }
-        }
-    }
-
-    @Override
-    public boolean removeByPrimaryKey(Long id) {
-        return backupMapper.deleteByPrimaryKey(id) > -1;
-    }
-
-    @Async
-    @EventListener(BackupReadyEvent.class)
-    public void onBackupReady(BackupReadyEvent event) {
-        Backup backup = event.getBackup();
-        try {
-            backup.setStatus(Backup.Status.DUMPING);
-            backupMapper.updateByPrimaryKeySelective(backup);
-            // 为防止导出过程中有人操作,导致部分数据不一致,在导出前锁定该公司不允许操作
-            CompanyLockCache.lock(backup.getCompanyId());
-            dump(backup);
-        } catch (Exception e) {
-            SpringContextHolder.getContext().publishEvent(
-                    new BackupFailedEvent(this, backup, e));
-        }
-    }
-
-    @Async
-    @EventListener(BackupFailedEvent.class)
-    public void onBackupFailed(BackupFailedEvent event) {
-        Backup backup = event.getBackup();
-        // 解除锁定
-        CompanyLockCache.unlock(backup.getCompanyId());
-        backup.setStatus(Backup.Status.FAILED);
-        backup.setMessage(event.getException().getMessage());
-        backupMapper.updateByPrimaryKeySelective(backup);
-    }
-
-    @Async
-    @EventListener(BackupSuccessEvent.class)
-    public void onBackupSuccess(BackupSuccessEvent event) {
-        Backup backup = event.getBackup();
-        // 解除锁定
-        CompanyLockCache.unlock(backup.getCompanyId());
-        backup.setStatus(Backup.Status.SUCCESS);
-        backup.setFilePath(event.getFileInfo().getId());
-        backupMapper.updateByPrimaryKeySelective(backup);
-    }
-
-}

+ 52 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/service/impl/SnapshotServiceImpl.java

@@ -0,0 +1,52 @@
+package com.usoftchina.saas.dc.service.impl;
+
+import com.github.pagehelper.PageInfo;
+import com.usoftchina.saas.context.BaseContextHolder;
+import com.usoftchina.saas.context.SpringContextHolder;
+import com.usoftchina.saas.dc.po.Snapshot;
+import com.usoftchina.saas.dc.repository.SnapshotRepository;
+import com.usoftchina.saas.dc.service.SnapshotService;
+import com.usoftchina.saas.dc.snapshot.event.ReadyToCreateEvent;
+import com.usoftchina.saas.dc.snapshot.event.RemovedEvent;
+import com.usoftchina.saas.page.PageRequest;
+import com.usoftchina.saas.page.StandardPage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Service
+public class SnapshotServiceImpl implements SnapshotService {
+
+    @Autowired
+    private SnapshotRepository snapshotRepository;
+
+    @Override
+    public Snapshot save() {
+        Snapshot snapshot = snapshotRepository.save(new Snapshot());
+        SpringContextHolder.getContext().publishEvent(new ReadyToCreateEvent(this, snapshot));
+        return snapshot;
+    }
+
+    @Override
+    public PageInfo<Snapshot> selectByCompany(PageRequest page) {
+        Page<Snapshot> snapshots = snapshotRepository.findByCompanyIdOrderByCreateTimeDesc(
+                BaseContextHolder.getCompanyId(), StandardPage.pageable(page));
+        return StandardPage.pageInfo(snapshots);
+    }
+
+    @Override
+    public void removeByPrimaryKey(String id) {
+        Optional<Snapshot> optional = snapshotRepository.findById(id);
+        if (optional.isPresent()) {
+            Snapshot snapshot = optional.get();
+            snapshotRepository.delete(snapshot);
+            SpringContextHolder.getContext().publishEvent(new RemovedEvent(this, snapshot));
+        }
+    }
+}

+ 21 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/CreateFailedEvent.java

@@ -0,0 +1,21 @@
+package com.usoftchina.saas.dc.snapshot.event;
+
+import com.usoftchina.saas.dc.po.Snapshot;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public class CreateFailedEvent extends SnapshotEvent{
+
+    private Exception exception;
+
+    public CreateFailedEvent(Object source, Snapshot snapshot, Exception exception) {
+        super(source, snapshot);
+        this.exception = exception;
+    }
+
+    public Exception getException() {
+        return exception;
+    }
+}

+ 13 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/CreatedEvent.java

@@ -0,0 +1,13 @@
+package com.usoftchina.saas.dc.snapshot.event;
+
+import com.usoftchina.saas.dc.po.Snapshot;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public class CreatedEvent extends SnapshotEvent{
+    public CreatedEvent(Object source, Snapshot snapshot) {
+        super(source, snapshot);
+    }
+}

+ 14 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/ReadyToCreateEvent.java

@@ -0,0 +1,14 @@
+package com.usoftchina.saas.dc.snapshot.event;
+
+import com.usoftchina.saas.dc.po.Snapshot;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public class ReadyToCreateEvent extends SnapshotEvent {
+
+    public ReadyToCreateEvent(Object source, Snapshot snapshot) {
+        super(source, snapshot);
+    }
+}

+ 15 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/RemovedEvent.java

@@ -0,0 +1,15 @@
+package com.usoftchina.saas.dc.snapshot.event;
+
+import com.usoftchina.saas.dc.po.Snapshot;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public class RemovedEvent extends SnapshotEvent {
+
+    public RemovedEvent(Object source, Snapshot snapshot) {
+        super(source, snapshot);
+    }
+}
+

+ 21 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/SnapshotEvent.java

@@ -0,0 +1,21 @@
+package com.usoftchina.saas.dc.snapshot.event;
+
+import com.usoftchina.saas.dc.po.Snapshot;
+import org.springframework.context.ApplicationEvent;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public abstract class SnapshotEvent extends ApplicationEvent {
+    private Snapshot snapshot;
+
+    public SnapshotEvent(Object source, Snapshot snapshot) {
+        super(source);
+        this.snapshot = snapshot;
+    }
+
+    public Snapshot getSnapshot() {
+        return snapshot;
+    }
+}

+ 108 - 0
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/event/SnapshotLifecycle.java

@@ -0,0 +1,108 @@
+package com.usoftchina.saas.dc.snapshot.event;
+
+import com.usoftchina.saas.account.cache.CompanyCache;
+import com.usoftchina.saas.account.cache.CompanyLockCache;
+import com.usoftchina.saas.context.SpringContextHolder;
+import com.usoftchina.saas.dc.po.DataSourceInfo;
+import com.usoftchina.saas.dc.po.Snapshot;
+import com.usoftchina.saas.dc.repository.SnapshotDataRepository;
+import com.usoftchina.saas.dc.repository.SnapshotRepository;
+import com.usoftchina.saas.dc.repository.SnapshotUsageRepository;
+import com.usoftchina.saas.dc.service.DataSourceInfoService;
+import com.usoftchina.saas.dc.snapshot.support.MysqlStrategy;
+import com.usoftchina.saas.utils.CollectionUtils;
+import com.usoftchina.saas.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.event.EventListener;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+@Component
+public class SnapshotLifecycle {
+
+    @Autowired
+    private SnapshotRepository snapshotRepository;
+
+    @Autowired
+    private SnapshotDataRepository snapshotDataRepository;
+
+    @Autowired
+    private SnapshotUsageRepository snapshotUsageRepository;
+
+    @Autowired
+    private DataSourceInfoService dataSourceInfoService;
+
+    @Autowired
+    private MysqlStrategy mysqlStrategy;
+
+    @Async
+    @EventListener(ReadyToCreateEvent.class)
+    public void onReadyToCreateEvent(ReadyToCreateEvent event) {
+        Snapshot snapshot = event.getSnapshot();
+        try {
+            snapshot.setStatus(Snapshot.Status.CREATING);
+            snapshotRepository.save(snapshot);
+            // 为防止导出过程中有人操作,导致部分数据不一致,在导出前锁定该公司不允许操作
+            CompanyLockCache.lock(snapshot.getCompanyId());
+            createSnapshotData(snapshot);
+            SpringContextHolder.getContext().publishEvent(new CreatedEvent(this, snapshot));
+        } catch (Exception e) {
+            SpringContextHolder.getContext().publishEvent(new CreateFailedEvent(this, snapshot, e));
+        }
+    }
+
+    /**
+     * 连接到不同数据中心,查找数据,生成快照数据
+     *
+     * @param snapshot
+     */
+    private void createSnapshotData(Snapshot snapshot) {
+        String dcName = StringUtils.nullIf(CompanyCache.current().getCompany().getDcName(), "default");
+        List<DataSourceInfo> dss = dataSourceInfoService.findByDcNameUseDefault(dcName);
+        if (!CollectionUtils.isEmpty(dss)) {
+            dss.parallelStream().forEach(ds -> {
+                if ("mysql".equals(ds.getDbType())) {
+                    mysqlStrategy.exp(snapshot, ds);
+                }
+            });
+        }
+    }
+
+    @Async
+    @EventListener(CreatedEvent.class)
+    public void onCreatedEvent(CreatedEvent event) {
+        Snapshot snapshot = event.getSnapshot();
+        // 解锁
+        CompanyLockCache.unlock(snapshot.getCompanyId());
+        snapshot.setStatus(Snapshot.Status.SUCCESS);
+        snapshotRepository.save(snapshot);
+    }
+
+    @Async
+    @EventListener(CreateFailedEvent.class)
+    public void onCreateFailedEvent(CreateFailedEvent event) {
+        Snapshot snapshot = event.getSnapshot();
+        // 解锁
+        CompanyLockCache.unlock(snapshot.getCompanyId());
+        snapshot.setStatus(Snapshot.Status.FAILED);
+        snapshot.setMessage(event.getException().getMessage());
+        snapshotRepository.save(snapshot);
+        // 快照创建失败,数据已经无意义了,删除
+        snapshotDataRepository.deleteBySnapshotId(snapshot.get_id());
+    }
+
+    @Async
+    @EventListener(RemovedEvent.class)
+    public void onRemovedEvent(RemovedEvent event) {
+        Snapshot snapshot = event.getSnapshot();
+        snapshotDataRepository.deleteBySnapshotId(snapshot.get_id());
+        snapshotUsageRepository.deleteByUsedSnapshotId(snapshot.get_id());
+        snapshotUsageRepository.deleteByOriginSnapshotId(snapshot.get_id());
+    }
+}

+ 2 - 2
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/CompanyStrategy.java → base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/support/CompanyStrategy.java

@@ -1,9 +1,9 @@
-package com.usoftchina.saas.dc.backup;
+package com.usoftchina.saas.dc.snapshot.support;
 
 /**
  * @author yingp
  * @date 2019/1/21
  */
-public interface CompanyStrategy{
+public interface CompanyStrategy {
     String COMPANY_ID_COLUMN = "company_id";
 }

+ 15 - 10
base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/backup/MysqlStrategy.java → base-servers/datacenter/datacenter-server/src/main/java/com/usoftchina/saas/dc/snapshot/support/MysqlStrategy.java

@@ -1,26 +1,27 @@
-package com.usoftchina.saas.dc.backup;
+package com.usoftchina.saas.dc.snapshot.support;
 
-import com.usoftchina.saas.context.BaseContextHolder;
 import com.usoftchina.saas.dc.mapper.CommonMapper;
 import com.usoftchina.saas.dc.mapper.SchemaMapper;
 import com.usoftchina.saas.dc.po.DataSourceInfo;
+import com.usoftchina.saas.dc.po.Snapshot;
+import com.usoftchina.saas.dc.po.SnapshotData;
+import com.usoftchina.saas.dc.repository.SnapshotDataRepository;
 import com.usoftchina.saas.jdbc.DynamicDataSourceContextHolder;
 import com.usoftchina.saas.jdbc.DynamicDataSourceRegister;
 import com.usoftchina.saas.utils.CollectionUtils;
-import com.usoftchina.saas.utils.JsonUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
-import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.List;
 
 /**
  * @author yingp
- * @date 2019/1/21
+ * @date 2019/1/22
  */
 @Component
 public class MysqlStrategy implements CompanyStrategy {
+
     @Autowired
     private DynamicDataSourceRegister dataSourceRegister;
 
@@ -30,8 +31,11 @@ public class MysqlStrategy implements CompanyStrategy {
     @Autowired
     private CommonMapper commonMapper;
 
-    public void exp(final DumpContext context, final DataSourceInfo ds) throws IOException{
-        final long companyId = BaseContextHolder.getCompanyId();
+    @Autowired
+    private SnapshotDataRepository snapshotDataRepository;
+
+    public void exp(final Snapshot snapshot, final DataSourceInfo ds) {
+        final long companyId = snapshot.getCompanyId();
         // 如果不存在数据源则自动创建
         dataSourceRegister.createDataSource(ds);
         DynamicDataSourceContextHolder.set(ds);
@@ -39,13 +43,14 @@ public class MysqlStrategy implements CompanyStrategy {
             // 查找所有与公司相关表
             List<String> tables = schemaMapper.selectTableNameBySchema(ds.getDbRealName(), COMPANY_ID_COLUMN);
             if (!CollectionUtils.isEmpty(tables)) {
-                for (String table : tables) {
+                tables.parallelStream().forEach(table -> {
                     // 查找指定表的所有数据
                     List<LinkedHashMap<String, Object>> data = commonMapper.select(String.format("select * from %s where %s=%s", table, COMPANY_ID_COLUMN, companyId));
                     if (!CollectionUtils.isEmpty(data)) {
-                        context.append(new DumpFile(context, ds, table, JsonUtils.toJsonString(data)));
+                        SnapshotData snapshotData = new SnapshotData(snapshot, ds, table, data);
+                        snapshotDataRepository.save(snapshotData);
                     }
-                }
+                });
             }
         } finally {
             DynamicDataSourceContextHolder.clear();

+ 7 - 2
base-servers/datacenter/datacenter-server/src/main/resources/application.yml

@@ -41,6 +41,9 @@ spring:
   jackson:
     date-format: yyyy-MM-dd HH:mm:ss
     time-zone: GMT+8
+  data:
+    mongodb:
+     uri: mongodb://10.1.81.63:27017/saas_data
 eureka:
   instance:
     leaseRenewalIntervalInSeconds: 10
@@ -53,7 +56,7 @@ eureka:
   client:
     registryFetchIntervalSeconds: 5
     serviceUrl:
-      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@10.1.81.61:8510/eureka/
+      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@10.1.81.61:8500/eureka/
 server:
   port: 8720
   tomcat:
@@ -80,4 +83,6 @@ mybatis:
   type-aliases-package: com.usoftchina.saas.dc.po
   mapper-locations: classpath:mapper/*.xml
   configuration:
-    call-setters-on-nulls: true
+    call-setters-on-nulls: true
+auth:
+  public-key: auth/pub.key

+ 3 - 0
base-servers/datacenter/datacenter-server/src/main/resources/config/application-docker-prod.yml

@@ -19,5 +19,8 @@ spring:
   redis:
     host: 10.10.100.173
     port: 6379
+  data:
+    mongodb:
+      uri: mongodb://10.10.100.123:27017/saas_data
 logging:
   destination: 10.10.100.160:5000

+ 0 - 62
base-servers/datacenter/datacenter-server/src/main/resources/mapper/BackupMapper.xml

@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
-<mapper namespace="com.usoftchina.saas.dc.mapper.BackupMapper">
-    <resultMap id="BaseResultMap" type="com.usoftchina.saas.dc.po.Backup">
-        <id column="id" jdbcType="BIGINT" property="id"/>
-        <result column="file_path" jdbcType="VARCHAR" property="filePath"/>
-        <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
-        <result column="creator_id" jdbcType="BIGINT" property="creatorId"/>
-        <result column="company_id" jdbcType="BIGINT" property="companyId"/>
-        <result column="status" jdbcType="INTEGER" property="status"/>
-        <result column="message" jdbcType="VARCHAR" property="message"/>
-    </resultMap>
-    <sql id="baseColumns">
-        id,file_path,create_time,creator_id,company_id,status,message
-    </sql>
-    <select id="selectByCompanyId" resultMap="BaseResultMap">
-        select <include refid="baseColumns"/> from backup where company_id=#{companyId} order by create_time desc
-    </select>
-    <insert id="insert" parameterType="com.usoftchina.saas.dc.po.Backup"
-            useGeneratedKeys="true" keyProperty="id">
-        insert into backup(file_path,create_time,creator_id,company_id,status,message)
-        values (#{filePath,jdbcType=VARCHAR},#{createTime,jdbcType=TIMESTAMP},#{creatorId,jdbcType=BIGINT},
-        #{companyId,jdbcType=BIGINT}, #{status,jdbcType=INTEGER}, #{message,jdbcType=VARCHAR})
-    </insert>
-    <update id="updateByPrimaryKey" parameterType="com.usoftchina.saas.dc.po.Backup">
-        update backup set
-        file_path=#{filePath,jdbcType=VARCHAR},
-        create_time=#{createTime,jdbcType=TIMESTAMP},
-        creator_id=#{creatorId,jdbcType=BIGINT},
-        company_id=#{companyId,jdbcType=BIGINT},
-        status=#{status,jdbcType=INTEGER},
-        message=#{message,jdbcType=VARCHAR}
-        where id=#{id,jdbcType=BIGINT}
-    </update>
-    <update id="updateByPrimaryKeySelective" parameterType="com.usoftchina.saas.dc.po.Backup">
-        update backup
-        <set>
-            <if test="filePath != null">
-                file_path=#{filePath,jdbcType=VARCHAR},
-            </if>
-            <if test="createTime != null">
-                create_time=#{createTime,jdbcType=TIMESTAMP},
-            </if>
-            <if test="creatorId != null">
-                creator_id=#{creatorId,jdbcType=BIGINT},
-            </if>
-            <if test="companyId != null">
-                company_id=#{companyId,jdbcType=BIGINT},
-            </if>
-            <if test="status != null">
-                status=#{status,jdbcType=INTEGER},
-            </if>
-            <if test="message != null">
-                message=#{status,jdbcType=VARCHAR},
-            </if>
-        </set>
-        where id=#{id,jdbcType=BIGINT}
-    </update>
-    <delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
-        delete from backup where id = #{id,jdbcType=BIGINT}
-    </delete>
-</mapper>

+ 66 - 0
framework/commons-compress/src/main/java/com/usoftchina/saas/commons/compress/UnZip.java

@@ -0,0 +1,66 @@
+package com.usoftchina.saas.commons.compress;
+
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.utils.IOUtils;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * @author yingp
+ * @date 2019/1/22
+ */
+public class UnZip {
+
+    private final ArchiveInputStream in;
+
+    private UnZip(InputStream in) throws ArchiveException{
+        this.in = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, in);
+    }
+
+    public static UnZip of(Path path) throws ArchiveException, FileNotFoundException{
+        return of(path.toFile());
+    }
+
+    public static UnZip of(File file) throws ArchiveException, FileNotFoundException{
+        return new UnZip(new BufferedInputStream(new FileInputStream(file)));
+    }
+
+    public static UnZip of(byte[] bytes) throws ArchiveException{
+        return new UnZip(new ByteArrayInputStream(bytes));
+    }
+
+    public void close() {
+        IOUtils.closeQuietly(in);
+    }
+
+    public void out(Path dest) throws IOException{
+        out(dest.toFile());
+    }
+
+    public void out(String dest) throws IOException{
+        out(Paths.get(dest));
+    }
+
+    public void out(File dest) throws IOException {
+        if (!dest.exists() || !dest.isDirectory()) {
+            dest.mkdirs();
+        }
+        String destFolder = dest.getAbsolutePath();
+        ZipArchiveEntry entry = null;
+        while ((entry = (ZipArchiveEntry) in.getNextEntry()) != null) {
+            Path entryPath = Paths.get(destFolder, entry.getName());
+            if (entry.isDirectory()) {
+                Files.createDirectory(entryPath);
+            } else {
+                Files.copy(in, entryPath);
+            }
+        }
+        close();
+    }
+}

+ 4 - 0
framework/commons-compress/src/test/java/com/usoftchina/saas/commons/compress/ZipTest.java

@@ -23,7 +23,11 @@ public class ZipTest {
 
         System.out.println(srcPath.toFile().getAbsolutePath());
         System.out.println(zipPath.toFile().getAbsolutePath());
+
+        Path unzipPath = Files.createTempDirectory("restore");
+        UnZip.of(zipPath).out(unzipPath);
 //        Files.delete(srcPath);
 //        Files.delete(zipPath);
+//        Files.delete(unzipPath);
     }
 }

+ 43 - 0
framework/core/src/main/java/com/usoftchina/saas/page/StandardPage.java

@@ -0,0 +1,43 @@
+package com.usoftchina.saas.page;
+
+import com.github.pagehelper.PageInfo;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+/**
+ * 部分服务使用了pagehelper工具,部分使用了spring-data的分页工具
+ * 需要提供一些方法进行转换,保证提供给前端的接口统一
+ *
+ * @author yingp
+ * @date 2019/1/22
+ */
+public class StandardPage {
+
+    /**
+     * 从spring-data的Page数据,转换为pagehelper的PageInfo数据
+     *
+     * @param page
+     * @param <T>
+     * @return
+     */
+   public static <T> PageInfo<T> pageInfo(Page<T> page) {
+       // spring-data的page从0开始
+       com.github.pagehelper.Page p = new com.github.pagehelper.Page(page.getNumber() + 1,
+               page.getSize());
+       p.setTotal(page.getTotalElements());
+       p.addAll(page.getContent());
+       return new PageInfo<>(p);
+   }
+
+    /**
+     * 分页参数转换为spring-data的Pageable
+     *
+     * @param pageRequest
+     * @return
+     */
+    public static Pageable pageable(PageRequest pageRequest) {
+        // spring-data的page从0开始
+        return org.springframework.data.domain.PageRequest.of(pageRequest.getNumber() - 1,
+                pageRequest.getSize());
+    }
+}

+ 11 - 1
script/mysql/init/manage.sql

@@ -15,4 +15,14 @@ create table `datasource` (
   db_port int comment '数据库端口',
   db_username varchar(30) comment '数据库登录账号',
 	db_password varchar(64) comment '数据库登录密码'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='数据连接';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='数据连接';
+
+create table `backup` (
+  id int unsigned primary key not null auto_increment,
+  file_path int unsigned comment '文件ID',
+  create_time datetime comment '创建时间',
+  creator_id int unsigned comment '创建人',
+  company_id int unsigned comment '公司',
+  status smallint comment '状态',
+  message varchar(1000) comment '错误信息'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='按公司数据备份';