diff --git b/.DS_Store a/.DS_Store
new file mode 100644
index 0000000..f7f3849
Binary files /dev/null and a/.DS_Store differ
diff --git b/.gitignore a/.gitignore
new file mode 100644
index 0000000..7763800
--- /dev/null
+++ a/.gitignore
@@ -0,0 +1,34 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/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/
+
+### VS Code ###
+.vscode/
+assets/
+logs/
\ No newline at end of file
diff --git b/.mvn/wrapper/MavenWrapperDownloader.java a/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..a45eb6b
--- /dev/null
+++ a/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed 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.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.6";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if (mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if (mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if (!outputFile.getParentFile().exists()) {
+ if (!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git b/.mvn/wrapper/maven-wrapper.jar a/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..2cc7d4a
Binary files /dev/null and a/.mvn/wrapper/maven-wrapper.jar differ
diff --git b/.mvn/wrapper/maven-wrapper.properties a/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..642d572
--- /dev/null
+++ a/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git b/mvnw a/mvnw
new file mode 100644
index 0000000..a16b543
--- /dev/null
+++ a/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 b/mvnw.cmd a/mvnw.cmd
new file mode 100644
index 0000000..c8d4337
--- /dev/null
+++ a/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 b/pom.xml a/pom.xml
new file mode 100644
index 0000000..1b28369
--- /dev/null
+++ a/pom.xml
@@ -0,0 +1,210 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.7.RELEASE
+
+
+
+ com.zhongzhi
+ zhongzhi
+ 1.0
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 3.3.0
+ 3.3.2
+ 2.9.2
+ 1.2.58
+ 2.0.0
+ 3.13
+ 1.1.0
+ 4.0.1
+ 3.9
+ 1.1.22
+ 5.2.0
+ 5.4.1
+ 3.10.3
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.freemarker
+ freemarker
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+ mysql
+ mysql-connector-java
+ runtime
+
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ ${druid.version}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ ${mybatis-plus.version}
+
+
+
+ com.baomidou
+ mybatis-plus-generator
+ ${generator.version}
+
+
+
+ com.alibaba
+ fastjson
+ ${fastjson.version}
+
+
+
+ io.springfox
+ springfox-swagger2
+ ${swagger2.version}
+
+
+
+ io.springfox
+ springfox-swagger-ui
+ ${swagger2.version}
+
+
+
+ com.amdelamar
+ jhash
+ ${jhash.version}
+
+
+
+ org.apache.poi
+ poi-ooxml
+ ${poi-ooxml.version}
+
+
+
+ com.aliyun
+ aliyun-java-sdk-dysmsapi
+ ${dysmsapi.version}
+
+
+ com.aliyun
+ aliyun-java-sdk-core
+ ${sdk-core.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${lang3.version}
+
+
+
+ com.itextpdf
+ itext-asian
+ ${itext-asian.version}
+
+
+
+ com.itextpdf
+ itextpdf
+ ${itextpdf.version}
+
+
+
+ com.auth0
+ java-jwt
+ ${java-jwt.version}
+
+
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ 3.15.0
+
+
+
+ com.tencentcloudapi
+ tencentcloud-sdk-java
+ 3.1.64
+
+
+
+ commons-httpclient
+ commons-httpclient
+ 3.1
+
+
+
+ org.apache.httpcomponents
+ fluent-hc
+ 4.5.13
+
+
+
+
+
+
+ central
+ aliyun maven
+ http://maven.aliyun.com/nexus/content/groups/public/
+ default
+
+ true
+
+
+
+
+
+ zhongzhi
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git b/src/.DS_Store a/src/.DS_Store
new file mode 100644
index 0000000..870a68b
Binary files /dev/null and a/src/.DS_Store differ
diff --git b/src/main/.DS_Store a/src/main/.DS_Store
new file mode 100644
index 0000000..80786e7
Binary files /dev/null and a/src/main/.DS_Store differ
diff --git b/src/main/java/.DS_Store a/src/main/java/.DS_Store
new file mode 100644
index 0000000..ed09e3d
Binary files /dev/null and a/src/main/java/.DS_Store differ
diff --git b/src/main/java/com/.DS_Store a/src/main/java/com/.DS_Store
new file mode 100644
index 0000000..6c815d8
Binary files /dev/null and a/src/main/java/com/.DS_Store differ
diff --git b/src/main/java/com/zhongzhi/.DS_Store a/src/main/java/com/zhongzhi/.DS_Store
new file mode 100644
index 0000000..3453da3
Binary files /dev/null and a/src/main/java/com/zhongzhi/.DS_Store differ
diff --git b/src/main/java/com/zhongzhi/ZhongzhiApplication.java a/src/main/java/com/zhongzhi/ZhongzhiApplication.java
new file mode 100644
index 0000000..b790a2a
--- /dev/null
+++ a/src/main/java/com/zhongzhi/ZhongzhiApplication.java
@@ -0,0 +1,17 @@
+package com.zhongzhi;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@MapperScan(basePackages = {"com.zhongzhi.dao"})
+@SpringBootApplication
+public class ZhongzhiApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ZhongzhiApplication.class, args);
+ }
+
+}
\ No newline at end of file
diff --git b/src/main/java/com/zhongzhi/common/configure/AliyunSmsProperties.java a/src/main/java/com/zhongzhi/common/configure/AliyunSmsProperties.java
new file mode 100644
index 0000000..8bf4bc1
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/configure/AliyunSmsProperties.java
@@ -0,0 +1,28 @@
+package com.zhongzhi.common.configure;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "sms")
+public class AliyunSmsProperties {
+
+ private String product;
+
+ private String domain;
+
+ private String accessKeyId;
+
+ private String accessKeySecret;
+
+ private String cpcode;
+
+ private String excode;
+
+ private String key;
+
+ private String rcsapi;
+
+}
diff --git b/src/main/java/com/zhongzhi/common/configure/MybatisPlusConfig.java a/src/main/java/com/zhongzhi/common/configure/MybatisPlusConfig.java
new file mode 100644
index 0000000..4ca9b62
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/configure/MybatisPlusConfig.java
@@ -0,0 +1,36 @@
+package com.zhongzhi.common.configure;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import com.zhongzhi.common.handler.MetaHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MybatisPlusConfig {
+
+ /**
+ * 分页
+ *
+ * @return
+ */
+ @Bean
+ public PaginationInterceptor paginationInterceptor() {
+ PaginationInterceptor page = new PaginationInterceptor();
+ page.setDialectType(DbType.MYSQL.getDb());
+ return page;
+ }
+
+ /**
+ * 自动填充功能
+ *
+ * @return
+ */
+ @Bean
+ public GlobalConfig globalConfig() {
+ GlobalConfig globalConfig = new GlobalConfig();
+ globalConfig.setMetaObjectHandler(new MetaHandler());
+ return globalConfig;
+ }
+}
\ No newline at end of file
diff --git b/src/main/java/com/zhongzhi/common/configure/RemoteProperties.java a/src/main/java/com/zhongzhi/common/configure/RemoteProperties.java
new file mode 100644
index 0000000..46b5fa0
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/configure/RemoteProperties.java
@@ -0,0 +1,36 @@
+package com.zhongzhi.common.configure;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * 读取状态码
+ *
+ *
+ * @author DengMin
+ * @date Created in 2020/08/24
+ */
+@Component
+@ConfigurationProperties(prefix = "c")
+@PropertySource(value = "classpath:code.properties", encoding = "UTF-8")
+public class RemoteProperties {
+
+ private static Map codeMessage = new HashMap<>();
+
+ public static String getMessage(Integer code) {
+ return codeMessage.get(code);
+ }
+
+ public Map getCodeMessage() {
+ return codeMessage;
+ }
+
+ public void setCodeMessage(Map codeMessage) {
+ RemoteProperties.codeMessage = codeMessage;
+ }
+}
\ No newline at end of file
diff --git b/src/main/java/com/zhongzhi/common/configure/SwaggerConfig.java a/src/main/java/com/zhongzhi/common/configure/SwaggerConfig.java
new file mode 100644
index 0000000..79547e7
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/configure/SwaggerConfig.java
@@ -0,0 +1,38 @@
+package com.zhongzhi.common.configure;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ *
+ * swagger2
+ *
+ *
+ * @author DengMin
+ * @since 2020/12/8
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig {
+
+ @Bean
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .pathMapping("/")
+ .select()
+ .apis(RequestHandlerSelectors.basePackage("com.zhongzhi.controller"))
+ .paths(PathSelectors.any())
+ .build()
+ .apiInfo(new ApiInfoBuilder()
+ .title("中职双创系统")
+ .description("接口文档")
+ .version("1.0")
+ .build());
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/configure/VODConfig.java a/src/main/java/com/zhongzhi/common/configure/VODConfig.java
new file mode 100644
index 0000000..aec1353
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/configure/VODConfig.java
@@ -0,0 +1,27 @@
+package com.zhongzhi.common.configure;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author: tuyp
+ * @create: 2020-06-01 16:46
+ */
+@Component
+@Data
+@ConfigurationProperties(prefix = "vod")
+public class VODConfig {
+
+ private String appId;
+
+ private String secretId;
+
+ private String secretKey;
+
+ private String api;
+
+ private String region;
+
+ private Integer classId;
+}
diff --git b/src/main/java/com/zhongzhi/common/configure/WebConfig.java a/src/main/java/com/zhongzhi/common/configure/WebConfig.java
new file mode 100644
index 0000000..3c656ea
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/configure/WebConfig.java
@@ -0,0 +1,75 @@
+package com.zhongzhi.common.configure;
+
+import com.zhongzhi.common.interceptor.AuthenticationInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.*;
+
+/**
+ * @author DengMin
+ * @date 2020/07/06
+ **/
+@Configuration
+public class WebConfig extends WebMvcConfigurationSupport {
+
+ @Autowired
+ private AuthenticationInterceptor authenticationInterceptor;
+
+ /**
+ * 跨域支持
+ *
+ * @param registry
+ */
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowCredentials(true)
+ .allowedOrigins("*")
+ .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
+ .maxAge(3600);
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ CorsConfiguration config = new CorsConfiguration();
+ config.setMaxAge(3600L);
+ config.addAllowedOrigin("*");
+ config.addAllowedMethod("*");
+ config.addAllowedHeader("*");
+ UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
+ configSource.registerCorsConfiguration("/**", config);
+ return new CorsFilter(configSource);
+ }
+
+ /**
+ * Swagger
+ *
+ * @param registry
+ */
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("/**")
+ .addResourceLocations("classpath:/static/");
+ registry.addResourceHandler("swagger-ui.html")
+ .addResourceLocations("classpath:/META-INF/resources/");
+ registry.addResourceHandler("/webjars/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/");
+ super.addResourceHandlers(registry);
+ }
+
+ /**
+ * 鉴权
+ *
+ * @param registry
+ */
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(authenticationInterceptor)
+ .excludePathPatterns("/static/*")
+ .addPathPatterns("/**");
+ }
+}
\ No newline at end of file
diff --git b/src/main/java/com/zhongzhi/common/constant/Code.java a/src/main/java/com/zhongzhi/common/constant/Code.java
new file mode 100644
index 0000000..69d55f2
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/Code.java
@@ -0,0 +1,33 @@
+package com.zhongzhi.common.constant;
+
+import lombok.Getter;
+
+@Getter
+public enum Code {
+
+ USERNAMENOTFOUND(1001, "用户不存在"),
+ BADCREDENTIALS(1002, "账户或者密码错误"),
+ ACCOUNTEXPIRED(1003, "账户过期"),
+ LOCKEDEXCEPTION(1004, "账户已锁定"),
+ DISABLEDEXCEPTION(1005, "账户已禁用"),
+ ACCESSDENIED(1006, "无权限访问"),
+ AUTHENTICATION(1007, "身份验证异常"),
+ NOHANDLERFOUND(1008, "找不到相应的视图处理器"),
+ PARAM_INVALID(1009, "参数不合法"),
+ TOKEN_EXCEPTION(1010, "无效的令牌"),
+ TOKEN_EXPIRED(1011, "令牌已过期"),
+ TOKEN_VERIFICATION_FAILED(1012, "令牌验证失败"),
+ OSS_ERROR(1013, "OSS文件上传异常"),
+ Network_ERROR(9000, "网络请求失败"),
+ SERVER_INTERNAL_ERROR(99999, "服务器内部错误"),
+ ;
+
+ private final Integer code;
+
+ private final String message;
+
+ Code(Integer code, String message) {
+ this.code = code;
+ this.message = message;
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/MemberType.java a/src/main/java/com/zhongzhi/common/constant/MemberType.java
new file mode 100644
index 0000000..62e4621
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/MemberType.java
@@ -0,0 +1,21 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 团队成员类型
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class MemberType {
+
+ /*
+ 团队负责人只能有一个且是项目申请人
+ */
+ public static final String PRINCIPAL = "团队负责人";
+
+ public static final String TEAM_MEMBER = "团队成员";
+
+ public static final String MENTOR = "指导教师";
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java a/src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java
new file mode 100644
index 0000000..d02ae14
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java
@@ -0,0 +1,84 @@
+package com.zhongzhi.common.constant;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class PDFCheckBox {
+
+ public static String getType(String type, String projectGroup) {
+ if (StringUtils.isBlank(type) &&
+ projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) {
+ return "□方案设计类 □模型创意类 □虚拟演示类";
+ } else if (StringUtils.isBlank(type) &&
+ projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) {
+ return "□服装与服饰类设计 □视觉传达类 □产品设计类";
+ }
+
+ String[] typeT = {"方案设计类", "模型创意类", "虚拟演示类"};
+ String typeValue = "";
+ if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) {
+ List typeList = Arrays.stream(typeT).collect(Collectors.toList());
+ List str = Arrays.stream(type.split(",")).collect(Collectors.toList());
+ for (String s : typeList) {
+ if (str.contains(s)) {
+ typeValue += "■" + s + " ";
+ } else {
+ typeValue += "□" + s + " ";
+ }
+ }
+ return typeValue;
+ } else if (projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) {
+ if (type.equals("服装与服饰类设计")) {
+ return "■服装与服饰类设计 □视觉传达类 □产品设计类";
+ } else if (type.equals("视觉传达类")) {
+ return "□服装与服饰类设计 ■视觉传达类 □产品设计类";
+ } else if (type.equals("产品设计类")) {
+ return "□服装与服饰类设计 □视觉传达类 ■产品设计类";
+ } else {
+ return "□服装与服饰类设计 □视觉传达类 □产品设计类";
+ }
+ }
+ return "";
+ }
+
+ public static String getRoadshow( String projectGroup) {
+ if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) {
+ return "□模型展示 □数字化演示" +
+ " □PPT演示 □其他";
+ } else if (projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) {
+ return "□物化产品展示 □作品模型展示" +
+ " □数字化演示 □PPT演示 □其他";
+ }
+
+ String[] roadshowT = {"模型展示", "数字化演示", "PPT演示", "其他"};
+ String[] roadshowC = {"物化产品展示", "作品模型展示", "数字化演示", "PPT演示", "其他"};
+
+// List str = Arrays.stream(roadshow.split(",")).collect(Collectors.toList());
+ String roadshowValue = "";
+ if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) {
+ List roadshowTList = Arrays.stream(roadshowT).collect(Collectors.toList());
+ for (String s : roadshowTList) {
+// if (str.contains(s)) {
+// roadshowValue += "■" + s + " ";
+// } else {
+// roadshowValue += "□" + s + " ";
+// }
+ }
+ return roadshowValue;
+ } else if (projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) {
+ List roadshowCList = Arrays.stream(roadshowC).collect(Collectors.toList());
+ for (String s : roadshowCList) {
+// if (str.contains(s)) {
+// roadshowValue += "■" + s + " ";
+// } else {
+// roadshowValue += "□" + s + " ";
+// }
+ }
+ return roadshowValue;
+ }
+ return "";
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/Platform.java a/src/main/java/com/zhongzhi/common/constant/Platform.java
new file mode 100644
index 0000000..00bcb93
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/Platform.java
@@ -0,0 +1,32 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 平台标识
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class Platform {
+
+ /*
+ 学生端
+ */
+ public static final String student = "student";
+
+ /*
+ 院校端
+ */
+ public static final String school = "school";
+
+ /*
+ 中心端
+ */
+ public static final String center = "center";
+
+ /*
+ 评审端
+ */
+ public static final String review = "review";
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/ProjectProgress.java a/src/main/java/com/zhongzhi/common/constant/ProjectProgress.java
new file mode 100644
index 0000000..12910d7
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/ProjectProgress.java
@@ -0,0 +1,9 @@
+package com.zhongzhi.common.constant;
+
+public class ProjectProgress {
+
+ public static final String REGISTERED = "已注册公司";
+
+ public static final String UNREGISTERED = "创意设计阶段";
+
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/ProjectReview.java a/src/main/java/com/zhongzhi/common/constant/ProjectReview.java
new file mode 100644
index 0000000..b104abc
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/ProjectReview.java
@@ -0,0 +1,30 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 项目评审状态
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class ProjectReview {
+
+ /**
+ * 评分状态(对于评分)
+ */
+ public static final String SUBMITTED = "已评审";
+
+ public static final String TO_SCORE = "待评审";
+
+ /**
+ * 评审状态(对于项目)
+ */
+ public static final String TO_REVIEWED = "待评审";
+
+ public static final String ASSIGNED = "已分配";
+
+ public static final String UNASSIGNED = "未分配";
+
+ public static final String REVIEW = "已评审";
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/ProjectSchedule.java a/src/main/java/com/zhongzhi/common/constant/ProjectSchedule.java
new file mode 100644
index 0000000..7f82823
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/ProjectSchedule.java
@@ -0,0 +1,24 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 项目进度
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class ProjectSchedule {
+
+ //报名阶段
+ public static final String REGISTER = "报名阶段";
+
+ // 校内赛
+ public static final String SCHOOL_REVIEW = "校级申请项目";
+
+// public static final String PRELIMINARY_REVIEW = "市级初赛项目";
+
+ public static final String SEMI_FINAL_REVIEW = "市级复赛项目";
+
+ public static final String FINAL_REVIEW = "市级决赛项目";
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/ProjectStatus.java a/src/main/java/com/zhongzhi/common/constant/ProjectStatus.java
new file mode 100644
index 0000000..41dcb23
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/ProjectStatus.java
@@ -0,0 +1,32 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 项目状态
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class ProjectStatus {
+
+// public static final String TO_REVIEW = "";
+
+ public static final String UN_SUBMITTED = "填写中";
+
+ public static final String WITHDRAWN = "已撤回";
+
+ public static final String SCHOOL_NOT_PASSED = "不予提交市级复赛";
+
+ public static final String REGISTER_NOT_PASSED = "报名不通过";
+
+ public static final String PRELIMINARY_NOT_PASSED = "不予提交市级初赛";
+
+ public static final String REMATCH_WINNING_AWARD = "市级优胜奖";
+
+ public static final String REMATCH_SILVER_AWARD = "市级银奖";
+
+ public static final String REMATCH_BRONZE_AWARD = "市级铜奖";
+
+ public static final String REMATCH_FINALS_GOLD_AWARD = "市级金奖";
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/ProjectType.java a/src/main/java/com/zhongzhi/common/constant/ProjectType.java
new file mode 100644
index 0000000..f591652
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/ProjectType.java
@@ -0,0 +1,32 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 项目组别
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class ProjectType {
+
+ /**
+ * 赛道
+ */
+ public static final String MAIN_TRACK = "主赛道";
+
+ public static final String SEED_TRACK = "种子赛道";
+
+ public static final String VOCATIONAL = "职教赛道";
+
+ /**
+ * 组别
+ */
+ public static final String TECHNOLOGY_INNOVATION_GROUP = "科技创新";
+
+ public static final String CULTURAL_CREATIVE_GROUP = "文化创意";
+
+ public static final String VOCATIONAL_GROUP = "高职";
+
+ public static final String SECONDARY_GROUP = "中职";
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/SMSTemplate.java a/src/main/java/com/zhongzhi/common/constant/SMSTemplate.java
new file mode 100644
index 0000000..bebf559
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/SMSTemplate.java
@@ -0,0 +1,31 @@
+package com.zhongzhi.common.constant;
+
+public class SMSTemplate {
+
+ /*
+ 项目进度通知
+ */
+ public static final String PROJECT_PROGRESS = "2760175";
+
+ /*
+ 项目提交通知
+ */
+ public static final String PROJECT_SUBMIT = "270159";
+
+ /*
+ 评审邀请通知 old
+ */
+ public static final String REVIEW_INVITATION_OLD = "2765806";
+
+ /**
+ *
+ */
+ public static final String REVIEW_INVITATION_NEW = "2939771";
+
+ /*
+ 撤销评审项目通知
+ */
+ public static final String CANCEL_REVIEW = "229303";
+
+
+}
diff --git b/src/main/java/com/zhongzhi/common/constant/SmsCode.java a/src/main/java/com/zhongzhi/common/constant/SmsCode.java
new file mode 100644
index 0000000..b49a411
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/constant/SmsCode.java
@@ -0,0 +1,30 @@
+package com.zhongzhi.common.constant;
+
+/**
+ *
+ * 短信标识
+ *
+ *
+ * @author DengMin
+ * @since 2021/6/9
+ */
+public class SmsCode {
+
+ /**
+ * 平台:student(学生端)、school(院校端)、center(中心端)、review(评审端)
+ */
+ public static final String student = "student";
+
+ public static final String school = "school";
+
+ public static final String center = "center";
+
+ public static final String review = "review";
+
+ /**
+ * 行为标识:register(注册标识)、login(登录标识)
+ */
+ public static final String register = "register";
+
+ public static final String login = "login";
+}
diff --git b/src/main/java/com/zhongzhi/common/exception/GlobalExceptionHandler.java a/src/main/java/com/zhongzhi/common/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..d24ae00
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/exception/GlobalExceptionHandler.java
@@ -0,0 +1,121 @@
+package com.zhongzhi.common.exception;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.zhongzhi.common.configure.RemoteProperties;
+import com.zhongzhi.common.constant.Code;
+import com.zhongzhi.common.utils.ResponseData;
+import com.zhongzhi.vo.ResponseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ /**
+ * 自定义异常
+ *
+ * @param e
+ * @return
+ */
+ @ExceptionHandler(value = HttpException.class)
+ public ResponseVO handlerException(HttpServletRequest request, HttpException e) {
+ String message = RemoteProperties.getMessage(e.getCode());
+ if (StringUtils.isBlank(message)) {
+ message = e.getMessage();
+ }
+ String url = request.getRequestURI();
+ return ResponseData.generateCreatedResponse(e.getCode(), message, url);
+ }
+
+ /**
+ * 404
+ *
+ * @param request
+ * @return
+ */
+ @ExceptionHandler(value = NoHandlerFoundException.class)
+ public ResponseVO NoHandlerFoundException(HttpServletRequest request) {
+ String url = request.getRequestURI();
+ return ResponseData.generateCreatedResponse(Code.NOHANDLERFOUND.getCode(), Code.NOHANDLERFOUND.getMessage(), url);
+ }
+
+ /**
+ * 请求方式错误
+ *
+ * @param request
+ * @return
+ */
+ @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
+ public ResponseVO HttpRequestMethodNotSupportedException(HttpServletRequest request) {
+ String url = request.getRequestURI();
+ return ResponseData.generateCreatedResponse(Code.NOHANDLERFOUND.getCode(), Code.NOHANDLERFOUND.getMessage(), url);
+ }
+
+ /**
+ * 参数不合法
+ *
+ * @param e
+ * @return
+ */
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseVO validateException(MethodArgumentNotValidException e) {
+ final List errList = new ArrayList<>();
+ e.getBindingResult().getAllErrors().stream().forEach(x -> {
+ errList.add(x.getDefaultMessage());
+ });
+ return ResponseData.generateCreatedResponse(Code.PARAM_INVALID.getCode(), Code.PARAM_INVALID.getMessage(), errList.toString());
+ }
+
+ /**
+ * JSON 序列化异常
+ *
+ * @param e
+ * @return
+ */
+ @ExceptionHandler(HttpMessageNotReadableException.class)
+ public ResponseVO exceptionHandler(HttpMessageNotReadableException e) {
+ log.error(e.getMessage());
+ return ResponseData.generateCreatedResponse(Code.PARAM_INVALID.getCode(), Code.PARAM_INVALID.getMessage() + ":{" + e.getMessage() + "}");
+ }
+
+ /**
+ * 校验异常
+ *
+ * @param e
+ * @return
+ */
+ @ExceptionHandler(BindException.class)
+ public ResponseVO BindException(BindException e) {
+ final List errList = new ArrayList<>();
+ e.getBindingResult().getAllErrors().stream().forEach(x -> {
+ errList.add(x.getDefaultMessage());
+ });
+ return ResponseData.generateCreatedResponse(Code.PARAM_INVALID.getCode(), Code.PARAM_INVALID.getMessage(), errList.toString());
+ }
+
+ /**
+ * 服务器内部错误
+ *
+ * @return
+ */
+ @ExceptionHandler(value = Exception.class)
+ public ResponseVO serverInternalError(Exception e, HttpServletRequest request) {
+ String url = request.getRequestURI();
+ log.error("path:" + url);
+ log.error("error:"+ e.getClass());
+ log.error("error message:"+ e.getLocalizedMessage() + e.getStackTrace()[0] + System.getProperty("line.separator"));
+ return ResponseData.generateCreatedResponse(Code.SERVER_INTERNAL_ERROR.getCode(), Code.SERVER_INTERNAL_ERROR.getMessage(), url);
+ }
+}
\ No newline at end of file
diff --git b/src/main/java/com/zhongzhi/common/exception/HttpException.java a/src/main/java/com/zhongzhi/common/exception/HttpException.java
new file mode 100644
index 0000000..b14bcc0
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/exception/HttpException.java
@@ -0,0 +1,45 @@
+package com.zhongzhi.common.exception;
+
+import com.zhongzhi.common.configure.RemoteProperties;
+
+/**
+ * 异常处理
+ *
+ * @author DengMin
+ * @date 2020/08/12
+ **/
+public class HttpException extends RuntimeException {
+
+ private Integer code;
+
+ private String message;
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public void setCode(Integer code) {
+ this.code = code;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public HttpException(Integer code) {
+ super(RemoteProperties.getMessage(code));
+ String message = RemoteProperties.getMessage(code);
+ this.message = message;
+ this.code = code;
+ }
+
+ public HttpException(Integer code, String message) {
+ this.message = message;
+ this.code = code;
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/generator/CodeGenerator.java a/src/main/java/com/zhongzhi/common/generator/CodeGenerator.java
new file mode 100644
index 0000000..7f325fb
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/generator/CodeGenerator.java
@@ -0,0 +1,126 @@
+package com.zhongzhi.common.generator;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.AutoGenerator;
+import com.baomidou.mybatisplus.generator.InjectionConfig;
+import com.baomidou.mybatisplus.generator.config.*;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+import com.zhongzhi.model.base.BaseModel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+import java.util.Scanner;
+
+/**
+ *
+ * 项目生成器
+ *
+ *
+ * @author DengMin
+ */
+public class CodeGenerator {
+
+ public static String scanner(String tip) {
+ StringBuilder help = new StringBuilder();
+ help.append("1.生成全部表 2.输入需要生成表名");
+ System.out.println(help);
+ Scanner scanner = new Scanner(System.in);
+ Integer ipt = Integer.valueOf(scanner.next());
+ if (ipt == 1) {
+ return "";
+ } else if (ipt == 2) {
+ StringBuilder help1 = new StringBuilder();
+ help1.append("请输入" + tip + ":");
+ System.out.println(help1);
+ Scanner scanner1 = new Scanner(System.in);
+ if (scanner1.hasNext()) {
+ String name = scanner1.next();
+ if (StringUtils.isNotEmpty(name)) {
+ return name;
+ }
+ }
+ throw new MybatisPlusException("请输入正确的" + tip + "!");
+ }
+ return scanner(tip);
+ }
+
+ public static void main(String[] args) {
+ final ResourceBundle rb = ResourceBundle.getBundle("mybatis-generator");
+ // 代码生成器
+ AutoGenerator mpg = new AutoGenerator();
+
+ // 全局配置
+ GlobalConfig gc = new GlobalConfig();
+ gc.setOutputDir(System.getProperty("user.dir") + rb.getString("outputDir"));
+ gc.setOpen(false);
+ gc.setBaseResultMap(true);
+ gc.setBaseColumnList(true);
+ gc.setAuthor(rb.getString("author"));
+ gc.setMapperName("%sMapper");
+ gc.setEntityName("%sDO");
+ gc.setServiceName("%sService");
+ gc.setServiceImplName("%sServiceImpl");
+ gc.setControllerName("%sController");
+ mpg.setGlobalConfig(gc);
+
+ // 数据源配置
+ DataSourceConfig dsc = new DataSourceConfig();
+ dsc.setDbType(DbType.MYSQL);
+ dsc.setUrl(rb.getString("url"));
+ dsc.setDriverName(rb.getString("driverName"));
+ dsc.setUsername(rb.getString("userName"));
+ dsc.setPassword(rb.getString("password"));
+ mpg.setDataSource(dsc);
+
+ // 包配置
+ PackageConfig pc = new PackageConfig();
+ pc.setParent(rb.getString("setParent"));
+ pc.setController("controller");
+ pc.setService("service");
+ pc.setServiceImpl("service.impl");
+ pc.setEntity("model");
+ pc.setMapper("mapper");
+ mpg.setPackageInfo(pc);
+
+ // 自定义配置
+ InjectionConfig cfg = new InjectionConfig() {
+ @Override
+ public void initMap() {
+ // to do nothing
+ }
+ };
+ List focList = new ArrayList<>();
+ focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
+ @Override
+ public String outputFile(TableInfo tableInfo) {
+ // 自定义输入文件名称
+ return System.getProperty("user.dir") + rb.getString("mapperPath") + tableInfo.getMapperName() + StringPool.DOT_XML;
+ }
+ });
+ cfg.setFileOutConfigList(focList);
+ mpg.setCfg(cfg);
+ mpg.setTemplate(new TemplateConfig().setXml(null));
+
+ // 策略配置
+ StrategyConfig strategy = new StrategyConfig();
+ strategy.setNaming(NamingStrategy.underline_to_camel);
+ strategy.setColumnNaming(NamingStrategy.underline_to_camel);
+ strategy.setSuperEntityClass(BaseModel.class);
+ strategy.setEntityLombokModel(true);
+ strategy.setRestControllerStyle(true);
+ String[] tables = scanner("表名,多个英文逗号分割").split(",");
+ if (StringUtils.isNotBlank(tables[0])) {
+ strategy.setInclude(tables);
+ }
+ strategy.setControllerMappingHyphenStyle(true);
+ mpg.setStrategy(strategy);
+ mpg.setTemplateEngine(new FreemarkerTemplateEngine());
+ mpg.execute();
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/handler/MetaHandler.java a/src/main/java/com/zhongzhi/common/handler/MetaHandler.java
new file mode 100644
index 0000000..6dd207e
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/handler/MetaHandler.java
@@ -0,0 +1,27 @@
+package com.zhongzhi.common.handler;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+/**
+ * 填充配置
+ *
+ * @author DengMin
+ * @date 2020/07/21
+ **/
+@Component
+public class MetaHandler implements MetaObjectHandler {
+
+ @Override
+ public void insertFill(MetaObject metaObject) {
+ this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
+ }
+
+ @Override
+ public void updateFill(MetaObject metaObject) {
+ this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/interceptor/AuthenticationInterceptor.java a/src/main/java/com/zhongzhi/common/interceptor/AuthenticationInterceptor.java
new file mode 100644
index 0000000..359f5e8
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/interceptor/AuthenticationInterceptor.java
@@ -0,0 +1,127 @@
+package com.zhongzhi.common.interceptor;
+
+import com.auth0.jwt.interfaces.Claim;
+import com.zhongzhi.common.constant.Code;
+import com.zhongzhi.common.constant.SmsCode;
+import com.zhongzhi.common.exception.HttpException;
+import com.zhongzhi.common.utils.JwtUtil;
+import com.zhongzhi.common.utils.Localstorage;
+import com.zhongzhi.common.utils.LoginRequired;
+import com.zhongzhi.model.AdministerDO;
+import com.zhongzhi.model.CollegesDictDO;
+import com.zhongzhi.model.ProjectJudgeDO;
+import com.zhongzhi.model.StudentDO;
+import com.zhongzhi.service.AdministerService;
+import com.zhongzhi.service.CollegesDictService;
+import com.zhongzhi.service.ProjectJudgeService;
+import com.zhongzhi.service.StudentService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ *
+ * 鉴权拦截器
+ *
+ *
+ * @author DengMin
+ * @since 2021/4/26
+ */
+@Component
+public class AuthenticationInterceptor implements HandlerInterceptor {
+
+ @Autowired
+ private StudentService studentService;
+
+ @Autowired
+ private AdministerService administerService;
+
+ @Autowired
+ private CollegesDictService collegesDictService;
+
+ @Autowired
+ private ProjectJudgeService projectJudgeService;
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+ if (!(handler instanceof HandlerMethod)) {
+ return true;
+ }
+
+ HandlerMethod handlerMethod = (HandlerMethod) handler;
+ Method method = handlerMethod.getMethod();
+ LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);
+ if (methodAnnotation != null) {
+ String authorization = request.getHeader("Authorization");
+ if (StringUtils.isBlank(authorization)) {
+ throw new HttpException(Code.TOKEN_EXCEPTION.getCode(), Code.TOKEN_EXCEPTION.getMessage());
+ }
+
+ String token = authorization;
+ if (authorization.startsWith("Bearer")) {
+ token = authorization.replace("Bearer ", "");
+ }
+
+ if (token == null || JwtUtil.isExpired(token) || !JwtUtil.verifyToken(token)) {
+ throw new HttpException(Code.TOKEN_EXCEPTION.getCode(), Code.TOKEN_EXCEPTION.getMessage());
+ }
+
+ Map claimMap = JwtUtil.getClaims(token);
+ if (claimMap != null) {
+ String[] role = methodAnnotation.value();
+ String type = claimMap.get("type").asString();
+ if (role.length > 0) {
+ if (Arrays.asList(role).contains(type)) {
+ if (SmsCode.student.equals(type)) {
+ StudentDO studentDO = studentService.getById(claimMap.get("id").asLong());
+ if (studentDO != null) {
+ Localstorage.setUser(studentDO, type);
+ return true;
+ } else {
+ Localstorage.remove();
+ throw new HttpException(Code.USERNAMENOTFOUND.getCode(), Code.USERNAMENOTFOUND.getMessage());
+ }
+ } else if (SmsCode.center.equals(type)) {
+ AdministerDO administerDO = administerService.getById(claimMap.get("id").asLong());
+ if (administerDO != null) {
+ Localstorage.setUser(administerDO, type);
+ return true;
+ } else {
+ Localstorage.remove();
+ throw new HttpException(Code.USERNAMENOTFOUND.getCode(), Code.USERNAMENOTFOUND.getMessage());
+ }
+ } else if (SmsCode.school.equals(type)) {
+ CollegesDictDO collegesDictDO = collegesDictService.getById(claimMap.get("id").asLong());
+ if (collegesDictDO != null) {
+ Localstorage.setUser(collegesDictDO, type);
+ return true;
+ } else {
+ Localstorage.remove();
+ throw new HttpException(Code.USERNAMENOTFOUND.getCode(), Code.USERNAMENOTFOUND.getMessage());
+ }
+ } else if (SmsCode.review.equals(type)) {
+ ProjectJudgeDO projectJudgeDO = projectJudgeService.getById(claimMap.get("id").asLong());
+ if (projectJudgeDO != null) {
+ Localstorage.setUser(projectJudgeDO, type);
+ return true;
+ } else {
+ Localstorage.remove();
+ throw new HttpException(Code.USERNAMENOTFOUND.getCode(), Code.USERNAMENOTFOUND.getMessage());
+ }
+ }
+ }
+ throw new HttpException(Code.ACCESSDENIED.getCode(), Code.ACCESSDENIED.getMessage());
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/utils/AliyunSmsUtil.java a/src/main/java/com/zhongzhi/common/utils/AliyunSmsUtil.java
new file mode 100644
index 0000000..1d02343
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/utils/AliyunSmsUtil.java
@@ -0,0 +1,216 @@
+package com.zhongzhi.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
+import com.zhongzhi.common.configure.AliyunSmsProperties;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import com.zhongzhi.common.constant.SMSTemplate;
+import com.zhongzhi.common.exception.HttpException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * 阿里云短信
+ *
+ *
+ * @author DengMin
+ * @since 2021/1/27
+ */
+
+@Slf4j
+@Component
+public class AliyunSmsUtil {
+
+ @Autowired
+ private AliyunSmsProperties aliyunSmsProperties;
+
+ /**
+ * 阿里云短信 -- 验证码
+ * @param phone
+ * @param code
+ * @return
+ */
+ public SendSmsResponse send(String phone, int code) {
+ try {
+ System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
+ System.setProperty("sun.net.client.defaultReadTimeout", "10000");
+
+ //初始化acsClient,暂不支持region化
+ IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", aliyunSmsProperties.getAccessKeyId(), aliyunSmsProperties.getAccessKeySecret());
+ DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", aliyunSmsProperties.getProduct(), aliyunSmsProperties.getDomain());
+ IAcsClient acsClient = new DefaultAcsClient(profile);
+
+ //组装请求对象-具体描述见控制台-文档部分内容
+ SendSmsRequest request = new SendSmsRequest();
+ //必填:待发送手机号
+ request.setPhoneNumbers(phone);
+ //必填:短信签名-可在短信控制台中找到
+ request.setSignName("双创平台");
+ //必填:短信模板-可在短信控制台中找到
+ request.setTemplateCode("SMS_229640297");
+ //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
+ request.setTemplateParam("{\"code\":\"" + code + "\"}");
+
+ //hint 此处可能会抛出异常,注意catch
+ SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
+ if (sendSmsResponse != null && sendSmsResponse.getCode().equals("OK")) {
+ return sendSmsResponse;
+ }
+
+ throw new Exception(sendSmsResponse.getMessage());
+ } catch (Exception e) {
+ log.error("---短信发送失败:" + e);
+ throw new HttpException(10011);
+ }
+ }
+
+ public static void main(String[] args) {
+// AliyunSmsUtil.sendNew("15201936167",000123);
+ }
+
+
+ /**
+ * 三网平台短信
+ * @param msg
+ * @param phone
+ * @param templateId
+ */
+ public void sendTemplateMsg(String msg, String phone, String templateId) {
+ Map map = new HashMap<>();
+ try {
+ map.put("cpcode", aliyunSmsProperties.getCpcode());
+ map.put("msg", msg);
+ map.put("mobiles", phone);
+ map.put("excode", aliyunSmsProperties.getExcode());
+ map.put("templetid", templateId);
+ String md5source = aliyunSmsProperties.getCpcode() + msg + phone + aliyunSmsProperties.getExcode() + templateId + aliyunSmsProperties.getKey();
+ map.put("sign", makeMD5(new String(md5source.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)).toLowerCase());
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity responseEntity = restTemplate.postForEntity(aliyunSmsProperties.getRcsapi(), map, String.class);
+ String body = responseEntity.getBody();
+ JSONObject object = JSON.parseObject(body);
+ if (Integer.valueOf(object.get("resultcode").toString()) != 0) {
+ log.error(object.get("resultmsg").toString());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+// /**
+// * 三网平台短信 新版本 https://flaginfo-cloud.yuque.com/staff-rozzgq/ofcpak
+// * @param msg
+// * @param phone
+// * @param templateId
+// */
+// public static void sendTemplateMsgNew(String msg, String phone, String templateId) {
+// String info = null;
+// try{
+// HttpClient httpclient = new HttpClient();
+// PostMethod post = new PostMethod("https://opassapi.infocloud.cc/sms/Api/SendGBK.do");//
+// post.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET,"gb2312");
+// post.addParameter("SpCode", templateId);
+// post.addParameter("LoginName", "7db124d0baf189d1e485350xxx");
+// post.addParameter("Password", "3df50b24fb8288b9da99d16bf527e9dbf13659748534dca6e0820xxx");
+// post.addParameter("MessageContent", msg);
+// post.addParameter("UserNumber", phone);
+// post.addParameter("SerialNumber", "");
+// post.addParameter("f", "1");
+// httpclient.executeMethod(post);
+// info = new String(post.getResponseBody(),"gbk");
+// System.out.println(info);
+// }catch (Exception e) {
+// e.printStackTrace();
+// }
+// }
+
+
+ public void sendTemplateMsgP(String msg, String phone, String templateId) {
+ Map map = new HashMap<>();
+ try {
+ map.put("cpcode", aliyunSmsProperties.getCpcode());
+ map.put("msg", msg);
+ map.put("mobiles", phone);
+ map.put("excode", aliyunSmsProperties.getExcode());
+ map.put("templetid", templateId);
+ String md5source = aliyunSmsProperties.getCpcode() + msg + phone + aliyunSmsProperties.getExcode() + templateId + aliyunSmsProperties.getKey();
+ map.put("sign", makeMD5(new String(md5source.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)).toLowerCase());
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity responseEntity = restTemplate.postForEntity(aliyunSmsProperties.getRcsapi(), map, String.class);
+ String body = responseEntity.getBody();
+ JSONObject object = JSON.parseObject(body);
+ if (Integer.valueOf(object.get("resultcode").toString()) != 0) {
+ log.error(object.get("resultmsg").toString());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public String makeMD5(String plainText) {
+ String re_md5 = "";
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.update(plainText.getBytes(StandardCharsets.UTF_8));
+ byte[] b = md.digest();
+ int i;
+ StringBuffer buf = new StringBuffer();
+ for (int offset = 0; offset < b.length; offset++) {
+ i = b[offset];
+ if (i < 0) {
+ i += 256;
+ }
+
+ if (i < 16) {
+ buf.append("0");
+ }
+ buf.append(Integer.toHexString(i));
+ }
+ re_md5 = buf.toString().toLowerCase();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return re_md5;
+ }
+
+
+// public static String getByteString( byte[] buff_out )
+// {
+// StringBuffer strBuf = new StringBuffer(buff_out.length * 3);
+// strBuf.append("Length[");
+// strBuf.append(buff_out.length);
+// strBuf.append("];Content[");
+// for ( int i = 0 ; i < buff_out.length ; ++i ) {
+// int l = buff_out[i] & 0x0F;
+// int h = (buff_out[i] & 0xF0) >> 4;
+//
+// char ll = (char) (l > 9 ? 'a' + l - 10 : '0' + l);
+// char hh = (char) (h > 9 ? 'a' + h - 10 : '0' + h);
+//
+// strBuf.append(hh);
+// strBuf.append(ll);
+// strBuf.append(" ");
+// }
+// strBuf.append("]");
+// return strBuf.toString().toUpperCase();
+// }
+
+}
\ No newline at end of file
diff --git b/src/main/java/com/zhongzhi/common/utils/ApplicationContextUtil.java a/src/main/java/com/zhongzhi/common/utils/ApplicationContextUtil.java
new file mode 100644
index 0000000..ec96cc1
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/utils/ApplicationContextUtil.java
@@ -0,0 +1,25 @@
+package com.zhongzhi.common.utils;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ApplicationContextUtil implements ApplicationContextAware {
+
+ private static ApplicationContext applicationContext;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ ApplicationContextUtil.applicationContext = applicationContext;
+ }
+
+ public static T getBean(Class clazz) {
+ return applicationContext.getBean(clazz);
+ }
+
+ public static T getBean(String name) {
+ return (T) applicationContext.getBean(name);
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/utils/DateFormatUtil.java a/src/main/java/com/zhongzhi/common/utils/DateFormatUtil.java
new file mode 100644
index 0000000..7784fb0
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/utils/DateFormatUtil.java
@@ -0,0 +1,187 @@
+package com.zhongzhi.common.utils;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.util.Date;
+
+/**
+ * Date格式工具
+ *
+ * @author DengMin
+ * @date 2020/08/03
+ **/
+public class DateFormatUtil {
+
+ public final static String FMT_sdf14_L = "yyyy-MM-dd HH:mm:ss";
+ public final static String FMT_sdf_yMd = "yyyy-MM-dd";
+ public final static String FMT_sdf_Hm = "H:mm";
+ public final static String cron = "s m H d M ? yyyy";
+
+ /**
+ * Date转String,自定义格式
+ *
+ * @param date
+ * @param pattern
+ * @return
+ */
+ public static String format(Date date, String pattern) {
+ try {
+ if (date == null) {
+ return null;
+ }
+
+ SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ return sdf.format(date);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * String转Date,自定义格式
+ *
+ * @param date
+ * @param pattern
+ * @return
+ */
+ public static Date parse(String date, String pattern) {
+ try {
+ if (StringUtils.isBlank(date)) {
+ return null;
+ }
+
+ SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ return sdf.parse(date);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * LocalDate转Date
+ *
+ * @param localDate
+ * @return
+ */
+ public static Date localDateToDate(LocalDate localDate) {
+ if (localDate == null) {
+ return null;
+ }
+
+ ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
+ return Date.from(zonedDateTime.toInstant());
+ }
+
+ /**
+ * LocalDate转String
+ *
+ * @param localDate
+ * @return
+ */
+ public static String localDateToString(LocalDate localDate) {
+ if (localDate == null) {
+ return null;
+ }
+
+ ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
+ return format(Date.from(zonedDateTime.toInstant()), FMT_sdf_yMd);
+ }
+
+ public static Date localDateTimeToDate(LocalDateTime localDateTime) {
+ if (localDateTime == null) {
+ return null;
+ }
+
+ return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
+ }
+
+ /**
+ * date转localDate
+ *
+ * @param date
+ * @return
+ */
+ public static LocalDate dateTOLocalDate(Date date) {
+ if (date == null) {
+ return null;
+ }
+ return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
+ }
+
+ /**
+ * String转LocalDate
+ *
+ * @param date
+ * @return
+ */
+ public static LocalDate localDateParse(String date) {
+ if (StringUtils.isBlank(date)) {
+ return null;
+ }
+ return LocalDate.parse(date);
+ }
+
+ /**
+ * 时间戳转LocalDate
+ *
+ * @param timestamp
+ * @return
+ */
+ public static LocalDate timestampTOLocalDate(Long timestamp) {
+ return Instant.ofEpochMilli(timestamp).atZone(ZoneOffset.ofHours(0)).toLocalDate();
+ }
+
+ /**
+ * 时间字符串转Cron
+ *
+ * @param date
+ * @return
+ */
+ public static String getCron(String date) {
+ try {
+ Date d = parse(date, FMT_sdf14_L);
+ SimpleDateFormat sdf = new SimpleDateFormat(cron);
+ return sdf.format(d);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 时间戳转日期字符串
+ *
+ * @param timestamp 时间戳
+ * @return 日期字符串
+ * @author ALiang
+ */
+ public static String timestampToDateString(Long timestamp) {
+ Date date = new Date(timestamp);
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat(FMT_sdf14_L);
+ return simpleDateFormat.format(date);
+ }
+
+ /**
+ * Date转LocalTime
+ *
+ * @param date
+ * @return
+ */
+ public static LocalTime dateToLocalTime(Date date) {
+ Instant instant = date.toInstant();
+ ZoneId zoneId = ZoneId.systemDefault();
+ LocalTime localTime = instant.atZone(zoneId).toLocalTime();
+ return localTime;
+ }
+
+ public static LocalDateTime dateToLocalDateTime(Date date) {
+ Instant instant = date.toInstant();
+ ZoneId zoneId = ZoneId.systemDefault();
+ LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
+ return localDateTime;
+ }
+}
diff --git b/src/main/java/com/zhongzhi/common/utils/ExcelColumn.java a/src/main/java/com/zhongzhi/common/utils/ExcelColumn.java
new file mode 100644
index 0000000..5c0a008
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/utils/ExcelColumn.java
@@ -0,0 +1,13 @@
+package com.zhongzhi.common.utils;
+
+import java.lang.annotation.*;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ExcelColumn {
+
+ String value() default "";
+
+ int col() default 1;
+}
diff --git b/src/main/java/com/zhongzhi/common/utils/ExcelUtil.java a/src/main/java/com/zhongzhi/common/utils/ExcelUtil.java
new file mode 100644
index 0000000..c39092d
--- /dev/null
+++ a/src/main/java/com/zhongzhi/common/utils/ExcelUtil.java
@@ -0,0 +1,336 @@
+package com.zhongzhi.common.utils;
+
+import com.zhongzhi.common.exception.HttpException;
+import com.zhongzhi.vo.ExcelFieldVO;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.hssf.usermodel.HSSFCellStyle;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.functions.T;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Component
+public class ExcelUtil {
+
+ private final static String EXCEL2003 = "xls";
+
+ private final static String EXCEL2007 = "xlsx";
+
+ public static List readExcel(Class cls, MultipartFile file) {
+ String fileName = file.getOriginalFilename();
+ if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
+ throw new HttpException(10800);
+ }
+
+ Workbook workbook = null;
+ List list = new ArrayList<>();
+ try {
+ InputStream stream = file.getInputStream();
+ if (fileName.endsWith(EXCEL2003)) {
+ workbook = new HSSFWorkbook(stream);
+ } else if (fileName.endsWith(EXCEL2007)) {
+ workbook = new XSSFWorkbook(stream);
+ }
+
+ if (workbook != null) {
+ Map> classMap = new HashMap<>();
+ List fields = Stream.of(cls.getDeclaredFields()).collect(Collectors.toList());
+ fields.forEach(field -> {
+ ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
+ if (annotation != null) {
+ String value = annotation.value();
+ if (StringUtils.isBlank(value)) {
+ return;
+ }
+
+ if (!classMap.containsKey(value)) {
+ classMap.put(value, new ArrayList<>());
+ }
+ field.setAccessible(true);
+ classMap.get(value).add(field);
+ }
+ });
+
+ boolean title = true;
+ Map> reflectionMap = new HashMap<>();
+ Sheet sheet = workbook.getSheetAt(0);
+ for (int i = 0; i <= sheet.getLastRowNum(); i++) {
+ Row row = sheet.getRow(i);
+ if (title) {
+ for (int j = 0; j <= row.getLastCellNum(); j++) {
+ Cell cell = row.getCell(j);
+ if (cell != null) {
+ String cellValue = cell.getStringCellValue();
+ if (StringUtils.isNotBlank(cellValue)) {
+ if (classMap.containsKey(cellValue)) {
+ reflectionMap.put(j, classMap.get(cellValue));
+ } else {
+ throw new HttpException(10802);
+ }
+ }
+ }
+ }
+ title = false;
+ } else {
+ if (row == null) {
+ continue;
+ }
+
+ boolean isBlank = true;
+ T t = cls.newInstance();
+ for (int j = 0; j <= row.getLastCellNum(); j++) {
+ if (reflectionMap.containsKey(j)) {
+ List fieldList = reflectionMap.get(j);
+ for (Field field : fieldList) {
+ Cell cell = row.getCell(j);
+ Class> type = field.getType();
+ Object cellValue = getCellValue(cell, type);
+ if (cellValue != null) {
+ isBlank = false;
+ }
+ handleField(t, cellValue, field);
+ }
+ }
+ }
+ if (!isBlank) {
+ list.add(t);
+ }
+ }
+ }
+ }
+ } catch (InstantiationException | IOException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ return list;
+ }
+
+ public static void writeExcel(String title, List fields, List