设为首页 收藏本站
查看: 1224|回复: 0

[经验分享] APDPlat中备份文件异地容灾机制之FTP上传

[复制链接]

尚未签到

发表于 2016-6-9 13:36:28 | 显示全部楼层 |阅读模式
  APDPlat在数据库备份成功之后,会调用一个系统扩展点,用户可以方便地编写自己的包含特定业务逻辑的插件,并可配置启用哪些插件。本文以将备份文件上传到FTP服务器以实现异地容灾为例子,来说明如何编写自己的插件并配置使其生效。
  
  1、如何编写?
  
  我们先看看系统扩展点,即BackupFileSender接口:
  

/**
* 备份文件发送器
* 将最新的备份文件发送到其他机器,防止服务器故障丢失数据
* @author 杨尚川
*/
public interface BackupFileSender {
public void send(File file);
}
  
  
  然后新建一个类FtpBackupFileSender,实现系统扩展点:
  

/**
* 将备份文件发送到FTP服务器上面
* @author 杨尚川
*/
@Service
public class FtpBackupFileSender implements BackupFileSender{
protected final APDPlatLogger LOG = new APDPlatLogger(getClass());
@Resource(name="ftpUtils")
private FtpUtils ftpUtils;
@Resource(name="configurationEncryptor")
private StandardPBEStringEncryptor configurationEncryptor;
@Override
public void send(File file) {
try{
String host = PropertyHolder.getProperty("ftp.server.host");
int port = PropertyHolder.getIntProperty("ftp.server.port");
String username = PropertyHolder.getProperty("ftp.server.username");
String password = PropertyHolder.getProperty("ftp.server.password");
if(username!=null && username.contains("ENC(") && username.contains(")")){
username=username.substring(4,username.length()-1);
}
if(password!=null && password.contains("ENC(") && password.contains(")")){
password=password.substring(4,password.length()-1);
}        
username = configurationEncryptor.decrypt(username);
password = configurationEncryptor.decrypt(password);
String dist = PropertyHolder.getProperty("log.backup.file.ftp.dir");
String database = PropertyHolder.getProperty("jpa.database");
dist = dist.replace("${database}", database);
LOG.info("本地备份文件:"+file.getAbsolutePath());
LOG.info("FTP服务器目标目录:"+dist);
boolean connect = ftpUtils.connect(host, port, username, password);
if(connect){
boolean result = ftpUtils.uploadTo(file, dist);
if(result){
LOG.info("备份文件上传到FTP服务器成功");
}else{
LOG.error("备份文件上传到FTP服务器失败");
}
}
}catch(Exception e){
LOG.error("备份文件上传到FTP服务器失败",e);
}
}
}
  
  
  这里有三个要点一是跟FTP服务器相关的信息(主机、端口、用户名、密码)从配置文件config.properties或config.local.properties中获取;使用FtpUtils的uploadTo方法实现实际的文件上传功能;三是使用StandardPBEStringEncryptor对加密的用户名和密码进行解密(配置文件中不存放明文用户名和密码)。
  
  先看看FTP服务器的配置信息,默认存放在config.properties中,用户可以在config.local.properties中进行重新指定以覆盖默认配置:
  

ftp.server.host=192.168.0.100
ftp.server.port=21
ftp.server.username=ENC(rAjYIMF6ANd2q/cTgX6SpQ==)
ftp.server.password=ENC(GHVWGhan3XajaRZF8QzZKQ==)
  
  
  接下来看看FtpUtils的实现:
  

/**
* FTP操作工具
* @author 杨尚川
*/
@Service
public class FtpUtils {
protected final APDPlatLogger LOG = new APDPlatLogger(getClass());
private FTPClient ftpClient;
/**
* 连接FTP服务器
* @param host FTP服务器地址
* @param port FTP服务器端口号
* @param username 用户名
* @param password 密码
* @return
*/
public boolean connect(String host, int port, String username, String password) {
try{
ftpClient = new FTPClient();
ftpClient.connect(host, port);
ftpClient.login(username, password);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
int reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
LOG.error("连接FTP服务器失败,响应码:"+reply);
return false;
}
}catch(IOException e){
LOG.error("连接FTP服务器失败",e);
return false;
}
return true;
}
/**
* 上传文件到服务器上的特定路径
* @param file 上传的文件或文件夹
* @param path 上传到ftp服务器哪个路径下
* @return
*/
public boolean uploadTo(File file, String path){
//切换到服务器上面的合适目录
//如果对应的目录不存在,则创建
LOG.info("上传文件 "+file.getAbsolutePath()+" 到服务器路径 "+path);
try{
String[] segs = path.split("/");
for(String seg : segs){
if(!ftpClient.changeWorkingDirectory(seg)){
ftpClient.makeDirectory(seg);
if(!ftpClient.changeWorkingDirectory(seg)){
LOG.error("服务器目录切换错误:"+seg);
return false;
}
}
}
}catch(IOException e){
LOG.error("服务器目录切换错误",e);
return false;
}
return upload(file);
}
/**
* 上传文件
* @param file 上传的文件或文件夹
* @return 是否上次成功
*/
private boolean upload(File file) {
try{
if (file.isDirectory()) {
ftpClient.makeDirectory(file.getName());
ftpClient.changeWorkingDirectory(file.getName());
File[] subFiles = file.listFiles();
for (File subFile : subFiles) {
if (subFile.isDirectory()) {
upload(subFile);
ftpClient.changeToParentDirectory();
} else {
try (FileInputStream input = new FileInputStream(subFile)) {
ftpClient.storeFile(subFile.getName(), input);
}
}
}
} else {
try (FileInputStream input = new FileInputStream(file)) {
ftpClient.storeFile(file.getName(), input);
}
}
}catch(IOException e){
LOG.error("上传文件失败",e);
return false;
}
return true;
}
}
  
  
  最后看看解密,StandardPBEStringEncryptor是定义在Spring的配置文件中的,默认加密和解密的密码是config:
  

<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration" />
</bean>
<bean id="environmentVariablesConfiguration" class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig">
<property name="algorithm" value="PBEWithMD5AndDES" />
<property name="password" value="config" />
</bean>
  
  
  那么如何对明文的用户名和密码进行加密,然后放入到配置文件中呢?
  
  可以使用APDPlat_Web子项目中的util.ConfigEncryptUtils类来实现:
  

/**
*把密文放到配置文件中的时候要注意:
* ENC(密文)
* @author 杨尚川
*/
public class ConfigEncryptUtils {
private static final StandardPBEStringEncryptor ENCRYPTOR = new StandardPBEStringEncryptor();
static{
EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();
config.setAlgorithm("PBEWithMD5AndDES");
//自己在用的时候更改此密码
config.setPassword("config");        
ENCRYPTOR.setConfig(config);
}
public static void main(String[] args){
String plaintext="test";
String ciphertext=ENCRYPTOR.encrypt(plaintext);
System.out.println(plaintext+" : "+ciphertext);
}
}
  
  
  在main方法中指定plaintext的值为待加密的字符串,然后运行ConfigEncryptUtils类,控制台输出如下:
  

test : pXnEaEXPoseN4lSNTuz3eQ==
  
  把密文放到配置文件中的时候要注意,在密文前加入ENC(,在密文后加入),形如ENC(密文),如下所示:
  

ftp.server.username=ENC(rAjYIMF6ANd2q/cTgX6SpQ==)
ftp.server.password=ENC(pXnEaEXPoseN4lSNTuz3eQ==)
  
  
  2、如何配置?
  
  插件编写完成之后,如何配置使其生效?
  
  config.local.properties中指定log.backup.file.sender的值为所编写的插件的Spring bean name,可指定多个,用;分割,如下所示:
  

log.backup.file.sender=ftpBackupFileSender;
  
  
  
  APDPlat托管在Github
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-228313-1-1.html 上篇帖子: Ftp链接传输数据假死&Windows本地测试正常问题 下篇帖子: java跨服务器保存文件:jcifs & FTP
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表