前段时间,因为各种原因,自己动手写了一个小的备份工具,用了一个星期,想想把它的设计思路放上来,当是笔记吧。

需求场景:这个工具起初的目的是为了解决朋友公司对其网络的限制(不可以用任何同步软件,git,外网SVN,U盘只读)。本来只是想做一个自动打包和发送邮件的工具,后来就发展成了这个。

软件功能:这个软件最终实现的功能包括1、读取配置文件,对配置文件中指定目录的文件进行日期检测,获取对应修改过的文件。2、将读出的文件进行压缩;3、将压缩文件发送到指定邮箱;4、对压缩文件进行历史版本的保留

根据最后的功能需求,工具最后选择采用的API包如下:

1、  使用commons-config实现配置文件的读写

2、  使用commons-io实现文件的检测和读写

3、  使用zip4j实现对文件的压缩

4、  使用javamail实现邮件的发送

系统最后的流程图如下:

主要的工具类如下:

 //用于发送邮件的Bean
package com.sean.bean; import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Properties; import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
/**
* 邮件类
* @author Sean
* @blog http://www.cnblogs.com/Seanit/
* @email hxy9104@126.com
* 2015-6-9
*/
public class EmailBean {
private Session session;
private MimeMessage message;
private Properties properties;
private MimeMultipart body; /**
* 默认构造函数
*/
public EmailBean(){
} public EmailBean(Properties properties){
this.properties=properties;
createMail(properties);
} public EmailBean(String src){
this.properties=new Properties();
try {
properties.load(new InputStreamReader(ClassLoader.getSystemResourceAsStream(src),"utf-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
createMail(properties);
} /**
* 创建连接
* @author Sean
* 2015-6-8
* @param properties 邮箱相关配置
*/
public void createMail(Properties properties) {
this.properties=properties;
try {
session=Session.getDefaultInstance(properties,null);
message=new MimeMessage(session);
body=new MimeMultipart();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("邮件初始化失败");
}
} /**
* 设置发件人
* @author Sean
* 2015-6-8
* @param from 发件人地址
* @return 成功返回true,失败防护false
*/
public boolean setFrom(String from){
try {
message.setFrom(new InternetAddress(from));
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 设置收件人
* @author Sean
* 2015-6-8
* @param toSend 收件人邮箱地址
* @return 成功返回true,失败防护false
*/
public boolean setTOSend(String toSend){
try {
message.setRecipients(RecipientType.TO, toSend);
return true;
} catch (MessagingException e) {
e.printStackTrace();
return false;
}
} /**
* 设置抄送人
* @author Sean
* 2015-6-8
* @param copyTo 抄送人地址
* @return 成功返回true,失败防护false
*/
public boolean setCopyTO(String copyTo){
try {
message.setRecipients(RecipientType.CC, (Address[])InternetAddress.parse(copyTo));
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 设置主题
* @author Sean
* 2015-6-8
* @param subject 邮件主题
* @return 成功返回true,失败防护false
*/
public boolean setSubject(String subject){
try {
message.setSubject(subject);
return true;
} catch (MessagingException e) {
e.printStackTrace();
return false;
}
} /**
* 设置邮件正文
* @author Sean
* 2015-6-8
* @param content 邮件正文
* @return 成功返回true,失败防护false
*/
public boolean setContent(String content){
try {
BodyPart bodyPart=new MimeBodyPart();
bodyPart.setContent(""+content, "text/html;charset=GBK");
body.addBodyPart(bodyPart);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 添加附件
* @author Sean
* 2015-6-8
* @param src 附件地址
* @return
*/
public boolean addFiles(String src){
try {
BodyPart bodyPart=new MimeBodyPart();
FileDataSource file =new FileDataSource(src);
bodyPart.setDataHandler(new DataHandler(file));
bodyPart.setFileName(file.getName());
body.addBodyPart(bodyPart);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 发送邮件
* @author Sean
* 2015-6-8
* @return
*/
public boolean send(){
Transport transport=null;
try {
message.setContent(body);
message.saveChanges();
transport=session.getTransport();
transport.connect(properties.getProperty("mail.smtp.host"), properties.getProperty("username"), properties.getProperty("password"));
transport.sendMessage(message, message.getRecipients(Message.RecipientType.TO));
if(message.getRecipients(Message.RecipientType.CC)!=null){
transport.sendMessage(message, message.getRecipients(Message.RecipientType.CC));
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}finally{
try {
transport.close();
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
 //用于操作配置文件的bean
package com.sean.bean; import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
/**
* 配置文件操作类
* 实现功能:对properties 文件进行读写操作
* @author Sean
* 2015-6-6
*/
public class PropertiesBean {
private String src="";
private PropertiesConfiguration pc=null;
/**
* 默认构造函数
*/
public PropertiesBean() {}
public PropertiesBean(String src) {
this.src=src;
init();
} /**
* 初始化函数
* @author Sean
* 2015-6-6
*/
public void init(){
if(src.trim().equals("")){
throw new RuntimeException("The path is null");
}
try {
pc=new PropertiesConfiguration(src);
} catch (ConfigurationException e) {
e.printStackTrace();
}
} /**
* 取值函数,根据对应的关键字获取对应的值
* @author Sean
* 2015-6-6
* @param key 关键字
* @return 返回关键字对应的值,若无该关键字,抛出异常
*/
public String getValue(String key){
if(!pc.containsKey(key)){
throw new RuntimeException("not such a key");
}
return pc.getString(key);
} /**
* 设置对应的值,传入键值对,根据关键字修改对应的值
* @author Sean
* 2015-6-6
* @param key 关键字
* @param value 值
*/
public void setValue(String key,String value){
if(!pc.containsKey(key)){
throw new RuntimeException("not such a key");
}
pc.setProperty(key, value);
try {
pc.save();
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} /**
* 设置配置文件的地址
* @author Sean
* 2015-6-6
* @param src 配置文件的路径
*/
public void setSrc(String src) {
this.src = src;
}
}
//用于进行IO操作的Bean

package com.sean.bean;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import org.apache.commons.io.FileUtils;
/**
* 文件操作工具类
* @author Sean
* @blog http://www.cnblogs.com/Seanit/
* @email hxy9104@126.com
* 2015-6-6
*/
public class FilesBean {
private List<File> list=null;
public FilesBean(){} /**
* 获取文件夹目录下的列表,目录为空返回空列表
* @param dir 传入对应文件夹目录
* @param ifFirst 控制递归时候的循环表示
* @return 返回list<File>文件列表
*/
public List<File> listFiles(String dir,boolean ifFirst){
/**
* 递归判断,仅在第一次调用函数的时候新建列表,为防止重复存入列表
*/
if(ifFirst){
list=new ArrayList<File>();
} if (dir==null||dir=="") {
return null;
}
for (File f : FileUtils.getFile(dir + "\\").listFiles()) { if (f.isDirectory()) {
listFiles(f.getAbsolutePath(),false);
} else {
list.add(f);
}
}
return list;
} /**
* 根据过滤条件获取列表
* @param dir 目录
* @param filter 过滤条件
* @param ifFirst 递归标识
* @return 返回文件列表
*/
public List<File> listFiles(String dir,String filter,boolean ifFirst){
/**
* 递归判断,仅在第一次调用函数的时候新建列表,为防止重复存入列表
*/
if(ifFirst){
list=new ArrayList<File>();
} if (dir==null||dir=="") {
return null;
}
for (File f : FileUtils.getFile(dir + "\\").listFiles()) { if (f.isDirectory()) {
listFiles(f.getAbsolutePath(),filter,false);
} else {
if(!f.getName().endsWith(filter)){
list.add(f);
} }
}
return list;
} /**
* 获取指定目录下,指定日期修改后的文件
* @param dir 传入指定检测目录
* @param date 传入指定修改日期
* @param ifFirst 控制递归时候的循环表示
* @return 返回获取的文件列表,若目录或日期为空,则返回null
*/
public List<File> getModifiedFiles(String dir,Date date,boolean ifFirst){
/**
* 递归判断,仅在第一次调用函数的时候新建列表,为防止重复存入列表
*/
if(ifFirst){
list=new ArrayList<File>();
} if (dir==null||dir==""||date==null) {
return null;
} for (File f : FileUtils.getFile(dir + "\\").listFiles()) {
if (f.isDirectory()) {
getModifiedFiles(f.getAbsolutePath(),date,false);
} else {
if (FileUtils.isFileNewer(f, date.getTime())) {
list.add(f);
}
}
}
return list;
} /**
* 获取某一日期之前创建的文件
* @author Sean
* 2015-6-9
* @param dir 文件路径
* @param ifFirst 控制递归时候的循环表示
* @param date 日期
* @return 返回列表
*/
public List<File> getOlderFiles(String dir,Date date,boolean ifFirst){
/**
* 递归判断,仅在第一次调用函数的时候新建列表,为防止重复存入列表
*/
if(ifFirst){
list=new ArrayList<File>();
} if (dir==null||dir==""||date==null) {
return null;
} for (File f : FileUtils.getFile(dir + "\\").listFiles()) {
if (f.isDirectory()) {
getOlderFiles(f.getAbsolutePath(),date,false);
} else {
if (FileUtils.isFileOlder(f, date)) {
list.add(f);
}
}
}
return list;
} /**
* 获取除过滤条件外的修改文件列表
* @param dir
* @param date
* @param filter
* @param ifFirst
* @return
*/
public List<File> getModifiedFiles(String dir,Date date,String filter,boolean ifFirst){
/**
* 递归判断,仅在第一次调用函数的时候新建列表,为防止重复存入列表
*/
if(ifFirst){
list=new ArrayList<File>();
} if (dir==null||dir==""||date==null) {
return null;
} for (File f : FileUtils.getFile(dir + "\\").listFiles()) {
if (f.isDirectory()) {
getModifiedFiles(f.getAbsolutePath(),date,filter,false);
} else {
if (FileUtils.isFileNewer(f, date.getTime())) {
if(!f.getName().endsWith(filter)){
list.add(f);
} }
}
}
return list;
} }
//用于压缩文件的工具类
package com.sean.utils; import java.io.File;
import java.util.ArrayList; import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants; public class ZipUtil {
/**
* 压缩文件列表,无目录结构
* @author Sean
* 2015-6-6
* @param zipSrc zip文件地址
* @param list 文件列表
* @return 若成功,返回文件地址,不成功返回null
*/
public static String zipFiles(String zipSrc,ArrayList<File> list){
ZipParameters zipParameters=new ZipParameters();
zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_MAXIMUM);
ZipFile zipFile=null;
try {
zipFile=new ZipFile(zipSrc);
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
try {
zipFile.addFiles(list, zipParameters);
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
return zipSrc;
} /**
* 压缩文件夹
* @author Sean
* 2015-6-6
* @param src 文件夹地址
* @param zipSrc 压缩文件存放地址
* @return 若成功,返回文件夹地址,若不成功,返回null
*/
public static String zipFolder(String src,String zipSrc){
ZipParameters zipParameters=new ZipParameters();
zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_MAXIMUM);
ZipFile zipFile=null;
try {
zipFile=new ZipFile(zipSrc);
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
try {
zipFile.addFolder(src, zipParameters);
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
return zipSrc;
} /**
* 往zip文件中添加文件列表
* @author Sean
* 2015-6-7
* @param zipSrc zip文件路径
* @param list 要添加的文件列表
* @param src 要添加到zip文件中的哪个路径
*/
public static void addFileToZip(String zipSrc,ArrayList<File> list,String src){
ZipFile zipFile=null;
try {
zipFile=new ZipFile(zipSrc);
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ZipParameters zipParameters=new ZipParameters();
zipParameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
zipParameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
zipParameters.setRootFolderInZip(src);
try {
zipFile.addFiles(list, zipParameters);
} catch (ZipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} } /**
* 添加文件列表到zip根目录下
* @author Sean
* 2015-6-7
* @param zipSrc zip文件地址
* @param list 添加的文件列表
*/
public static void addFileToZip(String zipSrc,ArrayList<File> list){
addFileToZip(zipSrc,list,"");
} }
主流程:
package com.sean.main; import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils; import com.sean.bean.EmailBean;
import com.sean.bean.FilesBean;
import com.sean.bean.PropertiesBean;
import com.sean.utils.ZipUtil; /**
* change2Mail 主程序
* 检测文件修改情况并发送给指定邮箱
* @version 1.0
* @author sean
* 2015-06-09
*
*/
public class Change2Mail { /**
* @param args
* @throws ParseException
*/
public static void main(String[] args) throws ParseException{
//获取properties操作类
PropertiesBean propertiesBean = new PropertiesBean("cfg.properties");
FilesBean filesBean=new FilesBean();
//邮件对象
EmailBean email=new EmailBean("cfg.properties");
String first = propertiesBean.getValue("first");
//当前日期
String today=new SimpleDateFormat("yyyyMMdd").format(new Date());
//邮件正文
String content="";
//首次使用判断
if (first.trim().equals("true")) {
System.out.println("首次运行");
content+="欢迎首次使用change2Mail,<br/>以下是你的更改文件备份目录<br/>";
//获取检查文件目录
String cheakDir = propertiesBean.getValue("cheakDir");
if(!StringUtils.isEmpty(cheakDir)){
System.out.println("正在进行更改文件目录备份。。。。。。");
//目录分割
String[] dirs = cheakDir.split(";");
for (int i = 0; i < dirs.length; i++) {
File tmp=new File(dirs[i]);
List<File> list=filesBean.listFiles(dirs[i],true);
//创建对应文件存储目录列表
File file=new File(ClassLoader.getSystemResource("").getPath()+tmp.getName());
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("创建目录列表记录文件失败。。。。。");
return ;
}
}
//将列表写入文件
logFiles(file,list);
//压缩文件并加入邮件
try {
ZipUtil.zipFolder(dirs[i], "tmp\\"+tmp.getName()+today+".zip");
content+=tmp.getName()+"<br/>";
email.addFiles("tmp\\"+tmp.getName()+today+".zip");
} catch (Exception e) {
e.printStackTrace();
System.out.println("压缩出错");
return ;
} }
}
content+="以下是你的固定备份目录<br/>";
String zipDir = propertiesBean.getValue("zipDir");
if(!StringUtils.isEmpty(zipDir)){
System.out.println("正在进行固定备份目录备份。。。。。。");
String[] zipDirs = zipDir.split(";");
for (int i = 0; i < zipDirs.length; i++) {
try {
File tmp=new File(zipDirs[i]);
ZipUtil.zipFolder(zipDirs[i], "tmp\\"+tmp.getName()+today+"bak.zip");
content+=tmp.getName()+"<br/>";
email.addFiles("tmp\\"+tmp.getName()+today+"bak.zip");
} catch (Exception e) {
e.printStackTrace();
System.out.println("压缩出错");
return ;
}
}
}
System.out.println("更新配置文件。。。。。");
propertiesBean.setValue("first", "false");
propertiesBean.setValue("lastData", today);
System.out.println("发送文件。。。。。");
email.setFrom(propertiesBean.getValue("username"));
email.setTOSend(propertiesBean.getValue("toSend"));
email.setContent(content);
email.setSubject("change2Mail备份文件"+today);
if(email.send()){
System.out.println("发送成功");
}else{
System.out.println("发送失败");
} } else {
System.out.println("备份开始。。。。。");
String data=propertiesBean.getValue("lastData");
String filter=propertiesBean.getValue("filter");
String cheakDir = propertiesBean.getValue("cheakDir");
content+="你好,自"+data+"起的文件变动如下:<br/>";
if(!StringUtils.isEmpty(cheakDir)){
System.out.println("正在进行更改文件目录备份。。。。。。");
String[] dirs = cheakDir.split(";");
for (int i = 0; i < dirs.length; i++) {
File tmp=new File(dirs[i]);
File file=new File(ClassLoader.getSystemResource("").getPath()+tmp.getName());
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
System.out.println("创建文档失败");
e.printStackTrace();
}
}
content+="文件夹"+tmp.getName()+":<br/>";
List<File> list=filesBean.getModifiedFiles(dirs[i],new SimpleDateFormat("yyyyMMdd").parse(data),filter,true);
List<File> now =filesBean.listFiles(dirs[i],filter,true);
List<File> news=new ArrayList<File>();
List<File> del=new ArrayList<File>();
List<File> modefy=new ArrayList<File>();
List<String> lines=null;
try {
lines=FileUtils.readLines(file);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("检查新建和修改的文件。。。。。。");
for(File f:list){
if(!lines.contains(f.getAbsolutePath())){
news.add(f);
}else{
modefy.add(f);
}
} System.out.println("检查删除的文件。。。。。。");
for(String f:lines){
File old=new File(f);
if(!now.contains(old)){
del.add(old);
}
}
logFiles(file,now);
content+="删除文件:<br/>";
for(File f:del){
content+=" "+f.getName()+"<br/>";
}
content+="新增文件:<br/>";
for(File f:news){
content+=" "+f.getName()+"<br/>";
}
content+="修改文件:<br/>";
for(File f:modefy){
content+=" "+f.getName()+"<br/>";
}
try {
if(list.size()!=0){
list.add(file);
ZipUtil.zipFiles("tmp\\"+tmp.getName()+today+".zip", (ArrayList<File>)list); email.addFiles("tmp\\"+tmp.getName()+today+".zip");
} } catch (Exception e) {
e.printStackTrace();
System.out.println("压缩失败");
return;
} } String zipDir = propertiesBean.getValue("zipDir");
if(!StringUtils.isEmpty(zipDir)){
System.out.println("正在进行固定备份目录备份。。。。。。");
String[] zipDirs = zipDir.split(";");
for (int i = 0; i < zipDirs.length; i++) {
try {
File tmp=new File(zipDirs[i]);
ZipUtil.zipFolder(zipDirs[i], "tmp\\"+tmp.getName()+today+"bak.zip");
email.addFiles("tmp\\"+tmp.getName()+today+"bak.zip");
} catch (Exception e) {
e.printStackTrace();
System.out.println("压缩出错");
return ;
}
}
} System.out.println("更改配置文件。。。。。");
propertiesBean.setValue("lastData", today);
System.out.println("发送文件。。。。。");
email.setFrom(propertiesBean.getValue("username"));
email.setTOSend(propertiesBean.getValue("toSend"));
email.setContent(content);
email.setSubject("change2Mail备份文件"+today);
if(email.send()){
System.out.println("发送成功");
}else{
System.out.println("发送失败");
} SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
long to = df.parse(today).getTime();
long todel=Integer.parseInt(propertiesBean.getValue("time"))*(1000 * 60 * 60 * 24);
Date lastBak=new Date(to-todel) ;
System.out.println("删除"+df.format(lastBak)+"之前保存的历史文件。。。。。");
List<File> fileToDel=filesBean.getOlderFiles("tmp\\", lastBak,true);
for(File f:fileToDel){
try {
FileUtils.deleteQuietly(f);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("删除"+f.getName()+"文件失败");
} }
System.out.println(new Date());
}
}
}
/**
* 将文件列表的绝对地址输出到一个文件中
* @param file 输出文件
* @param list 文件列表
* @return 成功返回true,失败返回false
*/
public static boolean logFiles(File file, List<File> list) {
List<String> lines=new ArrayList<String>();
try {
for (File f : list) {
lines.add(f.getAbsolutePath());
}
FileUtils.writeLines(file, lines,false);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
} }
配置文件:
#autho:sean
#data:2015/05/26
#email:hxy9104@126.com #mail config javamail的配置
mail.debug = true
mail.smtp.auth = true
mail.smtp.host = smtp.126.com
mail.transport.protocol = smtp #mail info 邮箱设置
username = 12121@126.com
password = 121212
toSend = 121212@qq.com #soft config 软件设置
#if the fisrt time to run 是否第一次运行
first = true
#the path to check 检测的目录
cheakDir = F:\\myfolder\\BaseClass;
#the path allways to zip 完全备份的目录
zipDir = F:\\myfolder\\myProject\\Change2Mail;
#the data lastcheck 最后备份时间
lastData = 20150629
#storage life of the bak zip 保留文件
time = 5
#filter string 过滤条件
filter = .class

工具github地址:https://github.com/Seanid/change2mail

为了便于使用,工具最后导出为jar包,并编写了一个bat进行执行,加入了jre文件夹,可以再无jdk环境下使用。最后压缩包地址:http://pan.baidu.com/s/1i3vQJv3

本工具只是个人闲时开发,纯属娱乐,大神勿喷

基于Java 的增量与完全备份小工具的更多相关文章

  1. 基于JAVA Socket的底层原理分析及工具实现

    前言 在工作开始之前,我们先来了解一下Socket 所谓Socket,又被称作套接字,它是一个抽象层,简单来说就是存在于不同平台(os)的公共接口.学过网络的同学可以把它理解为基于传输TCP/IP协议 ...

  2. 基于Java反射的map自动装配JavaBean工具类设计

    我们平时在用Myabtis时不是常常需要用map来传递参数,大体是如下的步骤: public List<Role> findRoles(Map<String,Object> p ...

  3. 【开源一个小工具】一键将网页内容推送到Kindle

    最近工作上稍微闲点,这一周利用下班时间写了一个小工具,其实功能挺简单但也小折腾了会. 工具名称:Simple Send to Kindle Github地址:https://github.com/zh ...

  4. HUDSON(Java开发的一种持续集成工具)

    Hudson是Jenkins的前身,是基于Java开发的一种持续集成工具,用于监控程序重复的工作,包括: 1.持续的软件版本发布/测试项目. 2.监控外部调用执行的工作. Hudson的特性 1.易于 ...

  5. MySQL数据库备份还原(基于binlog的增量备份)

    MySQL数据库备份还原(基于binlog的增量备份) 一.简介 1.增量备份      增量备份 是指在一次全备份或上一次增量备份后,以后每次的备份只需备份与前一次相比增加或者被修改的文件.这就意味 ...

  6. 基于binlog的增量备份

    1.1 增量备份简介 增量备份是指在一次全备份或上一次增量备份后,以后每次的备份只需备份与前一次相比增加或者被修改的文件.这就意味着,第一次增量备份的对象是进行全备后所产生的增加和修改的文件:第二次增 ...

  7. Lucene:基于Java的全文检索引擎简介

    Lucene:基于Java的全文检索引擎简介 Lucene是一个基于Java的全文索引工具包. 基于Java的全文索引/检索引擎--Lucene Lucene不是一个完整的全文索引应用,而是是一个用J ...

  8. Lucene:基于Java的全文检索引擎简介 (zhuan)

    http://www.chedong.com/tech/lucene.html ********************************************** Lucene是一个基于Ja ...

  9. [转]基于java的程序OutOfMemory问题的解决及Xms/Xmx/Xss的解释和应用

    长期以来一直都是做java应用的开发,所使用的开发工具基本上也都是基于java的,经常用的有eclipse, netbeans, ant, maven, cruisecontrol, tomcat, ...

随机推荐

  1. Make Things Move -- Javascript html5版(一)文件目录结构和工具方法准备

    从这一篇开始,就来开始我们的make things move之旅吧 在此之前,要知道ActionScript(AS)的语法和JS是不一样的,AS是相对于JS而言更好的支持了面向对象的特性,所以我们可以 ...

  2. wxWidgets的安装编译、相关配置、问题分析处理

    wxWidgets的安装编译.相关配置.问题分析处理 一.介绍部分 (win7 下的 GUI 效果图见 本篇文章的最后部分截图2张) wxWidgets是一个开源的跨平台的C++构架库(framewo ...

  3. Koala Framework

    Koala Framework是什么?我为什么要写这个框架?   当时的监管组,技术力量累积的很少,还在直连DB,使用着DataTable.DataSet作为数据的承载,监管是公司最近几年主推的项目, ...

  4. win8商店应用验证,二进制文件是在调试模式下生成的解决方案。

    程序是在release模式下生成的,并且arm和x64通过了验证,但是x86就出现了这个奇葩问题. 搞了半天发现是要把“优化代码”的选项勾上.

  5. C# 加密总结 一些常见的加密方法

    C# 加密总结 一些常见的加密方法 一 散列数据 代码如下: ? private static string CalculateSHA512Hash(string input)         {   ...

  6. sql server数据库中删除的过程

    这是在vb中的一个对数据库中数据的删除过程,点击按钮后程序第一句则是将你要删除的那条记录的位置作为书签保存到myBookmark这个变量里面,然后选择确定删除的话,首先执行if语句下的第一句 mrc. ...

  7. javascript操作正则表达式对象的方法总结

    //正则表达式对象 /* var s = 'good good study day day up '; var r, re; re = new RegExp('study',"g" ...

  8. android 豆瓣客户端 视频

    链接如下:http://download.csdn.net/detail/jltxgcy/5667337

  9. oc之里氏替换原则

    1. 里氏替换原则. LSP 子类对象可以替换父类对象的位置,并且程序的功能不受影响. 为什么? 1). 指针是1个父类类型,但是我们确给了指针1个子类对象的地址. 这样做当然是可以的,因为你要1个父 ...

  10. 点击某一按钮新增click,并切换页面

    应用场景:对于web端接收手机验证码的处理方法:1.如果有权限可以通过查询数据库来获得手机验证码,方便快捷.2.如果后台系统保存了手机验证码,可以去后台获取验证码,然后填写到前台页面,此方法有两种处理 ...