• 数据备份还原


    <?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">
        <modelVersion>4.0.0</modelVersion>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <groupId>com.louis</groupId>
        <artifactId>mango-backup</artifactId>
        <version>1.0.0</version>
        <packaging>jar</packaging>
        
        <name>mango-backup</name>
        <description>mango-backup</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <!-- spring boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.hibernate.validator</groupId>
                        <artifactId>hibernate-validator</artifactId>
                    </exclusion>
                </exclusions>
            </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.louis</groupId>
                <artifactId>mango-common</artifactId>
                <version>1.0.0</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
        
        <build>
            <resources>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>
    # tomcat
    server:
      port: 8002
    spring:
      application:
        name: mango-backup
    # backup datasource
    mango:
      backup:
        datasource:
          host: localhost
          userName: root
          password: admin
          database: mango
    package com.louis.mango.backup.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.CorsRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * 跨域配置
     * @author Louis
     * @date Jan 15, 2019
     */
    @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
        }
    }
    package com.louis.mango.backup.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    /**
     * Swagger配置
     * @author Louis
     * @date Jan 15, 2019
     */
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig {
        
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2).select()
                    .apis(RequestHandlerSelectors.any()).paths(PathSelectors.any()).build();
        }
        
    }
    package com.louis.mango.backup.constants;
    
    import java.io.File;
    
    /**
     * 常量类
     * @author Louis
     * @date Jan 15, 2019
     */
    public interface BackupConstants {
        
        /** 备份目录名称 */
        public static final String BACKUP_FOLDER_NAME = "_mango_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 = "mango" + 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;
        
    }
    package com.louis.mango.backup.datasource;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    /**
     * 数据源
     * @author Louis
     * @date Jan 15, 2019
     */
    @Component  
    @ConfigurationProperties(prefix = "mango.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;
        }
        
    }  
    package com.louis.mango.backup.service;
    
    import java.io.IOException;
    
    /**
     * MySql命令行备份恢复服务
     * @author Louis
     * @date Jan 15, 2019
     */
    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;
    
    }
    package com.louis.mango.backup.service.impl;
    
    import org.springframework.stereotype.Service;
    
    import com.louis.mango.backup.service.MysqlBackupService;
    import com.louis.mango.backup.util.MySqlBackupRestoreUtils;
    
    @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);
        }
    
    }
    package com.louis.mango.backup.util;
    
    /**
     * HTTP结果封装
     * @author Louis
     * @date Jan 15, 2019
     */
    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;
        }
        
    }
    package com.louis.mango.backup.util;
    
    import java.io.File;
    import java.io.IOException;
    
    /**
     * MySQL备份还原工具类
     * @author Louis
     * @date Jan 15, 2019
     */
    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(" --default-character-set=utf8 ").append(database);
            // 调用外部执行 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 = "admin";
            String database = "mango";
            
            System.out.println("开始备份");
            String backupFolderPath = "c:/dev/";
            String fileName = "mango.sql";
            backup(host, userName, password, backupFolderPath, fileName, database);
            System.out.println("备份成功");
            
            System.out.println("开始还原");
            String restoreFilePath = "c:/dev/mango.sql";
            restore(restoreFilePath, host, userName, password, database);
            System.out.println("还原成功");
    
        }
    
    }
    package com.louis.mango.backup.controller;
    
    import java.io.File;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import com.louis.mango.backup.constants.BackupConstants;
    import com.louis.mango.backup.datasource.BackupDataSourceProperties;
    import com.louis.mango.backup.service.MysqlBackupService;
    import com.louis.mango.backup.util.HttpResult;
    import com.louis.mango.common.utils.FileUtils;
    
    /**
     * 系统数据备份还原
     * @author Louis
     * @date Jan 15, 2019
     */
    @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();
        }
    
    }
    package com.louis.mango.common.utils;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileReader;
    import java.io.InputStream;
    
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 文件相关操作
     * 
     * @author Louis
     * @date Jan 14, 2019
     */
    public class FileUtils {
    
        /**
         * 下载文件
         * 
         * @param response
         * @param file
         * @param newFileName
         */
        public static void downloadFile(HttpServletResponse response, File file, String newFileName) {
            try {
                response.setHeader("Content-Disposition",
                        "attachment; filename=" + new String(newFileName.getBytes("ISO-8859-1"), "UTF-8"));
                BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
                InputStream is = new FileInputStream(file.getAbsolutePath());
                BufferedInputStream bis = new BufferedInputStream(is);
                int length = 0;
                byte[] temp = new byte[1 * 1024 * 10];
                while ((length = bis.read(temp)) != -1) {
                    bos.write(temp, 0, length);
                }
                bos.flush();
                bis.close();
                bos.close();
                is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 递归删除文件
         * 
         * @param file
         */
        public static void deleteFile(File file) {
            // 判断是否是一个目录, 不是的话跳过, 直接删除; 如果是一个目录, 先将其内容清空.
            if (file.isDirectory()) {
                // 获取子文件/目录
                File[] subFiles = file.listFiles();
                // 遍历该目录
                for (File subFile : subFiles) {
                    // 递归调用删除该文件: 如果这是一个空目录或文件, 一次递归就可删除.
                    // 如果这是一个非空目录, 多次递归清空其内容后再删除
                    deleteFile(subFile);
                }
            }
            // 删除空目录或文件
            file.delete();
        }
    
        /**
         * 获取项目根路径
         * 
         * @return
         */
        public static String getProjectPath() {
            String classPath = getClassPath();
            return new File(classPath).getParentFile().getParentFile().getAbsolutePath();
        }
    
        /**
         * 获取类路径
         * 
         * @return
         */
        public static String getClassPath() {
            String classPath = FileUtils.class.getClassLoader().getResource("").getPath();
            return classPath;
        }
    
        /**
         * 读取txt文件的内容
         * 
         * @param file 想要读取的文件路径
         * @return 返回文件内容
         */
        public static String readFile(String file) {
            return readFile(new File(file));
        }
    
        /**
         * 读取txt文件的内容
         * 
         * @param file 想要读取的文件对象
         * @return 返回文件内容
         */
        public static String readFile(File file) {
            StringBuilder result = new StringBuilder();
            try {
                BufferedReader br = new BufferedReader(new FileReader(file));// 构造一个BufferedReader类来读取文件
                String s = null;
                while ((s = br.readLine()) != null) {
                    // 使用readLine方法,一次读一行
                    result.append(System.lineSeparator() + s);
                }
                br.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result.toString();
        }
    }
    package com.louis.mango.backup;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    /**
     * 启动器
     * @author Louis
     * @date Jan 15, 2019
     */
    @SpringBootApplication(scanBasePackages={"com.louis.mango"})
    public class MangoBackupApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MangoBackupApplication.class, args);
        }
    }

     

     

     

     

     

     

     

     

  • 相关阅读:
    android中fragment的获取与隐藏
    Android Toolbar教程,Android标题栏经典设计教程
    Android6.0以后,在BroadcastReceiver中启动AlertDialog导致程序停止运行的问题及解决办法
    java数据结构和算法--------第六章
    动态规划--------0和1背包问题
    动态规划------平均切分数组之和为两部分
    java数据结构和算法-----第四章
    java数据结构和算法-------第三章
    java数据结构和算法----第二章
    动态规划----Ones and Zeroes
  • 原文地址:https://www.cnblogs.com/tszr/p/15866182.html
Copyright © 2020-2023  润新知