feat:增加备份管理模块

This commit is contained in:
wangyu 2022-01-03 23:21:43 +08:00
parent 2fcbb65a6f
commit 87ee0bd55c
8 changed files with 124 additions and 12 deletions

26
flyfish-backup/pom.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>flyfish-framework</artifactId>
<groupId>com.flyfish.framework</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>flyfish-backup</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.flyfish.framework</groupId>
<artifactId>flyfish-web</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,36 @@
package com.flyfish.framework.backup.controller;
import com.flyfish.framework.backup.domain.Backup;
import com.flyfish.framework.backup.scheduler.BackupScheduler;
import com.flyfish.framework.bean.Result;
import com.flyfish.framework.controller.reactive.ReactiveBaseController;
import com.flyfish.framework.domain.base.NameLikeQo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 备份controller
*
* @author wangyu
*/
@RestController
@RequestMapping("backups")
public class BackupController extends ReactiveBaseController<Backup, NameLikeQo<Backup>> {
@Resource
private BackupScheduler backupScheduler;
/**
* 立即创建备份
*
* @return 结果
*/
@PostMapping("task")
public Result<String> createTask() {
backupScheduler.backup();
return Result.accept("已创建备份,完成后会出现在列表中,请稍后刷新再试。");
}
}

View File

@ -1,10 +1,11 @@
package com.flyfish.framework.domain.po; package com.flyfish.framework.backup.domain;
import com.flyfish.framework.domain.base.AuditDomain; import com.flyfish.framework.domain.base.AuditDomain;
import com.flyfish.framework.enums.NamedEnum; import com.flyfish.framework.enums.NamedEnum;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
/** /**
* 系统备份 * 系统备份
@ -13,6 +14,7 @@ import lombok.Setter;
*/ */
@Getter @Getter
@Setter @Setter
@Document(collection = "backups")
public class Backup extends AuditDomain { public class Backup extends AuditDomain {
// 文件路径 // 文件路径

View File

@ -0,0 +1,12 @@
package com.flyfish.framework.backup.repository;
import com.flyfish.framework.backup.domain.Backup;
import com.flyfish.framework.repository.DefaultReactiveRepository;
/**
* 备份仓库
*
* @author wangyu
*/
public interface BackupRepository extends DefaultReactiveRepository<Backup> {
}

View File

@ -1,9 +1,8 @@
package com.flyfish.framework.scheduler; package com.flyfish.framework.backup.scheduler;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
/** /**

View File

@ -1,8 +1,8 @@
package com.flyfish.framework.scheduler; package com.flyfish.framework.backup.scheduler;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.flyfish.framework.backup.domain.Backup;
import com.flyfish.framework.domain.base.DomainService; import com.flyfish.framework.domain.base.DomainService;
import com.flyfish.framework.domain.po.Backup;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -20,6 +20,7 @@ import org.springframework.util.unit.DataSize;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.io.IOException;
import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.AsynchronousFileChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@ -29,6 +30,7 @@ import java.nio.file.StandardOpenOption;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -75,9 +77,8 @@ public class BackupScheduler {
public void backup() { public void backup() {
// 本次备份任务代号 // 本次备份任务代号
String code = UUID.randomUUID().toString(); String code = UUID.randomUUID().toString();
// 本次备份父目录 // 本次备份父目录出错时替换目录保证备份成功
String parent = backupPath + "/" + code; String parent = createIfNotExists(backupPath + "/" + code);
createIfNotExists(parent);
// 开始备份先构造一个指示器 // 开始备份先构造一个指示器
Backup backup = new Backup(); Backup backup = new Backup();
backup.setCreateTime(new Date()); backup.setCreateTime(new Date());
@ -85,6 +86,8 @@ public class BackupScheduler {
backup.setCode(code); backup.setCode(code);
backup.setStatus(Backup.Status.RUNNING); backup.setStatus(Backup.Status.RUNNING);
backup.setFilepath(parent + "/back.zip"); backup.setFilepath(parent + "/back.zip");
// 数据大小计数器
AtomicLong sizeCounter = new AtomicLong(0);
// 开始备份 // 开始备份
operations.save(backup) operations.save(backup)
.thenMany(Flux.fromIterable(this.collections)) .thenMany(Flux.fromIterable(this.collections))
@ -98,7 +101,9 @@ public class BackupScheduler {
BackupIndex index = new BackupIndex(); BackupIndex index = new BackupIndex();
index.setId(code); index.setId(code);
index.setItems(list.stream().map(content -> { index.setItems(list.stream().map(content -> {
DataSize size = DataSize.parse(new String(content.getContent(), StandardCharsets.UTF_8)); long currentSize = content.getContent().length;
sizeCounter.addAndGet(currentSize);
DataSize size = DataSize.ofBytes(currentSize);
BackupIndex.BackupItem item = new BackupIndex.BackupItem(); BackupIndex.BackupItem item = new BackupIndex.BackupItem();
item.setCollection(content.getCollection()); item.setCollection(content.getCollection());
item.setPath(parent + "/" + content.getCollection() + ".json"); item.setPath(parent + "/" + content.getCollection() + ".json");
@ -112,6 +117,7 @@ public class BackupScheduler {
backup.setLog("成功备份"); backup.setLog("成功备份");
backup.setPeriod(new Date().getTime() - backup.getCreateTime().getTime()); backup.setPeriod(new Date().getTime() - backup.getCreateTime().getTime());
backup.setStatus(Backup.Status.SUCCESS); backup.setStatus(Backup.Status.SUCCESS);
backup.setSize(DataSize.ofBytes(sizeCounter.get()).toKilobytes() + "KB");
return operations.save(backup); return operations.save(backup);
})) }))
.subscribe(v -> { .subscribe(v -> {
@ -131,11 +137,17 @@ public class BackupScheduler {
* @param filepath 路径 * @param filepath 路径
*/ */
@SneakyThrows @SneakyThrows
private void createIfNotExists(String filepath) { private String createIfNotExists(String filepath) {
Path path = Paths.get(filepath); Path path = Paths.get(filepath);
if (!Files.exists(path)) { if (!Files.exists(path)) {
Files.createDirectories(path); try {
Files.createDirectories(path);
} catch (IOException e) {
log.error(e.getMessage());
return createIfNotExists(System.getProperty("user.home") + filepath);
}
} }
return filepath;
} }
/** /**
@ -157,7 +169,7 @@ public class BackupScheduler {
* @return 结果 * @return 结果
*/ */
private Mono<Void> write(byte[] content, String path) { private Mono<Void> write(byte[] content, String path) {
return Mono.fromCallable(() -> AsynchronousFileChannel.open(Paths.get(path), StandardOpenOption.WRITE)) return Mono.fromCallable(() -> AsynchronousFileChannel.open(Files.createFile(Paths.get(path)), StandardOpenOption.WRITE))
.flatMapMany(channel -> DataBufferUtils.write(Mono.just(factory.wrap(content)), channel, 0)) .flatMapMany(channel -> DataBufferUtils.write(Mono.just(factory.wrap(content)), channel, 0))
.then(); .then();
} }

View File

@ -0,0 +1,24 @@
package com.flyfish.framework.backup.service;
import com.flyfish.framework.backup.domain.Backup;
import com.flyfish.framework.service.impl.BaseReactiveServiceImpl;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
/**
* 备份服务
*
* @author wangyu
*/
@Service
public class BackupService extends BaseReactiveServiceImpl<Backup> {
/**
* 恢复指定备份
*
* @return 结果
*/
public Mono<Void> restore(String id) {
return Mono.empty();
}
}

View File

@ -46,6 +46,7 @@
<module>flyfish-dict</module> <module>flyfish-dict</module>
<module>flyfish-form</module> <module>flyfish-form</module>
<module>flyfish-approval</module> <module>flyfish-approval</module>
<module>flyfish-backup</module>
</modules> </modules>
<repositories> <repositories>