🍎 新增自动备份

每天1点备份所有资源
pull/18/head
ruibaby 2018-06-05 10:57:09 +08:00
parent 3c1f251b88
commit 86d0eee96e
4 changed files with 92 additions and 150 deletions

View File

@ -7,6 +7,7 @@ import cc.ryanc.halo.service.AttachmentService;
import cc.ryanc.halo.service.OptionsService; import cc.ryanc.halo.service.OptionsService;
import cc.ryanc.halo.utils.HaloUtils; import cc.ryanc.halo.utils.HaloUtils;
import cc.ryanc.halo.web.controller.core.BaseController; import cc.ryanc.halo.web.controller.core.BaseController;
import cn.hutool.cron.CronUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -38,6 +39,9 @@ public class StartupConfig implements ApplicationListener<ContextRefreshedEvent>
this.loadOptions(); this.loadOptions();
this.loadFiles(); this.loadFiles();
this.loadThemes(); this.loadThemes();
//启动定时任务
CronUtil.start();
log.info("定时任务启动成功!");
} }
/** /**

View File

@ -8,6 +8,7 @@ import cc.ryanc.halo.model.dto.JsonResult;
import cc.ryanc.halo.service.MailService; import cc.ryanc.halo.service.MailService;
import cc.ryanc.halo.service.PostService; import cc.ryanc.halo.service.PostService;
import cc.ryanc.halo.utils.HaloUtils; import cc.ryanc.halo.utils.HaloUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil; import cn.hutool.core.util.ZipUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -52,13 +54,19 @@ public class BackupController {
* @return admin/admin_backup * @return admin/admin_backup
*/ */
@GetMapping @GetMapping
public String backup(Model model) { public String backup(@RequestParam(value = "type",defaultValue = "resources") String type,Model model) {
List<BackupDto> resourcesBackup = HaloUtils.getBackUps("resources"); List<BackupDto> backups = null;
List<BackupDto> databasesBackup = HaloUtils.getBackUps("databases"); if(StringUtils.equals(type,"resources")){
List<BackupDto> postsBackup = HaloUtils.getBackUps("posts"); backups = HaloUtils.getBackUps("resources");
model.addAttribute("resourcesBackup", resourcesBackup); }else if(StringUtils.equals(type,"databases")){
model.addAttribute("databasesBackup", databasesBackup); backups = HaloUtils.getBackUps("databases");
model.addAttribute("postsBackup", postsBackup); }else if(StringUtils.equals(type,"posts")){
backups = HaloUtils.getBackUps("posts");
}else{
backups = new ArrayList<>();
}
model.addAttribute("backups", backups);
model.addAttribute("type", type);
return "admin/admin_backup"; return "admin/admin_backup";
} }
@ -73,7 +81,7 @@ public class BackupController {
public JsonResult doBackup(@RequestParam("type") String type) { public JsonResult doBackup(@RequestParam("type") String type) {
if (StringUtils.equals("resources", type)) { if (StringUtils.equals("resources", type)) {
return this.backupResources(); return this.backupResources();
} else if (StringUtils.equals("db", type)) { } else if (StringUtils.equals("databases", type)) {
return this.backupDatabase(); return this.backupDatabase();
} else if (StringUtils.equals("posts", type)) { } else if (StringUtils.equals("posts", type)) {
return this.backupPosts(); return this.backupPosts();
@ -89,9 +97,14 @@ public class BackupController {
*/ */
public JsonResult backupDatabase() { public JsonResult backupDatabase() {
try { try {
String srcPath = System.getProperties().getProperty("user.home") + "/halo"; if(HaloUtils.getBackUps("databases").size()>10){
FileUtil.del(System.getProperties().getProperty("user.home") + "/halo/backup/databases/");
}
String srcPath = System.getProperties().getProperty("user.home") + "/halo/";
String distName = "databases_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss"); String distName = "databases_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss");
ZipUtil.zip(srcPath + "/halo.mv.db", System.getProperties().getProperty("user.home") + "/halo/backup/databases/" + distName + ".zip"); //压缩文件
ZipUtil.zip(srcPath + "halo.mv.db", System.getProperties().getProperty("user.home") + "/halo/backup/databases/" + distName + ".zip");
log.info("当前时间:"+DateUtil.now()+",执行了数据库备份。");
return new JsonResult(1, "备份成功!"); return new JsonResult(1, "备份成功!");
} catch (Exception e) { } catch (Exception e) {
log.error("未知错误:", e.getMessage()); log.error("未知错误:", e.getMessage());
@ -106,11 +119,15 @@ public class BackupController {
*/ */
public JsonResult backupResources() { public JsonResult backupResources() {
try { try {
if(HaloUtils.getBackUps("resources").size()>10){
FileUtil.del(System.getProperties().getProperty("user.home") + "/halo/backup/resources/");
}
File path = new File(ResourceUtils.getURL("classpath:").getPath()); File path = new File(ResourceUtils.getURL("classpath:").getPath());
String srcPath = path.getAbsolutePath(); String srcPath = path.getAbsolutePath();
String distName = "resources_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss"); String distName = "resources_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss");
//执行打包 //执行打包
ZipUtil.zip(srcPath, System.getProperties().getProperty("user.home") + "/halo/backup/resources/" + distName + ".zip"); ZipUtil.zip(srcPath, System.getProperties().getProperty("user.home") + "/halo/backup/resources/" + distName + ".zip");
log.info("当前时间:"+DateUtil.now()+",执行了资源文件备份。");
return new JsonResult(1, "备份成功!"); return new JsonResult(1, "备份成功!");
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -127,6 +144,9 @@ public class BackupController {
List<Post> posts = postService.findAllPosts(HaloConst.POST_TYPE_POST); List<Post> posts = postService.findAllPosts(HaloConst.POST_TYPE_POST);
posts.addAll(postService.findAllPosts(HaloConst.POST_TYPE_PAGE)); posts.addAll(postService.findAllPosts(HaloConst.POST_TYPE_PAGE));
try { try {
if(HaloUtils.getBackUps("posts").size()>10){
FileUtil.del(System.getProperties().getProperty("user.home") + "/halo/backup/posts/");
}
//打包好的文件名 //打包好的文件名
String distName = "posts_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss"); String distName = "posts_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss");
String srcPath = System.getProperties().getProperty("user.home") + "/halo/backup/posts/" + distName; String srcPath = System.getProperties().getProperty("user.home") + "/halo/backup/posts/" + distName;
@ -134,8 +154,9 @@ public class BackupController {
HaloUtils.postToFile(post.getPostContentMd(), srcPath, post.getPostTitle() + ".md"); HaloUtils.postToFile(post.getPostContentMd(), srcPath, post.getPostTitle() + ".md");
} }
//打包导出好的文章 //打包导出好的文章
ZipUtil.zip(srcPath, System.getProperties().getProperty("user.home") + "/halo/backup/posts/" + distName + ".zip"); ZipUtil.zip(srcPath, srcPath + ".zip");
FileUtil.del(srcPath); FileUtil.del(srcPath);
log.info("当前时间:"+DateUtil.now()+",执行了文章备份。");
return new JsonResult(1, "备份成功!"); return new JsonResult(1, "备份成功!");
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -0,0 +1,3 @@
cc.ryanc.halo.web.controller.admin.BackupController.backupResources = 0 0 1 * * ?
cc.ryanc.halo.web.controller.admin.BackupController.backupDatabase = 0 0 1 * * ?
cc.ryanc.halo.web.controller.admin.BackupController.backupPosts = 0 0 1 * * ?

View File

@ -6,6 +6,9 @@
<!-- 菜单栏模块 --> <!-- 菜单栏模块 -->
<#include "module/_sidebar.ftl"> <#include "module/_sidebar.ftl">
<div class="content-wrapper"> <div class="content-wrapper">
<style type="text/css" rel="stylesheet">
.resourceType,.databaseType,.postType{list-style:none;float:left;margin:0;padding-bottom:10px}
</style>
<section class="content-header"> <section class="content-header">
<h1 style="display: inline-block;">博客备份</h1> <h1 style="display: inline-block;">博客备份</h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
@ -18,143 +21,57 @@
</section> </section>
<section class="content container-fluid"> <section class="content container-fluid">
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-xs-12">
<div class="nav-tabs-custom"> <ul style="list-style: none;padding-left: 0">
<ul class="nav nav-tabs"> <li class="resourceType">
<li class="active"> <a data-pjax="true" href="/admin/backup?type=resources" <#if type=='resources'>style="color: #000" </#if>>资源文件备份</a>&nbsp;|&nbsp;
<a href="#resources" data-toggle="tab">资源目录备份</a> </li>
</li> <li class="databaseType">
<li> <a data-pjax="true" href="/admin/backup?type=databases" <#if type=='databases'>style="color: #000" </#if>>数据库备份</a>&nbsp;|&nbsp;
<a href="#database" data-toggle="tab">数据库备份</a> </li>
</li> <li class="postType">
<li> <a data-pjax="true" href="/admin/backup?type=posts" <#if type=='posts'>style="color: #000" </#if>>文章备份</a>
<a href="#post" data-toggle="tab">文章备份</a> </li>
</li> </ul>
</ul> </div>
<div class="tab-content"> <div class="col-xs-12">
<div class="tab-pane active" id="resources"> <div class="box box-primary">
<form method="post" class="form-horizontal" id="resourcesBackup"> <div class="box-body table-responsive">
<div class="box-body table-responsive" style="padding: 10px 0;"> <table class="table table-bordered table-hover">
<table class="table table-bordered table-hover"> <thead>
<thead> <tr>
<tr> <th>文件名称</th>
<th>文件名称</th> <th>备份时间</th>
<th>备份时间</th> <th>文件大小</th>
<th>文件大小</th> <th>文件类型</th>
<th>文件类型</th> <th>操作</th>
<th>操作</th> </tr>
</tr> </thead>
</thead> <tbody>
<tbody> <#if backups?size gt 0>
<#if resourcesBackup?size gt 0> <#list backups as backup>
<#list resourcesBackup as resource>
<tr>
<td>${resource.fileName}</td>
<td>${resource.createAt?string("yyyy-MM-dd HH:mm")}</td>
<td>${resource.fileSize}</td>
<td>${resource.fileType}</td>
<td>
<a href="/backup/resources/${resource.fileName}" class="btn btn-xs btn-primary" download="${resource.fileName}">下载</a>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${resource.fileName}','${resource.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${resource.fileName}','${resource.backupType}')">删除</button>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="5" style="text-align: center">暂无备份</td>
</tr>
</#if>
</tbody>
</table>
</div>
<div class="box-footer">
<button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('resources')">备份</button>
</div>
</form>
</div>
<div class="tab-pane" id="database">
<form method="post" class="form-horizontal" id="databaseBackup">
<div class="box-body table-responsive" style="padding: 10px 0;">
<table class="table table-bordered table-hover">
<thead>
<tr> <tr>
<th>文件名称</th> <td>${backup.fileName}</td>
<th>备份时间</th> <td>${backup.createAt?string("yyyy-MM-dd HH:mm")}</td>
<th>文件大小</th> <td>${backup.fileSize}</td>
<th>文件类型</th> <td>${backup.fileType}</td>
<th>操作</th> <td>
<a href="/backup/${type}/${backup.fileName}" class="btn btn-xs btn-primary" download="${backup.fileName}">下载</a>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${backup.fileName}','${backup.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${backup.fileName}','${backup.backupType}')">删除</button>
</td>
</tr> </tr>
</thead> </#list>
<tbody> <#else>
<#if databasesBackup?size gt 0> <tr>
<#list databasesBackup as database> <th colspan="5" style="text-align: center">暂无备份</th>
<tr> </tr>
<td>${database.fileName}</td> </#if>
<td>${database.createAt?string("yyyy-MM-dd HH:mm")}</td> </tbody>
<td>${database.fileSize}</td> </table>
<td>${database.fileType}</td> </div>
<td> <div class="box-footer clearfix">
<a href="/backup/databases/${database.fileName}" class="btn btn-xs btn-primary" download="${database.fileName}">下载</a> <button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('${type}')">备份</button>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${database.fileName}','${database.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${database.fileName}','${database.backupType}')">删除</button>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="5" style="text-align: center">暂无备份</td>
</tr>
</#if>
</tbody>
</table>
</div>
<div class="box-footer">
<button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('db')">备份</button>
</div>
</form>
</div>
<div class="tab-pane" id="post">
<form method="post" class="form-horizontal" id="postBackup">
<div class="box-body table-responsive" style="padding: 10px 0;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>文件名称</th>
<th>备份时间</th>
<th>文件大小</th>
<th>文件类型</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#if postsBackup?size gt 0>
<#list postsBackup as post>
<tr>
<td>${post.fileName}</td>
<td>${post.createAt?string("yyyy-MM-dd HH:mm")}</td>
<td>${post.fileSize}</td>
<td>${post.fileType}</td>
<td>
<a href="/backup/posts/${post.fileName}" class="btn btn-xs btn-primary" download="${post.fileName}">下载</a>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${post.fileName}','${post.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${post.fileName}','${post.backupType}')">删除</button>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="5" style="text-align: center">暂无备份</td>
</tr>
</#if>
</tbody>
</table>
</div>
<div class="box-footer">
<button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('posts')">备份</button>
</div>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -238,10 +155,7 @@
position: 'top-center', position: 'top-center',
textAlign: 'left', textAlign: 'left',
loader: true, loader: true,
loaderBg: '#ffffff', loaderBg: '#ffffff'
afterHidden: function () {
window.location.reload();
}
}); });
}else{ }else{
$.toast({ $.toast({