正在显示
27 个修改的文件
包含
3090 行增加
和
0 行删除
.gitignore
0 → 100644
| 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/ |
LICENSE
0 → 100644
| 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
0 → 100644
| 1 | +#### 七牛云对象存储管理工具介绍 | ||
| 2 | + | ||
| 3 | +- 设置文件前缀 | ||
| 4 | + | ||
| 5 | + 路径前缀可以用来分类文件,例如: `image/jpg/`your-file-name.jpg。 | ||
| 6 | + | ||
| 7 | +- 添加存储空间 | ||
| 8 | + | ||
| 9 | + 添加存储空间,需要同时指定空间名称,空间域名以及所在区域。 | ||
| 10 | + | ||
| 11 | +- 重置密钥 | ||
| 12 | + | ||
| 13 | + 如果你修改了KEY,可以在此处修改密钥(第一次使用也需要重置KEY)。 | ||
| 14 | + | ||
| 15 | + > 说明:出于安全考虑,建议您周期性地更换密钥。[查看我的密钥](https://portal.qiniu.com/user/key) [密钥安全使用须知](https://developer.qiniu.com/kodo/kb/1334/the-access-key-secret-key-encryption-key-safe-use-instructions) | ||
| 16 | + | ||
| 17 | +- 配置文件 | ||
| 18 | + | ||
| 19 | + 与应用在同级目录,其中 `config.json` 为配置文件 | ||
| 20 | + | ||
| 21 | +- 文件上传 | ||
| 22 | + | ||
| 23 | + 除了可(支持断点和覆盖)上传本地文件外,还可抓取网络文件到空间中 | ||
| 24 | + | ||
| 25 | +- 刷新列表 | ||
| 26 | + | ||
| 27 | + 刷新当前存储空间的资源列表 | ||
| 28 | + | ||
| 29 | +- 复制链接 | ||
| 30 | + | ||
| 31 | + 复制你选中文件的外链 | ||
| 32 | + | ||
| 33 | +- 删除文件 | ||
| 34 | + | ||
| 35 | + 从存储空间中删除你选中的所有文件 | ||
| 36 | + | ||
| 37 | +- 移动文件 | ||
| 38 | + | ||
| 39 | + 移动(或复制)选中的所有文件到指定的存储空间中(目前七牛还不支持跨区域移动文件) | ||
| 40 | + | ||
| 41 | + > 说明:勾选“保存文件副本”时表示当前操作为复制,不勾选时表示移动(会删除本存储空间的文件),默认勾选。 | ||
| 42 | + | ||
| 43 | +- 生存时间 | ||
| 44 | + | ||
| 45 | + 设置选中文件的生存时间,到期后七牛会自动删除这些文件 | ||
| 46 | + | ||
| 47 | +- 更新镜像 | ||
| 48 | + | ||
| 49 | + 此功能首先需要你配置了镜像存储 | ||
| 50 | + | ||
| 51 | + > 官方解释:对于配置了镜像存储的空间,如果镜像源站更新了文件内容,则默认情况下,七牛不会再主动从客户镜像源站同步新的副本,这个时候就需要利用这个prefetch接口来主动地将空间中的文件和更新后的源站副本进行同步。 | ||
| 52 | + | ||
| 53 | +- 公有下载 | ||
| 54 | + | ||
| 55 | + 直接下载选中的文件(私有的存储空间不可用) | ||
| 56 | + | ||
| 57 | +- 私有下载 | ||
| 58 | + | ||
| 59 | + 下载选中的私有存储空间的文件 | ||
| 60 | + | ||
| 61 | +- 打开文件 | ||
| 62 | + | ||
| 63 | + 用浏览器打开你选中的文件 | ||
| 64 | + | ||
| 65 | +- 文件刷新 | ||
| 66 | + | ||
| 67 | + 从七牛云镜像源刷新你选中的文件,保证用户下载的是最新上传的文件,而不是之前的旧版本。 | ||
| 68 | + | ||
| 69 | +- 日志下载 | ||
| 70 | + | ||
| 71 | + 从七牛下载指定日期的操作日志 | ||
| 72 | + | ||
| 73 | +> 说明:操作文件时,需要选中文件才能操作(支持多选)。由于下载私有空间的文件需要临时授权,所以文件的下载分为私有下载(生成临时授权然后下载文件)和公有下载(直接下载文件)。 | ||
| 74 | +另外数据统计的时间跨度不超过31天,否则无法获取数据,这是七牛官方规定的。 | ||
| 75 | + | ||
| 76 | +- 参考 [官方JavaSDK文档](https://developer.qiniu.com/kodo/sdk/1239/java) |
_config.yml
0 → 100644
| 1 | +theme: jekyll-theme-hacker |
mvnw
0 → 100644
| 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 "$@" |
mvnw.cmd
0 → 100644
| 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% |
pom.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 3 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| 4 | + <modelVersion>4.0.0</modelVersion> | ||
| 5 | + | ||
| 6 | + <groupId>com.zhazhapan</groupId> | ||
| 7 | + <artifactId>qiniu</artifactId> | ||
| 8 | + <version>1.0.8</version> | ||
| 9 | + <packaging>jar</packaging> | ||
| 10 | + | ||
| 11 | + <name>qiniu</name> | ||
| 12 | + <description>七牛同步工具</description> | ||
| 13 | + | ||
| 14 | + <properties> | ||
| 15 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| 16 | + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||
| 17 | + <java.version>1.8</java.version> | ||
| 18 | + </properties> | ||
| 19 | + | ||
| 20 | + <dependencies> | ||
| 21 | + <dependency> | ||
| 22 | + <groupId>com.qiniu</groupId> | ||
| 23 | + <artifactId>qiniu-java-sdk</artifactId> | ||
| 24 | + <version>[7.2.0, 7.2.99]</version> | ||
| 25 | + </dependency> | ||
| 26 | + <dependency> | ||
| 27 | + <groupId>com.zhazhapan</groupId> | ||
| 28 | + <artifactId>util</artifactId> | ||
| 29 | + <version>1.1.1</version> | ||
| 30 | + </dependency> | ||
| 31 | + <dependency> | ||
| 32 | + <groupId>org.projectlombok</groupId> | ||
| 33 | + <artifactId>lombok</artifactId> | ||
| 34 | + <version>1.18.2</version> | ||
| 35 | + </dependency> | ||
| 36 | + </dependencies> | ||
| 37 | + | ||
| 38 | + <build> | ||
| 39 | + <plugins> | ||
| 40 | + <plugin> | ||
| 41 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 42 | + <artifactId>maven-compiler-plugin</artifactId> | ||
| 43 | + <configuration> | ||
| 44 | + <source>1.8</source> | ||
| 45 | + <target>1.8</target> | ||
| 46 | + </configuration> | ||
| 47 | + </plugin> | ||
| 48 | + <plugin> | ||
| 49 | + <groupId>org.apache.maven.plugins</groupId> | ||
| 50 | + <artifactId>maven-shade-plugin</artifactId> | ||
| 51 | + <version>2.3</version> | ||
| 52 | + <executions> | ||
| 53 | + <execution> | ||
| 54 | + <phase>package</phase> | ||
| 55 | + <goals> | ||
| 56 | + <goal>shade</goal> | ||
| 57 | + </goals> | ||
| 58 | + <configuration> | ||
| 59 | + <transformers> | ||
| 60 | + <transformer | ||
| 61 | + implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | ||
| 62 | + <mainClass>org.code4everything.qiniu.QiniuApplication</mainClass> | ||
| 63 | + </transformer> | ||
| 64 | + </transformers> | ||
| 65 | + <artifactSet> | ||
| 66 | + </artifactSet> | ||
| 67 | + </configuration> | ||
| 68 | + </execution> | ||
| 69 | + </executions> | ||
| 70 | + </plugin> | ||
| 71 | + </plugins> | ||
| 72 | + </build> | ||
| 73 | +</project> |
| 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<ButtonType> 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 | +} |
| 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<String, Zone> 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 | +} |
| 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<String, LogData[]> 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 | +} |
| 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 | +} |
| 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<String> bucketCB; | ||
| 62 | + | ||
| 63 | + @FXML | ||
| 64 | + public TextField zoneTF; | ||
| 65 | + | ||
| 66 | + @FXML | ||
| 67 | + public TextArea uploadStatusTA; | ||
| 68 | + | ||
| 69 | + @FXML | ||
| 70 | + public ComboBox<String> prefixCB; | ||
| 71 | + | ||
| 72 | + @FXML | ||
| 73 | + public TableView<FileBean> 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<FileBean> 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<FileBean, String> nameTC; | ||
| 104 | + | ||
| 105 | + @FXML | ||
| 106 | + private TableColumn<FileBean, String> typeTC; | ||
| 107 | + | ||
| 108 | + @FXML | ||
| 109 | + private TableColumn<FileBean, String> sizeTC; | ||
| 110 | + | ||
| 111 | + @FXML | ||
| 112 | + private TableColumn<FileBean, String> timeTC; | ||
| 113 | + | ||
| 114 | + @FXML | ||
| 115 | + private Label sizeLabel; | ||
| 116 | + | ||
| 117 | + @FXML | ||
| 118 | + private Label lengthLabel; | ||
| 119 | + | ||
| 120 | + @FXML | ||
| 121 | + private AreaChart<String, Long> fluxAC; | ||
| 122 | + | ||
| 123 | + @FXML | ||
| 124 | + private AreaChart<String, Long> bandwidthAC; | ||
| 125 | + | ||
| 126 | + @FXML | ||
| 127 | + private DatePicker startDP; | ||
| 128 | + | ||
| 129 | + @FXML | ||
| 130 | + private DatePicker endDP; | ||
| 131 | + | ||
| 132 | + @FXML | ||
| 133 | + private ComboBox<String> fluxUnitCB; | ||
| 134 | + | ||
| 135 | + @FXML | ||
| 136 | + private ComboBox<String> bandwidthUnitCB; | ||
| 137 | + | ||
| 138 | + private String status = ""; | ||
| 139 | + | ||
| 140 | + /** | ||
| 141 | + * 父文件夹路径 | ||
| 142 | + */ | ||
| 143 | + private List<String> rootPath = new ArrayList<>(); | ||
| 144 | + | ||
| 145 | + public static MainController getInstance() { | ||
| 146 | + return mainController; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + public ObservableList<FileBean> getResData() { | ||
| 150 | + return resData; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + public void setResData(ObservableList<FileBean> 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<FileBean> 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<FileBean> 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<FileBean> 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<FileBean> 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<FileBean> selectedItems = resTV.getSelectionModel().getSelectedItems(); | ||
| 387 | + if (Checker.isEmpty(selectedItems)) { | ||
| 388 | + // 没有选择文件,结束方法 | ||
| 389 | + return; | ||
| 390 | + } | ||
| 391 | + Pair<SdkManager.FileAction, String[]> 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<FileBean> 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<FileBean> 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<FileBean> 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<File> 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<ButtonType> 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 | +} |
| 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 | +} |
| 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<BucketBean> buckets; | ||
| 28 | + | ||
| 29 | + private ArrayList<String> 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 | +} |
| 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 | +} |
| 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<FileBean> 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<FileBean> fileBeans, String bucket) { | ||
| 77 | + if (Checker.isNotEmpty(fileBeans) && QiniuUtils.checkNet()) { | ||
| 78 | + // 生成待删除的文件列表 | ||
| 79 | + String[] files = new String[fileBeans.size()]; | ||
| 80 | + ArrayList<FileBean> 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<FileBean> 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<FileBean> 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<String, CdnResult.LogData[]> 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<String, CdnResult.LogData[]> 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<String, Long> 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<String, Long> 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<String, CdnResult.BandwidthData> 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<String, Long> 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<String, Long> 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<String, CdnResult.FluxData> 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<String, Long> 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 | +} |
| 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 | +} |
| 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<String> result = dialog.showAndWait(); | ||
| 34 | + return result.orElse(null); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public static Optional<ButtonType> showInformation(String content) { | ||
| 38 | + return showInformation(null, content); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public static Optional<ButtonType> showInformation(String header, String content) { | ||
| 42 | + return showAlert(header, content, AlertType.INFORMATION); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public static Optional<ButtonType> showWarning(String content) { | ||
| 46 | + return showWarning(null, content); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public static Optional<ButtonType> showWarning(String header, String content) { | ||
| 50 | + return showAlert(header, content, AlertType.WARNING); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public static Optional<ButtonType> showError(String content) { | ||
| 54 | + return showError(null, content); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public static Optional<ButtonType> showError(String header, String content) { | ||
| 58 | + return showAlert(header, content, AlertType.ERROR); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public static Optional<ButtonType> showConfirmation(String content) { | ||
| 62 | + return showConfirmation(null, content); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public static Optional<ButtonType> showConfirmation(String header, String content) { | ||
| 66 | + return showAlert(header, content, AlertType.CONFIRMATION); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public static Optional<ButtonType> 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<ButtonType> 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<ButtonType> showAlert(String content) { | ||
| 103 | + return showAlert(null, content); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + public static Optional<ButtonType> showAlert(String content, AlertType alertType) { | ||
| 107 | + return showAlert(null, content, alertType); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + public static Optional<ButtonType> showAlert(String header, String content) { | ||
| 111 | + return showAlert(header, content, AlertType.INFORMATION); | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + public static Optional<ButtonType> showAlert(String header, String content, AlertType alertType) { | ||
| 115 | + return showAlert(header, content, alertType, Modality.NONE, null, StageStyle.DECORATED); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + public static Optional<ButtonType> 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 | +} |
| 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<SdkManager.FileAction, String[]> 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<String[]> 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<String> 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<String[]> 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<String[]> 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<String[]> 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<String[]> 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<String> 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<String[]> 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<String[]> getDialog(ButtonType ok) { | ||
| 174 | + Dialog<String[]> 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 | +} |
| 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 | +} |
src/main/resources/image/qiniu.png
0 → 100644
2.3 KB
src/main/resources/log4j.properties
0 → 100644
| 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 |
src/main/resources/view/Main.fxml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | + | ||
| 3 | +<?import javafx.geometry.*?> | ||
| 4 | +<?import javafx.scene.chart.*?> | ||
| 5 | +<?import javafx.scene.control.*?> | ||
| 6 | +<?import javafx.scene.layout.*?> | ||
| 7 | +<?import javafx.scene.text.Font?> | ||
| 8 | +<VBox xmlns="http://javafx.com/javafx/9" xmlns:fx="http://javafx.com/fxml/1" | ||
| 9 | + fx:controller="org.code4everything.qiniu.controller.MainController"> | ||
| 10 | + <BorderPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="600.0" | ||
| 11 | + prefWidth="700.0" VBox.vgrow="ALWAYS"> | ||
| 12 | + <center> | ||
| 13 | + <TabPane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="50.0" | ||
| 14 | + prefWidth="700.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER"> | ||
| 15 | + <Tab text="文件上传"> | ||
| 16 | + <HBox> | ||
| 17 | + <SplitPane dividerPositions="0.6" prefHeight="520.0" prefWidth="702.0" HBox.hgrow="ALWAYS"> | ||
| 18 | + <padding> | ||
| 19 | + <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> | ||
| 20 | + </padding> | ||
| 21 | + <VBox> | ||
| 22 | + <TextArea fx:id="uploadStatusTA" editable="false" | ||
| 23 | + maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" | ||
| 24 | + prefHeight="504.0" prefWidth="336.0" promptText="文件上传状态" VBox.vgrow="ALWAYS"> | ||
| 25 | + <contextMenu> | ||
| 26 | + <ContextMenu> | ||
| 27 | + <items> | ||
| 28 | + <MenuItem mnemonicParsing="false" onAction="#clearUploadStatus" | ||
| 29 | + text="清空"/> | ||
| 30 | + <MenuItem mnemonicParsing="false" onAction="#saveUploadStatus" | ||
| 31 | + text="另存为"/> | ||
| 32 | + <MenuItem mnemonicParsing="false" onAction="#copyUploadStatus" | ||
| 33 | + text="复制"/> | ||
| 34 | + </items> | ||
| 35 | + </ContextMenu> | ||
| 36 | + </contextMenu> | ||
| 37 | + <VBox.margin> | ||
| 38 | + <Insets right="10.0"/> | ||
| 39 | + </VBox.margin> | ||
| 40 | + </TextArea> | ||
| 41 | + </VBox> | ||
| 42 | + <VBox prefHeight="500.0" prefWidth="171.0"> | ||
| 43 | + <ComboBox fx:id="prefixCB" editable="true" maxHeight="1.7976931348623157E308" | ||
| 44 | + maxWidth="1.7976931348623157E308" prefHeight="35.0" prefWidth="277.0" | ||
| 45 | + promptText="文件前缀, 不设置则为空" VBox.vgrow="NEVER"> | ||
| 46 | + <VBox.margin> | ||
| 47 | + <Insets left="10.0"/> | ||
| 48 | + </VBox.margin> | ||
| 49 | + </ComboBox> | ||
| 50 | + <HBox prefHeight="100.0" prefWidth="200.0" VBox.vgrow="NEVER"> | ||
| 51 | + <padding> | ||
| 52 | + <Insets left="10.0" right="10.0" top="10.0"/> | ||
| 53 | + </padding> | ||
| 54 | + <CheckBox fx:id="recursiveCB" mnemonicParsing="false" text="文件夹递归" | ||
| 55 | + selected="true"/> | ||
| 56 | + <CheckBox fx:id="keepPathCB" mnemonicParsing="false" text="保持文件夹路径" selected="true"> | ||
| 57 | + <HBox.margin> | ||
| 58 | + <Insets left="10.0"/> | ||
| 59 | + </HBox.margin> | ||
| 60 | + </CheckBox> | ||
| 61 | + </HBox> | ||
| 62 | + <TextArea fx:id="selectedFileTA" maxHeight="1.7976931348623157E308" | ||
| 63 | + maxWidth="1.7976931348623157E308" onDragDropped="#dragFileDropped" | ||
| 64 | + onDragOver="#dragFileOver" prefHeight="800.0" prefWidth="332.0" | ||
| 65 | + promptText="文件路径, 一个文件一行, 支持拖曳文件, 支持抓取网络文件" VBox.vgrow="ALWAYS"> | ||
| 66 | + <VBox.margin> | ||
| 67 | + <Insets left="10.0" top="10.0"/> | ||
| 68 | + </VBox.margin> | ||
| 69 | + </TextArea> | ||
| 70 | + <HBox alignment="TOP_CENTER" VBox.vgrow="NEVER"> | ||
| 71 | + <VBox.margin> | ||
| 72 | + <Insets left="10.0" top="10.0"/> | ||
| 73 | + </VBox.margin> | ||
| 74 | + <Button contentDisplay="CENTER" maxHeight="1.7976931348623157E308" | ||
| 75 | + maxWidth="1.7976931348623157E308" mnemonicParsing="false" | ||
| 76 | + onAction="#showOpenFileDialog" prefHeight="27.0" prefWidth="156.0" | ||
| 77 | + text="选择文件" | ||
| 78 | + HBox.hgrow="ALWAYS"> | ||
| 79 | + <HBox.margin> | ||
| 80 | + <Insets right="10.0"/> | ||
| 81 | + </HBox.margin> | ||
| 82 | + </Button> | ||
| 83 | + <Button alignment="CENTER" maxHeight="1.7976931348623157E308" | ||
| 84 | + maxWidth="1.7976931348623157E308" mnemonicParsing="false" | ||
| 85 | + onAction="#uploadFile" prefHeight="27.0" prefWidth="156.0" text="开始上传" | ||
| 86 | + HBox.hgrow="ALWAYS"> | ||
| 87 | + <HBox.margin> | ||
| 88 | + <Insets left="10.0"/> | ||
| 89 | + </HBox.margin> | ||
| 90 | + </Button> | ||
| 91 | + </HBox> | ||
| 92 | + </VBox> | ||
| 93 | + </SplitPane> | ||
| 94 | + </HBox> | ||
| 95 | + </Tab> | ||
| 96 | + <Tab text="资源管理"> | ||
| 97 | + <VBox> | ||
| 98 | + <HBox alignment="CENTER_LEFT" prefHeight="52.0" prefWidth="700.0" VBox.vgrow="NEVER"> | ||
| 99 | + <padding> | ||
| 100 | + <Insets left="10.0"/> | ||
| 101 | + </padding> | ||
| 102 | + <Label alignment="CENTER" text="空间域名" HBox.hgrow="NEVER"> | ||
| 103 | + <font> | ||
| 104 | + <Font size="14.0"/> | ||
| 105 | + </font> | ||
| 106 | + </Label> | ||
| 107 | + <TextField fx:id="domainTF" editable="false" prefHeight="27.0" | ||
| 108 | + prefWidth="245.0" promptText="空间域名" HBox.hgrow="NEVER"> | ||
| 109 | + <HBox.margin> | ||
| 110 | + <Insets left="10.0"/> | ||
| 111 | + </HBox.margin> | ||
| 112 | + </TextField> | ||
| 113 | + <TextField fx:id="searchTF" onKeyReleased="#searchFile" prefHeight="27.0" | ||
| 114 | + prefWidth="275.0" promptText="搜索文件, 支持正则表达式" HBox.hgrow="NEVER"> | ||
| 115 | + <HBox.margin> | ||
| 116 | + <Insets left="10.0"/> | ||
| 117 | + </HBox.margin> | ||
| 118 | + </TextField> | ||
| 119 | + <HBox alignment="CENTER_RIGHT" HBox.hgrow="ALWAYS"> | ||
| 120 | + <HBox.margin> | ||
| 121 | + <Insets/> | ||
| 122 | + </HBox.margin> | ||
| 123 | + <padding> | ||
| 124 | + <Insets right="15.0"/> | ||
| 125 | + </padding> | ||
| 126 | + <Label fx:id="lengthLabel"/> | ||
| 127 | + </HBox> | ||
| 128 | + </HBox> | ||
| 129 | + <HBox VBox.vgrow="ALWAYS"> | ||
| 130 | + <TableView fx:id="resTV" editable="true" prefHeight="479.0" prefWidth="602.0" | ||
| 131 | + HBox.hgrow="ALWAYS"> | ||
| 132 | + <columns> | ||
| 133 | + <TableColumn fx:id="nameTC" prefWidth="278.0" text="文件名"/> | ||
| 134 | + <TableColumn fx:id="typeTC" minWidth="5.0" prefWidth="81.0" text="文件类型"/> | ||
| 135 | + <TableColumn fx:id="sizeTC" prefWidth="90.0" text="文件大小"/> | ||
| 136 | + <TableColumn fx:id="timeTC" prefWidth="152.0" text="最后更新时间"/> | ||
| 137 | + </columns> | ||
| 138 | + <HBox.margin> | ||
| 139 | + <Insets bottom="10.0" left="10.0"/> | ||
| 140 | + </HBox.margin> | ||
| 141 | + </TableView> | ||
| 142 | + <VBox alignment="TOP_CENTER" prefHeight="200.0" prefWidth="100.0" HBox.hgrow="NEVER"> | ||
| 143 | + <Button mnemonicParsing="false" onAction="#refreshResourceData" text="刷新列表" | ||
| 144 | + VBox.vgrow="NEVER"/> | ||
| 145 | + <Button mnemonicParsing="false" onAction="#copyLink" text="复制链接" VBox.vgrow="NEVER"> | ||
| 146 | + <VBox.margin> | ||
| 147 | + <Insets top="10.0"/> | ||
| 148 | + </VBox.margin> | ||
| 149 | + </Button> | ||
| 150 | + <Button mnemonicParsing="false" onAction="#deleteFile" text="删除文件" VBox.vgrow="NEVER"> | ||
| 151 | + <VBox.margin> | ||
| 152 | + <Insets top="10.0"/> | ||
| 153 | + </VBox.margin> | ||
| 154 | + </Button> | ||
| 155 | + <Button mnemonicParsing="false" onAction="#showFileMovableDialog" text="移动到..." | ||
| 156 | + VBox.vgrow="NEVER"> | ||
| 157 | + <VBox.margin> | ||
| 158 | + <Insets top="10.0"/> | ||
| 159 | + </VBox.margin> | ||
| 160 | + </Button> | ||
| 161 | + <Button mnemonicParsing="false" onAction="#setLife" text="生存时间" VBox.vgrow="NEVER"> | ||
| 162 | + <VBox.margin> | ||
| 163 | + <Insets top="10.0"/> | ||
| 164 | + </VBox.margin> | ||
| 165 | + </Button> | ||
| 166 | + <Button mnemonicParsing="false" onAction="#updateFile" text="更新镜像" VBox.vgrow="NEVER"> | ||
| 167 | + <VBox.margin> | ||
| 168 | + <Insets top="10.0"/> | ||
| 169 | + </VBox.margin> | ||
| 170 | + </Button> | ||
| 171 | + <Button mnemonicParsing="false" onAction="#publicDownload" text="公有下载" | ||
| 172 | + VBox.vgrow="NEVER"> | ||
| 173 | + <VBox.margin> | ||
| 174 | + <Insets top="10.0"/> | ||
| 175 | + </VBox.margin> | ||
| 176 | + </Button> | ||
| 177 | + <Button mnemonicParsing="false" onAction="#privateDownload" text="私有下载" | ||
| 178 | + VBox.vgrow="NEVER"> | ||
| 179 | + <VBox.margin> | ||
| 180 | + <Insets top="10.0"/> | ||
| 181 | + </VBox.margin> | ||
| 182 | + </Button> | ||
| 183 | + <Button mnemonicParsing="false" onAction="#openFile" text="打开文件" VBox.vgrow="NEVER"> | ||
| 184 | + <VBox.margin> | ||
| 185 | + <Insets top="10.0"/> | ||
| 186 | + </VBox.margin> | ||
| 187 | + </Button> | ||
| 188 | + <Button mnemonicParsing="false" onAction="#refreshFile" text="文件刷新" VBox.vgrow="NEVER"> | ||
| 189 | + <VBox.margin> | ||
| 190 | + <Insets top="10.0"/> | ||
| 191 | + </VBox.margin> | ||
| 192 | + </Button> | ||
| 193 | + <Button mnemonicParsing="false" onAction="#downloadCdnLog" text="日志下载" | ||
| 194 | + VBox.vgrow="NEVER"> | ||
| 195 | + <VBox.margin> | ||
| 196 | + <Insets top="10.0"/> | ||
| 197 | + </VBox.margin> | ||
| 198 | + </Button> | ||
| 199 | + <VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS"> | ||
| 200 | + <VBox.margin> | ||
| 201 | + <Insets top="10.0"/> | ||
| 202 | + </VBox.margin> | ||
| 203 | + <padding> | ||
| 204 | + <Insets bottom="10.0"/> | ||
| 205 | + </padding> | ||
| 206 | + <Label fx:id="sizeLabel"/> | ||
| 207 | + </VBox> | ||
| 208 | + </VBox> | ||
| 209 | + </HBox> | ||
| 210 | + </VBox> | ||
| 211 | + </Tab> | ||
| 212 | + <Tab text="数据统计"> | ||
| 213 | + <VBox> | ||
| 214 | + <HBox alignment="CENTER" minHeight="-Infinity" minWidth="-Infinity" prefHeight="40.0" | ||
| 215 | + prefWidth="700.0" VBox.vgrow="NEVER"> | ||
| 216 | + <Label text="开始日期" HBox.hgrow="NEVER"> | ||
| 217 | + <font> | ||
| 218 | + <Font size="14.0"/> | ||
| 219 | + </font> | ||
| 220 | + <HBox.margin> | ||
| 221 | + <Insets/> | ||
| 222 | + </HBox.margin> | ||
| 223 | + </Label> | ||
| 224 | + <DatePicker fx:id="startDP" onAction="#dateChange" prefWidth="125.0" promptText="开始日期" | ||
| 225 | + HBox.hgrow="NEVER"> | ||
| 226 | + <HBox.margin> | ||
| 227 | + <Insets left="10.0"/> | ||
| 228 | + </HBox.margin> | ||
| 229 | + </DatePicker> | ||
| 230 | + <Label text="结束日期"> | ||
| 231 | + <font> | ||
| 232 | + <Font size="14.0"/> | ||
| 233 | + </font> | ||
| 234 | + <HBox.margin> | ||
| 235 | + <Insets left="10.0"/> | ||
| 236 | + </HBox.margin> | ||
| 237 | + </Label> | ||
| 238 | + <DatePicker fx:id="endDP" onAction="#dateChange" prefWidth="125.0" promptText="结束日期" | ||
| 239 | + HBox.hgrow="NEVER"> | ||
| 240 | + <HBox.margin> | ||
| 241 | + <Insets left="10.0"/> | ||
| 242 | + </HBox.margin> | ||
| 243 | + </DatePicker> | ||
| 244 | + <ComboBox fx:id="fluxUnitCB" prefWidth="70.0" promptText="统计单位" HBox.hgrow="NEVER"> | ||
| 245 | + <HBox.margin> | ||
| 246 | + <Insets left="10.0"/> | ||
| 247 | + </HBox.margin> | ||
| 248 | + </ComboBox> | ||
| 249 | + <ComboBox fx:id="bandwidthUnitCB" prefWidth="70.0" promptText="统计单位"> | ||
| 250 | + <HBox.margin> | ||
| 251 | + <Insets left="10.0"/> | ||
| 252 | + </HBox.margin> | ||
| 253 | + </ComboBox> | ||
| 254 | + <Label text="时间跨度不超过31天" HBox.hgrow="NEVER"> | ||
| 255 | + <font> | ||
| 256 | + <Font size="14.0"/> | ||
| 257 | + </font> | ||
| 258 | + <HBox.margin> | ||
| 259 | + <Insets left="10.0"/> | ||
| 260 | + </HBox.margin> | ||
| 261 | + </Label> | ||
| 262 | + </HBox> | ||
| 263 | + <AreaChart fx:id="fluxAC" VBox.vgrow="ALWAYS"> | ||
| 264 | + <xAxis> | ||
| 265 | + <CategoryAxis side="BOTTOM"/> | ||
| 266 | + </xAxis> | ||
| 267 | + <yAxis> | ||
| 268 | + <NumberAxis side="LEFT"/> | ||
| 269 | + </yAxis> | ||
| 270 | + </AreaChart> | ||
| 271 | + <AreaChart fx:id="bandwidthAC" VBox.vgrow="ALWAYS"> | ||
| 272 | + <xAxis> | ||
| 273 | + <CategoryAxis side="BOTTOM"/> | ||
| 274 | + </xAxis> | ||
| 275 | + <yAxis> | ||
| 276 | + <NumberAxis side="LEFT"/> | ||
| 277 | + </yAxis> | ||
| 278 | + </AreaChart> | ||
| 279 | + </VBox> | ||
| 280 | + </Tab> | ||
| 281 | + </TabPane> | ||
| 282 | + </center> | ||
| 283 | + <top> | ||
| 284 | + <VBox BorderPane.alignment="CENTER"> | ||
| 285 | + <BorderPane.margin> | ||
| 286 | + <Insets/> | ||
| 287 | + </BorderPane.margin> | ||
| 288 | + <HBox VBox.vgrow="NEVER"> | ||
| 289 | + <padding> | ||
| 290 | + <Insets top="10" bottom="10"/> | ||
| 291 | + </padding> | ||
| 292 | + <ComboBox fx:id="bucketCB" minHeight="-Infinity" minWidth="-Infinity" prefHeight="27.0" | ||
| 293 | + prefWidth="205.0" promptText="还没有选择存储空间" HBox.hgrow="NEVER"> | ||
| 294 | + <HBox.margin> | ||
| 295 | + <Insets left="10.0"/> | ||
| 296 | + </HBox.margin> | ||
| 297 | + </ComboBox> | ||
| 298 | + <TextField fx:id="zoneTF" editable="false" promptText="存储区域" HBox.hgrow="NEVER"> | ||
| 299 | + <HBox.margin> | ||
| 300 | + <Insets left="10.0"/> | ||
| 301 | + </HBox.margin> | ||
| 302 | + </TextField> | ||
| 303 | + <Button mnemonicParsing="false" onAction="#showBucketDialog" text="添加存储空间" | ||
| 304 | + HBox.hgrow="NEVER"> | ||
| 305 | + <HBox.margin> | ||
| 306 | + <Insets left="10.0"/> | ||
| 307 | + </HBox.margin> | ||
| 308 | + </Button> | ||
| 309 | + <Button mnemonicParsing="false" onAction="#showKeyDialog" text="重置密钥" HBox.hgrow="NEVER"> | ||
| 310 | + <HBox.margin> | ||
| 311 | + <Insets left="10.0"/> | ||
| 312 | + </HBox.margin> | ||
| 313 | + </Button> | ||
| 314 | + <Button mnemonicParsing="false" onAction="#openConfigFile" text="打开配置文件" HBox.hgrow="NEVER"> | ||
| 315 | + <HBox.margin> | ||
| 316 | + <Insets left="10.0"/> | ||
| 317 | + </HBox.margin> | ||
| 318 | + </Button> | ||
| 319 | + </HBox> | ||
| 320 | + </VBox> | ||
| 321 | + </top> | ||
| 322 | + </BorderPane> | ||
| 323 | +</VBox> |
| 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 | +} |
| 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 | +} |
| 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 | +} |
-
请 注册 或 登录 后发表评论