七牛云存储同步工具——为Markdown写作诞生

缘起

三年前买下www.itechq.com这个域名,一直想折腾个自己的博客。由于种种原因,一直没有去折腾。随着国家的长城防火墙越来越厉害,免费翻墙变得越来越困难,从GoAgent到XX-Net,稳定性越来越差。今年年初,实在受不了了,就买了个搬瓦工的VPS(10G SSD,512M内存,一年19刀),自己搭建了一个Shadowsocks Server,每月1000G流量,手机、笔记本都通过它翻墙,目前还比较稳定(不要问我为啥不直接买个收费VPN,因为程序猿爱折腾)。VPN搞定后,发现VPS系统资源利用率很少,此时,又激发了自己的博客梦,从而走上了Wordpress、Hexo的折腾之路……

为何开发

刚开始博客空间是用WP搭建,花了差不多两周时间配置、修改主题代码,后来因为WP对Markdown支持太弱了,而且相对来说比较重,选择放弃,最后选择Hexo纯静态博客空间,托管到Github、Coding。之所以选择七牛作为存储,是因为在配置WP插件时用到wpjam-qiniu插件,可以将网站上的js、css、image等资源自动同步到七牛云,而Hexo没有此类插件。

后来在七牛官网看到官方同步工具qrsbox,虽然该工具能够同步image到七牛云,但是和自己想想的还是有一定差距,如:图片命名、存储目录、外链地址拷贝都比较麻烦。此时在简书上看到一篇文章如何使用七牛云做为图床?,看完后还是觉得步骤较为复杂,没有达到自己想要的效果,但它却触发了自己写个小工具的想法,于是开始构思工具包括哪些功能,最后确定如下功能:

  • 支持从剪切板获取图像上传;灵感来自 作业部落 CMD Markdown图片上传效果(一款很棒的Markdown编辑工具)
  • 支持本地图像上传;
  • 支持从网络下载图像并上传;
  • 图像上传后自动生成Markdown格式的图片引用标签;
  • 支持删除已上传的图像;
  • 支持系统托盘,类似QQ之类软件一样,双击打开。

开始编码

由于博主目前对Java语言最熟,所以技术上只能选择Java,后续准备学习Python,开发一个Python版本的。

七牛Java SDK参考

参考官方文档,链接地址

七牛同步代码

主要实现七牛云图片上传、删除功能!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
public class QiNiuSync {

private Logger logger = LoggerFactory.getLogger(this.getClass());

// 外链地址
private String outerLinkAddr = null;
// 授权信息
private String ACCESS_KEY = null;
private String SECRET_KEY = null;
//要上传的空间
private String bucketName = null;

//密钥配置
private Auth auth = null;

//创建上传对象
private UploadManager uploadManager;

public QiNiuSync() throws IOException {

if (outerLinkAddr == null) {
outerLinkAddr = ConfigUtil.getPropertie("OuterLinkAddr");
}
logger.info("OuterLinkAddr = " + outerLinkAddr);

if (ACCESS_KEY == null) {
ACCESS_KEY = ConfigUtil.getPropertie("AccessKey");
}
logger.info("ACCESS_KEY = " + ACCESS_KEY);

if (SECRET_KEY == null) {
SECRET_KEY = ConfigUtil.getPropertie("SecretKey");
}
logger.info("SECRET_KEY = " + SECRET_KEY);

if (bucketName == null) {
bucketName = ConfigUtil.getPropertie("BucketName");
}
logger.info("BucketName = " + bucketName);

if (auth == null){
auth = Auth.create(ACCESS_KEY, SECRET_KEY);
}
logger.info("auth = " + auth);

if (uploadManager == null){
uploadManager = new UploadManager();
}
logger.info("uploadManager = " + uploadManager);
}

/**
* 简单上传,使用默认策略,只需要设置上传的空间名就可以了
*/
public String getUpToken() {
return auth.uploadToken(bucketName);
}

/**
* 图片上传
*
* @param filePath 图片本地地址
* @param fileName 七牛Key
* @return 上传成功返回图片外链地址,上传失败返回null
* @throws IOException
*/
public String upload(String filePath, String fileName) {
try {
//调用put方法上传
Response res = uploadManager.put(filePath, fileName, getUpToken());
//打印返回的信息
logger.info("upload() Response : " + res.bodyString());

String outerLink = outerLinkAddr + fileName;
logger.info("outerLink :" + outerLink);
return outerLink;
} catch (Exception e) {
logger.error("upload() Exception : ", e);
}
return null;
}

/**
* 图片删除
*
* @param qiniuKey 七牛key
* @return 删除成功返回true,删除失败返回false
*/
public boolean delete(String qiniuKey) {
try {
BucketManager bucketManager = new BucketManager(auth);
//调用delete方法移动文件
bucketManager.delete(bucketName, qiniuKey);
return true;
} catch (Exception e) {
logger.error("delete() Exception : ", e);
}
return false;
}
}

剪切板代码

主要实现设置图片、文本信息到剪切板,从剪切板获取图片、文本信息!部分代码摘自网络。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class OperateClipboard {

private Logger logger = LoggerFactory.getLogger(this.getClass());

DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");


/**
* 设置系统剪切板,内容为图片
*
* @param image 图片
*/
public void setImageClipboard(Image image) {
ImageSelection imgSel = new ImageSelection(image);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel, null);
}

/**
* 获取剪贴板图像,并返回图像绝对路径
*
* @param rootPath 存储图像根目录
* @return 获取成功返回图片路径;获取失败返回null
*/
public String getImageClipboard(String rootPath) {
try {
//create qiniu objecte
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
//Get data from qiniu and assign it to an image.
//qiniu.getData() returns an object, so we need to cast it to a BufferdImage.
BufferedImage image = (BufferedImage) clipboard.getData(DataFlavor.imageFlavor);
//process file name
DESEncrypts desEncrypts = new DESEncrypts();
String filePath = desEncrypts.encrypt(dateFormat.format(new Date()));
String fileName = UUIDUtil.generateUUID() + ".png";
String rootFilePath = rootPath + filePath;
File rootFile = new File(rootFilePath);
if (!rootFile.exists()) {
rootFile.mkdirs();
}
String imageFileName = rootFilePath + File.separator + fileName;
//file that we'll save to disk.
File file = new File(imageFileName);

//class to write image to disk. You specify the image to be saved, its type,
// and then the file in which to write the image data.
ImageIO.write(image, "png", file);
logger.info("image capture success:" + imageFileName);
return imageFileName;
}
//getData throws this.
catch (Exception e) {
logger.error("Exception:", e);
return null;
}
}

/**
* 设置系统剪贴板,内容为文本
*
* @param refContent 文本内容
*/
public void setSystemClipboard(String refContent) {
String vc = refContent.trim();
StringSelection ss = new StringSelection(vc);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, null);
}

/**
* 获取系统剪切板的文本内容[如果系统剪切板复制的内容是文本]
*
* @return 获取成功返回剪切板内容,获取失败返回null
*/
public String getSystemClipboard() {
Clipboard sysClb = null;
sysClb = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable t = sysClb.getContents(null);
//Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null); //跟上面三行代码一样
try {
if (null != t && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
String text = (String) t.getTransferData(DataFlavor.stringFlavor);
return text;
}
} catch (Exception e) {
logger.error("Exception:", e);
return null;
}
return null;
}
}

成品

工具操作面板

62b0aae6828e8513/de66d8d153db474e8fcc58db99e7e192.png

快捷上传

62b0aae6828e8513/dd31939b0b2a47419e3740975eda035a.png

七牛云存储截图

62b0aae6828e8513/fd16d7880bb040d9b69f1810fbc33bbd.png

搞定,主要功能操作面板上都有,基本上满足博主需求~~