SpringBoot+SpringCloud+vue+Element開發項目——數據備份還原


一、新建工程

    新建jansens-backup工程,這是一個獨立運行於admin的服務模塊,可以分開獨立部署

二、添加依賴

    在pom.xml文件中添加web、swagger、common依賴包。

 <dependencies>
        <!-- spring boot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>com.read</groupId>
            <artifactId>jansens-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

三、添加配置

application.yml

# tomcat
server:
  port: 8002
spring:
  application:
    name: jansens-backup
# backup datasource
jansens:
  backup:
    datasource:
      host: localhost
      userName: root
      password: 123456
      database: jansens

四、自定義Banner文件

在resources目錄下添加一個自定義banner.txt文件

////////////////////////////////////////////////////////////////////  
//                          _ooOoo_                               //  
//                         o8888888o                              //  
//                         88" . "88                              //  
//                         (| ^_^ |)                              //  
//                         O\  =  /O                              //  
//                      ____/`---'\____                           //  
//                    .'  \\|     |//  `.                         //  
//                   /  \\|||  :  |||//  \                        //  
//                  /  _||||| -:- |||||-  \                       //  
//                  |   | \\\  -  /// |   |                       //  
//                  | \_|  ''\---/''  |   |                       //  
//                  \  .-\__  `-`  ___/-. /                       //  
//                ___`. .'  /--.--\  `. . ___                     //  
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //  
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //  
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //  
//      ========`-.____`-.___\_____/___.-`____.-'========         //  
//                           `=---='                              //  
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //  
//            佛祖保佑       上海研發     永無BUG                     //
////////////////////////////////////////////////////////////////////

五、修改啟動類

修改啟動類為JansensBackupApplication,指定掃描路徑為com.louis.jansens

JansensBackupApplication.java

@SpringBootApplication(scanBasePackages={"com.louis.jansens"})
@EnableSwagger2
public class JansensBackupApplication {
    public static void main(String[] args) {
        SpringApplication.run(JansensBackupApplication.class, args);
    }
}

 六、跨域配置

在config包添加跨域配置類

CorsConfig.java

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")    // 允許跨域訪問的路徑
                .allowedOrigins("*")    // 允許跨域訪問的源
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")    // 允許請求方法
                .maxAge(168000)    // 預檢間隔時間
                .allowedHeaders("*")  // 允許頭部設置
                .allowCredentials(true);    // 是否發送cookie
    }
}

七、Swagger配置

在config包添加swagger配置類

SwaggerConfig.java

/**
 * Swagger配置
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {
    
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).select()
                .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build();
    }
    
}

 八、數據源屬性

BackupDataSourceProperties.java

/**
 * 數據源
 */
@Component  
@ConfigurationProperties(prefix = "jansens.backup.datasource")
public class BackupDataSourceProperties {
    
    private String host;
    private String userName;
    private String password;
    private String database;
    public String getHost() {
        return host;
    }
    public void setHost(String host) {
        this.host = host;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getDatabase() {
        return database;
    }
    public void setDatabase(String database) {
        this.database = database;
    }
    
}  

九、備份還原接口

在service包下添加MysqlBackupService接口

MysqlBackupService.java

/**
 * MySql命令行備份恢復服務
 */
public interface MysqlBackupService {

    /**
     * 備份數據庫
     * @param host host地址,可以是本機也可以是遠程
     * @param userName 數據庫的用戶名
     * @param password 數據庫的密碼
     * @param savePath 備份的路徑
     * @param fileName 備份的文件名
     * @param databaseName 需要備份的數據庫的名稱
     * @return
     * @throws IOException 
     */
    boolean backup(String host, String userName, String password, String backupFolderPath, String fileName, String database) throws Exception;

    /**
     * 恢復數據庫
     * @param restoreFilePath 數據庫備份的腳本路徑
     * @param host IP地址
     * @param database 數據庫名稱
     * @param userName 用戶名
     * @param password 密碼
     * @return
     */
    boolean restore(String restoreFilePath, String host, String userName, String password, String database) throws Exception;

}

十、備份還原實現

在service.impl包下添加MysqlBackupServiceImpl實現類

MysqlBackupServiceImpl.java

@Service
public class MysqlBackupServiceImpl implements MysqlBackupService {

    @Override
    public boolean backup(String host, String userName, String password, String backupFolderPath, String fileName,
            String database) throws Exception {
        return MySqlBackupRestoreUtils.backup(host, userName, password, backupFolderPath, fileName, database);
    }

    @Override
    public boolean restore(String restoreFilePath, String host, String userName, String password, String database)
            throws Exception {
        return MySqlBackupRestoreUtils.restore(restoreFilePath, host, userName, password, database);
    }

}

十一、備份還原邏輯

在util包下創建一個備份還原工具類

MySqlBackupRestoreUtils.java

/**
 * MySQL備份還原工具類
 */
public class MySqlBackupRestoreUtils {

    /**
     * 備份數據庫
     * @param host host地址,可以是本機也可以是遠程
     * @param userName 數據庫的用戶名
     * @param password 數據庫的密碼
     * @param savePath 備份的路徑
     * @param fileName 備份的文件名
     * @param databaseName 需要備份的數據庫的名稱
     * @return
     * @throws IOException 
     */
    public static boolean backup(String host, String userName, String password, String backupFolderPath, String fileName,
                                 String database) throws Exception {
        File backupFolderFile = new File(backupFolderPath);
        if (!backupFolderFile.exists()) {
            // 如果目錄不存在則創建
            backupFolderFile.mkdirs();
        }
        if (!backupFolderPath.endsWith(File.separator) && !backupFolderPath.endsWith("/")) {
            backupFolderPath = backupFolderPath + File.separator;
        }
        // 拼接命令行的命令
        String backupFilePath = backupFolderPath + fileName;
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("mysqldump --opt").append(" --add-drop-database").append(" --add-drop-table");
        stringBuilder.append(" -h").append(host).append(" -u").append(userName).append(" -p").append(password);
        stringBuilder.append(" --result-file=").append(backupFilePath).append(".sql").append(" --default-character-set=utf8 ").append(database);
        System.out.println(stringBuilder.toString());
        // 調用外部執行 exe 文件的 Java API
        Process process = Runtime.getRuntime().exec(getCommand(stringBuilder.toString()));
        if (process.waitFor() == 0) {
            // 0 表示線程正常終止
            System.out.println("數據已經備份到 " + backupFilePath + " 文件中");
            return true;
        }
        return false;
    }

    /**
     * 還原數據庫
     * @param restoreFilePath 數據庫備份的腳本路徑
     * @param host IP地址
     * @param database 數據庫名稱
     * @param userName 用戶名
     * @param password 密碼
     * @return
     */
    public static boolean restore(String restoreFilePath, String host, String userName, String password, String database)
            throws Exception {
        File restoreFile = new File(restoreFilePath);
        if (restoreFile.isDirectory()) {
            for (File file : restoreFile.listFiles()) {
                if (file.exists() && file.getPath().endsWith(".sql")) {
                    restoreFilePath = file.getAbsolutePath();
                    break;
                }
            }
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("mysql -h").append(host).append(" -u").append(userName).append(" -p").append(password);
        stringBuilder.append(" ").append(database).append(" < ").append(restoreFilePath);
        try {
            Process process = Runtime.getRuntime().exec(getCommand(stringBuilder.toString()));
            if (process.waitFor() == 0) {
                System.out.println("數據已從 " + restoreFilePath + " 導入到數據庫中");
            }
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private static String[] getCommand(String command) {
        String os = System.getProperty("os.name");  
        String shell = "/bin/bash";
        String c = "-c";
        if(os.toLowerCase().startsWith("win")){  
            shell = "cmd";
            c = "/c";
        }  
        String[] cmd = { shell, c, command };
        return cmd;
    }

    public static void main(String[] args) throws Exception {
        String host = "localhost";
        String userName = "root";
        String password = "123456";
        String database = "jansens";
        
        System.out.println("開始備份");
        String backupFolderPath = "d:/dev/";
        String fileName = "mdh";
        backup(host, userName, password, backupFolderPath, fileName, database);
        System.out.println("備份成功");
        
        /*System.out.println("開始還原");
        String restoreFilePath = "d:/dev/mdh.sql";
        restore(restoreFilePath, host, userName, password, database);
        System.out.println("還原成功");*/

    }

}

在util包HTTP結果封裝類

HttpResult.java

/**
 * HTTP結果封裝
 */
public class HttpResult {

    private int code = 200;
    private String msg;
    private Object data;
    
    public static HttpResult error() {
        return error(500, "未知異常,請聯系管理員");
    }
    
    public static HttpResult error(String msg) {
        return error(500, msg);
    }
    
    public static HttpResult error(int code, String msg) {
        HttpResult r = new HttpResult();
        r.setCode(code);
        r.setMsg(msg);
        return r;
    }

    public static HttpResult ok(String msg) {
        HttpResult r = new HttpResult();
        r.setMsg(msg);
        return r;
    }
    
    public static HttpResult ok(Object data) {
        HttpResult r = new HttpResult();
        r.setData(data);
        return r;
    }
    
    public static HttpResult ok() {
        return new HttpResult();
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
    
}

在constants包新建一個BackupConstants常量類

/**
 * 常量類
 */
public interface BackupConstants {
    
    /** 備份目錄名稱 */
    public static final String BACKUP_FOLDER_NAME = "_jansens_backup";
    /** 備份目錄 */
    public static final String BACKUP_FOLDER = System.getProperty("user.home") + File.separator + BACKUP_FOLDER_NAME + File.separator;
    /** 還原目錄,默認就是備份目錄 */
    public static final String RESTORE_FOLDER = BACKUP_FOLDER;
    /** 日期格式 */
    public static final String DATE_FORMAT = "yyyy-MM-dd_HHmmss";
    /** SQL拓展名 */
    public static final String SQL_EXT = ".sql";
    /** 默認備份文件名 */
    public static final String BACKUP_FILE_NAME = "jansens" + SQL_EXT;
    /** 默認備份還原目錄名稱 */
    public static final String DEFAULT_BACKUP_NAME = "backup";
    /** 默認備份還原文件 */
    public static final String DEFAULT_RESTORE_FILE = BACKUP_FOLDER + DEFAULT_BACKUP_NAME + File.separator + BACKUP_FILE_NAME;
    
}

 

十二、備份還原控制器

在controller包新建MySqlBackupController控制器

MySqlBackupController.java

/**
 * 系統數據備份還原
 */
@RestController
@RequestMapping("/backup")
public class MySqlBackupController {

    @Autowired
    MysqlBackupService mysqlBackupService;
    @Autowired
    BackupDataSourceProperties properties;

    @GetMapping("/backup")
    public HttpResult backup() {
        String backupFodlerName = BackupConstants.DEFAULT_BACKUP_NAME + "_" + (new SimpleDateFormat(BackupConstants.DATE_FORMAT)).format(new Date());
        return backup(backupFodlerName);
    }

    private HttpResult backup(String backupFodlerName) {
        String host = properties.getHost();
        String userName = properties.getUserName();
        String password = properties.getPassword();
        String database = properties.getDatabase();
        String backupFolderPath = BackupConstants.BACKUP_FOLDER + backupFodlerName + File.separator;
        String fileName = BackupConstants.BACKUP_FILE_NAME;
        try {
            boolean success = mysqlBackupService.backup(host, userName, password, backupFolderPath, fileName, database);
            if(!success) {
                HttpResult.error("數據備份失敗");
            }
        } catch (Exception e) {
            return HttpResult.error(500, e.getMessage());
        }
        return HttpResult.ok();
    }
    
    @GetMapping("/restore")
    public HttpResult restore(@RequestParam String name) throws IOException {
        String host = properties.getHost();
        String userName = properties.getUserName();
        String password = properties.getPassword();
        String database = properties.getDatabase();
        String restoreFilePath = BackupConstants.RESTORE_FOLDER + name;
        try {
            mysqlBackupService.restore(restoreFilePath, host, userName, password, database);
        } catch (Exception e) {
            return HttpResult.error(500, e.getMessage());
        }
        return HttpResult.ok();
    }
    
    @GetMapping("/findRecords")
    public HttpResult findBackupRecords() {
        if(!new File(BackupConstants.DEFAULT_RESTORE_FILE).exists()) {
            // 初始默認備份文件
            backup(BackupConstants.DEFAULT_BACKUP_NAME);
        }
        List<Map<String, String>> backupRecords = new ArrayList<>();
        File restoreFolderFile = new File(BackupConstants.RESTORE_FOLDER);
        if(restoreFolderFile.exists()) {
            for(File file:restoreFolderFile.listFiles()) {
                Map<String, String> backup = new HashMap<>();
                backup.put("name", file.getName());
                backup.put("title", file.getName());
                if(BackupConstants.DEFAULT_BACKUP_NAME.equalsIgnoreCase(file.getName())) {
                    backup.put("title", "系統默認備份");
                }
                backupRecords.add(backup);
            }
        }
        // 排序,默認備份最前,然后按時間戳排序,新備份在前面
        backupRecords.sort((o1, o2) -> BackupConstants.DEFAULT_BACKUP_NAME.equalsIgnoreCase(o1.get("name")) ? -1
                : BackupConstants.DEFAULT_BACKUP_NAME.equalsIgnoreCase(o2.get("name")) ? 1 : o2.get("name").compareTo(o1.get("name")));
        return HttpResult.ok(backupRecords);
    }
    
    @GetMapping("/delete")
    public HttpResult deleteBackupRecord(@RequestParam String name) {
        if(BackupConstants.DEFAULT_BACKUP_NAME.equals(name)) {
            return HttpResult.error("系統默認備份無法刪除!");
        }
        String restoreFilePath = BackupConstants.BACKUP_FOLDER + name;
        try {
            FileUtils.deleteFile(new File(restoreFilePath));
        } catch (Exception e) {
            return HttpResult.error(500, e.getMessage());
        }
        return HttpResult.ok();
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM