├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── LICENSE ├── README.md ├── _config.yml ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── code4everything │ │ └── qiniu │ │ ├── QiniuApplication.java │ │ ├── api │ │ ├── SdkConfigurer.java │ │ └── SdkManager.java │ │ ├── constant │ │ └── QiniuValueConsts.java │ │ ├── controller │ │ └── MainController.java │ │ ├── model │ │ ├── BucketBean.java │ │ ├── ConfigBean.java │ │ └── FileBean.java │ │ ├── service │ │ └── QiniuService.java │ │ └── util │ │ ├── ConfigUtils.java │ │ ├── DialogUtils.java │ │ ├── QiniuDialog.java │ │ └── QiniuUtils.java └── resources │ ├── image │ └── qiniu.png │ ├── log4j.properties │ └── view │ └── Main.fxml └── test └── java └── org └── code4everything └── qiniu ├── FormatterTest.java ├── GsonTest.java ├── QiniuApplicationTest.java └── RegexpTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | logs/* 3 | config.json 4 | 5 | # Log file 6 | *.log 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | target/ 26 | pom.xml.tag 27 | pom.xml.releaseBackup 28 | pom.xml.versionsBackup 29 | pom.xml.next 30 | release.properties 31 | dependency-reduced-pom.xml 32 | buildNumber.properties 33 | .mvn/timing.properties 34 | 35 | # Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) 36 | !/.mvn/wrapper/maven-wrapper.jar 37 | 38 | ### IntelliJ IDEA ### 39 | .idea 40 | *.iws 41 | *.iml 42 | *.ipr 43 | 44 | .DS_Store 45 | !.mvn/wrapper/maven-wrapper.jar 46 | 47 | ### STS ### 48 | .apt_generated 49 | .classpath 50 | .factorypath 51 | .project 52 | .settings 53 | .springBeans 54 | 55 | ### NetBeans ### 56 | nbproject/private/ 57 | build/ 58 | nbbuild/ 59 | dist/ 60 | nbdist/ 61 | .nb-gradle/ 62 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4everything/qiniu/284253327473fc51e952b75db605719a096472e6/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 潘滔 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 欢迎体验我们全新的桌面端效率工具 2 | 3 | **欢迎体验我们全新的桌面端效率工具[RunFlow](https://myrest.top/myflow)。** 4 | 5 | > [https://myrest.top/myflow](https://myrest.top/myflow) 6 | 7 | ### 本仓库已停止更新,项目已迁移至[这里](https://gitee.com/code4everything/wetool-plugin) 8 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.zhazhapan 7 | qiniu 8 | 1.0.8 9 | jar 10 | 11 | qiniu 12 | 七牛同步工具 13 | 14 | 15 | UTF-8 16 | UTF-8 17 | 1.8 18 | 19 | 20 | 21 | 22 | com.qiniu 23 | qiniu-java-sdk 24 | [7.2.0, 7.2.99] 25 | 26 | 27 | com.zhazhapan 28 | util 29 | 1.1.1 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | 1.18.2 35 | 36 | 37 | 38 | 39 | 40 | 41 | org.apache.maven.plugins 42 | maven-compiler-plugin 43 | 44 | 1.8 45 | 1.8 46 | 47 | 48 | 49 | org.apache.maven.plugins 50 | maven-shade-plugin 51 | 2.3 52 | 53 | 54 | package 55 | 56 | shade 57 | 58 | 59 | 60 | 62 | org.code4everything.qiniu.QiniuApplication 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/QiniuApplication.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu; 2 | 3 | import com.zhazhapan.util.ThreadPool; 4 | import javafx.application.Application; 5 | import javafx.fxml.FXMLLoader; 6 | import javafx.scene.Scene; 7 | import javafx.scene.control.ButtonType; 8 | import javafx.scene.image.Image; 9 | import javafx.scene.layout.VBox; 10 | import javafx.stage.Stage; 11 | import org.apache.log4j.Logger; 12 | import org.code4everything.qiniu.constant.QiniuValueConsts; 13 | import org.code4everything.qiniu.model.ConfigBean; 14 | import org.code4everything.qiniu.util.ConfigUtils; 15 | import org.code4everything.qiniu.util.DialogUtils; 16 | 17 | import java.util.Optional; 18 | import java.util.concurrent.LinkedBlockingQueue; 19 | 20 | /** 21 | * @author pantao 22 | */ 23 | public class QiniuApplication extends Application { 24 | 25 | private static final Logger LOGGER = Logger.getLogger(QiniuApplication.class); 26 | 27 | private static Stage stage = null; 28 | 29 | private static ConfigBean configBean; 30 | 31 | public static Stage getStage() { 32 | return stage; 33 | } 34 | 35 | public static ConfigBean getConfigBean() { 36 | return configBean; 37 | } 38 | 39 | public static void setConfigBean(ConfigBean configBean) { 40 | QiniuApplication.configBean = configBean; 41 | } 42 | 43 | /** 44 | * 主程序入口 45 | */ 46 | public static void main(String[] args) { 47 | // 设置线程池大小 48 | ThreadPool.setMaximumPoolSize(10); 49 | // 设置线程池最大排队大小 50 | ThreadPool.setWorkQueue(new LinkedBlockingQueue<>(1024)); 51 | ThreadPool.init(); 52 | // 启动 JavaFX 应用 53 | launch(args); 54 | } 55 | 56 | /** 57 | * 由 JavaFX 调用 58 | */ 59 | @Override 60 | public void start(Stage stage) { 61 | try { 62 | // 加载视图页面 63 | VBox root = FXMLLoader.load(getClass().getResource(QiniuValueConsts.QINIU_VIEW_URL)); 64 | Scene scene = new Scene(root); 65 | stage.setScene(scene); 66 | } catch (Exception e) { 67 | LOGGER.error("init stage error: " + e.getMessage()); 68 | DialogUtils.showFatalError(QiniuValueConsts.INIT_APP_ERROR_HEADER, e); 69 | } 70 | // 设置图标 71 | stage.getIcons().add(new Image(getClass().getResourceAsStream("/image/qiniu.png"))); 72 | stage.setTitle(QiniuValueConsts.MAIN_TITLE); 73 | // 设置关闭窗口事件 74 | stage.setOnCloseRequest(event -> { 75 | Optional result = DialogUtils.showConfirmation(QiniuValueConsts.CONFIRM_EXIT); 76 | if (result.isPresent() && result.get() != ButtonType.OK) { 77 | // 取消退出事件 78 | event.consume(); 79 | return; 80 | } 81 | // 退出程序 82 | ThreadPool.executor.shutdown(); 83 | System.exit(0); 84 | }); 85 | QiniuApplication.stage = stage; 86 | stage.show(); 87 | // 加载配置文件 88 | ConfigUtils.loadConfig(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/api/SdkConfigurer.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.api; 2 | 3 | import com.qiniu.cdn.CdnManager; 4 | import com.qiniu.common.Zone; 5 | import com.qiniu.storage.BucketManager; 6 | import com.qiniu.storage.Configuration; 7 | import com.qiniu.storage.UploadManager; 8 | import com.qiniu.storage.persistent.FileRecorder; 9 | import com.qiniu.util.Auth; 10 | import com.zhazhapan.util.Utils; 11 | import org.apache.log4j.Logger; 12 | 13 | import java.io.IOException; 14 | import java.nio.file.Paths; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * @author pantao 20 | */ 21 | public class SdkConfigurer { 22 | 23 | private static final String[] BUCKET_NAME_ARRAY = {"华东", "华北", "华南", "北美"}; 24 | 25 | private static final Map ZONE = new HashMap<>(); 26 | 27 | private static final Logger LOGGER = Logger.getLogger(SdkConfigurer.class); 28 | 29 | private static Auth auth = null; 30 | 31 | private static UploadManager uploadManager = null; 32 | 33 | private static BucketManager bucketManager = null; 34 | 35 | private static CdnManager cdnManager = null; 36 | 37 | static { 38 | // 加载空间区域 39 | ZONE.put(BUCKET_NAME_ARRAY[0], Zone.zone0()); 40 | ZONE.put(BUCKET_NAME_ARRAY[1], Zone.zone1()); 41 | ZONE.put(BUCKET_NAME_ARRAY[2], Zone.zone2()); 42 | ZONE.put(BUCKET_NAME_ARRAY[3], Zone.zoneNa0()); 43 | } 44 | 45 | private SdkConfigurer() {} 46 | 47 | public static CdnManager getCdnManager() { 48 | return cdnManager; 49 | } 50 | 51 | public static BucketManager getBucketManager() { 52 | return bucketManager; 53 | } 54 | 55 | public static UploadManager getUploadManager() { 56 | return uploadManager; 57 | } 58 | 59 | public static Auth getAuth() { 60 | return auth; 61 | } 62 | 63 | /** 64 | * 创建上传需要的Auth 65 | */ 66 | public static void createAuth(String accessKey, String secretKey) { 67 | auth = Auth.create(accessKey, secretKey); 68 | cdnManager = new CdnManager(auth); 69 | } 70 | 71 | /** 72 | * 配置文件上传环境,不再做网络检查,请执行保证网络通畅 73 | */ 74 | public static boolean configUploadEnv(String zone, String bucket) { 75 | // 构造一个带指定Zone对象的配置类 76 | Configuration configuration = new Configuration(SdkConfigurer.ZONE.get(zone)); 77 | // 生成上传凭证,然后准备上传 78 | String workDir = Paths.get(Utils.getCurrentWorkDir(), bucket).toString(); 79 | try { 80 | FileRecorder fileRecorder = new FileRecorder(workDir); 81 | uploadManager = new UploadManager(configuration, fileRecorder); 82 | } catch (IOException e) { 83 | LOGGER.warn("load work directory failed, can't use file recorder"); 84 | uploadManager = new UploadManager(configuration); 85 | } 86 | bucketManager = new BucketManager(auth, configuration); 87 | return true; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/api/SdkManager.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.api; 2 | 3 | import com.qiniu.cdn.CdnResult; 4 | import com.qiniu.cdn.CdnResult.LogData; 5 | import com.qiniu.common.QiniuException; 6 | import com.qiniu.http.Response; 7 | import com.qiniu.storage.BucketManager; 8 | import com.qiniu.storage.model.BatchStatus; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * @author pantao 14 | */ 15 | public class SdkManager { 16 | 17 | /** 18 | * 自定义私有链接过期时间 19 | */ 20 | private static final long EXPIRE_IN_SECONDS = 24 * 60 * 60L; 21 | 22 | /** 23 | * 文件列表大小 24 | */ 25 | private static final int LIST_SIZE = 1000; 26 | 27 | /** 28 | * 获取空间带宽统计 29 | */ 30 | public CdnResult.BandwidthResult getBandwidthData(String[] domains, String startDate, String endDate) throws QiniuException { 31 | return SdkConfigurer.getCdnManager().getBandwidthData(domains, startDate, endDate, "day"); 32 | } 33 | 34 | /** 35 | * 获取空间的流量统计 36 | */ 37 | public CdnResult.FluxResult getFluxData(String[] domains, String startDate, String endDate) throws QiniuException { 38 | return SdkConfigurer.getCdnManager().getFluxData(domains, startDate, endDate, "day"); 39 | } 40 | 41 | /** 42 | * 日志下载,CDN 相关 43 | */ 44 | public Map listCdnLog(String[] domains, String logDate) throws QiniuException { 45 | return SdkConfigurer.getCdnManager().getCdnLogList(domains, logDate).data; 46 | } 47 | 48 | /** 49 | * 刷新文件,CDN 相关 50 | */ 51 | public void refreshFile(String[] files) throws QiniuException { 52 | // 单次方法调用刷新的链接不可以超过100个 53 | SdkConfigurer.getCdnManager().refreshUrls(files); 54 | } 55 | 56 | /** 57 | * 私有下载 58 | */ 59 | public String getPrivateUrl(String publicUrl) { 60 | return SdkConfigurer.getAuth().privateDownloadUrl(publicUrl, EXPIRE_IN_SECONDS); 61 | } 62 | 63 | /** 64 | * 更新镜像源 65 | */ 66 | public void prefetch(String bucket, String key) throws QiniuException { 67 | SdkConfigurer.getBucketManager().prefetch(bucket, key); 68 | } 69 | 70 | /** 71 | * 设置文件生存时间 72 | */ 73 | public void deleteAfterDays(String bucket, String key, int days) throws QiniuException { 74 | SdkConfigurer.getBucketManager().deleteAfterDays(bucket, key, days); 75 | } 76 | 77 | /** 78 | * 重命名文件 79 | */ 80 | public void renameFile(String bucket, String oldName, String newName) throws QiniuException { 81 | moveFile(bucket, oldName, bucket, newName); 82 | } 83 | 84 | /** 85 | * 移动文件 86 | */ 87 | public void moveFile(String srcBucket, String fromKey, String destBucket, String toKey) throws QiniuException { 88 | moveOrCopyFile(srcBucket, fromKey, destBucket, toKey, FileAction.MOVE); 89 | } 90 | 91 | /** 92 | * 移动或复制文件 93 | */ 94 | public void moveOrCopyFile(String srcBucket, String srcKey, String destBucket, String destKey, 95 | FileAction fileAction) throws QiniuException { 96 | if (FileAction.COPY == fileAction) { 97 | SdkConfigurer.getBucketManager().copy(srcBucket, srcKey, destBucket, destKey, true); 98 | } else { 99 | SdkConfigurer.getBucketManager().move(srcBucket, srcKey, destBucket, destKey, true); 100 | } 101 | } 102 | 103 | /** 104 | * 修改文件类型 105 | */ 106 | public void changeMime(String fileName, String newType, String bucket) throws QiniuException { 107 | SdkConfigurer.getBucketManager().changeMime(bucket, fileName, newType); 108 | } 109 | 110 | /** 111 | * 批量删除文件,单次批量请求的文件数量不得超过1000 112 | */ 113 | public BatchStatus[] batchDelete(String bucket, String[] keys) throws QiniuException { 114 | BucketManager.BatchOperations batchOperations = new BucketManager.BatchOperations(); 115 | batchOperations.addDeleteOp(bucket, keys); 116 | Response response = SdkConfigurer.getBucketManager().batch(batchOperations); 117 | return response.jsonToObject(BatchStatus[].class); 118 | } 119 | 120 | /** 121 | * 获取空间文件列表 122 | */ 123 | public BucketManager.FileListIterator getFileListIterator(String bucket) { 124 | return SdkConfigurer.getBucketManager().createFileListIterator(bucket, "", LIST_SIZE, ""); 125 | } 126 | 127 | public enum FileAction { 128 | // 复制或移动文件 129 | COPY, MOVE 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/constant/QiniuValueConsts.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.constant; 2 | 3 | import com.zhazhapan.util.Utils; 4 | 5 | import java.io.File; 6 | 7 | /** 8 | * 常量类 9 | * 10 | * @author pantao 11 | */ 12 | public class QiniuValueConsts { 13 | 14 | public static final String CONFIG_PATH = Utils.getCurrentWorkDir() + File.separator + "config.json"; 15 | 16 | public static final String QINIU_VIEW_URL = "/view/Main.fxml"; 17 | 18 | public static final String QINIU_KEY_URL = "https://portal.qiniu.com/user/key"; 19 | 20 | public static final String MAIN_TITLE = "七牛云管理工具"; 21 | 22 | public static final String INIT_APP_ERROR_HEADER = "初始化错误,无法继续运行"; 23 | 24 | public static final String OK = "确定"; 25 | 26 | public static final String CANCEL = "取消"; 27 | 28 | public static final String BUCKET_NAME = "空间名称"; 29 | 30 | public static final String BUCKET_ZONE_NAME = "存储区域"; 31 | 32 | public static final String BUCKET_URL = "空间域名"; 33 | 34 | public static final String[] BUCKET_NAME_ARRAY = {"华东", "华北", "华南", "北美"}; 35 | 36 | public static final String FILE_CHOOSER_TITLE = "选择需要上传的文件"; 37 | 38 | public static final String OPEN_FILE_ERROR = "打开文件失败"; 39 | 40 | public static final String UPLOAD_ERROR = "上传文件失败"; 41 | 42 | public static final String UPLOADING = "文件上传中,请耐心等待。。。。。。\r\n"; 43 | 44 | public static final String NEED_CHOOSE_BUCKET_OR_FILE = "请先选择一个存储空间或文件"; 45 | 46 | public static final String CONFIG_UPLOAD_ENVIRONMENT = "正在配置文件上传环境,请耐心等待。。。。。。\r\n"; 47 | 48 | public static final String RELOAD_CONFIG = "是否重新载入配置文件?"; 49 | 50 | public static final String DOMAIN_CONFIG_ERROR = "您还没有正确地配置空间域名"; 51 | 52 | public static final String REFRESH_SUCCESS = "刷新资源列表成功"; 53 | 54 | public static final String DELETE_ERROR = "删除文件时发生异常"; 55 | 56 | public static final String CHANGE_FILE_TYPE_ERROR = "删除文件发生异常"; 57 | 58 | public static final String MOVE_OR_RENAME_ERROR = "移动或重命名文件失败"; 59 | 60 | public static final String FILE_NAME = "文件名"; 61 | 62 | public static final String COPY_AS = "保存文件副本"; 63 | 64 | public static final String FILE_LIFE = "文件生存时间(天)"; 65 | 66 | public static final String UPDATE_ERROR = "更新镜像源失败"; 67 | 68 | public static final String DEFAULT_FILE_LIFE = "365"; 69 | 70 | public static final String CONFIG_DOWNLOAD_PATH = "配置文件下载路径"; 71 | 72 | public static final String INPUT_LOG_DATE = "请输入日志的日期"; 73 | 74 | public static final String BUCKET_FLUX_ERROR = "获取空间流量统计失败"; 75 | 76 | public static final String BUCKET_BAND_ERROR = "获取空间带宽统计失败"; 77 | 78 | public static final String BUCKET_FLUX_COUNT = "空间流量(KB)"; 79 | 80 | public static final String BUCKET_BANDWIDTH_COUNT = "空间带宽(KB)"; 81 | 82 | public static final long DATE_SPAN_OF_THIRTY_ONE = 31 * 24 * 60 * 60 * 1000L; 83 | 84 | public static final String CONFIRM_EXIT = "确定退出?"; 85 | 86 | private QiniuValueConsts() {} 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/controller/MainController.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.controller; 2 | 3 | import cn.hutool.core.date.DateUtil; 4 | import cn.hutool.core.util.StrUtil; 5 | import com.qiniu.common.QiniuException; 6 | import com.zhazhapan.util.Checker; 7 | import com.zhazhapan.util.Formatter; 8 | import com.zhazhapan.util.ThreadPool; 9 | import com.zhazhapan.util.Utils; 10 | import javafx.application.Platform; 11 | import javafx.collections.FXCollections; 12 | import javafx.collections.ObservableList; 13 | import javafx.fxml.FXML; 14 | import javafx.scene.chart.AreaChart; 15 | import javafx.scene.control.*; 16 | import javafx.scene.control.Label; 17 | import javafx.scene.control.TextArea; 18 | import javafx.scene.control.TextField; 19 | import javafx.scene.control.cell.PropertyValueFactory; 20 | import javafx.scene.control.cell.TextFieldTableCell; 21 | import javafx.scene.input.DragEvent; 22 | import javafx.scene.input.TransferMode; 23 | import javafx.stage.FileChooser; 24 | import javafx.util.Pair; 25 | import org.code4everything.qiniu.QiniuApplication; 26 | import org.code4everything.qiniu.api.SdkConfigurer; 27 | import org.code4everything.qiniu.api.SdkManager; 28 | import org.code4everything.qiniu.constant.QiniuValueConsts; 29 | import org.code4everything.qiniu.model.FileBean; 30 | import org.code4everything.qiniu.service.QiniuService; 31 | import org.code4everything.qiniu.util.ConfigUtils; 32 | import org.code4everything.qiniu.util.DialogUtils; 33 | import org.code4everything.qiniu.util.QiniuDialog; 34 | import org.code4everything.qiniu.util.QiniuUtils; 35 | 36 | import java.awt.*; 37 | import java.io.File; 38 | import java.time.LocalDate; 39 | import java.util.ArrayList; 40 | import java.util.Date; 41 | import java.util.List; 42 | import java.util.Optional; 43 | import java.util.regex.Pattern; 44 | 45 | /** 46 | * 界面控制类 47 | * 48 | * @author pantao 49 | */ 50 | public class MainController { 51 | 52 | private static final String UPLOAD_STATUS_TEMPLATE = "{}\tsuccess\t{}{}\t{}"; 53 | 54 | private static MainController mainController = null; 55 | 56 | private final QiniuService service = new QiniuService(); 57 | 58 | private final QiniuDialog dialog = new QiniuDialog(); 59 | 60 | @FXML 61 | public ComboBox bucketCB; 62 | 63 | @FXML 64 | public TextField zoneTF; 65 | 66 | @FXML 67 | public TextArea uploadStatusTA; 68 | 69 | @FXML 70 | public ComboBox prefixCB; 71 | 72 | @FXML 73 | public TableView resTV; 74 | 75 | @FXML 76 | public TextField searchTF; 77 | 78 | @FXML 79 | public CheckBox recursiveCB; 80 | 81 | @FXML 82 | public CheckBox keepPathCB; 83 | 84 | private ObservableList resData = null; 85 | 86 | /** 87 | * 空间总文件数 88 | */ 89 | private int dataLength = 0; 90 | 91 | /** 92 | * 空间使用总大小 93 | */ 94 | private long dataSize = 0; 95 | 96 | @FXML 97 | private TextArea selectedFileTA; 98 | 99 | @FXML 100 | private TextField domainTF; 101 | 102 | @FXML 103 | private TableColumn nameTC; 104 | 105 | @FXML 106 | private TableColumn typeTC; 107 | 108 | @FXML 109 | private TableColumn sizeTC; 110 | 111 | @FXML 112 | private TableColumn timeTC; 113 | 114 | @FXML 115 | private Label sizeLabel; 116 | 117 | @FXML 118 | private Label lengthLabel; 119 | 120 | @FXML 121 | private AreaChart fluxAC; 122 | 123 | @FXML 124 | private AreaChart bandwidthAC; 125 | 126 | @FXML 127 | private DatePicker startDP; 128 | 129 | @FXML 130 | private DatePicker endDP; 131 | 132 | @FXML 133 | private ComboBox fluxUnitCB; 134 | 135 | @FXML 136 | private ComboBox bandwidthUnitCB; 137 | 138 | private String status = ""; 139 | 140 | /** 141 | * 父文件夹路径 142 | */ 143 | private List rootPath = new ArrayList<>(); 144 | 145 | public static MainController getInstance() { 146 | return mainController; 147 | } 148 | 149 | public ObservableList getResData() { 150 | return resData; 151 | } 152 | 153 | public void setResData(ObservableList resData) { 154 | this.resData = resData; 155 | } 156 | 157 | public int getDataLength() { 158 | return dataLength; 159 | } 160 | 161 | public void setDataLength(int dataLength) { 162 | this.dataLength = dataLength; 163 | } 164 | 165 | public long getDataSize() { 166 | return dataSize; 167 | } 168 | 169 | public void setDataSize(long dataSize) { 170 | this.dataSize = dataSize; 171 | } 172 | 173 | /** 174 | * 初始化 175 | */ 176 | @FXML 177 | private void initialize() { 178 | mainController = this; 179 | nameTC.setCellValueFactory(new PropertyValueFactory<>("name")); 180 | // 设置文件名可编辑 181 | nameTC.setCellFactory(TextFieldTableCell.forTableColumn()); 182 | nameTC.setOnEditCommit(value -> { 183 | String name; 184 | FileBean fileBean = value.getTableView().getItems().get(value.getTablePosition().getRow()); 185 | // 编辑后重命名文件 186 | if (service.renameFile(bucketCB.getValue(), value.getOldValue(), value.getNewValue())) { 187 | name = value.getNewValue(); 188 | } else { 189 | name = value.getOldValue(); 190 | } 191 | if (Checker.isNotEmpty(searchTF.getText())) { 192 | resData.get(resData.indexOf(fileBean)).setName(name); 193 | } 194 | fileBean.setName(name); 195 | }); 196 | typeTC.setCellValueFactory(new PropertyValueFactory<>("type")); 197 | // 设置文件类型可编辑 198 | typeTC.setCellFactory(TextFieldTableCell.forTableColumn()); 199 | typeTC.setOnEditCommit(value -> { 200 | String type; 201 | FileBean fileBean = value.getTableView().getItems().get(value.getTablePosition().getRow()); 202 | // 编辑后更新文件类型 203 | if (service.changeType(fileBean.getName(), value.getNewValue(), bucketCB.getValue())) { 204 | type = value.getNewValue(); 205 | } else { 206 | type = value.getOldValue(); 207 | } 208 | if (Checker.isNotEmpty(searchTF.getText())) { 209 | resData.get(resData.indexOf(fileBean)).setType(type); 210 | } 211 | fileBean.setType(type); 212 | }); 213 | sizeTC.setCellValueFactory(new PropertyValueFactory<>("size")); 214 | timeTC.setCellValueFactory(new PropertyValueFactory<>("time")); 215 | // 设置表格允许多选 216 | resTV.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); 217 | // 设置默认的开始和结束日期,并事件刷新数据 218 | endDP.setValue(LocalDate.now()); 219 | long startTime = System.currentTimeMillis() - QiniuValueConsts.DATE_SPAN_OF_THIRTY_ONE; 220 | LocalDate localEndDate = Formatter.dateToLocalDate(new Date(startTime)); 221 | startDP.setValue(localEndDate); 222 | // 设置桶下拉框改变事件,改变后配置新的上传环境 223 | bucketCB.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { 224 | zoneTF.setText(QiniuApplication.getConfigBean().getZone(newValue)); 225 | searchTF.clear(); 226 | String url = QiniuApplication.getConfigBean().getUrl(newValue); 227 | if (Checker.isHyperLink(url)) { 228 | domainTF.setText(url); 229 | } else { 230 | domainTF.setText(QiniuValueConsts.DOMAIN_CONFIG_ERROR); 231 | } 232 | ThreadPool.executor.submit(() -> { 233 | if (SdkConfigurer.configUploadEnv(QiniuApplication.getConfigBean().getZone(newValue), newValue)) { 234 | // 加载文件列表 235 | mapResourceData(); 236 | // 刷新流量带宽统计 237 | dateChange(); 238 | } 239 | }); 240 | }); 241 | // 初始化统计单位选择框 242 | fluxUnitCB.getItems().addAll("KB", "MB", "GB", "TB"); 243 | fluxUnitCB.setValue("KB"); 244 | fluxUnitCB.getSelectionModel().selectedItemProperty().addListener((obs, o, n) -> drawChart(true, false)); 245 | bandwidthUnitCB.getItems().addAll(fluxUnitCB.getItems()); 246 | bandwidthUnitCB.setValue("KB"); 247 | bandwidthUnitCB.getSelectionModel().selectedItemProperty().addListener((obs, o, n) -> drawChart(false, true)); 248 | } 249 | 250 | /** 251 | * 开始拖曳文件 252 | */ 253 | public void dragFileOver(DragEvent event) { 254 | event.acceptTransferModes(TransferMode.ANY); 255 | } 256 | 257 | /** 258 | * 拖曳文件松开鼠标 259 | */ 260 | public void dragFileDropped(DragEvent event) { 261 | appendFile(event.getDragboard().getFiles()); 262 | } 263 | 264 | /** 265 | * 开始日期或结束日期改变,刷新流量、带宽统计 266 | */ 267 | public void dateChange() { 268 | drawChart(true, true); 269 | } 270 | 271 | /** 272 | * 绘制数据统计图表 273 | */ 274 | private void drawChart(boolean isFluxUnitChange, boolean isBandwidthUnitChange) { 275 | Date localStartDate = Formatter.localDateToDate(startDP.getValue()); 276 | Date localEndDate = Formatter.localDateToDate(endDP.getValue()); 277 | // 将本地日期装换成字符串 278 | String fromDate = Formatter.dateToString(localStartDate); 279 | String toDate = Formatter.dateToString(localEndDate); 280 | // 获取开始日期和结束日期的时间差 281 | long timeSpan = localEndDate.getTime() - localStartDate.getTime(); 282 | if (Checker.isNotEmpty(domainTF.getText()) && timeSpan >= 0 && timeSpan <= QiniuValueConsts.DATE_SPAN_OF_THIRTY_ONE) { 283 | Platform.runLater(() -> { 284 | String[] domains = {domainTF.getText()}; 285 | if (isFluxUnitChange) { 286 | // 获取流量数据 287 | String fluxUnit = fluxUnitCB.getValue(); 288 | fluxAC.getData().clear(); 289 | fluxAC.getData().add(service.getBucketFlux(domains, fromDate, toDate, fluxUnit)); 290 | } 291 | if (isBandwidthUnitChange) { 292 | // 获取带宽数据 293 | String bandUnit = bandwidthUnitCB.getValue(); 294 | bandwidthAC.getData().clear(); 295 | bandwidthAC.getData().add(service.getBucketBandwidth(domains, fromDate, toDate, bandUnit)); 296 | } 297 | }); 298 | } 299 | } 300 | 301 | /** 302 | * 下载日志 303 | */ 304 | public void downloadCdnLog() { 305 | String date = DialogUtils.showInputDialog(null, QiniuValueConsts.INPUT_LOG_DATE, 306 | Formatter.dateToString(new Date())); 307 | service.downloadCdnLog(date); 308 | } 309 | 310 | /** 311 | * 刷新文件 312 | */ 313 | public void refreshFile() { 314 | service.refreshFile(resTV.getSelectionModel().getSelectedItems(), domainTF.getText()); 315 | } 316 | 317 | /** 318 | * 用浏览器打开文件 319 | */ 320 | public void openFile() { 321 | ObservableList selectedItems = resTV.getSelectionModel().getSelectedItems(); 322 | if (Checker.isNotEmpty(selectedItems)) { 323 | String filename = selectedItems.get(0).getName(); 324 | QiniuUtils.openLink(QiniuUtils.buildUrl(filename, domainTF.getText())); 325 | } 326 | } 327 | 328 | /** 329 | * 私有下载 330 | */ 331 | public void privateDownload() { 332 | download(DownloadWay.PRIVATE); 333 | } 334 | 335 | /** 336 | * 下载文件 337 | */ 338 | private void download(DownloadWay way) { 339 | ObservableList selectedItems = resTV.getSelectionModel().getSelectedItems(); 340 | if (Checker.isNotEmpty(selectedItems)) { 341 | if (way == DownloadWay.PUBLIC) { 342 | selectedItems.forEach(bean -> service.publicDownload(bean.getName(), domainTF.getText())); 343 | } else { 344 | selectedItems.forEach(bean -> service.privateDownload(bean.getName(), domainTF.getText())); 345 | } 346 | } 347 | } 348 | 349 | /** 350 | * 公有下载 351 | */ 352 | public void publicDownload() { 353 | download(DownloadWay.PUBLIC); 354 | } 355 | 356 | /** 357 | * 更新镜像源 358 | */ 359 | public void updateFile() { 360 | ObservableList selectedItems = resTV.getSelectionModel().getSelectedItems(); 361 | if (Checker.isNotEmpty(selectedItems)) { 362 | selectedItems.forEach(bean -> service.updateFile(bucketCB.getValue(), bean.getName())); 363 | } 364 | } 365 | 366 | /** 367 | * 设置文件生存时间 368 | */ 369 | public void setLife() { 370 | ObservableList selectedItems = resTV.getSelectionModel().getSelectedItems(); 371 | if (Checker.isNotEmpty(selectedItems)) { 372 | // 弹出输入框 373 | String fileLife = DialogUtils.showInputDialog(null, QiniuValueConsts.FILE_LIFE, 374 | QiniuValueConsts.DEFAULT_FILE_LIFE); 375 | if (Checker.isNumber(fileLife)) { 376 | int life = Formatter.stringToInt(fileLife); 377 | selectedItems.forEach(bean -> service.setFileLife(bucketCB.getValue(), bean.getName(), life)); 378 | } 379 | } 380 | } 381 | 382 | /** 383 | * 显示移动或复制文件的弹窗 384 | */ 385 | public void showFileMovableDialog() { 386 | ObservableList selectedItems = resTV.getSelectionModel().getSelectedItems(); 387 | if (Checker.isEmpty(selectedItems)) { 388 | // 没有选择文件,结束方法 389 | return; 390 | } 391 | Pair resultPair; 392 | String bucket = bucketCB.getValue(); 393 | if (selectedItems.size() > 1) { 394 | resultPair = dialog.showFileDialog(bucket, "", false); 395 | } else { 396 | resultPair = dialog.showFileDialog(bucket, selectedItems.get(0).getName(), true); 397 | } 398 | if (Checker.isNotNull(resultPair)) { 399 | boolean useNewKey = Checker.isNotEmpty(resultPair.getValue()[1]); 400 | ObservableList fileBeans = resTV.getItems(); 401 | for (FileBean fileBean : selectedItems) { 402 | String fromBucket = bucketCB.getValue(); 403 | String toBucket = resultPair.getValue()[0]; 404 | String name = useNewKey ? resultPair.getValue()[1] : fileBean.getName(); 405 | boolean isSuccess = service.moveOrCopyFile(fromBucket, fileBean.getName(), toBucket, name, 406 | resultPair.getKey()); 407 | if (resultPair.getKey() == SdkManager.FileAction.MOVE && isSuccess) { 408 | boolean isInSearch = Checker.isNotEmpty(searchTF.getText()); 409 | if (fromBucket.equals(toBucket)) { 410 | // 更新文件名 411 | fileBean.setName(name); 412 | if (isInSearch) { 413 | fileBeans.get(fileBeans.indexOf(fileBean)).setName(name); 414 | } 415 | } else { 416 | // 删除数据源 417 | fileBeans.remove(fileBean); 418 | dataLength--; 419 | dataSize -= Formatter.sizeToLong(fileBean.getSize()); 420 | if (isInSearch) { 421 | fileBeans.remove(fileBean); 422 | } 423 | } 424 | } 425 | } 426 | countBucket(); 427 | } 428 | } 429 | 430 | /** 431 | * 删除文件 432 | */ 433 | public void deleteFile() { 434 | service.deleteFile(resTV.getSelectionModel().getSelectedItems(), bucketCB.getValue()); 435 | } 436 | 437 | /** 438 | * 复制链接 439 | */ 440 | public void copyLink() { 441 | ObservableList fileBeans = resTV.getSelectionModel().getSelectedItems(); 442 | if (Checker.isNotEmpty(fileBeans)) { 443 | // 只复制选中的第一个文件的链接 444 | Utils.copyToClipboard(QiniuUtils.buildUrl(fileBeans.get(0).getName(), domainTF.getText())); 445 | } 446 | } 447 | 448 | /** 449 | * 搜索资源文件,忽略大小写 450 | */ 451 | public void searchFile() { 452 | ArrayList files = new ArrayList<>(); 453 | String search = Checker.checkNull(searchTF.getText()); 454 | dataLength = 0; 455 | dataSize = 0; 456 | // 正则匹配查询 457 | Pattern pattern = Pattern.compile(search, Pattern.CASE_INSENSITIVE); 458 | for (FileBean file : resData) { 459 | if (pattern.matcher(file.getName()).find()) { 460 | files.add(file); 461 | dataLength++; 462 | dataSize += Formatter.sizeToLong(file.getSize()); 463 | } 464 | } 465 | countBucket(); 466 | resTV.setItems(FXCollections.observableArrayList(files)); 467 | } 468 | 469 | /** 470 | * 统计空间文件的数量以及大小 471 | */ 472 | public void countBucket() { 473 | lengthLabel.setText(Formatter.customFormatDecimal(dataLength, ",###") + " 个文件"); 474 | sizeLabel.setText(Formatter.formatSize(dataSize)); 475 | } 476 | 477 | /** 478 | * 刷新资源列表 479 | */ 480 | public void refreshResourceData() { 481 | mapResourceData(); 482 | DialogUtils.showInformation(QiniuValueConsts.REFRESH_SUCCESS); 483 | } 484 | 485 | /** 486 | * 将从存储空间获取的文件列表映射到表中 487 | */ 488 | private void mapResourceData() { 489 | ThreadPool.executor.submit(() -> { 490 | // 列出资源文件 491 | service.listFile(); 492 | Platform.runLater(() -> { 493 | resTV.setItems(resData); 494 | countBucket(); 495 | }); 496 | }); 497 | 498 | } 499 | 500 | /** 501 | * 添加桶至下拉框 502 | */ 503 | public void appendBucket(String bucket) { 504 | if (!bucketCB.getItems().contains(bucket)) { 505 | bucketCB.getItems().add(bucket); 506 | } 507 | } 508 | 509 | /** 510 | * 保存文件的上传状态 511 | */ 512 | public void saveUploadStatus() { 513 | FileChooser chooser = new FileChooser(); 514 | chooser.setTitle(QiniuValueConsts.FILE_CHOOSER_TITLE); 515 | chooser.setInitialDirectory(new File(Utils.getCurrentWorkDir())); 516 | File file = chooser.showSaveDialog(QiniuApplication.getStage()); 517 | QiniuUtils.saveFile(file, uploadStatusTA.getText()); 518 | } 519 | 520 | /** 521 | * 复制文件上传状态至剪贴板 522 | */ 523 | public void copyUploadStatus() { 524 | Utils.copyToClipboard(uploadStatusTA.getText()); 525 | } 526 | 527 | /** 528 | * 清空文件的上传状态 529 | */ 530 | public void clearUploadStatus() { 531 | uploadStatusTA.clear(); 532 | } 533 | 534 | /** 535 | * 显示选择文件的弹窗 536 | */ 537 | public void showOpenFileDialog() { 538 | FileChooser chooser = new FileChooser(); 539 | chooser.setTitle(QiniuValueConsts.FILE_CHOOSER_TITLE); 540 | chooser.setInitialDirectory(new File(Utils.getCurrentWorkDir())); 541 | appendFile(chooser.showOpenMultipleDialog(QiniuApplication.getStage())); 542 | } 543 | 544 | /** 545 | * 添加上传的文件,支持拖曳文件夹 546 | */ 547 | private void appendFile(List files) { 548 | if (Checker.isNotEmpty(files)) { 549 | File[] fileArray = new File[files.size()]; 550 | appendFile(files.toArray(fileArray), false); 551 | } 552 | } 553 | 554 | /** 555 | * 添加上传的文件,支持拖曳文件夹 556 | */ 557 | private void appendFile(File[] files, boolean isRecursive) { 558 | if (Checker.isNotNull(files)) { 559 | for (File file : files) { 560 | if (file.isDirectory()) { 561 | if (isRecursive) { 562 | // 递归添加文件 563 | if (recursiveCB.isSelected()) { 564 | appendFile(file.listFiles(), true); 565 | } 566 | } else { 567 | rootPath.add(file.getAbsolutePath()); 568 | appendFile(file.listFiles(), true); 569 | } 570 | } else if (!selectedFileTA.getText().contains(file.getAbsolutePath())) { 571 | selectedFileTA.insertText(0, file.getAbsolutePath() + "\r\n"); 572 | } 573 | } 574 | } 575 | } 576 | 577 | /** 578 | * 上传选择的文件 579 | */ 580 | public void uploadFile() { 581 | if (Checker.isEmpty(zoneTF.getText()) || Checker.isEmpty(selectedFileTA.getText())) { 582 | // 没有选择存储空间或文件,不能上传文件 583 | DialogUtils.showWarning(QiniuValueConsts.NEED_CHOOSE_BUCKET_OR_FILE); 584 | return; 585 | } 586 | // 新建一个线程上传文件的线程 587 | ThreadPool.executor.submit(() -> { 588 | Platform.runLater(() -> uploadStatusTA.insertText(0, QiniuValueConsts.CONFIG_UPLOAD_ENVIRONMENT)); 589 | String bucket = bucketCB.getValue(); 590 | // 默认不指定KEY的情况下,以文件内容的哈希值作为文件名 591 | String key = Checker.checkNull(prefixCB.getValue()); 592 | String[] paths = selectedFileTA.getText().split("\n"); 593 | // 去掉\r\n的长度 594 | int endIndex = QiniuValueConsts.UPLOADING.length() - 2; 595 | Platform.runLater(() -> uploadStatusTA.deleteText(0, 596 | QiniuValueConsts.CONFIG_UPLOAD_ENVIRONMENT.length() - 1)); 597 | // 总文件数 598 | for (String path : paths) { 599 | if (Checker.isNotEmpty(path)) { 600 | Platform.runLater(() -> uploadStatusTA.insertText(0, QiniuValueConsts.UPLOADING)); 601 | String filename = ""; 602 | String url = "http://" + QiniuApplication.getConfigBean().getUrl(bucket) + "/"; 603 | File file = new File(path); 604 | try { 605 | // 判断文件是否存在 606 | if (file.exists()) { 607 | // 保持文件相对父文件夹的路径 608 | if (keepPathCB.isSelected() && Checker.isNotEmpty(rootPath)) { 609 | for (String root : rootPath) { 610 | if (file.getAbsolutePath().startsWith(root)) { 611 | String postKey = root.substring(root.lastIndexOf(File.separator) + 1); 612 | filename = key + postKey + file.getAbsolutePath().substring(root.length()); 613 | break; 614 | } 615 | } 616 | } 617 | if (Checker.isEmpty(filename)) { 618 | filename = key + file.getName(); 619 | } 620 | service.uploadFile(bucket, path, filename); 621 | String now = DateUtil.formatDate(new Date()); 622 | status = StrUtil.format(UPLOAD_STATUS_TEMPLATE, now, url, filename, path); 623 | } else if (Checker.isHyperLink(path)) { 624 | // 抓取网络文件到空间中 625 | filename = key + QiniuUtils.getFileName(path); 626 | SdkConfigurer.getBucketManager().fetch(path, bucket, filename); 627 | String now = DateUtil.formatDate(new Date()); 628 | status = StrUtil.format(UPLOAD_STATUS_TEMPLATE, now, url, filename, path); 629 | } else { 630 | // 文件不存在 631 | status = DateUtil.formatDate(new Date()) + "\tfailed\t" + path; 632 | } 633 | } catch (QiniuException e) { 634 | status = DateUtil.formatDate(new Date()) + "\terror\t" + path; 635 | Platform.runLater(() -> DialogUtils.showException(QiniuValueConsts.UPLOAD_ERROR, e)); 636 | } 637 | Platform.runLater(() -> { 638 | uploadStatusTA.deleteText(0, endIndex); 639 | uploadStatusTA.insertText(0, status); 640 | }); 641 | } 642 | Platform.runLater(() -> selectedFileTA.deleteText(0, path.length() + (paths.length > 1 ? 1 : 0))); 643 | } 644 | rootPath.clear(); 645 | Platform.runLater(() -> { 646 | // 将光标移到最前面 647 | uploadStatusTA.positionCaret(0); 648 | // 清空待上传的文件列表 649 | selectedFileTA.clear(); 650 | }); 651 | mapResourceData(); 652 | // 添加文件前缀到配置文件 653 | savePrefix(key); 654 | }); 655 | } 656 | 657 | /** 658 | * 保存前缀 659 | */ 660 | private void savePrefix(String key) { 661 | if (Checker.isNotEmpty(key) && !QiniuApplication.getConfigBean().getPrefixes().contains(key)) { 662 | Platform.runLater(() -> prefixCB.getItems().add(key)); 663 | QiniuApplication.getConfigBean().getPrefixes().add(key); 664 | ConfigUtils.writeConfig(); 665 | } 666 | } 667 | 668 | /** 669 | * 打开配置文件 670 | */ 671 | public void openConfigFile() { 672 | try { 673 | Desktop.getDesktop().open(new File(QiniuValueConsts.CONFIG_PATH)); 674 | // 用户触发是否重载配置文件 675 | Optional result = DialogUtils.showConfirmation(QiniuValueConsts.RELOAD_CONFIG); 676 | if (result.isPresent() && result.get() == ButtonType.OK) { 677 | // 重新载入配置文件 678 | bucketCB.getItems().clear(); 679 | prefixCB.getItems().clear(); 680 | ConfigUtils.loadConfig(); 681 | } 682 | } catch (Exception e) { 683 | DialogUtils.showException(QiniuValueConsts.OPEN_FILE_ERROR, e); 684 | } 685 | } 686 | 687 | /** 688 | * 显示重置密钥的弹窗 689 | */ 690 | public void showKeyDialog() { 691 | boolean ok = dialog.showKeyDialog(); 692 | if (ok && Checker.isNotEmpty(zoneTF.getText())) { 693 | // 配置新的环境 694 | SdkConfigurer.configUploadEnv(zoneTF.getText(), bucketCB.getValue()); 695 | } 696 | } 697 | 698 | /** 699 | * 显示添加存储空间的弹窗 700 | */ 701 | public void showBucketDialog() { 702 | dialog.showBucketDialog(); 703 | } 704 | 705 | public enum DownloadWay { 706 | // 下载的方式,包括私有和公有 707 | PRIVATE, PUBLIC 708 | } 709 | } 710 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/model/BucketBean.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.io.Serializable; 8 | 9 | /** 10 | * 桶信息 11 | * 12 | * @author pantao 13 | * @since 2018/11/13 14 | */ 15 | @Data 16 | @AllArgsConstructor 17 | @NoArgsConstructor 18 | public class BucketBean implements Serializable { 19 | 20 | private String bucket; 21 | 22 | private String zone; 23 | 24 | private String url; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/model/ConfigBean.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.model; 2 | 3 | import cn.hutool.core.collection.CollectionUtil; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | import java.util.ArrayList; 10 | import java.util.Objects; 11 | 12 | /** 13 | * 应用配置信息 14 | * 15 | * @author pantao 16 | * @since 2018/11/12 17 | **/ 18 | @Data 19 | @NoArgsConstructor 20 | @AllArgsConstructor 21 | public class ConfigBean implements Serializable { 22 | 23 | private String accessKey; 24 | 25 | private String secretKey; 26 | 27 | private ArrayList buckets; 28 | 29 | private ArrayList prefixes; 30 | 31 | private String storagePath; 32 | 33 | public String getBucket(String bucket) { 34 | BucketBean bucketBean = getBucketBean(bucket); 35 | return Objects.isNull(bucketBean) ? "" : bucketBean.getBucket(); 36 | } 37 | 38 | public String getUrl(String bucket) { 39 | BucketBean bucketBean = getBucketBean(bucket); 40 | return Objects.isNull(bucketBean) ? "" : bucketBean.getUrl(); 41 | } 42 | 43 | public String getZone(String bucket) { 44 | BucketBean bucketBean = getBucketBean(bucket); 45 | return Objects.isNull(bucketBean) ? "" : bucketBean.getZone(); 46 | } 47 | 48 | public BucketBean getBucketBean(String bucket) { 49 | if (CollectionUtil.isNotEmpty(buckets)) { 50 | for (BucketBean bean : buckets) { 51 | if (Objects.equals(bean.getBucket(), bucket)) { 52 | return bean; 53 | } 54 | } 55 | } 56 | return null; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/model/FileBean.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 文件信息 9 | * 10 | * @author pantao 11 | */ 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class FileBean { 16 | 17 | private String name; 18 | 19 | private String type; 20 | 21 | private String size; 22 | 23 | private String time; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/service/QiniuService.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.service; 2 | 3 | import com.qiniu.cdn.CdnResult; 4 | import com.qiniu.common.QiniuException; 5 | import com.qiniu.storage.BucketManager; 6 | import com.qiniu.storage.model.BatchStatus; 7 | import com.qiniu.storage.model.FileInfo; 8 | import com.zhazhapan.util.Checker; 9 | import com.zhazhapan.util.Formatter; 10 | import javafx.application.Platform; 11 | import javafx.collections.FXCollections; 12 | import javafx.collections.ObservableList; 13 | import javafx.scene.chart.XYChart; 14 | import org.apache.log4j.Logger; 15 | import org.code4everything.qiniu.QiniuApplication; 16 | import org.code4everything.qiniu.api.SdkConfigurer; 17 | import org.code4everything.qiniu.api.SdkManager; 18 | import org.code4everything.qiniu.constant.QiniuValueConsts; 19 | import org.code4everything.qiniu.controller.MainController; 20 | import org.code4everything.qiniu.model.FileBean; 21 | import org.code4everything.qiniu.util.DialogUtils; 22 | import org.code4everything.qiniu.util.QiniuUtils; 23 | 24 | import java.util.ArrayList; 25 | import java.util.Map; 26 | 27 | /** 28 | * 七牛服务类 29 | * 30 | * @author pantao 31 | * @since 2018/11/13 32 | */ 33 | public class QiniuService { 34 | 35 | private static final Logger LOGGER = Logger.getLogger(QiniuService.class); 36 | 37 | private final SdkManager sdkManager = new SdkManager(); 38 | 39 | /** 40 | * 上传文件 41 | */ 42 | public void uploadFile(String bucket, String key, String filename) throws QiniuException { 43 | String upToken = SdkConfigurer.getAuth().uploadToken(bucket, filename); 44 | SdkConfigurer.getUploadManager().put(key, filename, upToken); 45 | } 46 | 47 | /** 48 | * 获取空间文件列表 49 | */ 50 | public void listFile() { 51 | MainController main = MainController.getInstance(); 52 | // 列举空间文件列表 53 | BucketManager.FileListIterator iterator = sdkManager.getFileListIterator(main.bucketCB.getValue()); 54 | ArrayList files = new ArrayList<>(); 55 | main.setDataLength(0); 56 | main.setDataSize(0); 57 | // 处理结果 58 | while (iterator.hasNext()) { 59 | FileInfo[] items = iterator.next(); 60 | for (FileInfo item : items) { 61 | main.setDataLength(main.getDataLength() + 1); 62 | main.setDataSize(main.getDataSize() + item.fsize); 63 | // 将七牛的时间单位(100纳秒)转换成毫秒,然后转换成时间 64 | String time = Formatter.timeStampToString(item.putTime / 10000); 65 | String size = Formatter.formatSize(item.fsize); 66 | FileBean file = new FileBean(item.key, item.mimeType, size, time); 67 | files.add(file); 68 | } 69 | } 70 | main.setResData(FXCollections.observableArrayList(files)); 71 | } 72 | 73 | /** 74 | * 批量删除文件,单次批量请求的文件数量不得超过1000 75 | */ 76 | public void deleteFile(ObservableList fileBeans, String bucket) { 77 | if (Checker.isNotEmpty(fileBeans) && QiniuUtils.checkNet()) { 78 | // 生成待删除的文件列表 79 | String[] files = new String[fileBeans.size()]; 80 | ArrayList selectedFiles = new ArrayList<>(); 81 | int i = 0; 82 | for (FileBean fileBean : fileBeans) { 83 | files[i++] = fileBean.getName(); 84 | selectedFiles.add(fileBean); 85 | } 86 | try { 87 | BatchStatus[] batchStatusList = sdkManager.batchDelete(bucket, files); 88 | MainController main = MainController.getInstance(); 89 | // 文件列表是否为搜索后结果 90 | boolean isInSearch = Checker.isNotEmpty(main.searchTF.getText()); 91 | ObservableList currentRes = main.resTV.getItems(); 92 | // 更新界面数据 93 | for (i = 0; i < files.length; i++) { 94 | BatchStatus status = batchStatusList[i]; 95 | String file = files[i]; 96 | if (status.code == 200) { 97 | main.getResData().remove(selectedFiles.get(i)); 98 | main.setDataLength(main.getDataLength() - 1); 99 | main.setDataSize(main.getDataSize() - Formatter.sizeToLong(selectedFiles.get(i).getSize())); 100 | if (isInSearch) { 101 | currentRes.remove(selectedFiles.get(i)); 102 | } 103 | } else { 104 | LOGGER.error("delete " + file + " failed, message -> " + status.data.error); 105 | DialogUtils.showError("删除文件:" + file + " 失败"); 106 | } 107 | } 108 | } catch (QiniuException e) { 109 | DialogUtils.showException(QiniuValueConsts.DELETE_ERROR, e); 110 | } 111 | MainController.getInstance().countBucket(); 112 | } 113 | } 114 | 115 | /** 116 | * 修改文件类型 117 | */ 118 | public boolean changeType(String fileName, String newType, String bucket) { 119 | boolean result = true; 120 | try { 121 | sdkManager.changeMime(bucket, fileName, newType); 122 | } catch (QiniuException e) { 123 | DialogUtils.showException(QiniuValueConsts.CHANGE_FILE_TYPE_ERROR, e); 124 | result = false; 125 | } 126 | return result; 127 | } 128 | 129 | /** 130 | * 重命名文件 131 | */ 132 | public boolean renameFile(String bucket, String oldName, String newName) { 133 | return moveFile(bucket, oldName, bucket, newName); 134 | } 135 | 136 | /** 137 | * 移动文件 138 | */ 139 | private boolean moveFile(String srcBucket, String fromKey, String destBucket, String toKey) { 140 | return moveOrCopyFile(srcBucket, fromKey, destBucket, toKey, SdkManager.FileAction.MOVE); 141 | } 142 | 143 | /** 144 | * 移动或复制文件 145 | */ 146 | public boolean moveOrCopyFile(String srcBucket, String srcKey, String destBucket, String destKey, 147 | SdkManager.FileAction fileAction) { 148 | boolean result = true; 149 | try { 150 | sdkManager.moveOrCopyFile(srcBucket, srcKey, destBucket, destKey, fileAction); 151 | } catch (QiniuException e) { 152 | LOGGER.error("move file failed, message -> " + e.getMessage()); 153 | DialogUtils.showException(QiniuValueConsts.MOVE_OR_RENAME_ERROR, e); 154 | result = false; 155 | } 156 | return result; 157 | } 158 | 159 | /** 160 | * 设置文件生存时间 161 | */ 162 | public void setFileLife(String bucket, String key, int days) { 163 | try { 164 | sdkManager.deleteAfterDays(bucket, key, days); 165 | LOGGER.info("set file life success"); 166 | } catch (QiniuException e) { 167 | LOGGER.error("set file life error, message -> " + e.getMessage()); 168 | DialogUtils.showException(QiniuValueConsts.MOVE_OR_RENAME_ERROR, e); 169 | } 170 | } 171 | 172 | /** 173 | * 更新镜像源 174 | */ 175 | public void updateFile(String bucket, String key) { 176 | try { 177 | sdkManager.prefetch(bucket, key); 178 | LOGGER.info("prefetch files success"); 179 | } catch (QiniuException e) { 180 | LOGGER.error("prefetch files error, message -> " + e.getMessage()); 181 | DialogUtils.showException(QiniuValueConsts.UPDATE_ERROR, e); 182 | } 183 | } 184 | 185 | /** 186 | * 公有下载 187 | */ 188 | public void publicDownload(String fileName, String domain) { 189 | QiniuUtils.download(QiniuUtils.buildUrl(fileName, domain)); 190 | } 191 | 192 | /** 193 | * 私有下载 194 | */ 195 | public void privateDownload(String fileName, String domain) { 196 | QiniuUtils.download(sdkManager.getPrivateUrl(QiniuUtils.buildUrl(fileName, domain))); 197 | } 198 | 199 | /** 200 | * 刷新文件 201 | */ 202 | public void refreshFile(ObservableList fileBeans, String domain) { 203 | if (Checker.isNotEmpty(fileBeans)) { 204 | String[] files = new String[fileBeans.size()]; 205 | int i = 0; 206 | // 获取公有链接 207 | for (FileBean fileBean : fileBeans) { 208 | files[i++] = QiniuUtils.buildUrl(fileBean.getName(), domain); 209 | } 210 | try { 211 | // 刷新文件 212 | sdkManager.refreshFile(files); 213 | } catch (QiniuException e) { 214 | LOGGER.error("refresh files error, message -> " + e.getMessage()); 215 | DialogUtils.showException(e); 216 | } 217 | } 218 | } 219 | 220 | /** 221 | * 日志下载 222 | */ 223 | public void downloadCdnLog(String logDate) { 224 | if (Checker.isNotEmpty(QiniuApplication.getConfigBean().getBuckets()) && Checker.isDate(logDate)) { 225 | // 转换域名成数组格式 226 | String[] domains = new String[QiniuApplication.getConfigBean().getBuckets().size()]; 227 | for (int i = 0; i < QiniuApplication.getConfigBean().getBuckets().size(); i++) { 228 | domains[i] = QiniuApplication.getConfigBean().getBuckets().get(i).getUrl(); 229 | } 230 | Map cdnLog = null; 231 | try { 232 | cdnLog = sdkManager.listCdnLog(domains, logDate); 233 | } catch (QiniuException e) { 234 | DialogUtils.showException(e); 235 | } 236 | if (Checker.isNotEmpty(cdnLog)) { 237 | // 下载日志 238 | for (Map.Entry logs : cdnLog.entrySet()) { 239 | for (CdnResult.LogData log : logs.getValue()) { 240 | QiniuUtils.download(log.url); 241 | } 242 | } 243 | } 244 | } 245 | } 246 | 247 | 248 | /** 249 | * 获取空间带宽统计,使用自定义单位 250 | */ 251 | public XYChart.Series getBucketBandwidth(String[] domains, String startDate, String endDate, 252 | String unit) { 253 | // 获取带宽数据 254 | CdnResult.BandwidthResult bandwidthResult = null; 255 | try { 256 | bandwidthResult = sdkManager.getBandwidthData(domains, startDate, endDate); 257 | } catch (QiniuException e) { 258 | Platform.runLater(() -> DialogUtils.showException(QiniuValueConsts.BUCKET_BAND_ERROR, e)); 259 | } 260 | // 设置图表 261 | XYChart.Series series = new XYChart.Series<>(); 262 | series.setName(QiniuValueConsts.BUCKET_BANDWIDTH_COUNT.replaceAll("[A-Z]+", unit)); 263 | // 格式化数据 264 | if (Checker.isNotNull(bandwidthResult) && Checker.isNotEmpty(bandwidthResult.data)) { 265 | long unitSize = Formatter.sizeToLong("1 " + unit); 266 | for (Map.Entry bandwidth : bandwidthResult.data.entrySet()) { 267 | CdnResult.BandwidthData bandwidthData = bandwidth.getValue(); 268 | if (Checker.isNotNull(bandwidthData)) { 269 | setSeries(bandwidthResult.time, bandwidthData.china, bandwidthData.oversea, series, unitSize); 270 | } 271 | } 272 | } 273 | return series; 274 | } 275 | 276 | /** 277 | * 获取空间的流量统计,使用自定义单位 278 | */ 279 | public XYChart.Series getBucketFlux(String[] domains, String startDate, String endDate, String unit) { 280 | // 获取流量数据 281 | CdnResult.FluxResult fluxResult = null; 282 | try { 283 | fluxResult = sdkManager.getFluxData(domains, startDate, endDate); 284 | } catch (QiniuException e) { 285 | Platform.runLater(() -> DialogUtils.showException(QiniuValueConsts.BUCKET_FLUX_ERROR, e)); 286 | } 287 | // 设置图表 288 | XYChart.Series series = new XYChart.Series<>(); 289 | series.setName(QiniuValueConsts.BUCKET_FLUX_COUNT.replaceAll("[A-Z]+", unit)); 290 | // 格式化数据 291 | if (Checker.isNotNull(fluxResult) && Checker.isNotEmpty(fluxResult.data)) { 292 | long unitSize = Formatter.sizeToLong("1 " + unit); 293 | for (Map.Entry flux : fluxResult.data.entrySet()) { 294 | CdnResult.FluxData fluxData = flux.getValue(); 295 | if (Checker.isNotNull(fluxData)) { 296 | setSeries(fluxResult.time, fluxData.china, fluxData.oversea, series, unitSize); 297 | } 298 | } 299 | } 300 | return series; 301 | } 302 | 303 | /** 304 | * 处理带宽数据 305 | */ 306 | private void setSeries(String[] times, Long[] china, Long[] oversea, XYChart.Series series, 307 | long unit) { 308 | int i = 0; 309 | for (String time : times) { 310 | long size = 0; 311 | if (Checker.isNotEmpty(china)) { 312 | size += china[i]; 313 | } 314 | if (Checker.isNotEmpty(oversea)) { 315 | size += oversea[i]; 316 | } 317 | series.getData().add(new XYChart.Data<>(time.substring(5, 10), size / unit)); 318 | i++; 319 | } 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/util/ConfigUtils.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.util; 2 | 3 | import cn.hutool.core.collection.CollectionUtil; 4 | import cn.hutool.core.io.FileUtil; 5 | import cn.hutool.core.util.ObjectUtil; 6 | import cn.hutool.core.util.StrUtil; 7 | import com.alibaba.fastjson.JSONObject; 8 | import javafx.application.Platform; 9 | import org.code4everything.qiniu.QiniuApplication; 10 | import org.code4everything.qiniu.api.SdkConfigurer; 11 | import org.code4everything.qiniu.constant.QiniuValueConsts; 12 | import org.code4everything.qiniu.controller.MainController; 13 | import org.code4everything.qiniu.model.BucketBean; 14 | import org.code4everything.qiniu.model.ConfigBean; 15 | 16 | import java.util.ArrayList; 17 | 18 | /** 19 | * 配置文件工具类 20 | * 21 | * @author pantao 22 | * @since 2018/11/12 23 | **/ 24 | public class ConfigUtils { 25 | 26 | private static final String CONFIG_PATH = QiniuValueConsts.CONFIG_PATH; 27 | 28 | private ConfigUtils() {} 29 | 30 | /** 31 | * 加载配置文件 32 | */ 33 | public static void loadConfig() { 34 | QiniuApplication.setConfigBean(new ConfigBean()); 35 | if (FileUtil.exist(CONFIG_PATH)) { 36 | ConfigBean config = JSONObject.parseObject(FileUtil.readUtf8String(CONFIG_PATH), ConfigBean.class); 37 | if (ObjectUtil.isNotNull(config)) { 38 | QiniuApplication.setConfigBean(config); 39 | if (StrUtil.isNotEmpty(config.getAccessKey()) && StrUtil.isNotEmpty(config.getSecretKey())) { 40 | // 创建上传权限 41 | SdkConfigurer.createAuth(config.getAccessKey(), config.getSecretKey()); 42 | } 43 | MainController controller = MainController.getInstance(); 44 | if (CollectionUtil.isEmpty(config.getBuckets())) { 45 | // 设置一个空的桶列表,防止出现空指针 46 | config.setBuckets(new ArrayList<>()); 47 | } else { 48 | Platform.runLater(() -> { 49 | // 添加桶 50 | config.getBuckets().forEach(bucket -> controller.appendBucket(bucket.getBucket())); 51 | // 选中第一个桶 52 | BucketBean bucket = config.getBuckets().get(0); 53 | controller.bucketCB.setValue(bucket.getBucket()); 54 | controller.zoneTF.setText(bucket.getZone()); 55 | }); 56 | } 57 | if (CollectionUtil.isEmpty(config.getPrefixes())) { 58 | // 设置一个空的前缀列表,防止出现空指针 59 | config.setPrefixes(new ArrayList<>()); 60 | } else { 61 | // 添加前缀 62 | Platform.runLater(() -> config.getPrefixes().forEach(prefix -> controller.prefixCB.getItems().add(prefix))); 63 | } 64 | return; 65 | } 66 | } 67 | // 设置一个空的配置对象,防止出现空指针 68 | ConfigBean configBean = new ConfigBean(); 69 | configBean.setPrefixes(new ArrayList<>()); 70 | configBean.setBuckets(new ArrayList<>()); 71 | QiniuApplication.setConfigBean(configBean); 72 | writeConfig(); 73 | } 74 | 75 | /** 76 | * 写配置文件 77 | */ 78 | public static void writeConfig() { 79 | FileUtil.writeUtf8String(JSONObject.toJSONString(QiniuApplication.getConfigBean(), true), CONFIG_PATH); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/util/DialogUtils.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.util; 2 | 3 | import javafx.scene.control.Alert; 4 | import javafx.scene.control.Alert.AlertType; 5 | import javafx.scene.control.ButtonType; 6 | import javafx.scene.control.TextArea; 7 | import javafx.scene.control.TextInputDialog; 8 | import javafx.scene.layout.GridPane; 9 | import javafx.scene.layout.Priority; 10 | import javafx.stage.Modality; 11 | import javafx.stage.StageStyle; 12 | import javafx.stage.Window; 13 | import org.code4everything.qiniu.constant.QiniuValueConsts; 14 | 15 | import java.io.PrintWriter; 16 | import java.io.StringWriter; 17 | import java.util.Optional; 18 | 19 | /** 20 | * 弹窗工具类 21 | * 22 | * @author pantao 对JavaFX对话框进行封装 23 | */ 24 | public class DialogUtils { 25 | 26 | private DialogUtils() {} 27 | 28 | public static String showInputDialog(String header, String content, String defaultValue) { 29 | TextInputDialog dialog = new TextInputDialog(defaultValue); 30 | dialog.setTitle(QiniuValueConsts.MAIN_TITLE); 31 | dialog.setHeaderText(header); 32 | dialog.setContentText(content); 33 | Optional result = dialog.showAndWait(); 34 | return result.orElse(null); 35 | } 36 | 37 | public static Optional showInformation(String content) { 38 | return showInformation(null, content); 39 | } 40 | 41 | public static Optional showInformation(String header, String content) { 42 | return showAlert(header, content, AlertType.INFORMATION); 43 | } 44 | 45 | public static Optional showWarning(String content) { 46 | return showWarning(null, content); 47 | } 48 | 49 | public static Optional showWarning(String header, String content) { 50 | return showAlert(header, content, AlertType.WARNING); 51 | } 52 | 53 | public static Optional showError(String content) { 54 | return showError(null, content); 55 | } 56 | 57 | public static Optional showError(String header, String content) { 58 | return showAlert(header, content, AlertType.ERROR); 59 | } 60 | 61 | public static Optional showConfirmation(String content) { 62 | return showConfirmation(null, content); 63 | } 64 | 65 | public static Optional showConfirmation(String header, String content) { 66 | return showAlert(header, content, AlertType.CONFIRMATION); 67 | } 68 | 69 | public static Optional showException(Exception e) { 70 | return showException(null, e); 71 | } 72 | 73 | public static void showFatalError(String header, Exception e) { 74 | showException(header, e); 75 | System.exit(0); 76 | } 77 | 78 | public static Optional showException(String header, Exception e) { 79 | // 获取一个警告对象 80 | Alert alert = getAlert(header, "错误信息追踪:", AlertType.ERROR); 81 | // 打印异常信息 82 | StringWriter stringWriter = new StringWriter(); 83 | PrintWriter printWriter = new PrintWriter(stringWriter); 84 | e.printStackTrace(printWriter); 85 | String exception = stringWriter.toString(); 86 | // 显示异常信息 87 | TextArea textArea = new TextArea(exception); 88 | textArea.setEditable(false); 89 | textArea.setWrapText(true); 90 | // 设置弹窗容器 91 | textArea.setMaxWidth(Double.MAX_VALUE); 92 | textArea.setMaxHeight(Double.MAX_VALUE); 93 | GridPane.setVgrow(textArea, Priority.ALWAYS); 94 | GridPane.setHgrow(textArea, Priority.ALWAYS); 95 | GridPane gridPane = new GridPane(); 96 | gridPane.setMaxWidth(Double.MAX_VALUE); 97 | gridPane.add(textArea, 0, 0); 98 | alert.getDialogPane().setExpandableContent(gridPane); 99 | return alert.showAndWait(); 100 | } 101 | 102 | public static Optional showAlert(String content) { 103 | return showAlert(null, content); 104 | } 105 | 106 | public static Optional showAlert(String content, AlertType alertType) { 107 | return showAlert(null, content, alertType); 108 | } 109 | 110 | public static Optional showAlert(String header, String content) { 111 | return showAlert(header, content, AlertType.INFORMATION); 112 | } 113 | 114 | public static Optional showAlert(String header, String content, AlertType alertType) { 115 | return showAlert(header, content, alertType, Modality.NONE, null, StageStyle.DECORATED); 116 | } 117 | 118 | public static Optional showAlert(String header, String content, AlertType alertType, 119 | Modality modality, Window window, StageStyle style) { 120 | return getAlert(header, content, alertType, modality, window, style).showAndWait(); 121 | } 122 | 123 | public static Alert getAlert(String header, String content, AlertType alertType) { 124 | return getAlert(header, content, alertType, Modality.APPLICATION_MODAL, null, StageStyle.DECORATED); 125 | } 126 | 127 | public static Alert getAlert(String header, String content, AlertType alertType, Modality modality, Window window 128 | , StageStyle style) { 129 | Alert alert = new Alert(alertType); 130 | alert.setTitle(QiniuValueConsts.MAIN_TITLE); 131 | alert.setHeaderText(header); 132 | alert.setContentText(content); 133 | alert.initModality(modality); 134 | alert.initOwner(window); 135 | alert.initStyle(style); 136 | return alert; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/util/QiniuDialog.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.util; 2 | 3 | import com.zhazhapan.util.Checker; 4 | import com.zhazhapan.util.dialog.Dialogs; 5 | import javafx.application.Platform; 6 | import javafx.scene.Node; 7 | import javafx.scene.control.*; 8 | import javafx.scene.layout.GridPane; 9 | import javafx.stage.Modality; 10 | import javafx.util.Pair; 11 | import org.code4everything.qiniu.QiniuApplication; 12 | import org.code4everything.qiniu.api.SdkConfigurer; 13 | import org.code4everything.qiniu.api.SdkManager; 14 | import org.code4everything.qiniu.constant.QiniuValueConsts; 15 | import org.code4everything.qiniu.controller.MainController; 16 | import org.code4everything.qiniu.model.BucketBean; 17 | 18 | import java.util.Optional; 19 | 20 | /** 21 | * 应用弹窗 22 | * 23 | * @author pantao 24 | * @since 2018/11/13 25 | */ 26 | public class QiniuDialog { 27 | 28 | /** 29 | * 显示移动文件的弹窗 30 | */ 31 | public Pair showFileDialog(String bucket, String key, boolean setKey) { 32 | MainController main = MainController.getInstance(); 33 | ButtonType ok = new ButtonType(QiniuValueConsts.OK, ButtonBar.ButtonData.OK_DONE); 34 | Dialog dialog = getDialog(ok); 35 | // 文件名输入框 36 | TextField keyTextField = new TextField(); 37 | keyTextField.setPrefWidth(300); 38 | keyTextField.setPromptText(QiniuValueConsts.FILE_NAME); 39 | keyTextField.setText(key); 40 | // 空间选择框 41 | ComboBox bucketCombo = new ComboBox<>(); 42 | bucketCombo.getItems().addAll(main.bucketCB.getItems()); 43 | bucketCombo.setValue(bucket); 44 | // 保存文件副本复选框 45 | CheckBox copyAsCheckBox = new CheckBox(QiniuValueConsts.COPY_AS); 46 | copyAsCheckBox.setSelected(true); 47 | // 设置容器 48 | GridPane grid = Dialogs.getGridPane(); 49 | grid.add(copyAsCheckBox, 0, 0, 2, 1); 50 | grid.add(new Label(QiniuValueConsts.BUCKET_NAME), 0, 1); 51 | grid.add(bucketCombo, 1, 1); 52 | if (setKey) { 53 | // 显示文件名输入框 54 | grid.add(new Label(QiniuValueConsts.FILE_NAME), 0, 2); 55 | grid.add(keyTextField, 1, 2); 56 | Platform.runLater(keyTextField::requestFocus); 57 | } 58 | dialog.getDialogPane().setContent(grid); 59 | // 数据转换器 60 | dialog.setResultConverter(dialogButton -> { 61 | if (dialogButton == ok) { 62 | return new String[]{bucketCombo.getValue(), keyTextField.getText()}; 63 | } 64 | return null; 65 | }); 66 | // 读取数据 67 | Optional result = dialog.showAndWait(); 68 | if (result.isPresent()) { 69 | bucket = bucketCombo.getValue(); 70 | key = keyTextField.getText(); 71 | SdkManager.FileAction action = copyAsCheckBox.isSelected() ? SdkManager.FileAction.COPY : 72 | SdkManager.FileAction.MOVE; 73 | return new Pair<>(action, new String[]{bucket, key}); 74 | } else { 75 | return null; 76 | } 77 | } 78 | 79 | /** 80 | * 显示输入密钥的对话框 81 | * 82 | * @return 返回用户是否点击确定按钮 83 | */ 84 | public boolean showKeyDialog() { 85 | ButtonType ok = new ButtonType(QiniuValueConsts.OK, ButtonBar.ButtonData.OK_DONE); 86 | Dialog dialog = getDialog(ok); 87 | // 文本框 88 | TextField ak = new TextField(); 89 | ak.setMinWidth(400); 90 | ak.setPromptText("Access Key"); 91 | TextField sk = new TextField(); 92 | sk.setPromptText("Secret Key"); 93 | // 设置超链接 94 | Hyperlink hyperlink = new Hyperlink("查看我的KEY:" + QiniuValueConsts.QINIU_KEY_URL); 95 | hyperlink.setOnAction(event -> QiniuUtils.openLink(QiniuValueConsts.QINIU_KEY_URL)); 96 | // 设置容器 97 | GridPane grid = Dialogs.getGridPane(); 98 | grid.add(hyperlink, 0, 0, 2, 1); 99 | grid.add(new Label("Access Key:"), 0, 1); 100 | grid.add(ak, 1, 1); 101 | grid.add(new Label("Secret Key:"), 0, 2); 102 | grid.add(sk, 1, 2); 103 | Node okButton = dialog.getDialogPane().lookupButton(ok); 104 | okButton.setDisable(true); 105 | dialog.getDialogPane().setContent(grid); 106 | Platform.runLater(ak::requestFocus); 107 | // 监听文本框的输入状态 108 | ak.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || sk.getText().trim().isEmpty())); 109 | sk.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || ak.getText().trim().isEmpty())); 110 | // 等待用户操作 111 | Optional result = dialog.showAndWait(); 112 | // 处理结果 113 | if (result.isPresent() && Checker.isNotEmpty(ak.getText()) && Checker.isNotEmpty(sk.getText())) { 114 | QiniuApplication.getConfigBean().setAccessKey(ak.getText()); 115 | QiniuApplication.getConfigBean().setSecretKey(sk.getText()); 116 | SdkConfigurer.createAuth(ak.getText(), sk.getText()); 117 | ConfigUtils.writeConfig(); 118 | return true; 119 | } 120 | return false; 121 | } 122 | 123 | /** 124 | * 显示添加桶的弹窗 125 | */ 126 | public void showBucketDialog() { 127 | ButtonType ok = new ButtonType(QiniuValueConsts.OK, ButtonBar.ButtonData.OK_DONE); 128 | Dialog dialog = getDialog(ok); 129 | // 桶名称输入框 130 | TextField bucket = new TextField(); 131 | bucket.setPromptText(QiniuValueConsts.BUCKET_NAME); 132 | // 桶域名输入框 133 | TextField url = new TextField(); 134 | url.setPromptText(QiniuValueConsts.BUCKET_URL); 135 | // 桶区域输入框 136 | ComboBox zone = new ComboBox<>(); 137 | zone.getItems().addAll(QiniuValueConsts.BUCKET_NAME_ARRAY); 138 | zone.setValue(QiniuValueConsts.BUCKET_NAME_ARRAY[0]); 139 | // 设置容器 140 | GridPane grid = Dialogs.getGridPane(); 141 | grid.add(new Label(QiniuValueConsts.BUCKET_NAME), 0, 0); 142 | grid.add(bucket, 1, 0); 143 | grid.add(new Label(QiniuValueConsts.BUCKET_URL), 0, 1); 144 | grid.add(url, 1, 1); 145 | grid.add(new Label(QiniuValueConsts.BUCKET_ZONE_NAME), 0, 2); 146 | grid.add(zone, 1, 2); 147 | Node okButton = dialog.getDialogPane().lookupButton(ok); 148 | okButton.setDisable(true); 149 | dialog.getDialogPane().setContent(grid); 150 | Platform.runLater(bucket::requestFocus); 151 | // 监听文本框的输入状态 152 | bucket.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || url.getText().isEmpty())); 153 | url.textProperty().addListener((observable, oldValue, newValue) -> okButton.setDisable(newValue.trim().isEmpty() || bucket.getText().isEmpty())); 154 | // 结果转换器 155 | dialog.setResultConverter(dialogButton -> { 156 | if (dialogButton == ok) { 157 | return new String[]{bucket.getText(), zone.getValue(), (Checker.isHyperLink(url.getText()) ? 158 | url.getText() : "example.com")}; 159 | } 160 | return null; 161 | }); 162 | // 等待用户操作 163 | Optional result = dialog.showAndWait(); 164 | result.ifPresent(res -> { 165 | // 处理结果 166 | Platform.runLater(() -> MainController.getInstance().appendBucket(res[0])); 167 | BucketBean bucketBean = new BucketBean(res[0], res[1], res[2]); 168 | QiniuApplication.getConfigBean().getBuckets().add(bucketBean); 169 | ConfigUtils.writeConfig(); 170 | }); 171 | } 172 | 173 | private Dialog getDialog(ButtonType ok) { 174 | Dialog dialog = new Dialog<>(); 175 | dialog.setTitle(QiniuValueConsts.MAIN_TITLE); 176 | dialog.setHeaderText(null); 177 | dialog.initModality(Modality.APPLICATION_MODAL); 178 | // 自定义确认和取消按钮 179 | ButtonType cancel = new ButtonType(QiniuValueConsts.CANCEL, ButtonBar.ButtonData.CANCEL_CLOSE); 180 | dialog.getDialogPane().getButtonTypes().addAll(ok, cancel); 181 | return dialog; 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /src/main/java/org/code4everything/qiniu/util/QiniuUtils.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu.util; 2 | 3 | import cn.hutool.core.lang.Validator; 4 | import cn.hutool.http.HttpUtil; 5 | import com.zhazhapan.util.FileExecutor; 6 | import com.zhazhapan.util.Formatter; 7 | import com.zhazhapan.util.ThreadPool; 8 | import com.zhazhapan.util.Utils; 9 | import com.zhazhapan.util.dialog.Alerts; 10 | import org.apache.log4j.Logger; 11 | import org.code4everything.qiniu.QiniuApplication; 12 | import org.code4everything.qiniu.constant.QiniuValueConsts; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | import java.io.UnsupportedEncodingException; 18 | import java.net.URL; 19 | import java.net.URLEncoder; 20 | 21 | /** 22 | * @author pantao 23 | * @since 2018/4/14 24 | */ 25 | public class QiniuUtils { 26 | 27 | private static final Logger LOGGER = Logger.getLogger(QiniuUtils.class); 28 | 29 | private static final String HTTP = "http"; 30 | 31 | private QiniuUtils() {} 32 | 33 | /** 34 | * 下载文件 35 | * 36 | * @param url 文件链接 37 | */ 38 | public static void download(String url) { 39 | // 验证存储路径 40 | if (Validator.isEmpty(QiniuApplication.getConfigBean().getStoragePath())) { 41 | // 显示存储路径输入框 42 | String storagePath = DialogUtils.showInputDialog(null, QiniuValueConsts.CONFIG_DOWNLOAD_PATH, 43 | Utils.getCurrentWorkDir()); 44 | if (Validator.isEmpty(storagePath)) { 45 | return; 46 | } 47 | QiniuApplication.getConfigBean().setStoragePath(storagePath); 48 | ConfigUtils.writeConfig(); 49 | } 50 | final String dest = QiniuApplication.getConfigBean().getStoragePath(); 51 | // 下载文件 52 | ThreadPool.executor.execute(() -> HttpUtil.downloadFile(url, dest)); 53 | } 54 | 55 | /** 56 | * 检查是否连接网络 57 | */ 58 | public static boolean checkNet() { 59 | try { 60 | URL url = new URL("https://www.qiniu.com/"); 61 | InputStream in = url.openStream(); 62 | in.close(); 63 | return true; 64 | } catch (IOException e) { 65 | LOGGER.error("there is no connection to the network"); 66 | return false; 67 | } 68 | } 69 | 70 | public static void saveLogFile(String file, String content) { 71 | try { 72 | FileExecutor.saveLogFile(file, content); 73 | } catch (IOException e) { 74 | Alerts.showError(QiniuValueConsts.MAIN_TITLE, e.getMessage()); 75 | } 76 | } 77 | 78 | public static void saveFile(File file, String content) { 79 | try { 80 | FileExecutor.saveFile(file, content); 81 | } catch (IOException e) { 82 | Alerts.showError(QiniuValueConsts.MAIN_TITLE, e.getMessage()); 83 | } 84 | } 85 | 86 | public static void openLink(String url) { 87 | try { 88 | Utils.openLink(url); 89 | } catch (Exception e) { 90 | Alerts.showError(QiniuValueConsts.MAIN_TITLE, e.getMessage()); 91 | } 92 | } 93 | 94 | public static String getFileName(String string) { 95 | try { 96 | return Formatter.getFileName(string); 97 | } catch (UnsupportedEncodingException e) { 98 | LOGGER.error("get file name of url failed, message -> " + e.getMessage()); 99 | return ""; 100 | } 101 | } 102 | 103 | /** 104 | * 拼接链接 105 | */ 106 | public static String buildUrl(String fileName, String domain) { 107 | if (!domain.startsWith(HTTP)) { 108 | domain = HTTP + "://" + domain; 109 | } 110 | fileName = fileName.replaceAll(" ", "qn_code_per_20").replaceAll("/", "qn_code_per_2F"); 111 | try { 112 | fileName = URLEncoder.encode(fileName, "utf-8").replaceAll("qn_code_per_2F", "/"); 113 | return String.format("%s/%s", domain, fileName.replaceAll("qn_code_per_20", "%20")); 114 | } catch (UnsupportedEncodingException e) { 115 | LOGGER.error("encode url failed, message -> " + e.getMessage()); 116 | return ""; 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/resources/image/qiniu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/code4everything/qiniu/284253327473fc51e952b75db605719a096472e6/src/main/resources/image/qiniu.png -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootCategory=INFO, file 2 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 3 | log4j.appender.file.file=logs/qiniu 4 | log4j.appender.file.DatePattern='.'yyyy-MM-dd'.log' 5 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 6 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %c{1}:%L - %m%n 7 | -------------------------------------------------------------------------------- /src/main/resources/view/Main.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 12 |
13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 70 | 71 | 72 | 73 | 74 | 83 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 107 | 109 | 110 | 111 | 112 | 113 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 128 | 129 | 130 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 150 | 155 | 161 | 166 | 171 | 177 | 183 | 188 | 193 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 216 | 224 | 226 | 227 | 228 | 229 | 230 | 238 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 |
283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 309 | 314 | 319 | 320 | 321 | 322 |
323 |
324 | -------------------------------------------------------------------------------- /src/test/java/org/code4everything/qiniu/FormatterTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.code4everything.qiniu; 5 | 6 | import org.junit.Test; 7 | 8 | import com.zhazhapan.util.Formatter; 9 | 10 | /** 11 | * @author pantao 12 | * 13 | */ 14 | public class FormatterTest { 15 | 16 | @Test 17 | public void testSizeToLong() { 18 | String[] sizes = { "23.12 MB", "12.89 KB", "23 B", "23.77 GB", "89.12 TB" }; 19 | for (String size : sizes) { 20 | System.out.println(Formatter.sizeToLong(size)); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/test/java/org/code4everything/qiniu/GsonTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.code4everything.qiniu; 5 | 6 | import org.junit.Test; 7 | 8 | import com.google.gson.JsonArray; 9 | import com.google.gson.JsonElement; 10 | import com.google.gson.JsonObject; 11 | import com.google.gson.JsonParser; 12 | import com.zhazhapan.util.Checker; 13 | 14 | /** 15 | * @author pantao 16 | * 17 | */ 18 | public class GsonTest { 19 | 20 | public String configJson = "{accessKey:123456,secretKey:abcdef,buckets:[{bucket:zhazhapan,zone:华东}]}"; 21 | 22 | @Test 23 | public void testGson() { 24 | JsonObject json = new JsonParser().parse(configJson).getAsJsonObject(); 25 | JsonElement buckets = json.get("buckets"); 26 | if (Checker.isNotNull(buckets)) { 27 | JsonArray array = buckets.getAsJsonArray(); 28 | for (JsonElement element : array) { 29 | System.out.println(((JsonObject) element).get("bucket").getAsString()); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/org/code4everything/qiniu/QiniuApplicationTest.java: -------------------------------------------------------------------------------- 1 | package org.code4everything.qiniu; 2 | 3 | import org.junit.Test; 4 | 5 | /** 6 | * @author pantao 7 | */ 8 | 9 | public class QiniuApplicationTest { 10 | 11 | @Test 12 | public void testContext() { 13 | 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/org/code4everything/qiniu/RegexpTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package org.code4everything.qiniu; 5 | 6 | import com.zhazhapan.util.Checker; 7 | import org.code4everything.qiniu.util.QiniuUtils; 8 | import org.junit.Test; 9 | 10 | /** 11 | * @author pantao 12 | */ 13 | public class RegexpTest { 14 | 15 | @Test 16 | public void testGetFileName() { 17 | String[] files = {"http://oxns0wnsc.bkt.clouddn.com/fims/css/distpicker.css", "http://oxns0wnsc.bkt.clouddn" 18 | + ".com/fims/css/distpicker", "http://oxns0wnsc.bkt.clouddn.com/fims/css/easy-responsive-tabs.css", 19 | "http://oxns0wnsc.bkt.clouddn.com/zhazhapan/test/%E6%BD%98%E6%BB%94-18780459330-Java%E5%BC%80%E5%8F" 20 | + "%91.docx"}; 21 | for (String file : files) { 22 | System.out.println(QiniuUtils.getFileName(file)); 23 | } 24 | } 25 | 26 | @Test 27 | public void testHyperlink() { 28 | System.out.println(Checker.isHyperLink("https://portal.qiniu.com/bucket/zhazhapan/resource")); 29 | System.out.println(Checker.isHyperLink("http://portal.qiniu.com/bucket/zhazhapan/resource")); 30 | System.out.println(Checker.isHyperLink("portal.qiniu.com/bucket/zhazhapan/resource")); 31 | System.out.println(Checker.isHyperLink("oxns0wnsc.bkt.clouddn.com")); 32 | System.out.println(Checker.isHyperLink("hhttp://portal")); 33 | System.out.println(Checker.isHyperLink("https://cn.wordpress.org/wordpress-4.8.1-zh_CN.zip")); 34 | } 35 | } 36 | --------------------------------------------------------------------------------