作者 钟来

初始提交

# Compiled class file
logs/*
config.json
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
!/.mvn/wrapper/maven-wrapper.jar
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
.DS_Store
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
... ...
MIT License
Copyright (c) 2017 潘滔
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
... ...
#### 七牛云对象存储管理工具介绍
- 设置文件前缀
路径前缀可以用来分类文件,例如: `image/jpg/`your-file-name.jpg。
- 添加存储空间
添加存储空间,需要同时指定空间名称,空间域名以及所在区域。
- 重置密钥
如果你修改了KEY,可以在此处修改密钥(第一次使用也需要重置KEY)。
> 说明:出于安全考虑,建议您周期性地更换密钥。[查看我的密钥](https://portal.qiniu.com/user/key) [密钥安全使用须知](https://developer.qiniu.com/kodo/kb/1334/the-access-key-secret-key-encryption-key-safe-use-instructions)
- 配置文件
与应用在同级目录,其中 `config.json` 为配置文件
- 文件上传
除了可(支持断点和覆盖)上传本地文件外,还可抓取网络文件到空间中
- 刷新列表
刷新当前存储空间的资源列表
- 复制链接
复制你选中文件的外链
- 删除文件
从存储空间中删除你选中的所有文件
- 移动文件
移动(或复制)选中的所有文件到指定的存储空间中(目前七牛还不支持跨区域移动文件)
> 说明:勾选“保存文件副本”时表示当前操作为复制,不勾选时表示移动(会删除本存储空间的文件),默认勾选。
- 生存时间
设置选中文件的生存时间,到期后七牛会自动删除这些文件
- 更新镜像
此功能首先需要你配置了镜像存储
> 官方解释:对于配置了镜像存储的空间,如果镜像源站更新了文件内容,则默认情况下,七牛不会再主动从客户镜像源站同步新的副本,这个时候就需要利用这个prefetch接口来主动地将空间中的文件和更新后的源站副本进行同步。
- 公有下载
直接下载选中的文件(私有的存储空间不可用)
- 私有下载
下载选中的私有存储空间的文件
- 打开文件
用浏览器打开你选中的文件
- 文件刷新
从七牛云镜像源刷新你选中的文件,保证用户下载的是最新上传的文件,而不是之前的旧版本。
- 日志下载
从七牛下载指定日期的操作日志
> 说明:操作文件时,需要选中文件才能操作(支持多选)。由于下载私有空间的文件需要临时授权,所以文件的下载分为私有下载(生成临时授权然后下载文件)和公有下载(直接下载文件)。
另外数据统计的时间跨度不超过31天,否则无法获取数据,这是七牛官方规定的。
- 参考 [官方JavaSDK文档](https://developer.qiniu.com/kodo/sdk/1239/java)
... ...
theme: jekyll-theme-hacker
\ No newline at end of file
... ...
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Migwn, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
echo $MAVEN_PROJECTBASEDIR
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
... ...
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
... ...
<?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>
<groupId>com.zhazhapan</groupId>
<artifactId>qiniu</artifactId>
<version>1.0.8</version>
<packaging>jar</packaging>
<name>qiniu</name>
<description>七牛同步工具</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.2.0, 7.2.99]</version>
</dependency>
<dependency>
<groupId>com.zhazhapan</groupId>
<artifactId>util</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.code4everything.qiniu.QiniuApplication</mainClass>
</transformer>
</transformers>
<artifactSet>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
... ...
package org.code4everything.qiniu;
import com.zhazhapan.util.ThreadPool;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.ButtonType;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.apache.log4j.Logger;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import org.code4everything.qiniu.model.ConfigBean;
import org.code4everything.qiniu.util.ConfigUtils;
import org.code4everything.qiniu.util.DialogUtils;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @author pantao
*/
public class QiniuApplication extends Application {
private static final Logger LOGGER = Logger.getLogger(QiniuApplication.class);
private static Stage stage = null;
private static ConfigBean configBean;
public static Stage getStage() {
return stage;
}
public static ConfigBean getConfigBean() {
return configBean;
}
public static void setConfigBean(ConfigBean configBean) {
QiniuApplication.configBean = configBean;
}
/**
* 主程序入口
*/
public static void main(String[] args) {
// 设置线程池大小
ThreadPool.setMaximumPoolSize(10);
// 设置线程池最大排队大小
ThreadPool.setWorkQueue(new LinkedBlockingQueue<>(1024));
ThreadPool.init();
// 启动 JavaFX 应用
launch(args);
}
/**
* 由 JavaFX 调用
*/
@Override
public void start(Stage stage) {
try {
// 加载视图页面
VBox root = FXMLLoader.load(getClass().getResource(QiniuValueConsts.QINIU_VIEW_URL));
Scene scene = new Scene(root);
stage.setScene(scene);
} catch (Exception e) {
LOGGER.error("init stage error: " + e.getMessage());
DialogUtils.showFatalError(QiniuValueConsts.INIT_APP_ERROR_HEADER, e);
}
// 设置图标
stage.getIcons().add(new Image(getClass().getResourceAsStream("/image/qiniu.png")));
stage.setTitle(QiniuValueConsts.MAIN_TITLE);
// 设置关闭窗口事件
stage.setOnCloseRequest(event -> {
Optional<ButtonType> result = DialogUtils.showConfirmation(QiniuValueConsts.CONFIRM_EXIT);
if (result.isPresent() && result.get() != ButtonType.OK) {
// 取消退出事件
event.consume();
return;
}
// 退出程序
ThreadPool.executor.shutdown();
System.exit(0);
});
QiniuApplication.stage = stage;
stage.show();
// 加载配置文件
ConfigUtils.loadConfig();
}
}
... ...
package org.code4everything.qiniu.api;
import com.qiniu.cdn.CdnManager;
import com.qiniu.common.Zone;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.persistent.FileRecorder;
import com.qiniu.util.Auth;
import com.zhazhapan.util.Utils;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
/**
* @author pantao
*/
public class SdkConfigurer {
private static final String[] BUCKET_NAME_ARRAY = {"华东", "华北", "华南", "北美"};
private static final Map<String, Zone> ZONE = new HashMap<>();
private static final Logger LOGGER = Logger.getLogger(SdkConfigurer.class);
private static Auth auth = null;
private static UploadManager uploadManager = null;
private static BucketManager bucketManager = null;
private static CdnManager cdnManager = null;
static {
// 加载空间区域
ZONE.put(BUCKET_NAME_ARRAY[0], Zone.zone0());
ZONE.put(BUCKET_NAME_ARRAY[1], Zone.zone1());
ZONE.put(BUCKET_NAME_ARRAY[2], Zone.zone2());
ZONE.put(BUCKET_NAME_ARRAY[3], Zone.zoneNa0());
}
private SdkConfigurer() {}
public static CdnManager getCdnManager() {
return cdnManager;
}
public static BucketManager getBucketManager() {
return bucketManager;
}
public static UploadManager getUploadManager() {
return uploadManager;
}
public static Auth getAuth() {
return auth;
}
/**
* 创建上传需要的Auth
*/
public static void createAuth(String accessKey, String secretKey) {
auth = Auth.create(accessKey, secretKey);
cdnManager = new CdnManager(auth);
}
/**
* 配置文件上传环境,不再做网络检查,请执行保证网络通畅
*/
public static boolean configUploadEnv(String zone, String bucket) {
// 构造一个带指定Zone对象的配置类
Configuration configuration = new Configuration(SdkConfigurer.ZONE.get(zone));
// 生成上传凭证,然后准备上传
String workDir = Paths.get(Utils.getCurrentWorkDir(), bucket).toString();
try {
FileRecorder fileRecorder = new FileRecorder(workDir);
uploadManager = new UploadManager(configuration, fileRecorder);
} catch (IOException e) {
LOGGER.warn("load work directory failed, can't use file recorder");
uploadManager = new UploadManager(configuration);
}
bucketManager = new BucketManager(auth, configuration);
return true;
}
}
... ...
package org.code4everything.qiniu.api;
import com.qiniu.cdn.CdnResult;
import com.qiniu.cdn.CdnResult.LogData;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.model.BatchStatus;
import java.util.Map;
/**
* @author pantao
*/
public class SdkManager {
/**
* 自定义私有链接过期时间
*/
private static final long EXPIRE_IN_SECONDS = 24 * 60 * 60L;
/**
* 文件列表大小
*/
private static final int LIST_SIZE = 1000;
/**
* 获取空间带宽统计
*/
public CdnResult.BandwidthResult getBandwidthData(String[] domains, String startDate, String endDate) throws QiniuException {
return SdkConfigurer.getCdnManager().getBandwidthData(domains, startDate, endDate, "day");
}
/**
* 获取空间的流量统计
*/
public CdnResult.FluxResult getFluxData(String[] domains, String startDate, String endDate) throws QiniuException {
return SdkConfigurer.getCdnManager().getFluxData(domains, startDate, endDate, "day");
}
/**
* 日志下载,CDN 相关
*/
public Map<String, LogData[]> listCdnLog(String[] domains, String logDate) throws QiniuException {
return SdkConfigurer.getCdnManager().getCdnLogList(domains, logDate).data;
}
/**
* 刷新文件,CDN 相关
*/
public void refreshFile(String[] files) throws QiniuException {
// 单次方法调用刷新的链接不可以超过100个
SdkConfigurer.getCdnManager().refreshUrls(files);
}
/**
* 私有下载
*/
public String getPrivateUrl(String publicUrl) {
return SdkConfigurer.getAuth().privateDownloadUrl(publicUrl, EXPIRE_IN_SECONDS);
}
/**
* 更新镜像源
*/
public void prefetch(String bucket, String key) throws QiniuException {
SdkConfigurer.getBucketManager().prefetch(bucket, key);
}
/**
* 设置文件生存时间
*/
public void deleteAfterDays(String bucket, String key, int days) throws QiniuException {
SdkConfigurer.getBucketManager().deleteAfterDays(bucket, key, days);
}
/**
* 重命名文件
*/
public void renameFile(String bucket, String oldName, String newName) throws QiniuException {
moveFile(bucket, oldName, bucket, newName);
}
/**
* 移动文件
*/
public void moveFile(String srcBucket, String fromKey, String destBucket, String toKey) throws QiniuException {
moveOrCopyFile(srcBucket, fromKey, destBucket, toKey, FileAction.MOVE);
}
/**
* 移动或复制文件
*/
public void moveOrCopyFile(String srcBucket, String srcKey, String destBucket, String destKey,
FileAction fileAction) throws QiniuException {
if (FileAction.COPY == fileAction) {
SdkConfigurer.getBucketManager().copy(srcBucket, srcKey, destBucket, destKey, true);
} else {
SdkConfigurer.getBucketManager().move(srcBucket, srcKey, destBucket, destKey, true);
}
}
/**
* 修改文件类型
*/
public void changeMime(String fileName, String newType, String bucket) throws QiniuException {
SdkConfigurer.getBucketManager().changeMime(bucket, fileName, newType);
}
/**
* 批量删除文件,单次批量请求的文件数量不得超过1000
*/
public BatchStatus[] batchDelete(String bucket, String[] keys) throws QiniuException {
BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations();
batchOperations.addDeleteOp(bucket, keys);
Response response = SdkConfigurer.getBucketManager().batch(batchOperations);
return response.jsonToObject(BatchStatus[].class);
}
/**
* 获取空间文件列表
*/
public BucketManager.FileListIterator getFileListIterator(String bucket) {
return SdkConfigurer.getBucketManager().createFileListIterator(bucket, "", LIST_SIZE, "");
}
public enum FileAction {
// 复制或移动文件
COPY, MOVE
}
}
... ...
package org.code4everything.qiniu.constant;
import com.zhazhapan.util.Utils;
import java.io.File;
/**
* 常量类
*
* @author pantao
*/
public class QiniuValueConsts {
public static final String CONFIG_PATH = Utils.getCurrentWorkDir() + File.separator + "config.json";
public static final String QINIU_VIEW_URL = "/view/Main.fxml";
public static final String QINIU_KEY_URL = "https://portal.qiniu.com/user/key";
public static final String MAIN_TITLE = "七牛云管理工具";
public static final String INIT_APP_ERROR_HEADER = "初始化错误,无法继续运行";
public static final String OK = "确定";
public static final String CANCEL = "取消";
public static final String BUCKET_NAME = "空间名称";
public static final String BUCKET_ZONE_NAME = "存储区域";
public static final String BUCKET_URL = "空间域名";
public static final String[] BUCKET_NAME_ARRAY = {"华东", "华北", "华南", "北美"};
public static final String FILE_CHOOSER_TITLE = "选择需要上传的文件";
public static final String OPEN_FILE_ERROR = "打开文件失败";
public static final String UPLOAD_ERROR = "上传文件失败";
public static final String UPLOADING = "文件上传中,请耐心等待。。。。。。\r\n";
public static final String NEED_CHOOSE_BUCKET_OR_FILE = "请先选择一个存储空间或文件";
public static final String CONFIG_UPLOAD_ENVIRONMENT = "正在配置文件上传环境,请耐心等待。。。。。。\r\n";
public static final String RELOAD_CONFIG = "是否重新载入配置文件?";
public static final String DOMAIN_CONFIG_ERROR = "您还没有正确地配置空间域名";
public static final String REFRESH_SUCCESS = "刷新资源列表成功";
public static final String DELETE_ERROR = "删除文件时发生异常";
public static final String CHANGE_FILE_TYPE_ERROR = "删除文件发生异常";
public static final String MOVE_OR_RENAME_ERROR = "移动或重命名文件失败";
public static final String FILE_NAME = "文件名";
public static final String COPY_AS = "保存文件副本";
public static final String FILE_LIFE = "文件生存时间(天)";
public static final String UPDATE_ERROR = "更新镜像源失败";
public static final String DEFAULT_FILE_LIFE = "365";
public static final String CONFIG_DOWNLOAD_PATH = "配置文件下载路径";
public static final String INPUT_LOG_DATE = "请输入日志的日期";
public static final String BUCKET_FLUX_ERROR = "获取空间流量统计失败";
public static final String BUCKET_BAND_ERROR = "获取空间带宽统计失败";
public static final String BUCKET_FLUX_COUNT = "空间流量(KB)";
public static final String BUCKET_BANDWIDTH_COUNT = "空间带宽(KB)";
public static final long DATE_SPAN_OF_THIRTY_ONE = 31 * 24 * 60 * 60 * 1000L;
public static final String CONFIRM_EXIT = "确定退出?";
private QiniuValueConsts() {}
}
... ...
package org.code4everything.qiniu.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.qiniu.common.QiniuException;
import com.zhazhapan.util.Checker;
import com.zhazhapan.util.Formatter;
import com.zhazhapan.util.ThreadPool;
import com.zhazhapan.util.Utils;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.chart.AreaChart;
import javafx.scene.control.*;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.input.DragEvent;
import javafx.scene.input.TransferMode;
import javafx.stage.FileChooser;
import javafx.util.Pair;
import org.code4everything.qiniu.QiniuApplication;
import org.code4everything.qiniu.api.SdkConfigurer;
import org.code4everything.qiniu.api.SdkManager;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import org.code4everything.qiniu.model.FileBean;
import org.code4everything.qiniu.service.QiniuService;
import org.code4everything.qiniu.util.ConfigUtils;
import org.code4everything.qiniu.util.DialogUtils;
import org.code4everything.qiniu.util.QiniuDialog;
import org.code4everything.qiniu.util.QiniuUtils;
import java.awt.*;
import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
/**
* 界面控制类
*
* @author pantao
*/
public class MainController {
private static final String UPLOAD_STATUS_TEMPLATE = "{}\tsuccess\t{}{}\t{}";
private static MainController mainController = null;
private final QiniuService service = new QiniuService();
private final QiniuDialog dialog = new QiniuDialog();
@FXML
public ComboBox<String> bucketCB;
@FXML
public TextField zoneTF;
@FXML
public TextArea uploadStatusTA;
@FXML
public ComboBox<String> prefixCB;
@FXML
public TableView<FileBean> resTV;
@FXML
public TextField searchTF;
@FXML
public CheckBox recursiveCB;
@FXML
public CheckBox keepPathCB;
private ObservableList<FileBean> resData = null;
/**
* 空间总文件数
*/
private int dataLength = 0;
/**
* 空间使用总大小
*/
private long dataSize = 0;
@FXML
private TextArea selectedFileTA;
@FXML
private TextField domainTF;
@FXML
private TableColumn<FileBean, String> nameTC;
@FXML
private TableColumn<FileBean, String> typeTC;
@FXML
private TableColumn<FileBean, String> sizeTC;
@FXML
private TableColumn<FileBean, String> timeTC;
@FXML
private Label sizeLabel;
@FXML
private Label lengthLabel;
@FXML
private AreaChart<String, Long> fluxAC;
@FXML
private AreaChart<String, Long> bandwidthAC;
@FXML
private DatePicker startDP;
@FXML
private DatePicker endDP;
@FXML
private ComboBox<String> fluxUnitCB;
@FXML
private ComboBox<String> bandwidthUnitCB;
private String status = "";
/**
* 父文件夹路径
*/
private List<String> rootPath = new ArrayList<>();
public static MainController getInstance() {
return mainController;
}
public ObservableList<FileBean> getResData() {
return resData;
}
public void setResData(ObservableList<FileBean> resData) {
this.resData = resData;
}
public int getDataLength() {
return dataLength;
}
public void setDataLength(int dataLength) {
this.dataLength = dataLength;
}
public long getDataSize() {
return dataSize;
}
public void setDataSize(long dataSize) {
this.dataSize = dataSize;
}
/**
* 初始化
*/
@FXML
private void initialize() {
mainController = this;
nameTC.setCellValueFactory(new PropertyValueFactory<>("name"));
// 设置文件名可编辑
nameTC.setCellFactory(TextFieldTableCell.forTableColumn());
nameTC.setOnEditCommit(value -> {
String name;
FileBean fileBean = value.getTableView().getItems().get(value.getTablePosition().getRow());
// 编辑后重命名文件
if (service.renameFile(bucketCB.getValue(), value.getOldValue(), value.getNewValue())) {
name = value.getNewValue();
} else {
name = value.getOldValue();
}
if (Checker.isNotEmpty(searchTF.getText())) {
resData.get(resData.indexOf(fileBean)).setName(name);
}
fileBean.setName(name);
});
typeTC.setCellValueFactory(new PropertyValueFactory<>("type"));
// 设置文件类型可编辑
typeTC.setCellFactory(TextFieldTableCell.forTableColumn());
typeTC.setOnEditCommit(value -> {
String type;
FileBean fileBean = value.getTableView().getItems().get(value.getTablePosition().getRow());
// 编辑后更新文件类型
if (service.changeType(fileBean.getName(), value.getNewValue(), bucketCB.getValue())) {
type = value.getNewValue();
} else {
type = value.getOldValue();
}
if (Checker.isNotEmpty(searchTF.getText())) {
resData.get(resData.indexOf(fileBean)).setType(type);
}
fileBean.setType(type);
});
sizeTC.setCellValueFactory(new PropertyValueFactory<>("size"));
timeTC.setCellValueFactory(new PropertyValueFactory<>("time"));
// 设置表格允许多选
resTV.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// 设置默认的开始和结束日期,并事件刷新数据
endDP.setValue(LocalDate.now());
long startTime = System.currentTimeMillis() - QiniuValueConsts.DATE_SPAN_OF_THIRTY_ONE;
LocalDate localEndDate = Formatter.dateToLocalDate(new Date(startTime));
startDP.setValue(localEndDate);
// 设置桶下拉框改变事件,改变后配置新的上传环境
bucketCB.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
zoneTF.setText(QiniuApplication.getConfigBean().getZone(newValue));
searchTF.clear();
String url = QiniuApplication.getConfigBean().getUrl(newValue);
if (Checker.isHyperLink(url)) {
domainTF.setText(url);
} else {
domainTF.setText(QiniuValueConsts.DOMAIN_CONFIG_ERROR);
}
ThreadPool.executor.submit(() -> {
if (SdkConfigurer.configUploadEnv(QiniuApplication.getConfigBean().getZone(newValue), newValue)) {
// 加载文件列表
mapResourceData();
// 刷新流量带宽统计
dateChange();
}
});
});
// 初始化统计单位选择框
fluxUnitCB.getItems().addAll("KB", "MB", "GB", "TB");
fluxUnitCB.setValue("KB");
fluxUnitCB.getSelectionModel().selectedItemProperty().addListener((obs, o, n) -> drawChart(true, false));
bandwidthUnitCB.getItems().addAll(fluxUnitCB.getItems());
bandwidthUnitCB.setValue("KB");
bandwidthUnitCB.getSelectionModel().selectedItemProperty().addListener((obs, o, n) -> drawChart(false, true));
}
/**
* 开始拖曳文件
*/
public void dragFileOver(DragEvent event) {
event.acceptTransferModes(TransferMode.ANY);
}
/**
* 拖曳文件松开鼠标
*/
public void dragFileDropped(DragEvent event) {
appendFile(event.getDragboard().getFiles());
}
/**
* 开始日期或结束日期改变,刷新流量、带宽统计
*/
public void dateChange() {
drawChart(true, true);
}
/**
* 绘制数据统计图表
*/
private void drawChart(boolean isFluxUnitChange, boolean isBandwidthUnitChange) {
Date localStartDate = Formatter.localDateToDate(startDP.getValue());
Date localEndDate = Formatter.localDateToDate(endDP.getValue());
// 将本地日期装换成字符串
String fromDate = Formatter.dateToString(localStartDate);
String toDate = Formatter.dateToString(localEndDate);
// 获取开始日期和结束日期的时间差
long timeSpan = localEndDate.getTime() - localStartDate.getTime();
if (Checker.isNotEmpty(domainTF.getText()) && timeSpan >= 0 && timeSpan <= QiniuValueConsts.DATE_SPAN_OF_THIRTY_ONE) {
Platform.runLater(() -> {
String[] domains = {domainTF.getText()};
if (isFluxUnitChange) {
// 获取流量数据
String fluxUnit = fluxUnitCB.getValue();
fluxAC.getData().clear();
fluxAC.getData().add(service.getBucketFlux(domains, fromDate, toDate, fluxUnit));
}
if (isBandwidthUnitChange) {
// 获取带宽数据
String bandUnit = bandwidthUnitCB.getValue();
bandwidthAC.getData().clear();
bandwidthAC.getData().add(service.getBucketBandwidth(domains, fromDate, toDate, bandUnit));
}
});
}
}
/**
* 下载日志
*/
public void downloadCdnLog() {
String date = DialogUtils.showInputDialog(null, QiniuValueConsts.INPUT_LOG_DATE,
Formatter.dateToString(new Date()));
service.downloadCdnLog(date);
}
/**
* 刷新文件
*/
public void refreshFile() {
service.refreshFile(resTV.getSelectionModel().getSelectedItems(), domainTF.getText());
}
/**
* 用浏览器打开文件
*/
public void openFile() {
ObservableList<FileBean> selectedItems = resTV.getSelectionModel().getSelectedItems();
if (Checker.isNotEmpty(selectedItems)) {
String filename = selectedItems.get(0).getName();
QiniuUtils.openLink(QiniuUtils.buildUrl(filename, domainTF.getText()));
}
}
/**
* 私有下载
*/
public void privateDownload() {
download(DownloadWay.PRIVATE);
}
/**
* 下载文件
*/
private void download(DownloadWay way) {
ObservableList<FileBean> selectedItems = resTV.getSelectionModel().getSelectedItems();
if (Checker.isNotEmpty(selectedItems)) {
if (way == DownloadWay.PUBLIC) {
selectedItems.forEach(bean -> service.publicDownload(bean.getName(), domainTF.getText()));
} else {
selectedItems.forEach(bean -> service.privateDownload(bean.getName(), domainTF.getText()));
}
}
}
/**
* 公有下载
*/
public void publicDownload() {
download(DownloadWay.PUBLIC);
}
/**
* 更新镜像源
*/
public void updateFile() {
ObservableList<FileBean> selectedItems = resTV.getSelectionModel().getSelectedItems();
if (Checker.isNotEmpty(selectedItems)) {
selectedItems.forEach(bean -> service.updateFile(bucketCB.getValue(), bean.getName()));
}
}
/**
* 设置文件生存时间
*/
public void setLife() {
ObservableList<FileBean> selectedItems = resTV.getSelectionModel().getSelectedItems();
if (Checker.isNotEmpty(selectedItems)) {
// 弹出输入框
String fileLife = DialogUtils.showInputDialog(null, QiniuValueConsts.FILE_LIFE,
QiniuValueConsts.DEFAULT_FILE_LIFE);
if (Checker.isNumber(fileLife)) {
int life = Formatter.stringToInt(fileLife);
selectedItems.forEach(bean -> service.setFileLife(bucketCB.getValue(), bean.getName(), life));
}
}
}
/**
* 显示移动或复制文件的弹窗
*/
public void showFileMovableDialog() {
ObservableList<FileBean> selectedItems = resTV.getSelectionModel().getSelectedItems();
if (Checker.isEmpty(selectedItems)) {
// 没有选择文件,结束方法
return;
}
Pair<SdkManager.FileAction, String[]> resultPair;
String bucket = bucketCB.getValue();
if (selectedItems.size() > 1) {
resultPair = dialog.showFileDialog(bucket, "", false);
} else {
resultPair = dialog.showFileDialog(bucket, selectedItems.get(0).getName(), true);
}
if (Checker.isNotNull(resultPair)) {
boolean useNewKey = Checker.isNotEmpty(resultPair.getValue()[1]);
ObservableList<FileBean> fileBeans = resTV.getItems();
for (FileBean fileBean : selectedItems) {
String fromBucket = bucketCB.getValue();
String toBucket = resultPair.getValue()[0];
String name = useNewKey ? resultPair.getValue()[1] : fileBean.getName();
boolean isSuccess = service.moveOrCopyFile(fromBucket, fileBean.getName(), toBucket, name,
resultPair.getKey());
if (resultPair.getKey() == SdkManager.FileAction.MOVE && isSuccess) {
boolean isInSearch = Checker.isNotEmpty(searchTF.getText());
if (fromBucket.equals(toBucket)) {
// 更新文件名
fileBean.setName(name);
if (isInSearch) {
fileBeans.get(fileBeans.indexOf(fileBean)).setName(name);
}
} else {
// 删除数据源
fileBeans.remove(fileBean);
dataLength--;
dataSize -= Formatter.sizeToLong(fileBean.getSize());
if (isInSearch) {
fileBeans.remove(fileBean);
}
}
}
}
countBucket();
}
}
/**
* 删除文件
*/
public void deleteFile() {
service.deleteFile(resTV.getSelectionModel().getSelectedItems(), bucketCB.getValue());
}
/**
* 复制链接
*/
public void copyLink() {
ObservableList<FileBean> fileBeans = resTV.getSelectionModel().getSelectedItems();
if (Checker.isNotEmpty(fileBeans)) {
// 只复制选中的第一个文件的链接
Utils.copyToClipboard(QiniuUtils.buildUrl(fileBeans.get(0).getName(), domainTF.getText()));
}
}
/**
* 搜索资源文件,忽略大小写
*/
public void searchFile() {
ArrayList<FileBean> files = new ArrayList<>();
String search = Checker.checkNull(searchTF.getText());
dataLength = 0;
dataSize = 0;
// 正则匹配查询
Pattern pattern = Pattern.compile(search, Pattern.CASE_INSENSITIVE);
for (FileBean file : resData) {
if (pattern.matcher(file.getName()).find()) {
files.add(file);
dataLength++;
dataSize += Formatter.sizeToLong(file.getSize());
}
}
countBucket();
resTV.setItems(FXCollections.observableArrayList(files));
}
/**
* 统计空间文件的数量以及大小
*/
public void countBucket() {
lengthLabel.setText(Formatter.customFormatDecimal(dataLength, ",###") + " 个文件");
sizeLabel.setText(Formatter.formatSize(dataSize));
}
/**
* 刷新资源列表
*/
public void refreshResourceData() {
mapResourceData();
DialogUtils.showInformation(QiniuValueConsts.REFRESH_SUCCESS);
}
/**
* 将从存储空间获取的文件列表映射到表中
*/
private void mapResourceData() {
ThreadPool.executor.submit(() -> {
// 列出资源文件
service.listFile();
Platform.runLater(() -> {
resTV.setItems(resData);
countBucket();
});
});
}
/**
* 添加桶至下拉框
*/
public void appendBucket(String bucket) {
if (!bucketCB.getItems().contains(bucket)) {
bucketCB.getItems().add(bucket);
}
}
/**
* 保存文件的上传状态
*/
public void saveUploadStatus() {
FileChooser chooser = new FileChooser();
chooser.setTitle(QiniuValueConsts.FILE_CHOOSER_TITLE);
chooser.setInitialDirectory(new File(Utils.getCurrentWorkDir()));
File file = chooser.showSaveDialog(QiniuApplication.getStage());
QiniuUtils.saveFile(file, uploadStatusTA.getText());
}
/**
* 复制文件上传状态至剪贴板
*/
public void copyUploadStatus() {
Utils.copyToClipboard(uploadStatusTA.getText());
}
/**
* 清空文件的上传状态
*/
public void clearUploadStatus() {
uploadStatusTA.clear();
}
/**
* 显示选择文件的弹窗
*/
public void showOpenFileDialog() {
FileChooser chooser = new FileChooser();
chooser.setTitle(QiniuValueConsts.FILE_CHOOSER_TITLE);
chooser.setInitialDirectory(new File(Utils.getCurrentWorkDir()));
appendFile(chooser.showOpenMultipleDialog(QiniuApplication.getStage()));
}
/**
* 添加上传的文件,支持拖曳文件夹
*/
private void appendFile(List<File> files) {
if (Checker.isNotEmpty(files)) {
File[] fileArray = new File[files.size()];
appendFile(files.toArray(fileArray), false);
}
}
/**
* 添加上传的文件,支持拖曳文件夹
*/
private void appendFile(File[] files, boolean isRecursive) {
if (Checker.isNotNull(files)) {
for (File file : files) {
if (file.isDirectory()) {
if (isRecursive) {
// 递归添加文件
if (recursiveCB.isSelected()) {
appendFile(file.listFiles(), true);
}
} else {
rootPath.add(file.getAbsolutePath());
appendFile(file.listFiles(), true);
}
} else if (!selectedFileTA.getText().contains(file.getAbsolutePath())) {
selectedFileTA.insertText(0, file.getAbsolutePath() + "\r\n");
}
}
}
}
/**
* 上传选择的文件
*/
public void uploadFile() {
if (Checker.isEmpty(zoneTF.getText()) || Checker.isEmpty(selectedFileTA.getText())) {
// 没有选择存储空间或文件,不能上传文件
DialogUtils.showWarning(QiniuValueConsts.NEED_CHOOSE_BUCKET_OR_FILE);
return;
}
// 新建一个线程上传文件的线程
ThreadPool.executor.submit(() -> {
Platform.runLater(() -> uploadStatusTA.insertText(0, QiniuValueConsts.CONFIG_UPLOAD_ENVIRONMENT));
String bucket = bucketCB.getValue();
// 默认不指定KEY的情况下,以文件内容的哈希值作为文件名
String key = Checker.checkNull(prefixCB.getValue());
String[] paths = selectedFileTA.getText().split("\n");
// 去掉\r\n的长度
int endIndex = QiniuValueConsts.UPLOADING.length() - 2;
Platform.runLater(() -> uploadStatusTA.deleteText(0,
QiniuValueConsts.CONFIG_UPLOAD_ENVIRONMENT.length() - 1));
// 总文件数
for (String path : paths) {
if (Checker.isNotEmpty(path)) {
Platform.runLater(() -> uploadStatusTA.insertText(0, QiniuValueConsts.UPLOADING));
String filename = "";
String url = "http://" + QiniuApplication.getConfigBean().getUrl(bucket) + "/";
File file = new File(path);
try {
// 判断文件是否存在
if (file.exists()) {
// 保持文件相对父文件夹的路径
if (keepPathCB.isSelected() && Checker.isNotEmpty(rootPath)) {
for (String root : rootPath) {
if (file.getAbsolutePath().startsWith(root)) {
String postKey = root.substring(root.lastIndexOf(File.separator) + 1);
filename = key + postKey + file.getAbsolutePath().substring(root.length());
break;
}
}
}
if (Checker.isEmpty(filename)) {
filename = key + file.getName();
}
service.uploadFile(bucket, path, filename);
String now = DateUtil.formatDate(new Date());
status = StrUtil.format(UPLOAD_STATUS_TEMPLATE, now, url, filename, path);
} else if (Checker.isHyperLink(path)) {
// 抓取网络文件到空间中
filename = key + QiniuUtils.getFileName(path);
SdkConfigurer.getBucketManager().fetch(path, bucket, filename);
String now = DateUtil.formatDate(new Date());
status = StrUtil.format(UPLOAD_STATUS_TEMPLATE, now, url, filename, path);
} else {
// 文件不存在
status = DateUtil.formatDate(new Date()) + "\tfailed\t" + path;
}
} catch (QiniuException e) {
status = DateUtil.formatDate(new Date()) + "\terror\t" + path;
Platform.runLater(() -> DialogUtils.showException(QiniuValueConsts.UPLOAD_ERROR, e));
}
Platform.runLater(() -> {
uploadStatusTA.deleteText(0, endIndex);
uploadStatusTA.insertText(0, status);
});
}
Platform.runLater(() -> selectedFileTA.deleteText(0, path.length() + (paths.length > 1 ? 1 : 0)));
}
rootPath.clear();
Platform.runLater(() -> {
// 将光标移到最前面
uploadStatusTA.positionCaret(0);
// 清空待上传的文件列表
selectedFileTA.clear();
});
mapResourceData();
// 添加文件前缀到配置文件
savePrefix(key);
});
}
/**
* 保存前缀
*/
private void savePrefix(String key) {
if (Checker.isNotEmpty(key) && !QiniuApplication.getConfigBean().getPrefixes().contains(key)) {
Platform.runLater(() -> prefixCB.getItems().add(key));
QiniuApplication.getConfigBean().getPrefixes().add(key);
ConfigUtils.writeConfig();
}
}
/**
* 打开配置文件
*/
public void openConfigFile() {
try {
Desktop.getDesktop().open(new File(QiniuValueConsts.CONFIG_PATH));
// 用户触发是否重载配置文件
Optional<ButtonType> result = DialogUtils.showConfirmation(QiniuValueConsts.RELOAD_CONFIG);
if (result.isPresent() && result.get() == ButtonType.OK) {
// 重新载入配置文件
bucketCB.getItems().clear();
prefixCB.getItems().clear();
ConfigUtils.loadConfig();
}
} catch (Exception e) {
DialogUtils.showException(QiniuValueConsts.OPEN_FILE_ERROR, e);
}
}
/**
* 显示重置密钥的弹窗
*/
public void showKeyDialog() {
boolean ok = dialog.showKeyDialog();
if (ok && Checker.isNotEmpty(zoneTF.getText())) {
// 配置新的环境
SdkConfigurer.configUploadEnv(zoneTF.getText(), bucketCB.getValue());
}
}
/**
* 显示添加存储空间的弹窗
*/
public void showBucketDialog() {
dialog.showBucketDialog();
}
public enum DownloadWay {
// 下载的方式,包括私有和公有
PRIVATE, PUBLIC
}
}
... ...
package org.code4everything.qiniu.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 桶信息
*
* @author pantao
* @since 2018/11/13
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BucketBean implements Serializable {
private String bucket;
private String zone;
private String url;
}
... ...
package org.code4everything.qiniu.model;
import cn.hutool.core.collection.CollectionUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Objects;
/**
* 应用配置信息
*
* @author pantao
* @since 2018/11/12
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ConfigBean implements Serializable {
private String accessKey;
private String secretKey;
private ArrayList<BucketBean> buckets;
private ArrayList<String> prefixes;
private String storagePath;
public String getBucket(String bucket) {
BucketBean bucketBean = getBucketBean(bucket);
return Objects.isNull(bucketBean) ? "" : bucketBean.getBucket();
}
public String getUrl(String bucket) {
BucketBean bucketBean = getBucketBean(bucket);
return Objects.isNull(bucketBean) ? "" : bucketBean.getUrl();
}
public String getZone(String bucket) {
BucketBean bucketBean = getBucketBean(bucket);
return Objects.isNull(bucketBean) ? "" : bucketBean.getZone();
}
public BucketBean getBucketBean(String bucket) {
if (CollectionUtil.isNotEmpty(buckets)) {
for (BucketBean bean : buckets) {
if (Objects.equals(bean.getBucket(), bucket)) {
return bean;
}
}
}
return null;
}
}
... ...
package org.code4everything.qiniu.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 文件信息
*
* @author pantao
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FileBean {
private String name;
private String type;
private String size;
private String time;
}
... ...
package org.code4everything.qiniu.service;
import com.qiniu.cdn.CdnResult;
import com.qiniu.common.QiniuException;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.model.BatchStatus;
import com.qiniu.storage.model.FileInfo;
import com.zhazhapan.util.Checker;
import com.zhazhapan.util.Formatter;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.chart.XYChart;
import org.apache.log4j.Logger;
import org.code4everything.qiniu.QiniuApplication;
import org.code4everything.qiniu.api.SdkConfigurer;
import org.code4everything.qiniu.api.SdkManager;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import org.code4everything.qiniu.controller.MainController;
import org.code4everything.qiniu.model.FileBean;
import org.code4everything.qiniu.util.DialogUtils;
import org.code4everything.qiniu.util.QiniuUtils;
import java.util.ArrayList;
import java.util.Map;
/**
* 七牛服务类
*
* @author pantao
* @since 2018/11/13
*/
public class QiniuService {
private static final Logger LOGGER = Logger.getLogger(QiniuService.class);
private final SdkManager sdkManager = new SdkManager();
/**
* 上传文件
*/
public void uploadFile(String bucket, String key, String filename) throws QiniuException {
String upToken = SdkConfigurer.getAuth().uploadToken(bucket, filename);
SdkConfigurer.getUploadManager().put(key, filename, upToken);
}
/**
* 获取空间文件列表
*/
public void listFile() {
MainController main = MainController.getInstance();
// 列举空间文件列表
BucketManager.FileListIterator iterator = sdkManager.getFileListIterator(main.bucketCB.getValue());
ArrayList<FileBean> files = new ArrayList<>();
main.setDataLength(0);
main.setDataSize(0);
// 处理结果
while (iterator.hasNext()) {
FileInfo[] items = iterator.next();
for (FileInfo item : items) {
main.setDataLength(main.getDataLength() + 1);
main.setDataSize(main.getDataSize() + item.fsize);
// 将七牛的时间单位(100纳秒)转换成毫秒,然后转换成时间
String time = Formatter.timeStampToString(item.putTime / 10000);
String size = Formatter.formatSize(item.fsize);
FileBean file = new FileBean(item.key, item.mimeType, size, time);
files.add(file);
}
}
main.setResData(FXCollections.observableArrayList(files));
}
/**
* 批量删除文件,单次批量请求的文件数量不得超过1000
*/
public void deleteFile(ObservableList<FileBean> fileBeans, String bucket) {
if (Checker.isNotEmpty(fileBeans) && QiniuUtils.checkNet()) {
// 生成待删除的文件列表
String[] files = new String[fileBeans.size()];
ArrayList<FileBean> selectedFiles = new ArrayList<>();
int i = 0;
for (FileBean fileBean : fileBeans) {
files[i++] = fileBean.getName();
selectedFiles.add(fileBean);
}
try {
BatchStatus[] batchStatusList = sdkManager.batchDelete(bucket, files);
MainController main = MainController.getInstance();
// 文件列表是否为搜索后结果
boolean isInSearch = Checker.isNotEmpty(main.searchTF.getText());
ObservableList<FileBean> currentRes = main.resTV.getItems();
// 更新界面数据
for (i = 0; i < files.length; i++) {
BatchStatus status = batchStatusList[i];
String file = files[i];
if (status.code == 200) {
main.getResData().remove(selectedFiles.get(i));
main.setDataLength(main.getDataLength() - 1);
main.setDataSize(main.getDataSize() - Formatter.sizeToLong(selectedFiles.get(i).getSize()));
if (isInSearch) {
currentRes.remove(selectedFiles.get(i));
}
} else {
LOGGER.error("delete " + file + " failed, message -> " + status.data.error);
DialogUtils.showError("删除文件:" + file + " 失败");
}
}
} catch (QiniuException e) {
DialogUtils.showException(QiniuValueConsts.DELETE_ERROR, e);
}
MainController.getInstance().countBucket();
}
}
/**
* 修改文件类型
*/
public boolean changeType(String fileName, String newType, String bucket) {
boolean result = true;
try {
sdkManager.changeMime(bucket, fileName, newType);
} catch (QiniuException e) {
DialogUtils.showException(QiniuValueConsts.CHANGE_FILE_TYPE_ERROR, e);
result = false;
}
return result;
}
/**
* 重命名文件
*/
public boolean renameFile(String bucket, String oldName, String newName) {
return moveFile(bucket, oldName, bucket, newName);
}
/**
* 移动文件
*/
private boolean moveFile(String srcBucket, String fromKey, String destBucket, String toKey) {
return moveOrCopyFile(srcBucket, fromKey, destBucket, toKey, SdkManager.FileAction.MOVE);
}
/**
* 移动或复制文件
*/
public boolean moveOrCopyFile(String srcBucket, String srcKey, String destBucket, String destKey,
SdkManager.FileAction fileAction) {
boolean result = true;
try {
sdkManager.moveOrCopyFile(srcBucket, srcKey, destBucket, destKey, fileAction);
} catch (QiniuException e) {
LOGGER.error("move file failed, message -> " + e.getMessage());
DialogUtils.showException(QiniuValueConsts.MOVE_OR_RENAME_ERROR, e);
result = false;
}
return result;
}
/**
* 设置文件生存时间
*/
public void setFileLife(String bucket, String key, int days) {
try {
sdkManager.deleteAfterDays(bucket, key, days);
LOGGER.info("set file life success");
} catch (QiniuException e) {
LOGGER.error("set file life error, message -> " + e.getMessage());
DialogUtils.showException(QiniuValueConsts.MOVE_OR_RENAME_ERROR, e);
}
}
/**
* 更新镜像源
*/
public void updateFile(String bucket, String key) {
try {
sdkManager.prefetch(bucket, key);
LOGGER.info("prefetch files success");
} catch (QiniuException e) {
LOGGER.error("prefetch files error, message -> " + e.getMessage());
DialogUtils.showException(QiniuValueConsts.UPDATE_ERROR, e);
}
}
/**
* 公有下载
*/
public void publicDownload(String fileName, String domain) {
QiniuUtils.download(QiniuUtils.buildUrl(fileName, domain));
}
/**
* 私有下载
*/
public void privateDownload(String fileName, String domain) {
QiniuUtils.download(sdkManager.getPrivateUrl(QiniuUtils.buildUrl(fileName, domain)));
}
/**
* 刷新文件
*/
public void refreshFile(ObservableList<FileBean> fileBeans, String domain) {
if (Checker.isNotEmpty(fileBeans)) {
String[] files = new String[fileBeans.size()];
int i = 0;
// 获取公有链接
for (FileBean fileBean : fileBeans) {
files[i++] = QiniuUtils.buildUrl(fileBean.getName(), domain);
}
try {
// 刷新文件
sdkManager.refreshFile(files);
} catch (QiniuException e) {
LOGGER.error("refresh files error, message -> " + e.getMessage());
DialogUtils.showException(e);
}
}
}
/**
* 日志下载
*/
public void downloadCdnLog(String logDate) {
if (Checker.isNotEmpty(QiniuApplication.getConfigBean().getBuckets()) && Checker.isDate(logDate)) {
// 转换域名成数组格式
String[] domains = new String[QiniuApplication.getConfigBean().getBuckets().size()];
for (int i = 0; i < QiniuApplication.getConfigBean().getBuckets().size(); i++) {
domains[i] = QiniuApplication.getConfigBean().getBuckets().get(i).getUrl();
}
Map<String, CdnResult.LogData[]> cdnLog = null;
try {
cdnLog = sdkManager.listCdnLog(domains, logDate);
} catch (QiniuException e) {
DialogUtils.showException(e);
}
if (Checker.isNotEmpty(cdnLog)) {
// 下载日志
for (Map.Entry<String, CdnResult.LogData[]> logs : cdnLog.entrySet()) {
for (CdnResult.LogData log : logs.getValue()) {
QiniuUtils.download(log.url);
}
}
}
}
}
/**
* 获取空间带宽统计,使用自定义单位
*/
public XYChart.Series<String, Long> getBucketBandwidth(String[] domains, String startDate, String endDate,
String unit) {
// 获取带宽数据
CdnResult.BandwidthResult bandwidthResult = null;
try {
bandwidthResult = sdkManager.getBandwidthData(domains, startDate, endDate);
} catch (QiniuException e) {
Platform.runLater(() -> DialogUtils.showException(QiniuValueConsts.BUCKET_BAND_ERROR, e));
}
// 设置图表
XYChart.Series<String, Long> series = new XYChart.Series<>();
series.setName(QiniuValueConsts.BUCKET_BANDWIDTH_COUNT.replaceAll("[A-Z]+", unit));
// 格式化数据
if (Checker.isNotNull(bandwidthResult) && Checker.isNotEmpty(bandwidthResult.data)) {
long unitSize = Formatter.sizeToLong("1 " + unit);
for (Map.Entry<String, CdnResult.BandwidthData> bandwidth : bandwidthResult.data.entrySet()) {
CdnResult.BandwidthData bandwidthData = bandwidth.getValue();
if (Checker.isNotNull(bandwidthData)) {
setSeries(bandwidthResult.time, bandwidthData.china, bandwidthData.oversea, series, unitSize);
}
}
}
return series;
}
/**
* 获取空间的流量统计,使用自定义单位
*/
public XYChart.Series<String, Long> getBucketFlux(String[] domains, String startDate, String endDate, String unit) {
// 获取流量数据
CdnResult.FluxResult fluxResult = null;
try {
fluxResult = sdkManager.getFluxData(domains, startDate, endDate);
} catch (QiniuException e) {
Platform.runLater(() -> DialogUtils.showException(QiniuValueConsts.BUCKET_FLUX_ERROR, e));
}
// 设置图表
XYChart.Series<String, Long> series = new XYChart.Series<>();
series.setName(QiniuValueConsts.BUCKET_FLUX_COUNT.replaceAll("[A-Z]+", unit));
// 格式化数据
if (Checker.isNotNull(fluxResult) && Checker.isNotEmpty(fluxResult.data)) {
long unitSize = Formatter.sizeToLong("1 " + unit);
for (Map.Entry<String, CdnResult.FluxData> flux : fluxResult.data.entrySet()) {
CdnResult.FluxData fluxData = flux.getValue();
if (Checker.isNotNull(fluxData)) {
setSeries(fluxResult.time, fluxData.china, fluxData.oversea, series, unitSize);
}
}
}
return series;
}
/**
* 处理带宽数据
*/
private void setSeries(String[] times, Long[] china, Long[] oversea, XYChart.Series<String, Long> series,
long unit) {
int i = 0;
for (String time : times) {
long size = 0;
if (Checker.isNotEmpty(china)) {
size += china[i];
}
if (Checker.isNotEmpty(oversea)) {
size += oversea[i];
}
series.getData().add(new XYChart.Data<>(time.substring(5, 10), size / unit));
i++;
}
}
}
... ...
package org.code4everything.qiniu.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import javafx.application.Platform;
import org.code4everything.qiniu.QiniuApplication;
import org.code4everything.qiniu.api.SdkConfigurer;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import org.code4everything.qiniu.controller.MainController;
import org.code4everything.qiniu.model.BucketBean;
import org.code4everything.qiniu.model.ConfigBean;
import java.util.ArrayList;
/**
* 配置文件工具类
*
* @author pantao
* @since 2018/11/12
**/
public class ConfigUtils {
private static final String CONFIG_PATH = QiniuValueConsts.CONFIG_PATH;
private ConfigUtils() {}
/**
* 加载配置文件
*/
public static void loadConfig() {
QiniuApplication.setConfigBean(new ConfigBean());
if (FileUtil.exist(CONFIG_PATH)) {
ConfigBean config = JSONObject.parseObject(FileUtil.readUtf8String(CONFIG_PATH), ConfigBean.class);
if (ObjectUtil.isNotNull(config)) {
QiniuApplication.setConfigBean(config);
if (StrUtil.isNotEmpty(config.getAccessKey()) && StrUtil.isNotEmpty(config.getSecretKey())) {
// 创建上传权限
SdkConfigurer.createAuth(config.getAccessKey(), config.getSecretKey());
}
MainController controller = MainController.getInstance();
if (CollectionUtil.isEmpty(config.getBuckets())) {
// 设置一个空的桶列表,防止出现空指针
config.setBuckets(new ArrayList<>());
} else {
Platform.runLater(() -> {
// 添加桶
config.getBuckets().forEach(bucket -> controller.appendBucket(bucket.getBucket()));
// 选中第一个桶
BucketBean bucket = config.getBuckets().get(0);
controller.bucketCB.setValue(bucket.getBucket());
controller.zoneTF.setText(bucket.getZone());
});
}
if (CollectionUtil.isEmpty(config.getPrefixes())) {
// 设置一个空的前缀列表,防止出现空指针
config.setPrefixes(new ArrayList<>());
} else {
// 添加前缀
Platform.runLater(() -> config.getPrefixes().forEach(prefix -> controller.prefixCB.getItems().add(prefix)));
}
return;
}
}
// 设置一个空的配置对象,防止出现空指针
ConfigBean configBean = new ConfigBean();
configBean.setPrefixes(new ArrayList<>());
configBean.setBuckets(new ArrayList<>());
QiniuApplication.setConfigBean(configBean);
writeConfig();
}
/**
* 写配置文件
*/
public static void writeConfig() {
FileUtil.writeUtf8String(JSONObject.toJSONString(QiniuApplication.getConfigBean(), true), CONFIG_PATH);
}
}
... ...
package org.code4everything.qiniu.util;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextInputDialog;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Modality;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Optional;
/**
* 弹窗工具类
*
* @author pantao 对JavaFX对话框进行封装
*/
public class DialogUtils {
private DialogUtils() {}
public static String showInputDialog(String header, String content, String defaultValue) {
TextInputDialog dialog = new TextInputDialog(defaultValue);
dialog.setTitle(QiniuValueConsts.MAIN_TITLE);
dialog.setHeaderText(header);
dialog.setContentText(content);
Optional<String> result = dialog.showAndWait();
return result.orElse(null);
}
public static Optional<ButtonType> showInformation(String content) {
return showInformation(null, content);
}
public static Optional<ButtonType> showInformation(String header, String content) {
return showAlert(header, content, AlertType.INFORMATION);
}
public static Optional<ButtonType> showWarning(String content) {
return showWarning(null, content);
}
public static Optional<ButtonType> showWarning(String header, String content) {
return showAlert(header, content, AlertType.WARNING);
}
public static Optional<ButtonType> showError(String content) {
return showError(null, content);
}
public static Optional<ButtonType> showError(String header, String content) {
return showAlert(header, content, AlertType.ERROR);
}
public static Optional<ButtonType> showConfirmation(String content) {
return showConfirmation(null, content);
}
public static Optional<ButtonType> showConfirmation(String header, String content) {
return showAlert(header, content, AlertType.CONFIRMATION);
}
public static Optional<ButtonType> showException(Exception e) {
return showException(null, e);
}
public static void showFatalError(String header, Exception e) {
showException(header, e);
System.exit(0);
}
public static Optional<ButtonType> showException(String header, Exception e) {
// 获取一个警告对象
Alert alert = getAlert(header, "错误信息追踪:", AlertType.ERROR);
// 打印异常信息
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
e.printStackTrace(printWriter);
String exception = stringWriter.toString();
// 显示异常信息
TextArea textArea = new TextArea(exception);
textArea.setEditable(false);
textArea.setWrapText(true);
// 设置弹窗容器
textArea.setMaxWidth(Double.MAX_VALUE);
textArea.setMaxHeight(Double.MAX_VALUE);
GridPane.setVgrow(textArea, Priority.ALWAYS);
GridPane.setHgrow(textArea, Priority.ALWAYS);
GridPane gridPane = new GridPane();
gridPane.setMaxWidth(Double.MAX_VALUE);
gridPane.add(textArea, 0, 0);
alert.getDialogPane().setExpandableContent(gridPane);
return alert.showAndWait();
}
public static Optional<ButtonType> showAlert(String content) {
return showAlert(null, content);
}
public static Optional<ButtonType> showAlert(String content, AlertType alertType) {
return showAlert(null, content, alertType);
}
public static Optional<ButtonType> showAlert(String header, String content) {
return showAlert(header, content, AlertType.INFORMATION);
}
public static Optional<ButtonType> showAlert(String header, String content, AlertType alertType) {
return showAlert(header, content, alertType, Modality.NONE, null, StageStyle.DECORATED);
}
public static Optional<ButtonType> showAlert(String header, String content, AlertType alertType,
Modality modality, Window window, StageStyle style) {
return getAlert(header, content, alertType, modality, window, style).showAndWait();
}
public static Alert getAlert(String header, String content, AlertType alertType) {
return getAlert(header, content, alertType, Modality.APPLICATION_MODAL, null, StageStyle.DECORATED);
}
public static Alert getAlert(String header, String content, AlertType alertType, Modality modality, Window window
, StageStyle style) {
Alert alert = new Alert(alertType);
alert.setTitle(QiniuValueConsts.MAIN_TITLE);
alert.setHeaderText(header);
alert.setContentText(content);
alert.initModality(modality);
alert.initOwner(window);
alert.initStyle(style);
return alert;
}
}
... ...
package org.code4everything.qiniu.util;
import com.zhazhapan.util.Checker;
import com.zhazhapan.util.dialog.Dialogs;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.stage.Modality;
import javafx.util.Pair;
import org.code4everything.qiniu.QiniuApplication;
import org.code4everything.qiniu.api.SdkConfigurer;
import org.code4everything.qiniu.api.SdkManager;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import org.code4everything.qiniu.controller.MainController;
import org.code4everything.qiniu.model.BucketBean;
import java.util.Optional;
/**
* 应用弹窗
*
* @author pantao
* @since 2018/11/13
*/
public class QiniuDialog {
/**
* 显示移动文件的弹窗
*/
public Pair<SdkManager.FileAction, String[]> showFileDialog(String bucket, String key, boolean setKey) {
MainController main = MainController.getInstance();
ButtonType ok = new ButtonType(QiniuValueConsts.OK, ButtonBar.ButtonData.OK_DONE);
Dialog<String[]> dialog = getDialog(ok);
// 文件名输入框
TextField keyTextField = new TextField();
keyTextField.setPrefWidth(300);
keyTextField.setPromptText(QiniuValueConsts.FILE_NAME);
keyTextField.setText(key);
// 空间选择框
ComboBox<String> bucketCombo = new ComboBox<>();
bucketCombo.getItems().addAll(main.bucketCB.getItems());
bucketCombo.setValue(bucket);
// 保存文件副本复选框
CheckBox copyAsCheckBox = new CheckBox(QiniuValueConsts.COPY_AS);
copyAsCheckBox.setSelected(true);
// 设置容器
GridPane grid = Dialogs.getGridPane();
grid.add(copyAsCheckBox, 0, 0, 2, 1);
grid.add(new Label(QiniuValueConsts.BUCKET_NAME), 0, 1);
grid.add(bucketCombo, 1, 1);
if (setKey) {
// 显示文件名输入框
grid.add(new Label(QiniuValueConsts.FILE_NAME), 0, 2);
grid.add(keyTextField, 1, 2);
Platform.runLater(keyTextField::requestFocus);
}
dialog.getDialogPane().setContent(grid);
// 数据转换器
dialog.setResultConverter(dialogButton -> {
if (dialogButton == ok) {
return new String[]{bucketCombo.getValue(), keyTextField.getText()};
}
return null;
});
// 读取数据
Optional<String[]> result = dialog.showAndWait();
if (result.isPresent()) {
bucket = bucketCombo.getValue();
key = keyTextField.getText();
SdkManager.FileAction action = copyAsCheckBox.isSelected() ? SdkManager.FileAction.COPY :
SdkManager.FileAction.MOVE;
return new Pair<>(action, new String[]{bucket, key});
} else {
return null;
}
}
/**
* 显示输入密钥的对话框
*
* @return 返回用户是否点击确定按钮
*/
public boolean showKeyDialog() {
ButtonType ok = new ButtonType(QiniuValueConsts.OK, ButtonBar.ButtonData.OK_DONE);
Dialog<String[]> dialog = getDialog(ok);
// 文本框
TextField ak = new TextField();
ak.setMinWidth(400);
ak.setPromptText("Access Key");
TextField sk = new TextField();
sk.setPromptText("Secret Key");
// 设置超链接
Hyperlink hyperlink = new Hyperlink("查看我的KEY:" + QiniuValueConsts.QINIU_KEY_URL);
hyperlink.setOnAction(event -> QiniuUtils.openLink(QiniuValueConsts.QINIU_KEY_URL));
// 设置容器
GridPane grid = Dialogs.getGridPane();
grid.add(hyperlink, 0, 0, 2, 1);
grid.add(new Label("Access Key:"), 0, 1);
grid.add(ak, 1, 1);
grid.add(new Label("Secret Key:"), 0, 2);
grid.add(sk, 1, 2);
Node okButton = dialog.getDialogPane().lookupButton(ok);
okButton.setDisable(true);
dialog.getDialogPane().setContent(grid);
Platform.runLater(ak::requestFocus);
// 监听文本框的输入状态
ak.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || sk.getText().trim().isEmpty()));
sk.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || ak.getText().trim().isEmpty()));
// 等待用户操作
Optional<String[]> result = dialog.showAndWait();
// 处理结果
if (result.isPresent() && Checker.isNotEmpty(ak.getText()) && Checker.isNotEmpty(sk.getText())) {
QiniuApplication.getConfigBean().setAccessKey(ak.getText());
QiniuApplication.getConfigBean().setSecretKey(sk.getText());
SdkConfigurer.createAuth(ak.getText(), sk.getText());
ConfigUtils.writeConfig();
return true;
}
return false;
}
/**
* 显示添加桶的弹窗
*/
public void showBucketDialog() {
ButtonType ok = new ButtonType(QiniuValueConsts.OK, ButtonBar.ButtonData.OK_DONE);
Dialog<String[]> dialog = getDialog(ok);
// 桶名称输入框
TextField bucket = new TextField();
bucket.setPromptText(QiniuValueConsts.BUCKET_NAME);
// 桶域名输入框
TextField url = new TextField();
url.setPromptText(QiniuValueConsts.BUCKET_URL);
// 桶区域输入框
ComboBox<String> zone = new ComboBox<>();
zone.getItems().addAll(QiniuValueConsts.BUCKET_NAME_ARRAY);
zone.setValue(QiniuValueConsts.BUCKET_NAME_ARRAY[0]);
// 设置容器
GridPane grid = Dialogs.getGridPane();
grid.add(new Label(QiniuValueConsts.BUCKET_NAME), 0, 0);
grid.add(bucket, 1, 0);
grid.add(new Label(QiniuValueConsts.BUCKET_URL), 0, 1);
grid.add(url, 1, 1);
grid.add(new Label(QiniuValueConsts.BUCKET_ZONE_NAME), 0, 2);
grid.add(zone, 1, 2);
Node okButton = dialog.getDialogPane().lookupButton(ok);
okButton.setDisable(true);
dialog.getDialogPane().setContent(grid);
Platform.runLater(bucket::requestFocus);
// 监听文本框的输入状态
bucket.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || url.getText().isEmpty()));
url.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || bucket.getText().isEmpty()));
// 结果转换器
dialog.setResultConverter(dialogButton -> {
if (dialogButton == ok) {
return new String[]{bucket.getText(), zone.getValue(), (Checker.isHyperLink(url.getText()) ?
url.getText() : "example.com")};
}
return null;
});
// 等待用户操作
Optional<String[]> result = dialog.showAndWait();
result.ifPresent(res -> {
// 处理结果
Platform.runLater(() -> MainController.getInstance().appendBucket(res[0]));
BucketBean bucketBean = new BucketBean(res[0], res[1], res[2]);
QiniuApplication.getConfigBean().getBuckets().add(bucketBean);
ConfigUtils.writeConfig();
});
}
private Dialog<String[]> getDialog(ButtonType ok) {
Dialog<String[]> dialog = new Dialog<>();
dialog.setTitle(QiniuValueConsts.MAIN_TITLE);
dialog.setHeaderText(null);
dialog.initModality(Modality.APPLICATION_MODAL);
// 自定义确认和取消按钮
ButtonType cancel = new ButtonType(QiniuValueConsts.CANCEL, ButtonBar.ButtonData.CANCEL_CLOSE);
dialog.getDialogPane().getButtonTypes().addAll(ok, cancel);
return dialog;
}
}
... ...
package org.code4everything.qiniu.util;
import cn.hutool.core.lang.Validator;
import cn.hutool.http.HttpUtil;
import com.zhazhapan.util.FileExecutor;
import com.zhazhapan.util.Formatter;
import com.zhazhapan.util.ThreadPool;
import com.zhazhapan.util.Utils;
import com.zhazhapan.util.dialog.Alerts;
import org.apache.log4j.Logger;
import org.code4everything.qiniu.QiniuApplication;
import org.code4everything.qiniu.constant.QiniuValueConsts;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLEncoder;
/**
* @author pantao
* @since 2018/4/14
*/
public class QiniuUtils {
private static final Logger LOGGER = Logger.getLogger(QiniuUtils.class);
private static final String HTTP = "http";
private QiniuUtils() {}
/**
* 下载文件
*
* @param url 文件链接
*/
public static void download(String url) {
// 验证存储路径
if (Validator.isEmpty(QiniuApplication.getConfigBean().getStoragePath())) {
// 显示存储路径输入框
String storagePath = DialogUtils.showInputDialog(null, QiniuValueConsts.CONFIG_DOWNLOAD_PATH,
Utils.getCurrentWorkDir());
if (Validator.isEmpty(storagePath)) {
return;
}
QiniuApplication.getConfigBean().setStoragePath(storagePath);
ConfigUtils.writeConfig();
}
final String dest = QiniuApplication.getConfigBean().getStoragePath();
// 下载文件
ThreadPool.executor.execute(() -> HttpUtil.downloadFile(url, dest));
}
/**
* 检查是否连接网络
*/
public static boolean checkNet() {
try {
URL url = new URL("https://www.qiniu.com/");
InputStream in = url.openStream();
in.close();
return true;
} catch (IOException e) {
LOGGER.error("there is no connection to the network");
return false;
}
}
public static void saveLogFile(String file, String content) {
try {
FileExecutor.saveLogFile(file, content);
} catch (IOException e) {
Alerts.showError(QiniuValueConsts.MAIN_TITLE, e.getMessage());
}
}
public static void saveFile(File file, String content) {
try {
FileExecutor.saveFile(file, content);
} catch (IOException e) {
Alerts.showError(QiniuValueConsts.MAIN_TITLE, e.getMessage());
}
}
public static void openLink(String url) {
try {
Utils.openLink(url);
} catch (Exception e) {
Alerts.showError(QiniuValueConsts.MAIN_TITLE, e.getMessage());
}
}
public static String getFileName(String string) {
try {
return Formatter.getFileName(string);
} catch (UnsupportedEncodingException e) {
LOGGER.error("get file name of url failed, message -> " + e.getMessage());
return "";
}
}
/**
* 拼接链接
*/
public static String buildUrl(String fileName, String domain) {
if (!domain.startsWith(HTTP)) {
domain = HTTP + "://" + domain;
}
fileName = fileName.replaceAll(" ", "qn_code_per_20").replaceAll("/", "qn_code_per_2F");
try {
fileName = URLEncoder.encode(fileName, "utf-8").replaceAll("qn_code_per_2F", "/");
return String.format("%s/%s", domain, fileName.replaceAll("qn_code_per_20", "%20"));
} catch (UnsupportedEncodingException e) {
LOGGER.error("encode url failed, message -> " + e.getMessage());
return "";
}
}
}
... ...
log4j.rootCategory=INFO, file
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.file=logs/qiniu
log4j.appender.file.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %c{1}:%L - %m%n
... ...
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Font?>
<VBox xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.code4everything.qiniu.controller.MainController">
<BorderPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="600.0"
prefWidth="700.0" VBox.vgrow="ALWAYS">
<center>
<TabPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="50.0"
prefWidth="700.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
<Tab text="文件上传">
<HBox>
<SplitPane dividerPositions="0.6" prefHeight="520.0" prefWidth="702.0" HBox.hgrow="ALWAYS">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/>
</padding>
<VBox>
<TextArea fx:id="uploadStatusTA" editable="false"
maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="504.0" prefWidth="336.0" promptText="文件上传状态" VBox.vgrow="ALWAYS">
<contextMenu>
<ContextMenu>
<items>
<MenuItem mnemonicParsing="false" onAction="#clearUploadStatus"
text="清空"/>
<MenuItem mnemonicParsing="false" onAction="#saveUploadStatus"
text="另存为"/>
<MenuItem mnemonicParsing="false" onAction="#copyUploadStatus"
text="复制"/>
</items>
</ContextMenu>
</contextMenu>
<VBox.margin>
<Insets right="10.0"/>
</VBox.margin>
</TextArea>
</VBox>
<VBox prefHeight="500.0" prefWidth="171.0">
<ComboBox fx:id="prefixCB" editable="true" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" prefHeight="35.0" prefWidth="277.0"
promptText="文件前缀, 不设置则为空" VBox.vgrow="NEVER">
<VBox.margin>
<Insets left="10.0"/>
</VBox.margin>
</ComboBox>
<HBox prefHeight="100.0" prefWidth="200.0" VBox.vgrow="NEVER">
<padding>
<Insets left="10.0" right="10.0" top="10.0"/>
</padding>
<CheckBox fx:id="recursiveCB" mnemonicParsing="false" text="文件夹递归"
selected="true"/>
<CheckBox fx:id="keepPathCB" mnemonicParsing="false" text="保持文件夹路径" selected="true">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</CheckBox>
</HBox>
<TextArea fx:id="selectedFileTA" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" onDragDropped="#dragFileDropped"
onDragOver="#dragFileOver" prefHeight="800.0" prefWidth="332.0"
promptText="文件路径, 一个文件一行, 支持拖曳文件, 支持抓取网络文件" VBox.vgrow="ALWAYS">
<VBox.margin>
<Insets left="10.0" top="10.0"/>
</VBox.margin>
</TextArea>
<HBox alignment="TOP_CENTER" VBox.vgrow="NEVER">
<VBox.margin>
<Insets left="10.0" top="10.0"/>
</VBox.margin>
<Button contentDisplay="CENTER" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" mnemonicParsing="false"
onAction="#showOpenFileDialog" prefHeight="27.0" prefWidth="156.0"
text="选择文件"
HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets right="10.0"/>
</HBox.margin>
</Button>
<Button alignment="CENTER" maxHeight="1.7976931348623157E308"
maxWidth="1.7976931348623157E308" mnemonicParsing="false"
onAction="#uploadFile" prefHeight="27.0" prefWidth="156.0" text="开始上传"
HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Button>
</HBox>
</VBox>
</SplitPane>
</HBox>
</Tab>
<Tab text="资源管理">
<VBox>
<HBox alignment="CENTER_LEFT" prefHeight="52.0" prefWidth="700.0" VBox.vgrow="NEVER">
<padding>
<Insets left="10.0"/>
</padding>
<Label alignment="CENTER" text="空间域名" HBox.hgrow="NEVER">
<font>
<Font size="14.0"/>
</font>
</Label>
<TextField fx:id="domainTF" editable="false" prefHeight="27.0"
prefWidth="245.0" promptText="空间域名" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
<TextField fx:id="searchTF" onKeyReleased="#searchFile" prefHeight="27.0"
prefWidth="275.0" promptText="搜索文件, 支持正则表达式" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
<HBox alignment="CENTER_RIGHT" HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets/>
</HBox.margin>
<padding>
<Insets right="15.0"/>
</padding>
<Label fx:id="lengthLabel"/>
</HBox>
</HBox>
<HBox VBox.vgrow="ALWAYS">
<TableView fx:id="resTV" editable="true" prefHeight="479.0" prefWidth="602.0"
HBox.hgrow="ALWAYS">
<columns>
<TableColumn fx:id="nameTC" prefWidth="278.0" text="文件名"/>
<TableColumn fx:id="typeTC" minWidth="5.0" prefWidth="81.0" text="文件类型"/>
<TableColumn fx:id="sizeTC" prefWidth="90.0" text="文件大小"/>
<TableColumn fx:id="timeTC" prefWidth="152.0" text="最后更新时间"/>
</columns>
<HBox.margin>
<Insets bottom="10.0" left="10.0"/>
</HBox.margin>
</TableView>
<VBox alignment="TOP_CENTER" prefHeight="200.0" prefWidth="100.0" HBox.hgrow="NEVER">
<Button mnemonicParsing="false" onAction="#refreshResourceData" text="刷新列表"
VBox.vgrow="NEVER"/>
<Button mnemonicParsing="false" onAction="#copyLink" text="复制链接" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#deleteFile" text="删除文件" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#showFileMovableDialog" text="移动到..."
VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#setLife" text="生存时间" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#updateFile" text="更新镜像" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#publicDownload" text="公有下载"
VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#privateDownload" text="私有下载"
VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#openFile" text="打开文件" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#refreshFile" text="文件刷新" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#downloadCdnLog" text="日志下载"
VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
</Button>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<VBox.margin>
<Insets top="10.0"/>
</VBox.margin>
<padding>
<Insets bottom="10.0"/>
</padding>
<Label fx:id="sizeLabel"/>
</VBox>
</VBox>
</HBox>
</VBox>
</Tab>
<Tab text="数据统计">
<VBox>
<HBox alignment="CENTER" minHeight="-Infinity" minWidth="-Infinity" prefHeight="40.0"
prefWidth="700.0" VBox.vgrow="NEVER">
<Label text="开始日期" HBox.hgrow="NEVER">
<font>
<Font size="14.0"/>
</font>
<HBox.margin>
<Insets/>
</HBox.margin>
</Label>
<DatePicker fx:id="startDP" onAction="#dateChange" prefWidth="125.0" promptText="开始日期"
HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</DatePicker>
<Label text="结束日期">
<font>
<Font size="14.0"/>
</font>
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Label>
<DatePicker fx:id="endDP" onAction="#dateChange" prefWidth="125.0" promptText="结束日期"
HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</DatePicker>
<ComboBox fx:id="fluxUnitCB" prefWidth="70.0" promptText="统计单位" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</ComboBox>
<ComboBox fx:id="bandwidthUnitCB" prefWidth="70.0" promptText="统计单位">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</ComboBox>
<Label text="时间跨度不超过31天" HBox.hgrow="NEVER">
<font>
<Font size="14.0"/>
</font>
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Label>
</HBox>
<AreaChart fx:id="fluxAC" VBox.vgrow="ALWAYS">
<xAxis>
<CategoryAxis side="BOTTOM"/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</AreaChart>
<AreaChart fx:id="bandwidthAC" VBox.vgrow="ALWAYS">
<xAxis>
<CategoryAxis side="BOTTOM"/>
</xAxis>
<yAxis>
<NumberAxis side="LEFT"/>
</yAxis>
</AreaChart>
</VBox>
</Tab>
</TabPane>
</center>
<top>
<VBox BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets/>
</BorderPane.margin>
<HBox VBox.vgrow="NEVER">
<padding>
<Insets top="10" bottom="10"/>
</padding>
<ComboBox fx:id="bucketCB" minHeight="-Infinity" minWidth="-Infinity" prefHeight="27.0"
prefWidth="205.0" promptText="还没有选择存储空间" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</ComboBox>
<TextField fx:id="zoneTF" editable="false" promptText="存储区域" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
<Button mnemonicParsing="false" onAction="#showBucketDialog" text="添加存储空间"
HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#showKeyDialog" text="重置密钥" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Button>
<Button mnemonicParsing="false" onAction="#openConfigFile" text="打开配置文件" HBox.hgrow="NEVER">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</Button>
</HBox>
</VBox>
</top>
</BorderPane>
</VBox>
... ...
/**
*
*/
package org.code4everything.qiniu;
import org.junit.Test;
import com.zhazhapan.util.Formatter;
/**
* @author pantao
*
*/
public class FormatterTest {
@Test
public void testSizeToLong() {
String[] sizes = { "23.12 MB", "12.89 KB", "23 B", "23.77 GB", "89.12 TB" };
for (String size : sizes) {
System.out.println(Formatter.sizeToLong(size));
}
}
}
... ...
/**
*
*/
package org.code4everything.qiniu;
import org.junit.Test;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.zhazhapan.util.Checker;
/**
* @author pantao
*
*/
public class GsonTest {
public String configJson = "{accessKey:123456,secretKey:abcdef,buckets:[{bucket:zhazhapan,zone:华东}]}";
@Test
public void testGson() {
JsonObject json = new JsonParser().parse(configJson).getAsJsonObject();
JsonElement buckets = json.get("buckets");
if (Checker.isNotNull(buckets)) {
JsonArray array = buckets.getAsJsonArray();
for (JsonElement element : array) {
System.out.println(((JsonObject) element).get("bucket").getAsString());
}
}
}
}
... ...
package org.code4everything.qiniu;
import org.junit.Test;
/**
* @author pantao
*/
public class QiniuApplicationTest {
@Test
public void testContext() {
}
}
... ...
/**
*
*/
package org.code4everything.qiniu;
import com.zhazhapan.util.Checker;
import org.code4everything.qiniu.util.QiniuUtils;
import org.junit.Test;
/**
* @author pantao
*/
public class RegexpTest {
@Test
public void testGetFileName() {
String[] files = {"http://oxns0wnsc.bkt.clouddn.com/fims/css/distpicker.css", "http://oxns0wnsc.bkt.clouddn"
+ ".com/fims/css/distpicker", "http://oxns0wnsc.bkt.clouddn.com/fims/css/easy-responsive-tabs.css",
"http://oxns0wnsc.bkt.clouddn.com/zhazhapan/test/%E6%BD%98%E6%BB%94-18780459330-Java%E5%BC%80%E5%8F"
+ "%91.docx"};
for (String file : files) {
System.out.println(QiniuUtils.getFileName(file));
}
}
@Test
public void testHyperlink() {
System.out.println(Checker.isHyperLink("https://portal.qiniu.com/bucket/zhazhapan/resource"));
System.out.println(Checker.isHyperLink("http://portal.qiniu.com/bucket/zhazhapan/resource"));
System.out.println(Checker.isHyperLink("portal.qiniu.com/bucket/zhazhapan/resource"));
System.out.println(Checker.isHyperLink("oxns0wnsc.bkt.clouddn.com"));
System.out.println(Checker.isHyperLink("hhttp://portal"));
System.out.println(Checker.isHyperLink("https://cn.wordpress.org/wordpress-4.8.1-zh_CN.zip"));
}
}
... ...