commit ab8deba513bb1ecc901ed2955c162c5689cb04d1
Author: terry.wang <32783747@qq.com>
Date: Thu Nov 13 13:52:44 2025 +0800
init version hrs for new gitea
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7844780
--- /dev/null
+++ b/README.md
@@ -0,0 +1,92 @@
+# hrs
+
+
+
+## Getting started
+
+To make it easy for you to get started with GitLab, here's a list of recommended next steps.
+
+Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
+
+## Add your files
+
+- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
+- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
+
+```
+cd existing_repo
+git remote add origin http://192.168.10.240/kelfy/hrs.git
+git branch -M main
+git push -uf origin main
+```
+
+## Integrate with your tools
+
+- [ ] [Set up project integrations](http://192.168.10.240/kelfy/hrs/-/settings/integrations)
+
+## Collaborate with your team
+
+- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
+- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
+- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
+- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
+- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
+
+## Test and Deploy
+
+Use the built-in continuous integration in GitLab.
+
+- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
+- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
+- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
+- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
+- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+
+***
+
+# Editing this README
+
+When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
+
+## Suggestions for a good README
+Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+
+## Name
+Choose a self-explaining name for your project.
+
+## Description
+Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+
+## Badges
+On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+
+## Visuals
+Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+
+## Installation
+Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+
+## Usage
+Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+
+## Support
+Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+
+## Roadmap
+If you have ideas for releases in the future, it is a good idea to list them in the README.
+
+## Contributing
+State if you are open to contributions and what your requirements are for accepting them.
+
+For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+
+You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+
+## Authors and acknowledgment
+Show your appreciation to those who have contributed to the project.
+
+## License
+For open source projects, say how it is licensed.
+
+## Project status
+If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
diff --git a/mvnw b/mvnw
new file mode 100644
index 0000000..a16b543
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,310 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="`/usr/libexec/java_home`"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=`java-config --jre-home`
+ fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG="`dirname "$PRG"`/$link"
+ fi
+ done
+
+ saveddir=`pwd`
+
+ M2_HOME=`dirname "$PRG"`/..
+
+ # make it fully qualified
+ M2_HOME=`cd "$M2_HOME" && pwd`
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --unix "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="`(cd "$M2_HOME"; pwd)`"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="`which javac`"
+ if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=`which readlink`
+ if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+ if $darwin ; then
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+ else
+ javaExecutable="`readlink -f \"$javaExecutable\"`"
+ fi
+ javaHome="`dirname \"$javaExecutable\"`"
+ javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="`which java`"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=`cd "$wdir/.."; pwd`
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' < "$1")"
+ fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+ esac
+ done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+ fi
+
+ if command -v wget > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=`cygpath --path --windows "$javaClass"`
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=`cygpath --path --windows "$M2_HOME"`
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..c8d4337
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..2680ead
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,193 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.5.4
+
+
+ com.saye
+ hrs
+ 0.0.1-SNAPSHOT
+ war
+ hrs
+ hrs
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ log4j-to-slf4j
+ org.apache.logging.log4j
+
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 2.2.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+
+ net.sourceforge.nekohtml
+ nekohtml
+ 1.9.21
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.github.pagehelper
+ pagehelper
+ 5.0.0
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-autoconfigure
+ 1.2.3
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+ 1.2.3
+
+
+ com.alibaba
+ fastjson
+ 1.2.73
+
+
+
+ org.apache.poi
+ poi
+ 3.14
+
+
+ org.apache.poi
+ poi-ooxml
+ 3.14
+
+
+
+ org.jsoup
+ jsoup
+ 1.13.1
+
+
+ org.apache.shiro
+ shiro-spring
+ 1.6.0
+
+
+ javax.servlet
+ javax.servlet-api
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+ com.gitee.qdbp.thirdparty
+ ueditor
+ 1.4.3.3
+
+
+ commons-fileupload
+ commons-fileupload
+ 1.3.2
+
+
+ commons-codec
+ commons-codec
+ 1.9
+
+
+ org.json
+ json
+ 20160810
+
+
+ dom4j
+ dom4j
+ 1.6.1
+
+
+ jaxen
+ jaxen
+ 1.1.6
+
+
+ xml-apis
+ xml-apis
+ 1.4.01
+
+
+
+ com.google.guava
+ guava
+ 32.1.2-jre
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/baidu/ueditor/ActionEnter.java b/src/main/java/com/baidu/ueditor/ActionEnter.java
new file mode 100644
index 0000000..33a3dc7
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/ActionEnter.java
@@ -0,0 +1,127 @@
+package com.baidu.ueditor;
+
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.baidu.ueditor.define.ActionMap;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.State;
+import com.baidu.ueditor.hunter.FileManager;
+import com.baidu.ueditor.hunter.ImageHunter;
+import com.baidu.ueditor.upload.Uploader;
+
+public class ActionEnter {
+
+ private HttpServletRequest request = null;
+
+ private String rootPath = null;
+ private String contextPath = null;
+
+ private String actionType = null;
+
+ private ConfigManager configManager = null;
+
+ public ActionEnter ( HttpServletRequest request, String rootPath ) {
+
+ this.request = request;
+ this.rootPath = rootPath;
+ this.actionType = request.getParameter( "action" );
+ this.contextPath = request.getContextPath();
+ this.configManager = ConfigManager.getInstance( this.rootPath, this.contextPath, request.getRequestURI() );
+
+ }
+
+ public String exec () {
+
+ String callbackName = this.request.getParameter("callback");
+
+ if ( callbackName != null ) {
+
+ if ( !validCallbackName( callbackName ) ) {
+ return new BaseState( false, AppInfo.ILLEGAL ).toJSONString();
+ }
+
+ return callbackName+"("+this.invoke()+");";
+
+ } else {
+ return this.invoke();
+ }
+
+ }
+
+ public String invoke() {
+
+ if ( actionType == null || !ActionMap.mapping.containsKey( actionType ) ) {
+ return new BaseState( false, AppInfo.INVALID_ACTION ).toJSONString();
+ }
+
+ if ( this.configManager == null || !this.configManager.valid() ) {
+ return new BaseState( false, AppInfo.CONFIG_ERROR ).toJSONString();
+ }
+
+ State state = null;
+
+ int actionCode = ActionMap.getType( this.actionType );
+
+ Map conf = null;
+
+ switch ( actionCode ) {
+
+ case ActionMap.CONFIG:
+ return this.configManager.getAllConfig().toString();
+
+ case ActionMap.UPLOAD_IMAGE:
+ case ActionMap.UPLOAD_SCRAWL:
+ case ActionMap.UPLOAD_VIDEO:
+ case ActionMap.UPLOAD_FILE:
+ conf = this.configManager.getConfig( actionCode );
+ state = new Uploader( request, conf ).doExec();
+ break;
+
+ case ActionMap.CATCH_IMAGE:
+ conf = configManager.getConfig( actionCode );
+ String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) );
+ state = new ImageHunter( conf ).capture( list );
+ break;
+
+ case ActionMap.LIST_IMAGE:
+ case ActionMap.LIST_FILE:
+ conf = configManager.getConfig( actionCode );
+ int start = this.getStartIndex();
+ state = new FileManager( conf ).listFile( start );
+ break;
+
+ }
+
+ return state.toJSONString();
+
+ }
+
+ public int getStartIndex () {
+
+ String start = this.request.getParameter( "start" );
+
+ try {
+ return Integer.parseInt( start );
+ } catch ( Exception e ) {
+ return 0;
+ }
+
+ }
+
+ /**
+ * callback参数验证
+ */
+ public boolean validCallbackName ( String name ) {
+
+ if ( name.matches( "^[a-zA-Z_]+[\\w0-9_]*$" ) ) {
+ return true;
+ }
+
+ return false;
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/baidu/ueditor/ConfigManager.java b/src/main/java/com/baidu/ueditor/ConfigManager.java
new file mode 100644
index 0000000..3073cf7
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/ConfigManager.java
@@ -0,0 +1,230 @@
+package com.baidu.ueditor;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import com.baidu.ueditor.define.ActionMap;
+
+/**
+ * 配置管理器
+ * @author hancong03@baidu.com
+ *
+ */
+public final class ConfigManager {
+
+ private final String rootPath;
+ private final String originalPath;
+ private final String contextPath;
+ private static final String configFileName = "config.json";
+ private String parentPath = null;
+ private JSONObject jsonConfig = null;
+ // 涂鸦上传filename定义
+ private final static String SCRAWL_FILE_NAME = "scrawl";
+ // 远程图片抓取filename定义
+ private final static String REMOTE_FILE_NAME = "remote";
+
+ /*
+ * 通过一个给定的路径构建一个配置管理器, 该管理器要求地址路径所在目录下必须存在config.properties文件
+ */
+ private ConfigManager ( String rootPath, String contextPath, String uri ) throws FileNotFoundException, IOException {
+
+ rootPath = rootPath.replace( "\\", "/" );
+
+ this.rootPath = rootPath;
+ this.contextPath = contextPath;
+
+ if ( contextPath.length() > 0 ) {
+ this.originalPath = this.rootPath + uri.substring( contextPath.length() );
+ } else {
+ this.originalPath = this.rootPath + uri;
+ }
+
+ this.initEnv();
+
+ }
+
+ /**
+ * 配置管理器构造工厂
+ * @param rootPath 服务器根路径
+ * @param contextPath 服务器所在项目路径
+ * @param uri 当前访问的uri
+ * @return 配置管理器实例或者null
+ */
+ public static ConfigManager getInstance ( String rootPath, String contextPath, String uri ) {
+
+ try {
+ return new ConfigManager(rootPath, contextPath, uri);
+ } catch ( Exception e ) {
+ return null;
+ }
+
+ }
+
+ // 验证配置文件加载是否正确
+ public boolean valid () {
+ return this.jsonConfig != null;
+ }
+
+ public JSONObject getAllConfig () {
+
+ return this.jsonConfig;
+
+ }
+
+ public Map getConfig ( int type ) {
+
+ Map conf = new HashMap();
+ String savePath = null;
+
+ switch ( type ) {
+
+ case ActionMap.UPLOAD_FILE:
+ conf.put( "isBase64", "false" );
+ conf.put( "maxSize", this.jsonConfig.getLong( "fileMaxSize" ) );
+ conf.put( "allowFiles", this.getArray( "fileAllowFiles" ) );
+ conf.put( "fieldName", this.jsonConfig.getString( "fileFieldName" ) );
+ savePath = this.jsonConfig.getString( "filePathFormat" );
+ break;
+
+ case ActionMap.UPLOAD_IMAGE:
+ conf.put( "isBase64", "false" );
+ conf.put( "maxSize", this.jsonConfig.getLong( "imageMaxSize" ) );
+ conf.put( "allowFiles", this.getArray( "imageAllowFiles" ) );
+ conf.put( "fieldName", this.jsonConfig.getString( "imageFieldName" ) );
+ savePath = this.jsonConfig.getString( "imagePathFormat" );
+ break;
+
+ case ActionMap.UPLOAD_VIDEO:
+ conf.put( "maxSize", this.jsonConfig.getLong( "videoMaxSize" ) );
+ conf.put( "allowFiles", this.getArray( "videoAllowFiles" ) );
+ conf.put( "fieldName", this.jsonConfig.getString( "videoFieldName" ) );
+ savePath = this.jsonConfig.getString( "videoPathFormat" );
+ break;
+
+ case ActionMap.UPLOAD_SCRAWL:
+ conf.put( "filename", ConfigManager.SCRAWL_FILE_NAME );
+ conf.put( "maxSize", this.jsonConfig.getLong( "scrawlMaxSize" ) );
+ conf.put( "fieldName", this.jsonConfig.getString( "scrawlFieldName" ) );
+ conf.put( "isBase64", "true" );
+ savePath = this.jsonConfig.getString( "scrawlPathFormat" );
+ break;
+
+ case ActionMap.CATCH_IMAGE:
+ conf.put( "filename", ConfigManager.REMOTE_FILE_NAME );
+ conf.put( "filter", this.getArray( "catcherLocalDomain" ) );
+ conf.put( "maxSize", this.jsonConfig.getLong( "catcherMaxSize" ) );
+ conf.put( "allowFiles", this.getArray( "catcherAllowFiles" ) );
+ conf.put( "fieldName", this.jsonConfig.getString( "catcherFieldName" ) + "[]" );
+ savePath = this.jsonConfig.getString( "catcherPathFormat" );
+ break;
+
+ case ActionMap.LIST_IMAGE:
+ conf.put( "allowFiles", this.getArray( "imageManagerAllowFiles" ) );
+ conf.put( "dir", this.jsonConfig.getString( "imageManagerListPath" ) );
+ conf.put( "count", this.jsonConfig.getInt( "imageManagerListSize" ) );
+ break;
+
+ case ActionMap.LIST_FILE:
+ conf.put( "allowFiles", this.getArray( "fileManagerAllowFiles" ) );
+ conf.put( "dir", this.jsonConfig.getString( "fileManagerListPath" ) );
+ conf.put( "count", this.jsonConfig.getInt( "fileManagerListSize" ) );
+ break;
+
+ }
+ conf.put( "basePath", this.jsonConfig.getString("basePath") );
+ conf.put( "savePath", savePath );
+ conf.put( "rootPath", this.rootPath );
+
+ return conf;
+
+ }
+
+ private void initEnv () throws FileNotFoundException, IOException {
+
+ File file = new File( this.originalPath );
+
+ if ( !file.isAbsolute() ) {
+ file = new File( file.getAbsolutePath() );
+ }
+
+ this.parentPath = file.getParent();
+
+ String configContent = this.readFile( this.getConfigPath() );
+
+ try{
+ JSONObject jsonConfig = new JSONObject( configContent );
+ this.jsonConfig = jsonConfig;
+ } catch ( Exception e ) {
+ this.jsonConfig = null;
+ }
+
+ }
+
+ private String getConfigPath () {
+ //return this.parentPath + File.separator + ConfigManager.configFileName;
+ /*=========手动修改部分=========*/
+ try{
+ //获取classpath下的config.json路径
+ return this.getClass().getClassLoader().getResource("config.json").toURI().getPath();
+ }catch (URISyntaxException e){
+ return null;
+ }
+ }
+
+ private String[] getArray ( String key ) {
+
+ JSONArray jsonArray = this.jsonConfig.getJSONArray( key );
+ String[] result = new String[ jsonArray.length() ];
+
+ for ( int i = 0, len = jsonArray.length(); i < len; i++ ) {
+ result[i] = jsonArray.getString( i );
+ }
+
+ return result;
+
+ }
+
+ private String readFile ( String path ) throws IOException {
+
+ StringBuilder builder = new StringBuilder();
+
+ try {
+
+ InputStreamReader reader = new InputStreamReader( new FileInputStream( path ), "UTF-8" );
+ BufferedReader bfReader = new BufferedReader( reader );
+
+ String tmpContent = null;
+
+ while ( ( tmpContent = bfReader.readLine() ) != null ) {
+ builder.append( tmpContent );
+ }
+
+ bfReader.close();
+
+ } catch ( UnsupportedEncodingException e ) {
+ // 忽略
+ }
+
+ return this.filter( builder.toString() );
+
+ }
+
+ // 过滤输入字符串, 剔除多行注释以及替换掉反斜杠
+ private String filter ( String input ) {
+
+ return input.replaceAll( "/\\*[\\s\\S]*?\\*/", "" );
+
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/Encoder.java b/src/main/java/com/baidu/ueditor/Encoder.java
new file mode 100644
index 0000000..00bce19
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/Encoder.java
@@ -0,0 +1,24 @@
+package com.baidu.ueditor;
+
+public class Encoder {
+
+ public static String toUnicode ( String input ) {
+
+ StringBuilder builder = new StringBuilder();
+ char[] chars = input.toCharArray();
+
+ for ( char ch : chars ) {
+
+ if ( ch < 256 ) {
+ builder.append( ch );
+ } else {
+ builder.append( "\\u" + Integer.toHexString( ch& 0xffff ) );
+ }
+
+ }
+
+ return builder.toString();
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/baidu/ueditor/PathFormat.java b/src/main/java/com/baidu/ueditor/PathFormat.java
new file mode 100644
index 0000000..080ea48
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/PathFormat.java
@@ -0,0 +1,157 @@
+package com.baidu.ueditor;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class PathFormat {
+
+ private static final String TIME = "time";
+ private static final String FULL_YEAR = "yyyy";
+ private static final String YEAR = "yy";
+ private static final String MONTH = "mm";
+ private static final String DAY = "dd";
+ private static final String HOUR = "hh";
+ private static final String MINUTE = "ii";
+ private static final String SECOND = "ss";
+ private static final String RAND = "rand";
+
+ private static Date currentDate = null;
+
+ public static String parse ( String input ) {
+
+ Pattern pattern = Pattern.compile( "\\{([^\\}]+)\\}", Pattern.CASE_INSENSITIVE );
+ Matcher matcher = pattern.matcher(input);
+
+ PathFormat.currentDate = new Date();
+
+ StringBuffer sb = new StringBuffer();
+
+ while ( matcher.find() ) {
+
+ matcher.appendReplacement(sb, PathFormat.getString( matcher.group( 1 ) ) );
+
+ }
+
+ matcher.appendTail(sb);
+
+ return sb.toString();
+ }
+
+ /**
+ * 格式化路径, 把windows路径替换成标准路径
+ * @param input 待格式化的路径
+ * @return 格式化后的路径
+ */
+ public static String format ( String input ) {
+
+ return input.replace( "\\", "/" );
+
+ }
+
+ public static String parse ( String input, String filename ) {
+
+ Pattern pattern = Pattern.compile( "\\{([^\\}]+)\\}", Pattern.CASE_INSENSITIVE );
+ Matcher matcher = pattern.matcher(input);
+ String matchStr = null;
+
+ PathFormat.currentDate = new Date();
+
+ StringBuffer sb = new StringBuffer();
+
+ while ( matcher.find() ) {
+
+ matchStr = matcher.group( 1 );
+ if ( matchStr.indexOf( "filename" ) != -1 ) {
+ filename = filename.replace( "$", "\\$" ).replaceAll( "[\\/:*?\"<>|]", "" );
+ matcher.appendReplacement(sb, filename );
+ } else {
+ matcher.appendReplacement(sb, PathFormat.getString( matchStr ) );
+ }
+
+ }
+
+ matcher.appendTail(sb);
+
+ return sb.toString();
+ }
+
+ private static String getString ( String pattern ) {
+
+ pattern = pattern.toLowerCase();
+
+ // time 处理
+ if ( pattern.indexOf( PathFormat.TIME ) != -1 ) {
+ return PathFormat.getTimestamp();
+ } else if ( pattern.indexOf( PathFormat.FULL_YEAR ) != -1 ) {
+ return PathFormat.getFullYear();
+ } else if ( pattern.indexOf( PathFormat.YEAR ) != -1 ) {
+ return PathFormat.getYear();
+ } else if ( pattern.indexOf( PathFormat.MONTH ) != -1 ) {
+ return PathFormat.getMonth();
+ } else if ( pattern.indexOf( PathFormat.DAY ) != -1 ) {
+ return PathFormat.getDay();
+ } else if ( pattern.indexOf( PathFormat.HOUR ) != -1 ) {
+ return PathFormat.getHour();
+ } else if ( pattern.indexOf( PathFormat.MINUTE ) != -1 ) {
+ return PathFormat.getMinute();
+ } else if ( pattern.indexOf( PathFormat.SECOND ) != -1 ) {
+ return PathFormat.getSecond();
+ } else if ( pattern.indexOf( PathFormat.RAND ) != -1 ) {
+ return PathFormat.getRandom( pattern );
+ }
+
+ return pattern;
+
+ }
+
+ private static String getTimestamp () {
+ return System.currentTimeMillis() + "";
+ }
+
+ private static String getFullYear () {
+ return new SimpleDateFormat( "yyyy" ).format( PathFormat.currentDate );
+ }
+
+ private static String getYear () {
+ return new SimpleDateFormat( "yy" ).format( PathFormat.currentDate );
+ }
+
+ private static String getMonth () {
+ return new SimpleDateFormat( "MM" ).format( PathFormat.currentDate );
+ }
+
+ private static String getDay () {
+ return new SimpleDateFormat( "dd" ).format( PathFormat.currentDate );
+ }
+
+ private static String getHour () {
+ return new SimpleDateFormat( "HH" ).format( PathFormat.currentDate );
+ }
+
+ private static String getMinute () {
+ return new SimpleDateFormat( "mm" ).format( PathFormat.currentDate );
+ }
+
+ private static String getSecond () {
+ return new SimpleDateFormat( "ss" ).format( PathFormat.currentDate );
+ }
+
+ private static String getRandom ( String pattern ) {
+
+ int length = 0;
+ pattern = pattern.split( ":" )[ 1 ].trim();
+
+ length = Integer.parseInt( pattern );
+
+ return ( Math.random() + "" ).replace( ".", "" ).substring( 0, length );
+
+ }
+
+ public static void main(String[] args) {
+ // TODO Auto-generated method stub
+
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/ActionMap.java b/src/main/java/com/baidu/ueditor/define/ActionMap.java
new file mode 100644
index 0000000..88f4f32
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/ActionMap.java
@@ -0,0 +1,42 @@
+package com.baidu.ueditor.define;
+
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * 定义请求action类型
+ * @author hancong03@baidu.com
+ *
+ */
+@SuppressWarnings("serial")
+public final class ActionMap {
+
+ public static final Map mapping;
+ // 获取配置请求
+ public static final int CONFIG = 0;
+ public static final int UPLOAD_IMAGE = 1;
+ public static final int UPLOAD_SCRAWL = 2;
+ public static final int UPLOAD_VIDEO = 3;
+ public static final int UPLOAD_FILE = 4;
+ public static final int CATCH_IMAGE = 5;
+ public static final int LIST_FILE = 6;
+ public static final int LIST_IMAGE = 7;
+
+ static {
+ mapping = new HashMap(){{
+ put( "config", ActionMap.CONFIG );
+ put( "uploadimage", ActionMap.UPLOAD_IMAGE );
+ put( "uploadscrawl", ActionMap.UPLOAD_SCRAWL );
+ put( "uploadvideo", ActionMap.UPLOAD_VIDEO );
+ put( "uploadfile", ActionMap.UPLOAD_FILE );
+ put( "catchimage", ActionMap.CATCH_IMAGE );
+ put( "listfile", ActionMap.LIST_FILE );
+ put( "listimage", ActionMap.LIST_IMAGE );
+ }};
+ }
+
+ public static int getType ( String key ) {
+ return ActionMap.mapping.get( key );
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/ActionState.java b/src/main/java/com/baidu/ueditor/define/ActionState.java
new file mode 100644
index 0000000..b0fad34
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/ActionState.java
@@ -0,0 +1,5 @@
+package com.baidu.ueditor.define;
+
+public enum ActionState {
+ UNKNOW_ERROR
+}
diff --git a/src/main/java/com/baidu/ueditor/define/AppInfo.java b/src/main/java/com/baidu/ueditor/define/AppInfo.java
new file mode 100644
index 0000000..b869f2a
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/AppInfo.java
@@ -0,0 +1,77 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class AppInfo {
+
+ public static final int SUCCESS = 0;
+ public static final int MAX_SIZE = 1;
+ public static final int PERMISSION_DENIED = 2;
+ public static final int FAILED_CREATE_FILE = 3;
+ public static final int IO_ERROR = 4;
+ public static final int NOT_MULTIPART_CONTENT = 5;
+ public static final int PARSE_REQUEST_ERROR = 6;
+ public static final int NOTFOUND_UPLOAD_DATA = 7;
+ public static final int NOT_ALLOW_FILE_TYPE = 8;
+
+ public static final int INVALID_ACTION = 101;
+ public static final int CONFIG_ERROR = 102;
+
+ public static final int PREVENT_HOST = 201;
+ public static final int CONNECTION_ERROR = 202;
+ public static final int REMOTE_FAIL = 203;
+
+ public static final int NOT_DIRECTORY = 301;
+ public static final int NOT_EXIST = 302;
+
+ public static final int ILLEGAL = 401;
+
+ public static Map info = new HashMap(){{
+
+ put( AppInfo.SUCCESS, "SUCCESS" );
+
+ // 无效的Action
+ put( AppInfo.INVALID_ACTION, "\u65E0\u6548\u7684Action" );
+ // 配置文件初始化失败
+ put( AppInfo.CONFIG_ERROR, "\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u5931\u8D25" );
+ // 抓取远程图片失败
+ put( AppInfo.REMOTE_FAIL, "\u6293\u53D6\u8FDC\u7A0B\u56FE\u7247\u5931\u8D25" );
+
+ // 被阻止的远程主机
+ put( AppInfo.PREVENT_HOST, "\u88AB\u963B\u6B62\u7684\u8FDC\u7A0B\u4E3B\u673A" );
+ // 远程连接出错
+ put( AppInfo.CONNECTION_ERROR, "\u8FDC\u7A0B\u8FDE\u63A5\u51FA\u9519" );
+
+ // "文件大小超出限制"
+ put( AppInfo.MAX_SIZE, "\u6587\u4ef6\u5927\u5c0f\u8d85\u51fa\u9650\u5236" );
+ // 权限不足, 多指写权限
+ put( AppInfo.PERMISSION_DENIED, "\u6743\u9650\u4E0D\u8DB3" );
+ // 创建文件失败
+ put( AppInfo.FAILED_CREATE_FILE, "\u521B\u5EFA\u6587\u4EF6\u5931\u8D25" );
+ // IO错误
+ put( AppInfo.IO_ERROR, "IO\u9519\u8BEF" );
+ // 上传表单不是multipart/form-data类型
+ put( AppInfo.NOT_MULTIPART_CONTENT, "\u4E0A\u4F20\u8868\u5355\u4E0D\u662Fmultipart/form-data\u7C7B\u578B" );
+ // 解析上传表单错误
+ put( AppInfo.PARSE_REQUEST_ERROR, "\u89E3\u6790\u4E0A\u4F20\u8868\u5355\u9519\u8BEF" );
+ // 未找到上传数据
+ put( AppInfo.NOTFOUND_UPLOAD_DATA, "\u672A\u627E\u5230\u4E0A\u4F20\u6570\u636E" );
+ // 不允许的文件类型
+ put( AppInfo.NOT_ALLOW_FILE_TYPE, "\u4E0D\u5141\u8BB8\u7684\u6587\u4EF6\u7C7B\u578B" );
+
+ // 指定路径不是目录
+ put( AppInfo.NOT_DIRECTORY, "\u6307\u5B9A\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55" );
+ // 指定路径并不存在
+ put( AppInfo.NOT_EXIST, "\u6307\u5B9A\u8DEF\u5F84\u5E76\u4E0D\u5B58\u5728" );
+
+ // callback参数名不合法
+ put( AppInfo.ILLEGAL, "Callback\u53C2\u6570\u540D\u4E0D\u5408\u6CD5" );
+
+ }};
+
+ public static String getStateInfo ( int key ) {
+ return AppInfo.info.get( key );
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/BaseState.java b/src/main/java/com/baidu/ueditor/define/BaseState.java
new file mode 100644
index 0000000..dcc881b
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/BaseState.java
@@ -0,0 +1,90 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.baidu.ueditor.Encoder;
+
+public class BaseState implements State {
+
+ private boolean state = false;
+ private String info = null;
+
+ private Map infoMap = new HashMap();
+
+ public BaseState () {
+ this.state = true;
+ }
+
+ public BaseState ( boolean state ) {
+ this.setState( state );
+ }
+
+ public BaseState ( boolean state, String info ) {
+ this.setState( state );
+ this.info = info;
+ }
+
+ public BaseState ( boolean state, int infoCode ) {
+ this.setState( state );
+ this.info = AppInfo.getStateInfo( infoCode );
+ }
+
+ public boolean isSuccess () {
+ return this.state;
+ }
+
+ public void setState ( boolean state ) {
+ this.state = state;
+ }
+
+ public void setInfo ( String info ) {
+ this.info = info;
+ }
+
+ public void setInfo ( int infoCode ) {
+ this.info = AppInfo.getStateInfo( infoCode );
+ }
+
+ @Override
+ public String toJSONString() {
+ return this.toString();
+ }
+
+ public String toString () {
+
+ String key = null;
+ String stateVal = this.isSuccess() ? AppInfo.getStateInfo( AppInfo.SUCCESS ) : this.info;
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append( "{\"state\": \"" + stateVal + "\"" );
+
+ Iterator iterator = this.infoMap.keySet().iterator();
+
+ while ( iterator.hasNext() ) {
+
+ key = iterator.next();
+
+ builder.append( ",\"" + key + "\": \"" + this.infoMap.get(key) + "\"" );
+
+ }
+
+ builder.append( "}" );
+
+ return Encoder.toUnicode( builder.toString() );
+
+ }
+
+ @Override
+ public void putInfo(String name, String val) {
+ this.infoMap.put(name, val);
+ }
+
+ @Override
+ public void putInfo(String name, long val) {
+ this.putInfo(name, val+"");
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/FileType.java b/src/main/java/com/baidu/ueditor/define/FileType.java
new file mode 100644
index 0000000..9195b85
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/FileType.java
@@ -0,0 +1,31 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class FileType {
+
+ public static final String JPG = "JPG";
+
+ private static final Map types = new HashMap(){{
+
+ put( FileType.JPG, ".jpg" );
+
+ }};
+
+ public static String getSuffix ( String key ) {
+ return FileType.types.get( key );
+ }
+
+ /**
+ * 根据给定的文件名,获取其后缀信息
+ * @param filename
+ * @return
+ */
+ public static String getSuffixByFilename ( String filename ) {
+
+ return filename.substring( filename.lastIndexOf( "." ) ).toLowerCase();
+
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/MIMEType.java b/src/main/java/com/baidu/ueditor/define/MIMEType.java
new file mode 100644
index 0000000..77c6cdd
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/MIMEType.java
@@ -0,0 +1,20 @@
+package com.baidu.ueditor.define;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MIMEType {
+
+ public static final Map types = new HashMap(){{
+ put( "image/gif", ".gif" );
+ put( "image/jpeg", ".jpg" );
+ put( "image/jpg", ".jpg" );
+ put( "image/png", ".png" );
+ put( "image/bmp", ".bmp" );
+ }};
+
+ public static String getSuffix ( String mime ) {
+ return MIMEType.types.get( mime );
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/MultiState.java b/src/main/java/com/baidu/ueditor/define/MultiState.java
new file mode 100644
index 0000000..26caefb
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/MultiState.java
@@ -0,0 +1,112 @@
+package com.baidu.ueditor.define;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.baidu.ueditor.Encoder;
+
+/**
+ * 多状态集合状态
+ * 其包含了多个状态的集合, 其本身自己也是一个状态
+ * @author hancong03@baidu.com
+ *
+ */
+public class MultiState implements State {
+
+ private boolean state = false;
+ private String info = null;
+ private Map intMap = new HashMap();
+ private Map infoMap = new HashMap();
+ private List stateList = new ArrayList();
+
+ public MultiState ( boolean state ) {
+ this.state = state;
+ }
+
+ public MultiState ( boolean state, String info ) {
+ this.state = state;
+ this.info = info;
+ }
+
+ public MultiState ( boolean state, int infoKey ) {
+ this.state = state;
+ this.info = AppInfo.getStateInfo( infoKey );
+ }
+
+ @Override
+ public boolean isSuccess() {
+ return this.state;
+ }
+
+ public void addState ( State state ) {
+ stateList.add( state.toJSONString() );
+ }
+
+ /**
+ * 该方法调用无效果
+ */
+ @Override
+ public void putInfo(String name, String val) {
+ this.infoMap.put(name, val);
+ }
+
+ @Override
+ public String toJSONString() {
+
+ String stateVal = this.isSuccess() ? AppInfo.getStateInfo( AppInfo.SUCCESS ) : this.info;
+
+ StringBuilder builder = new StringBuilder();
+
+ builder.append( "{\"state\": \"" + stateVal + "\"" );
+
+ // 数字转换
+ Iterator iterator = this.intMap.keySet().iterator();
+
+ while ( iterator.hasNext() ) {
+
+ stateVal = iterator.next();
+
+ builder.append( ",\""+ stateVal +"\": " + this.intMap.get( stateVal ) );
+
+ }
+
+ iterator = this.infoMap.keySet().iterator();
+
+ while ( iterator.hasNext() ) {
+
+ stateVal = iterator.next();
+
+ builder.append( ",\""+ stateVal +"\": \"" + this.infoMap.get( stateVal ) + "\"" );
+
+ }
+
+ builder.append( ", list: [" );
+
+
+ iterator = this.stateList.iterator();
+
+ while ( iterator.hasNext() ) {
+
+ builder.append( iterator.next() + "," );
+
+ }
+
+ if ( this.stateList.size() > 0 ) {
+ builder.deleteCharAt( builder.length() - 1 );
+ }
+
+ builder.append( " ]}" );
+
+ return Encoder.toUnicode( builder.toString() );
+
+ }
+
+ @Override
+ public void putInfo(String name, long val) {
+ this.intMap.put( name, val );
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/define/State.java b/src/main/java/com/baidu/ueditor/define/State.java
new file mode 100644
index 0000000..8f22274
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/define/State.java
@@ -0,0 +1,18 @@
+package com.baidu.ueditor.define;
+
+/**
+ * 处理状态接口
+ * @author hancong03@baidu.com
+ *
+ */
+public interface State {
+
+ public boolean isSuccess ();
+
+ public void putInfo( String name, String val );
+
+ public void putInfo ( String name, long val );
+
+ public String toJSONString ();
+
+}
diff --git a/src/main/java/com/baidu/ueditor/hunter/FileManager.java b/src/main/java/com/baidu/ueditor/hunter/FileManager.java
new file mode 100644
index 0000000..5a8c1a0
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/hunter/FileManager.java
@@ -0,0 +1,112 @@
+package com.baidu.ueditor.hunter;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.io.FileUtils;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.MultiState;
+import com.baidu.ueditor.define.State;
+
+public class FileManager {
+
+ private String dir = null;
+ private String rootPath = null;
+ private String[] allowFiles = null;
+ private int count = 0;
+
+ public FileManager ( Map conf ) {
+
+ this.rootPath = (String)conf.get( "rootPath" );
+ this.dir = this.rootPath + (String)conf.get( "dir" );
+ this.allowFiles = this.getAllowFiles( conf.get("allowFiles") );
+ this.count = (Integer)conf.get( "count" );
+
+ }
+
+ public State listFile ( int index ) {
+
+ File dir = new File( this.dir );
+ State state = null;
+
+ if ( !dir.exists() ) {
+ return new BaseState( false, AppInfo.NOT_EXIST );
+ }
+
+ if ( !dir.isDirectory() ) {
+ return new BaseState( false, AppInfo.NOT_DIRECTORY );
+ }
+
+ Collection list = FileUtils.listFiles( dir, this.allowFiles, true );
+
+ if ( index < 0 || index > list.size() ) {
+ state = new MultiState( true );
+ } else {
+ Object[] fileList = Arrays.copyOfRange( list.toArray(), index, index + this.count );
+ state = this.getState( fileList );
+ }
+
+ state.putInfo( "start", index );
+ state.putInfo( "total", list.size() );
+
+ return state;
+
+ }
+
+ private State getState ( Object[] files ) {
+
+ MultiState state = new MultiState( true );
+ BaseState fileState = null;
+
+ File file = null;
+
+ for ( Object obj : files ) {
+ if ( obj == null ) {
+ break;
+ }
+ file = (File)obj;
+ fileState = new BaseState( true );
+ fileState.putInfo( "url", PathFormat.format( this.getPath( file ) ) );
+ state.addState( fileState );
+ }
+
+ return state;
+
+ }
+
+ private String getPath ( File file ) {
+
+ String path = file.getAbsolutePath();
+
+ return path.replace( this.rootPath, "/" );
+
+ }
+
+ private String[] getAllowFiles ( Object fileExt ) {
+
+ String[] exts = null;
+ String ext = null;
+
+ if ( fileExt == null ) {
+ return new String[ 0 ];
+ }
+
+ exts = (String[])fileExt;
+
+ for ( int i = 0, len = exts.length; i < len; i++ ) {
+
+ ext = exts[ i ];
+ exts[ i ] = ext.replace( ".", "" );
+
+ }
+
+ return exts;
+
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/hunter/ImageHunter.java b/src/main/java/com/baidu/ueditor/hunter/ImageHunter.java
new file mode 100644
index 0000000..265bfed
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/hunter/ImageHunter.java
@@ -0,0 +1,144 @@
+package com.baidu.ueditor.hunter;
+
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.MIMEType;
+import com.baidu.ueditor.define.MultiState;
+import com.baidu.ueditor.define.State;
+import com.baidu.ueditor.upload.StorageManager;
+
+/**
+ * 图片抓取器
+ * @author hancong03@baidu.com
+ *
+ */
+public class ImageHunter {
+
+ private String filename = null;
+ private String savePath = null;
+ private String rootPath = null;
+ private List allowTypes = null;
+ private long maxSize = -1;
+
+ private List filters = null;
+
+ public ImageHunter ( Map conf ) {
+
+ this.filename = (String)conf.get( "filename" );
+ this.savePath = (String)conf.get( "savePath" );
+ this.rootPath = (String)conf.get( "rootPath" );
+ this.maxSize = (Long)conf.get( "maxSize" );
+ this.allowTypes = Arrays.asList( (String[])conf.get( "allowFiles" ) );
+ this.filters = Arrays.asList( (String[])conf.get( "filter" ) );
+
+ }
+
+ public State capture ( String[] list ) {
+
+ MultiState state = new MultiState( true );
+
+ for ( String source : list ) {
+ state.addState( captureRemoteData( source ) );
+ }
+
+ return state;
+
+ }
+
+ public State captureRemoteData ( String urlStr ) {
+
+ HttpURLConnection connection = null;
+ URL url = null;
+ String suffix = null;
+
+ try {
+ url = new URL( urlStr );
+
+ if ( !validHost( url.getHost() ) ) {
+ return new BaseState( false, AppInfo.PREVENT_HOST );
+ }
+
+ connection = (HttpURLConnection) url.openConnection();
+
+ connection.setInstanceFollowRedirects( true );
+ connection.setUseCaches( true );
+
+ if ( !validContentState( connection.getResponseCode() ) ) {
+ return new BaseState( false, AppInfo.CONNECTION_ERROR );
+ }
+
+ suffix = MIMEType.getSuffix( connection.getContentType() );
+
+ if ( !validFileType( suffix ) ) {
+ return new BaseState( false, AppInfo.NOT_ALLOW_FILE_TYPE );
+ }
+
+ if ( !validFileSize( connection.getContentLength() ) ) {
+ return new BaseState( false, AppInfo.MAX_SIZE );
+ }
+
+ String savePath = this.getPath( this.savePath, this.filename, suffix );
+ String physicalPath = this.rootPath + savePath;
+
+ State state = StorageManager.saveFileByInputStream( connection.getInputStream(), physicalPath );
+
+ if ( state.isSuccess() ) {
+ state.putInfo( "url", PathFormat.format( savePath ) );
+ state.putInfo( "source", urlStr );
+ }
+
+ return state;
+
+ } catch ( Exception e ) {
+ return new BaseState( false, AppInfo.REMOTE_FAIL );
+ }
+
+ }
+
+ private String getPath ( String savePath, String filename, String suffix ) {
+
+ return PathFormat.parse( savePath + suffix, filename );
+
+ }
+
+ private boolean validHost ( String hostname ) {
+ try {
+ InetAddress ip = InetAddress.getByName(hostname);
+
+ if (ip.isSiteLocalAddress()) {
+ return false;
+ }
+ } catch (UnknownHostException e) {
+ return false;
+ }
+
+ return !filters.contains( hostname );
+
+ }
+
+ private boolean validContentState ( int code ) {
+
+ return HttpURLConnection.HTTP_OK == code;
+
+ }
+
+ private boolean validFileType ( String type ) {
+
+ return this.allowTypes.contains( type );
+
+ }
+
+ private boolean validFileSize ( int size ) {
+ return size < this.maxSize;
+ }
+
+}
diff --git a/src/main/java/com/baidu/ueditor/upload/Base64Uploader.java b/src/main/java/com/baidu/ueditor/upload/Base64Uploader.java
new file mode 100644
index 0000000..2f81076
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/upload/Base64Uploader.java
@@ -0,0 +1,52 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.FileType;
+import com.baidu.ueditor.define.State;
+
+import java.util.Map;
+
+import org.apache.commons.codec.binary.Base64;
+
+public final class Base64Uploader {
+
+ public static State save(String content, Map conf) {
+
+ byte[] data = decode(content);
+
+ long maxSize = ((Long) conf.get("maxSize")).longValue();
+
+ if (!validSize(data, maxSize)) {
+ return new BaseState(false, AppInfo.MAX_SIZE);
+ }
+
+ String suffix = FileType.getSuffix("JPG");
+
+ String savePath = PathFormat.parse((String) conf.get("savePath"),
+ (String) conf.get("filename"));
+
+ savePath = savePath + suffix;
+ String physicalPath = (String) conf.get("rootPath") + savePath;
+
+ State storageState = StorageManager.saveBinaryFile(data, physicalPath);
+
+ if (storageState.isSuccess()) {
+ storageState.putInfo("url", PathFormat.format(savePath));
+ storageState.putInfo("type", suffix);
+ storageState.putInfo("original", "");
+ }
+
+ return storageState;
+ }
+
+ private static byte[] decode(String content) {
+ return Base64.decodeBase64(content);
+ }
+
+ private static boolean validSize(byte[] data, long length) {
+ return data.length <= length;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/baidu/ueditor/upload/BinaryUploader.java b/src/main/java/com/baidu/ueditor/upload/BinaryUploader.java
new file mode 100644
index 0000000..452ced3
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/upload/BinaryUploader.java
@@ -0,0 +1,108 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.PathFormat;
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.FileType;
+import com.baidu.ueditor.define.State;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+
+public class BinaryUploader {
+
+ public static final State save(HttpServletRequest request,
+ Map conf) {
+ // FileItemStream fileStream = null;
+ // boolean isAjaxUpload = request.getHeader( "X_Requested_With" ) != null;
+
+ if (!ServletFileUpload.isMultipartContent(request)) {
+ return new BaseState(false, AppInfo.NOT_MULTIPART_CONTENT);
+ }
+
+ // ServletFileUpload upload = new ServletFileUpload(
+ // new DiskFileItemFactory());
+ //
+ // if ( isAjaxUpload ) {
+ // upload.setHeaderEncoding( "UTF-8" );
+ // }
+
+ try {
+ // FileItemIterator iterator = upload.getItemIterator(request);
+ //
+ // while (iterator.hasNext()) {
+ // fileStream = iterator.next();
+ //
+ // if (!fileStream.isFormField())
+ // break;
+ // fileStream = null;
+ // }
+ //
+ // if (fileStream == null) {
+ // return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
+ // }
+ MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
+ MultipartFile multipartFile = multipartRequest.getFile(conf.get("fieldName").toString());
+ if(multipartFile==null){
+ return new BaseState(false, AppInfo.NOTFOUND_UPLOAD_DATA);
+ }
+
+ String savePath = (String) conf.get("savePath");
+ //String originFileName = fileStream.getName();
+ String originFileName = multipartFile.getOriginalFilename();
+ String suffix = FileType.getSuffixByFilename(originFileName);
+
+ originFileName = originFileName.substring(0,
+ originFileName.length() - suffix.length());
+ savePath = savePath + suffix;
+
+ long maxSize = ((Long) conf.get("maxSize")).longValue();
+
+ if (!validType(suffix, (String[]) conf.get("allowFiles"))) {
+ return new BaseState(false, AppInfo.NOT_ALLOW_FILE_TYPE);
+ }
+
+ savePath = PathFormat.parse(savePath, originFileName);
+
+ String basePath=(String) conf.get("basePath");
+ String physicalPath = basePath + savePath;
+
+ //InputStream is = fileStream.openStream();
+ InputStream is = multipartFile.getInputStream();
+ State storageState = StorageManager.saveFileByInputStream(is,
+ physicalPath, maxSize);
+ is.close();
+
+ if (storageState.isSuccess()) {
+ storageState.putInfo("url", PathFormat.format(savePath));
+ storageState.putInfo("type", suffix);
+ storageState.putInfo("original", originFileName + suffix);
+ }
+
+ return storageState;
+ // } catch (FileUploadException e) {
+ // return new BaseState(false, AppInfo.PARSE_REQUEST_ERROR);
+ } catch (IOException e) {
+ }
+ return new BaseState(false, AppInfo.IO_ERROR);
+ }
+
+ private static boolean validType(String type, String[] allowTypes) {
+ List list = Arrays.asList(allowTypes);
+
+ return list.contains(type);
+ }
+}
diff --git a/src/main/java/com/baidu/ueditor/upload/StorageManager.java b/src/main/java/com/baidu/ueditor/upload/StorageManager.java
new file mode 100644
index 0000000..b8793ef
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/upload/StorageManager.java
@@ -0,0 +1,156 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.define.AppInfo;
+import com.baidu.ueditor.define.BaseState;
+import com.baidu.ueditor.define.State;
+import org.apache.commons.io.FileUtils;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+
+public class StorageManager {
+ public static final int BUFFER_SIZE = 8192;
+
+ public StorageManager() {
+ }
+
+ public static State saveBinaryFile(byte[] data, String path) {
+ File file = new File(path);
+
+ State state = valid(file);
+
+ if (!state.isSuccess()) {
+ return state;
+ }
+
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(file));
+ bos.write(data);
+ bos.flush();
+ bos.close();
+ } catch (IOException ioe) {
+ return new BaseState(false, AppInfo.IO_ERROR);
+ }
+
+ state = new BaseState(true, file.getAbsolutePath());
+ state.putInfo( "size", data.length );
+ state.putInfo( "title", file.getName() );
+ return state;
+ }
+
+ public static State saveFileByInputStream(InputStream is, String path,
+ long maxSize) {
+ State state = null;
+
+ File tmpFile = getTmpFile();
+
+ byte[] dataBuf = new byte[ 2048 ];
+ BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);
+
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);
+
+ int count = 0;
+ while ((count = bis.read(dataBuf)) != -1) {
+ bos.write(dataBuf, 0, count);
+ }
+ bos.flush();
+ bos.close();
+
+ if (tmpFile.length() > maxSize) {
+ tmpFile.delete();
+ return new BaseState(false, AppInfo.MAX_SIZE);
+ }
+
+ state = saveTmpFile(tmpFile, path);
+
+ if (!state.isSuccess()) {
+ tmpFile.delete();
+ }
+
+ return state;
+
+ } catch (IOException e) {
+ }
+ return new BaseState(false, AppInfo.IO_ERROR);
+ }
+
+ public static State saveFileByInputStream(InputStream is, String path) {
+ State state = null;
+
+ File tmpFile = getTmpFile();
+
+ byte[] dataBuf = new byte[ 2048 ];
+ BufferedInputStream bis = new BufferedInputStream(is, StorageManager.BUFFER_SIZE);
+
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(
+ new FileOutputStream(tmpFile), StorageManager.BUFFER_SIZE);
+
+ int count = 0;
+ while ((count = bis.read(dataBuf)) != -1) {
+ bos.write(dataBuf, 0, count);
+ }
+ bos.flush();
+ bos.close();
+
+ state = saveTmpFile(tmpFile, path);
+
+ if (!state.isSuccess()) {
+ tmpFile.delete();
+ }
+
+ return state;
+ } catch (IOException e) {
+ }
+ return new BaseState(false, AppInfo.IO_ERROR);
+ }
+
+ private static File getTmpFile() {
+ File tmpDir = FileUtils.getTempDirectory();
+ String tmpFileName = (Math.random() * 10000 + "").replace(".", "");
+ return new File(tmpDir, tmpFileName);
+ }
+
+ private static State saveTmpFile(File tmpFile, String path) {
+ State state = null;
+ File targetFile = new File(path);
+
+ if (targetFile.canWrite()) {
+ return new BaseState(false, AppInfo.PERMISSION_DENIED);
+ }
+ try {
+ FileUtils.moveFile(tmpFile, targetFile);
+ } catch (IOException e) {
+ return new BaseState(false, AppInfo.IO_ERROR);
+ }
+
+ state = new BaseState(true);
+ state.putInfo( "size", targetFile.length() );
+ state.putInfo( "title", targetFile.getName() );
+
+ return state;
+ }
+
+ private static State valid(File file) {
+ File parentPath = file.getParentFile();
+
+ if ((!parentPath.exists()) && (!parentPath.mkdirs())) {
+ return new BaseState(false, AppInfo.FAILED_CREATE_FILE);
+ }
+
+ if (!parentPath.canWrite()) {
+ return new BaseState(false, AppInfo.PERMISSION_DENIED);
+ }
+
+ return new BaseState(true);
+ }
+}
diff --git a/src/main/java/com/baidu/ueditor/upload/Uploader.java b/src/main/java/com/baidu/ueditor/upload/Uploader.java
new file mode 100644
index 0000000..2312d1b
--- /dev/null
+++ b/src/main/java/com/baidu/ueditor/upload/Uploader.java
@@ -0,0 +1,29 @@
+package com.baidu.ueditor.upload;
+
+import com.baidu.ueditor.define.State;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+
+public class Uploader {
+ private HttpServletRequest request = null;
+ private Map conf = null;
+
+ public Uploader(HttpServletRequest request, Map conf) {
+ this.request = request;
+ this.conf = conf;
+ }
+
+ public final State doExec() {
+ String filedName = (String) this.conf.get("fieldName");
+ State state = null;
+
+ if ("true".equals(this.conf.get("isBase64"))) {
+ state = Base64Uploader.save(this.request.getParameter(filedName),
+ this.conf);
+ } else {
+ state = BinaryUploader.save(this.request, this.conf);
+ }
+
+ return state;
+ }
+}
diff --git a/src/main/java/com/saye/hrs/HrsApplication.java b/src/main/java/com/saye/hrs/HrsApplication.java
new file mode 100644
index 0000000..b3c77d2
--- /dev/null
+++ b/src/main/java/com/saye/hrs/HrsApplication.java
@@ -0,0 +1,20 @@
+package com.saye.hrs;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@SpringBootApplication
+@MapperScan("com.saye.hrs.mapper")
+@EnableTransactionManagement //开启事务
+@EnableScheduling
+public class HrsApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(HrsApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/saye/hrs/ServletInitializer.java b/src/main/java/com/saye/hrs/ServletInitializer.java
new file mode 100644
index 0000000..14953c2
--- /dev/null
+++ b/src/main/java/com/saye/hrs/ServletInitializer.java
@@ -0,0 +1,13 @@
+package com.saye.hrs;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+public class ServletInitializer extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(HrsApplication.class);
+ }
+
+}
diff --git a/src/main/java/com/saye/hrs/commons/JsonResult.java b/src/main/java/com/saye/hrs/commons/JsonResult.java
new file mode 100644
index 0000000..fe29cb7
--- /dev/null
+++ b/src/main/java/com/saye/hrs/commons/JsonResult.java
@@ -0,0 +1,120 @@
+package com.saye.hrs.commons;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.Serializable;
+
+/**
+ * 用于封装AJAX调用以后的JSON返回值
+ * 其中正确返回值:
+ * {state:0, data:返回数据, message:错误消息}
+ * 错误返回值:
+ * {state:1, data:null, message:错误消息}
+ **/
+public class JsonResult implements Serializable {
+
+ private static final long serialVersionUID = -3644950655568598241L;
+ //定义jackson对象
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+
+ /**
+ * 返回是否成功的状态, 0表示成功,
+ * 1或其他值 表示失败
+ */
+ private boolean state;
+ /**
+ * 成功时候,返回的JSON数据
+ */
+ private Object data;
+ /**
+ * 是错误时候的错误消息
+ */
+ private String message;
+
+
+ public JsonResult() {
+ }
+
+ public JsonResult(boolean state, Object data, String message) {
+ this.state = state;
+ this.data = data;
+ this.message = message;
+ }
+
+ public JsonResult(Throwable e){
+ state = false;
+ data=null;
+ message=e.getMessage();
+ }
+
+ public JsonResult(Object data){
+ state = true;
+ this.data=data;
+ message="";
+ }
+
+ public boolean isState() {
+ return state;
+ }
+
+ public void setState(boolean state) {
+ this.state = state;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+
+ public void setData(Object data) {
+ this.data = data;
+ }
+
+
+ public String getMessage() {
+ return message;
+ }
+
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public static String jsonResultSuccess(Object data, String message){
+ JsonResult jsonResult=new JsonResult();
+ jsonResult.setState(true);
+ jsonResult.setMessage(message);
+ jsonResult.setData(data);
+ return ObjectToJson(jsonResult);
+ }
+
+
+ public static String jsonResultFalse(String message){
+ JsonResult jsonResult=new JsonResult();
+ jsonResult.setState(false);
+ jsonResult.setMessage(message);
+ return ObjectToJson(jsonResult);
+ }
+
+ /**
+ * 将对象转化为json字符串
+ * @param data
+ * @return
+ */
+ public static String ObjectToJson(Object data){
+ try{
+ String string = MAPPER.writeValueAsString(data);
+ return string;
+ } catch (JsonProcessingException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "JsonResult [state=" + state + ", data=" + data + ", message=" + message + "]";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/saye/hrs/commons/TokenGenerateUtil.java b/src/main/java/com/saye/hrs/commons/TokenGenerateUtil.java
new file mode 100644
index 0000000..55928b4
--- /dev/null
+++ b/src/main/java/com/saye/hrs/commons/TokenGenerateUtil.java
@@ -0,0 +1,95 @@
+package com.saye.hrs.commons;
+
+import org.apache.commons.codec.CharEncoding;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+
+/**
+ *
+ * token生成工具类
+ *
+ *
+ * @author caoshiyan
+ * @version V1.0
+ * @date 2015年12月29日 上午10:16:14
+ * @modificationHistory=========================逻辑或功能性重大变更记录
+ * @modify by user: {修改人} 2015年12月29日
+ * @since
+ */
+public class TokenGenerateUtil {
+
+ /**
+ *
+ * MD5加密工具类
+ *
+ * @author caoshiyan
+ * @version V1.0
+ * @date 2015年11月30日 下午4:40:16
+ * @param s
+ * @return
+ *
+ * @modificationHistory=========================逻辑或功能性重大变更记录
+ * @modify by user: {修改人} 2015年11月30日
+ * @modify by reason:{方法名}:{原因}
+ * @since
+ */
+ public final static String md5(String s) {
+ char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ try {
+ MessageDigest mdTemp = MessageDigest.getInstance("MD5");
+ try {
+ // 最重要的是这句,需要加上编码类型
+ mdTemp.update(s.getBytes(CharEncoding.UTF_8));
+ } catch (UnsupportedEncodingException e) {
+ mdTemp.update(s.getBytes());
+ }
+ byte[] md = mdTemp.digest();
+ int j = md.length;
+ char str[] = new char[j * 2];
+ int k = 0;
+ for (int i = 0; i < j; i++) {
+ byte byte0 = md[i];
+ str[k++] = hexDigits[byte0 >>> 4 & 0xf];
+ str[k++] = hexDigits[byte0 & 0xf];
+ }
+ return new String(str).toUpperCase();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ *
+ * 生成token
+ *
+ * @author caoshiyan
+ * @version V1.0
+ * @date 2015年11月18日 下午6:28:01
+ * @param url GET请求URL带参数串;POST请求URL不带参数串,参数以JSON格式传入paramJson
+ * @param paramJson POST参数JSON格式
+ * @param secret 加密secret
+ * @return String 生成的token值
+ *
+ * @modificationHistory=========================逻辑或功能性重大变更记录
+ * @modify by user: {修改人} 2015年11月18日
+ * @modify by reason:{方法名}:{原因}
+ * @since
+ */
+ public final static String buildToken(String url, String paramJson, String secret) {
+ String tempUrl = null;
+ tempUrl = url.substring("http://".length());
+ int index = tempUrl.indexOf("/");
+ String URI = tempUrl.substring(index);
+ String[] ss = URI.split("\\?");
+ if (ss.length > 1) {
+ return md5(ss[0] + ss[1] + secret);
+ } else {
+ return md5(ss[0] + paramJson + secret);
+ }
+ }
+ public static void main(String[] args) {
+ System.out.println(md5("/webapi/service/vss/getPlatEncodeDeviceResList{\"pageNo\":1,\"pageSize\":1000,\"appkey\":\"8a3018ac\",\"time\":1610594097178}69befa1eca0644af8000fd23d7b8c0f7"));
+ }
+}
+///webapi/service/vss/getPlatEncodeDeviceResList{"pageNo":1,"pageSize":1000,"appkey":"8a3018ac","time":1610594044620}69befa1eca0644af8000fd23d7b8c0f7
diff --git a/src/main/java/com/saye/hrs/commons/date/DateDUtil.java b/src/main/java/com/saye/hrs/commons/date/DateDUtil.java
new file mode 100644
index 0000000..2e144d2
--- /dev/null
+++ b/src/main/java/com/saye/hrs/commons/date/DateDUtil.java
@@ -0,0 +1,329 @@
+package com.saye.hrs.commons.date;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+public class DateDUtil {
+
+
+ public static String yyyy_MM_dd = "yyyy-MM-dd";
+ public static String yyyyMMdd = "yyyyMMdd";
+ public static String yyyyMM = "yyyyMM";
+ public static String yyyy_MM = "yyyy-MM";
+ public static String yyyy_MM_dd_HH_00 = "yyyy-MM-dd HH:00";
+ public static String yyyy_MM_dd_HH_mm = "yyyy-MM-dd HH:mm";
+ public static String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
+ public static String yyyy_MM_dd_HH_mm_ss_SS = "yyyy-MM-dd HH:mm:ss.SS";
+ public static String yyyyMMddHHmm = "yyyyMMddHHmm";
+ public static String yyyyMMddHHmmss = "yyyyMMddHHmmss";
+ public static String yyyyMMddHHmmssSS = "yyyyMMddHHmmssSS";
+ public static String yyMMdd = "yyMMdd";
+ public static String yyyy_MM_dd_00_00 = "yyyy-MM-dd 00:00";
+
+ /**
+ * 将字符串时间改成Date类型
+ * @param format
+ * @param dateStr
+ * @return
+ */
+ public static Date strToDate(String format,String dateStr) {
+
+ Date date = null;
+
+ try {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
+ date = simpleDateFormat.parse(dateStr);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+
+ return date;
+ }
+
+
+ /**
+ * 将Date时间转成字符串
+ * @param format
+ * @param date
+ * @return
+ */
+ public static String DateToStr(String format,Date date){
+
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
+
+ return simpleDateFormat.format(date);
+ }
+
+
+
+ /**
+ * 获取2个字符日期的天数差
+ * @param p_startDate
+ * @param p_endDate
+ * @return 天数差
+ */
+ public static long getDaysOfTowDiffDate( String p_startDate, String p_endDate ){
+
+ Date l_startDate = DateDUtil.strToDate(DateDUtil.yyyy_MM_dd, p_startDate);
+ Date l_endDate = DateDUtil.strToDate(DateDUtil.yyyy_MM_dd, p_endDate);
+ long l_startTime = l_startDate.getTime();
+ long l_endTime = l_endDate.getTime();
+ long betweenDays = (long) ( ( l_endTime - l_startTime ) / ( 1000 * 60 * 60 * 24 ) );
+ return betweenDays;
+ }
+
+
+ /**
+ * 获取2个字符日期的天数差
+ * @param l_startDate
+ * @param l_endDate
+ * @return 天数差
+ */
+ public static long getDaysOfTowDiffDate( Date l_startDate, Date l_endDate ){
+
+ long l_startTime = l_startDate.getTime();
+ long l_endTime = l_endDate.getTime();
+ long betweenDays = (long) ( ( l_endTime - l_startTime ) / ( 1000 * 60 * 60 * 24 ) );
+ return betweenDays;
+ }
+
+
+ /**
+ * 给出日期添加一段时间后的日期
+ * @param dateStr
+ * @param plus
+ * @return
+ */
+ public static String getPlusDays(String format,String dateStr,long plus){
+
+ Date date = DateDUtil.strToDate(format, dateStr);
+
+ long time = date.getTime()+ plus*24*60*60*1000;
+
+
+ return DateDUtil.DateToStr(format,new Date(time));
+ }
+
+
+ /**
+ * 给出日期添加一段时间后的日期
+ * @param format
+ * @param date
+ * @param plus
+ * @return
+ */
+ public static String getPlusDays(String format,Date date,long plus){
+
+
+ long time = date.getTime()+ plus*24*60*60*1000;
+
+
+ return DateDUtil.DateToStr(format,new Date(time));
+ }
+
+ /**
+ * 给出日期添加一段时间前的日期
+ * @param format
+ * @param date
+ * @param forth
+ * @return
+ */
+ public static String getForthDays(String format,Date date,long forth){
+
+
+ long time = date.getTime()- forth*24*60*60*1000;
+
+
+ return DateDUtil.DateToStr(format,new Date(time));
+ }
+
+ /**
+ * 给出时间添加几个小时后的时间
+ * @param format
+ * @param dateStr
+ * @param plus
+ * @return
+ */
+ public static String getPlusHours(String format,String dateStr,long plus){
+
+ Date date = DateDUtil.strToDate(format, dateStr);
+
+ long time = date.getTime()+ plus*60*60*1000;
+
+
+ return DateDUtil.DateToStr(format,new Date(time));
+ }
+
+ /**
+ * 给出时间添加几个分钟后的时间
+ * @param format
+ * @param dateStr
+ * @param plus
+ * @return
+ */
+ public static String getPlusMinutes(String format,String dateStr,long plus){
+
+ Date date = DateDUtil.strToDate(format, dateStr);
+
+ long time = date.getTime()+ plus*60*1000;
+
+
+ return DateDUtil.DateToStr(format,new Date(time));
+ }
+
+ /**
+ * 得到当前时间,格式如:yyyy-MM-dd HH:mm:ss:SS
+ * @return
+ */
+ public static String getCurrentTime(){
+
+ String nowTime = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd_HH_mm_ss_SS, new Date());
+ return nowTime;
+ }
+
+ /**
+ * 得到当前时间,格式如:yyyy-MM-dd HH:mm:ss
+ * @return
+ */
+ public static String getTheCurrentTime(){
+
+ String nowTime = DateDUtil.DateToStr(DateDUtil.yyyy_MM_dd_HH_mm_ss, new Date());
+ return nowTime;
+ }
+
+ /**
+ * 得到当前日期,格式如:yyyyMMdd
+ * @return
+ */
+ public static String getCurrentDate(){
+
+ String nowDate = DateDUtil.DateToStr(DateDUtil.yyyyMMdd, new Date());
+ return nowDate;
+ }
+
+ /**
+ * 得到当前日期,格式如:yyyyMMdd
+ * @return
+ */
+ public static String getCurrentDate(String format){
+
+ String nowDate = DateDUtil.DateToStr(format, new Date());
+ return nowDate;
+ }
+
+ /**
+ * 获取2个字符日期的分钟数差
+ * @param p_startDate
+ * @param p_endDate
+ * @return 相差的分钟
+ */
+ public static long getMinutesOfTowDiffDate(String p_startDate, String p_endDate ){
+
+ Date l_startDate = DateDUtil.strToDate(DateDUtil.yyyy_MM_dd_HH_mm_ss_SS, p_startDate);
+ Date l_endDate = DateDUtil.strToDate(DateDUtil.yyyy_MM_dd_HH_mm_ss_SS, p_endDate);
+ long l_startTime = l_startDate.getTime();
+ long l_endTime = l_endDate.getTime();
+ long betweenMinutes = (long) ( ( l_endTime - l_startTime ) / ( 1000 * 60) );
+ return betweenMinutes;
+ }
+
+ /**
+ * 获取2个字符日期的分钟数差
+ * @param p_startDate
+ * @param p_endDate
+ * @return 相差的分钟
+ */
+ public static long getMinutesOfTowDiffDateMin(String format,String p_startDate, String p_endDate ){
+
+ Date l_startDate = DateDUtil.strToDate(format, p_startDate);
+ Date l_endDate = DateDUtil.strToDate(format, p_endDate);
+ long l_startTime = l_startDate.getTime();
+ long l_endTime = l_endDate.getTime();
+ long betweenMinutes = (long) ( ( l_endTime - l_startTime ) / ( 1000 * 60) );
+ return betweenMinutes;
+ }
+ public static long getMonthIntervalOfTowDiffDate(String p_startMonth, String p_endMonth){
+
+ Date l_startDate = DateDUtil.strToDate(DateDUtil.yyyy_MM, p_startMonth);
+ Date l_endDate = DateDUtil.strToDate(DateDUtil.yyyy_MM, p_endMonth);
+
+
+ Calendar calender = Calendar.getInstance();
+ calender.setTime(l_startDate);
+
+ long l_startMonth = calender.get(Calendar.MONTH)+1;
+ long l_startYear = calender.get(Calendar.YEAR);
+
+ calender.setTime(l_endDate);
+
+ long l_endMonth =calender.get(Calendar.MONTH)+1;
+ long l_endYear = calender.get(Calendar.YEAR);
+
+ long betweenYear = l_endYear - l_startYear;
+ long betweenMonth = (long) ( l_endMonth - l_startMonth ) ;
+
+ return betweenYear * 12 + betweenMonth;
+ }
+
+ /**
+ * 将字符串日期转为cron表达式
+ */
+ public static String getCron(String execute_time) throws Exception{
+
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss);
+ Date date = simpleDateFormat.parse(execute_time);
+ SimpleDateFormat dateFormat = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
+ return dateFormat.format(date);
+ }
+ /**
+ * 获取当前年月日日期
+ */
+
+ public static String getCDate(){
+ Calendar now = Calendar.getInstance();
+ String year=now.get(Calendar.YEAR)+"";
+ String month=(now.get(Calendar.MONTH) + 1) + "";
+ String day=now.get(Calendar.DAY_OF_MONTH)+"";
+ if ((now.get(Calendar.MONTH) + 1) < 10) month = "0" + month;
+ if (now.get(Calendar.DAY_OF_MONTH) < 10) day= "0" + day;
+ String nowDate = year+"年"+month+"月"+day+"日";
+ return nowDate;
+ }
+
+ public static List findWeekDays(String week) {
+ List list = new ArrayList();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ Calendar c = Calendar.getInstance();
+ // 今天是一周中的第几天
+ int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
+
+ if (c.getFirstDayOfWeek() == Calendar.SUNDAY) {
+ c.add(Calendar.DAY_OF_MONTH, 1);
+ }
+
+ if("lastWeek".equals(week)){
+ dayOfWeek = -dayOfWeek-7;
+ }else if("thisWeek".equals(week)){
+ dayOfWeek = -dayOfWeek;
+ }else if("nextWeek".equals(week)){
+ dayOfWeek = -dayOfWeek+7;
+ }
+ // 计算一周开始的日期
+ c.add(Calendar.DAY_OF_MONTH, dayOfWeek);
+
+ for (int i = 1; i <= 7; i++) {
+ c.add(Calendar.DAY_OF_MONTH, 1);
+ list.add(sdf.format(c.getTime()));
+ }
+ return list;
+ }
+
+ public static void main(String[] args) {
+ System.out.println();
+ }
+
+}
diff --git a/src/main/java/com/saye/hrs/commons/encrypt/EncryptUtil.java b/src/main/java/com/saye/hrs/commons/encrypt/EncryptUtil.java
new file mode 100644
index 0000000..ba39c0a
--- /dev/null
+++ b/src/main/java/com/saye/hrs/commons/encrypt/EncryptUtil.java
@@ -0,0 +1,68 @@
+package com.saye.hrs.commons.encrypt;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class EncryptUtil {
+
+ // AES ecb模式解密 key:秘钥 initVector:偏移量 encrypted:加密内容
+ public static String decrypt(String key,String initVector,String encrypted) {
+ try {
+ IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
+ SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
+
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
+ cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
+ byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
+
+ return new String(original);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ return null;
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.out.println(decrypt("a6xdabhysfescfbu","encryptionIntVec","oYzamqnnyJ8GG6646PDYBQ=="));
+ }
+
+ public static String getSHA256Str(String str){
+ MessageDigest messageDigest;
+ String encodeStr = "";
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-256");
+ messageDigest.update(str.getBytes("UTF-8"));
+ encodeStr = byte2Hex(messageDigest.digest());
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return encodeStr;
+ }
+ /**
+ * 将byte转为16进制
+ * @param bytes
+ * @return
+ */
+ private static String byte2Hex(byte[] bytes){
+ StringBuffer stringBuffer = new StringBuffer();
+ String temp = null;
+ for (int i=0;i data;
+ private Object[] statisticData;
+ private String titleName;
+ private short titleHeight = 500;
+ private short headerHeight = 300;
+ private short cellHeight = 300;
+ private HSSFWorkbook wb;
+ private HSSFSheet sheet;
+ private HSSFCellStyle headerCellStyle;
+ private HSSFCellStyle cellStyle;
+ private String[] header;
+ private String[] subHeader;
+ private String[] width;
+ private String[] sqlKey;
+ private IConversionByExport conversion;
+ private List mergeRanges = new ArrayList();
+
+ private Boolean isHeaderMergeTwo = Boolean.FALSE;
+ private int headerRowIndex = 1;
+ private int subHeaderRowIndex = 2;
+
+ private int titleMergeColumnIndex = 0;
+ private HashMap modifiedDataHeightHM = new HashMap(); //要修改的数据行的高度
+ private short subHeaderHeight = 300;
+
+ private Boolean isCreateFreezePane = true;
+
+ private HashMap skipedDataIndexMap; //要空行的数据列序号:KEY为data的序号 , VALUE默认为1
+ private List> resetCellStyleList = new ArrayList>(); //要重新设置样式的单元格:KEY为行号,VALUE为列号
+ private HSSFCellStyle resetCellStyle;
+
+ /**
+ *
+ *构造函数:得到一个纵向打印在A4纸上的xls
+ *
+ */
+ public ExportXLS(String[] header){
+
+ this.wb = new HSSFWorkbook();
+ this.sheet = this.createSheet(false, ExportXLS.A4);
+
+ this.headerCellStyle = this.createCellStyle(ExportXLS.ALIGN_CENTER, VERTICAL_CENTER, 1111, HEADERSIZE, new HSSFColor.GREY_25_PERCENT().getIndex());
+ this.cellStyle = this.createCellStyle(ExportXLS.ALIGN_CENTER, VERTICAL_CENTER, 1111, HEADERSIZE, new HSSFColor.WHITE().getIndex());
+
+ this.setTitleName("export");
+ this.setHeader(header);
+ }
+
+
+ /**
+ * 设置打印纸大小,横向还是纵向
+ * @param header
+ * @param sqlKey
+ * @param pageSize
+ * @param landscapeFlag
+ */
+ public ExportXLS(String[] header,String[] sqlKey,Short pageSize,boolean landscapeFlag){
+
+ this.wb = new HSSFWorkbook();
+ this.sheet = this.createSheet(landscapeFlag, pageSize);
+
+ this.headerCellStyle = this.createCellStyle(ExportXLS.ALIGN_CENTER, VERTICAL_CENTER, 1111, HEADERSIZE, new HSSFColor.GREY_25_PERCENT().getIndex());
+ HSSFFont titlefont = this.wb.createFont(); //设置字体
+ titlefont.setFontHeightInPoints(ExportXLS.HEADERSIZE);
+ titlefont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
+ headerCellStyle.setFont(titlefont);
+
+ this.cellStyle = this.createCellStyle(ExportXLS.ALIGN_CENTER, VERTICAL_CENTER, 1111, HEADERSIZE, new HSSFColor.WHITE().getIndex());
+
+ this.setTitleName("export");
+ this.setHeader(header);
+ this.setSqlKey(sqlKey);
+ }
+
+
+
+ private void setHeader(String[] header){
+ this.header = header;
+
+ //默认设置每个单元格的宽度为3500
+ int length = this.header.length;
+ this.width = new String[length];
+ for(int i=0;i this.header.length){
+
+ for (int i = this.header.length; i < this.subHeader.length; i++) {
+
+ HSSFCell headerCell = headerRow.createCell(i);
+ headerCell.setCellStyle(this.headerCellStyle);
+ headerCell.setCellValue("");
+ }
+ }
+
+ //填入副标题数据
+ HSSFRow subHeaderRow = this.sheet.createRow(this.subHeaderRowIndex);
+ subHeaderRow.setHeight(this.subHeaderHeight);
+ for(int i=0;i resetCellStyleHM = resetCellStyleList.get(i);
+ Iterator> it = resetCellStyleHM.entrySet().iterator();
+ while (it.hasNext()) {
+
+ Map.Entry entry = it.next();
+ Integer rowIndex = entry.getKey();
+ Integer columnIndex = entry.getValue();
+ this.sheet.getRow(rowIndex).getCell(columnIndex).setCellStyle(this.resetCellStyle);
+ }
+ }
+ }
+
+
+ //设置合并开始标识
+ boolean mergedStartFlag = false;
+ int[] startAndEnd = null;
+ List mergedIndex = new ArrayList();
+
+ if(null != this.statisticData){
+
+ //追加统计行
+ HSSFRow appendRow = this.sheet.createRow(this.sheet.getLastRowNum()+1);
+ for(int i=0;i dataList){
+ this.data = dataList;
+ }
+
+
+
+
+ /* (非 Javadoc)
+ * @see com.saye.common.export.IEport#appendStatisticRow(Object StatisticData)
+ */
+ public void appendStatisticRow(Object statisticData) {
+
+ //如果不存在转换对象,则使用默认的转换方法
+ if(this.conversion != null){
+ this.statisticData = this.conversion.conversion(statisticData, this.sqlKey);
+ }else{
+ this.statisticData = this.conversion(statisticData);
+ }
+
+ }
+ /* (非 Javadoc)
+ * @see com.saye.common.export.IEport#returnClientDownload(javax.servlet.http.HttpServletResponse)
+ */
+ public void returnClientDownload(HttpServletResponse response) throws IOException{
+
+ //将数据装填到sheet中
+ this.fillSheet();
+
+ response.reset();
+ response.setContentType("application/vnd.ms-excel");
+ response.setHeader("Content-Disposition","attachment; filename=" + new String(this.titleName.getBytes("gb2312"),"ISO8859-1")+".xls");
+ OutputStream os = null;
+ try {
+ os = response.getOutputStream();
+ this.wb.write(os);
+ } catch (Exception e) {
+ } finally {
+ if(os != null) {
+ os.close();
+ os = null;
+ }
+ }
+ }
+
+
+ /* (非 Javadoc)
+ * @see com.saye.common.export.IEport#returnClientOpen(javax.servlet.http.HttpServletResponse)
+ */
+ public void returnClientOpen(HttpServletResponse response) throws IOException{
+
+ //将数据装填到sheet中
+ this.fillSheet();
+
+ response.reset();
+ response.setContentType("application/vnd.ms-excel");
+ response.setHeader("Content-Disposition","online; filename=" + new String(this.titleName.getBytes("gb2312"),"ISO8859-1")+".xls");
+ try {
+ wb.write(response.getOutputStream());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ /* (非 Javadoc)
+ * @see com.saye.common.export.IEport#modifTitleHeight(short height)
+ */
+ public void modifTitleHeight(short height) {
+ this.titleHeight = height;
+ }
+
+ /**
+ * 设置副标题
+ * @param subHeader
+ */
+ public void setSubHeader(String[] subHeader){
+
+ this.subHeader = subHeader;
+
+ //默认设置每个单元格的宽度为3500
+ int headerLength = this.header.length;
+ int subHeaderLength = 0;
+ if(null != subHeader && 0 != subHeader.length){
+ subHeaderLength = this.subHeader.length;
+ }
+ int length = headerLength > subHeaderLength ? headerLength : subHeaderLength;
+ this.width = new String[length];
+ for(int i=0;i modifiedDataHeightHM) {
+ this.modifiedDataHeightHM = modifiedDataHeightHM;
+ }
+
+ /**
+ * 设置头部副标题高度
+ * @param subHeaderHeight
+ */
+ public void modifySubHeaderHeight(short subHeaderHeight) {
+ this.subHeaderHeight = subHeaderHeight;
+ }
+
+ /**
+ * 设置是否创建冻结窗体
+ * @param isCreateFreezePane
+ */
+ public void setIsCreateFreezePane(Boolean isCreateFreezePane) {
+ this.isCreateFreezePane = isCreateFreezePane;
+ }
+
+ /**
+ * 设置要空行的数据列序号
+ * @param skipedDataIndexMap
+ */
+ public void setSkipedDataIndexMap(HashMap skipedDataIndexMap) {
+ this.skipedDataIndexMap = skipedDataIndexMap;
+ }
+
+ /**
+ * 设置 重新设置样式的单元格序号及样式:样式为空时,默认为头部标题样式
+ * @param resetCellStyleList
+ * @param resetCellStyle
+ */
+ public void resetCellForCellStyle(List> resetCellStyleList, HSSFCellStyle resetCellStyle) {
+
+ this.resetCellStyleList = resetCellStyleList;
+ if(null == resetCellStyle){
+ resetCellStyle = this.headerCellStyle;
+ }
+ this.resetCellStyle = resetCellStyle;
+ }
+
+ /**
+ * 设置 工作薄 密码保护
+ * @param pwd
+ */
+ public void protectSheet(String pwd) {
+
+ this.sheet.protectSheet(pwd);
+ }
+
+ /**
+ * 设定抬头是否合并两行:在new ExportXLS之后就SET
+ * @param isHeaderMergeTwo
+ */
+ public void setIsHeaderMergeTwo(Boolean isHeaderMergeTwo) {
+
+ this.isHeaderMergeTwo = isHeaderMergeTwo;
+ if(!this.isHeaderMergeTwo){
+ this.headerRowIndex = 1;
+ this.subHeaderRowIndex = 2;
+ }
+ }
+
+}
diff --git a/src/main/java/com/saye/hrs/commons/excel/ExportXLSX.java b/src/main/java/com/saye/hrs/commons/excel/ExportXLSX.java
new file mode 100644
index 0000000..7159334
--- /dev/null
+++ b/src/main/java/com/saye/hrs/commons/excel/ExportXLSX.java
@@ -0,0 +1,790 @@
+
+package com.saye.hrs.commons.excel;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.awt.*;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.*;
+
+
+public class ExportXLSX implements IExport ,ISetExport{
+
+ Log logger = LogFactory.getLog(this.getClass());
+
+
+ public final static short ROWHEIGHT = 20; /*行高*/
+ public final static double PAGEMARGIN = 0.1;/*页边距*/
+ public final static short TITLESIZE = 16;/*标题文字大小*/
+ public final static short HEADERSIZE = 12;/*列头文字大小*/
+ public final static short DATA_CHARACTERSIZE = 9;/*汉字大小*/
+ public final static short DATA_NUMSIZE = 9;/*数字大小*/
+ public final static short DATA_DATESIZE = 9;/*日期大小*/
+ public final static String ALIGN_LEFT = "LEFT";/*水平居左*/
+ public final static String ALIGN_RIGHT = "RIGHT";/*水平居右*/
+ public final static String ALIGN_CENTER = "CENTER";/*水平居右*/
+ public final static String VERTICAL_TOP = "TOP";/*垂直居上*/
+ public final static String VERTICAL_CENTER = "MIDDLE";/*垂直居中*/
+ public final static String VERTICAL_BOTTOM = "BOTTOM";/*垂直居下*/
+ public final static short A4 = XSSFPrintSetup.A4_PAPERSIZE;
+ public final static short A5 = XSSFPrintSetup.A5_PAPERSIZE;
+ public final static short A3 = 8;
+
+
+
+ public final static String MERGEDEND = "_mergedend_";//表示合并次单元格
+
+
+
+
+
+ private List