Forráskód Böngészése

合同审核平台-权限版,初次提交。

jessie 5 éve
commit
3ec9386972
63 módosított fájl, 4451 hozzáadás és 0 törlés
  1. 310 0
      mvnw
  2. 182 0
      mvnw.cmd
  3. 191 0
      pom.xml
  4. 19 0
      src/main/java/com/pavis/ai/app/cr/CrApplication.java
  5. 31 0
      src/main/java/com/pavis/ai/app/cr/common/config/CorsFilterConfig.java
  6. 31 0
      src/main/java/com/pavis/ai/app/cr/common/config/CrConfig.java
  7. 28 0
      src/main/java/com/pavis/ai/app/cr/common/config/FeignMultipartSupportConfig.java
  8. 62 0
      src/main/java/com/pavis/ai/app/cr/common/config/FeignSpringFormEncoder.java
  9. 21 0
      src/main/java/com/pavis/ai/app/cr/common/config/MybatisPlusConfig.java
  10. 15 0
      src/main/java/com/pavis/ai/app/cr/common/config/PasswordEncoderConfig.java
  11. 48 0
      src/main/java/com/pavis/ai/app/cr/common/config/RabbitMqConfig.java
  12. 27 0
      src/main/java/com/pavis/ai/app/cr/common/config/ResourceServerConfig.java
  13. 37 0
      src/main/java/com/pavis/ai/app/cr/common/config/Swagger2Config.java
  14. 24 0
      src/main/java/com/pavis/ai/app/cr/common/config/WebMvcConfig.java
  15. 27 0
      src/main/java/com/pavis/ai/app/cr/common/config/WebSecurityConfig.java
  16. 58 0
      src/main/java/com/pavis/ai/app/cr/common/config/constants/Constants.java
  17. 103 0
      src/main/java/com/pavis/ai/app/cr/common/config/constants/ErrorCode.java
  18. 21 0
      src/main/java/com/pavis/ai/app/cr/common/config/constants/ResourceType.java
  19. 17 0
      src/main/java/com/pavis/ai/app/cr/common/config/properties/CommonProperties.java
  20. 16 0
      src/main/java/com/pavis/ai/app/cr/common/config/properties/Dir.java
  21. 15 0
      src/main/java/com/pavis/ai/app/cr/common/config/properties/Url.java
  22. 22 0
      src/main/java/com/pavis/ai/app/cr/common/exception/AlertException.java
  23. 36 0
      src/main/java/com/pavis/ai/app/cr/common/exception/BaseException.java
  24. 179 0
      src/main/java/com/pavis/ai/app/cr/common/exception/GlobalExceptionHandler.java
  25. 106 0
      src/main/java/com/pavis/ai/app/cr/common/http/ErrorCode.java
  26. 155 0
      src/main/java/com/pavis/ai/app/cr/common/http/ResultBody.java
  27. 27 0
      src/main/java/com/pavis/ai/app/cr/common/utils/AuthenticationUtils.java
  28. 93 0
      src/main/java/com/pavis/ai/app/cr/common/utils/BeanConvertUtils.java
  29. 11 0
      src/main/java/com/pavis/ai/app/cr/common/utils/DateUtils.java
  30. 110 0
      src/main/java/com/pavis/ai/app/cr/common/utils/EncodeUtils.java
  31. 24 0
      src/main/java/com/pavis/ai/app/cr/common/utils/IgnoreUtils.java
  32. 29 0
      src/main/java/com/pavis/ai/app/cr/common/utils/RandomValueUtils.java
  33. 83 0
      src/main/java/com/pavis/ai/app/cr/common/utils/SpringContextHolder.java
  34. 540 0
      src/main/java/com/pavis/ai/app/cr/common/utils/StrUtils.java
  35. 469 0
      src/main/java/com/pavis/ai/app/cr/common/utils/WebUtils.java
  36. 43 0
      src/main/java/com/pavis/ai/app/cr/controller/Controller.java
  37. 59 0
      src/main/java/com/pavis/ai/app/cr/controller/TestController.java
  38. 27 0
      src/main/java/com/pavis/ai/app/cr/form/ResData.java
  39. 17 0
      src/main/java/com/pavis/ai/app/cr/form/SendUrl.java
  40. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractAddressMapper.java
  41. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractAmountCheckMapper.java
  42. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractClassificationMapper.java
  43. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractEnterpriseMapper.java
  44. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractSubjectDateMapper.java
  45. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractSubjectMobileMapper.java
  46. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/ContractSubjectNameMapper.java
  47. 15 0
      src/main/java/com/pavis/ai/app/cr/mapper/UploadMapper.java
  48. 29 0
      src/main/java/com/pavis/ai/app/cr/model/ContractAddress.java
  49. 32 0
      src/main/java/com/pavis/ai/app/cr/model/ContractAmountCheck.java
  50. 28 0
      src/main/java/com/pavis/ai/app/cr/model/ContractClassification.java
  51. 31 0
      src/main/java/com/pavis/ai/app/cr/model/ContractEnterprise.java
  52. 29 0
      src/main/java/com/pavis/ai/app/cr/model/ContractSubjectDate.java
  53. 29 0
      src/main/java/com/pavis/ai/app/cr/model/ContractSubjectMobile.java
  54. 29 0
      src/main/java/com/pavis/ai/app/cr/model/ContractSubjectName.java
  55. 26 0
      src/main/java/com/pavis/ai/app/cr/model/Upload.java
  56. 47 0
      src/main/java/com/pavis/ai/app/cr/service/SendService.java
  57. 15 0
      src/main/java/com/pavis/ai/app/cr/service/UploadService.java
  58. 595 0
      src/main/java/com/pavis/ai/app/cr/service/impl/UploadServiceImpl.java
  59. 49 0
      src/main/resources/application-dev.yml
  60. 24 0
      src/main/resources/application-prod.yml
  61. 17 0
      src/main/resources/application.yml
  62. 22 0
      src/main/resources/error.properties
  63. 16 0
      src/test/java/com/pavis/ai/app/cr/CrApplicationTests.java

+ 310 - 0
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 "$@"

+ 182 - 0
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%

+ 191 - 0
pom.xml

@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.1.13.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.pavis.ai.app</groupId>
+    <artifactId>cr</artifactId>
+    <version>0.0.1</version>
+    <name>cr</name>
+    <description>合同审核系统</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <spring-cloud.version>Greenwich.SR5</spring-cloud.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-oauth2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-rabbit-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- 通用包 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>27.0.1-jre</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.47</version>
+        </dependency>
+
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.14</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <version>1.8</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.9.4</version>
+        </dependency>
+
+    </dependencies>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 19 - 0
src/main/java/com/pavis/ai/app/cr/CrApplication.java

@@ -0,0 +1,19 @@
+package com.pavis.ai.app.cr;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@MapperScan("com.pavis.ai.app.cr.mapper")
+@EnableAsync
+@SpringBootApplication
+@EnableFeignClients
+public class CrApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(CrApplication.class, args);
+    }
+
+}

+ 31 - 0
src/main/java/com/pavis/ai/app/cr/common/config/CorsFilterConfig.java

@@ -0,0 +1,31 @@
+package com.pavis.ai.app.cr.common.config;
+
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class CorsFilterConfig implements Filter {
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
+        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+        httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
+        httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
+        httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
+        if ("OPTIONS".equalsIgnoreCase(httpServletRequest.getMethod())) {
+            httpServletResponse.setStatus(HttpServletResponse.SC_OK);
+        } else {
+            chain.doFilter(httpServletRequest, httpServletResponse);
+        }
+    }
+}

+ 31 - 0
src/main/java/com/pavis/ai/app/cr/common/config/CrConfig.java

@@ -0,0 +1,31 @@
+package com.pavis.ai.app.cr.common.config;
+
+import com.pavis.ai.app.cr.common.config.properties.CommonProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
+import org.springframework.web.client.RestTemplate;
+
+import javax.sql.DataSource;
+
+import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
+
+@Configuration
+@EnableConfigurationProperties({CommonProperties.class})
+public class CrConfig {
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Bean
+    public JdbcClientDetailsService jdbcClientDetailsService() {
+        return new JdbcClientDetailsService(dataSource);
+    }
+
+    @Bean
+    public RestTemplate restTemplate() {
+        return new RestTemplate();
+    }
+}

+ 28 - 0
src/main/java/com/pavis/ai/app/cr/common/config/FeignMultipartSupportConfig.java

@@ -0,0 +1,28 @@
+package com.pavis.ai.app.cr.common.config;
+
+import feign.codec.Encoder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Scope;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-17 14:33
+ * @desc FeignMultipartSupportConfig
+ **/
+@Configuration
+public class FeignMultipartSupportConfig {
+    @Bean
+    @Primary
+    @Scope("prototype")
+    public Encoder multipartFormEncoder() {
+        // return new SpringFormEncoder();
+        return new FeignSpringFormEncoder();
+    }
+
+    @Bean
+    public feign.Logger.Level multipartLoggerLevel() {
+        return feign.Logger.Level.FULL;
+    }
+}

+ 62 - 0
src/main/java/com/pavis/ai/app/cr/common/config/FeignSpringFormEncoder.java

@@ -0,0 +1,62 @@
+package com.pavis.ai.app.cr.common.config;
+
+import feign.RequestTemplate;
+import feign.codec.EncodeException;
+import feign.codec.Encoder;
+import feign.form.ContentType;
+import feign.form.FormEncoder;
+import feign.form.MultipartFormContentProcessor;
+import feign.form.spring.SpringManyMultipartFilesWriter;
+import feign.form.spring.SpringSingleMultipartFileWriter;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-19 9:24
+ * @desc FeignSpringFormEncoder
+ **/
+public class FeignSpringFormEncoder extends FormEncoder {
+    /**
+     * Constructor with the default Feign's encoder as a delegate.
+     */
+    public FeignSpringFormEncoder() {
+        this(new Default());
+    }
+
+
+    /**
+     * Constructor with specified delegate encoder.
+     *
+     * @param delegate delegate encoder, if this encoder couldn't encode object.
+     */
+    public FeignSpringFormEncoder(Encoder delegate) {
+        super(delegate);
+
+        MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(ContentType.MULTIPART);
+        processor.addWriter(new SpringSingleMultipartFileWriter());
+        processor.addWriter(new SpringManyMultipartFilesWriter());
+    }
+
+
+    @Override
+    public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
+        if (bodyType.equals(MultipartFile.class)) {
+            MultipartFile file = (MultipartFile) object;
+            Map data = Collections.singletonMap(file.getName(), object);
+            super.encode(data, MAP_STRING_WILDCARD, template);
+            return;
+        } else if (bodyType.equals(MultipartFile[].class)) {
+            MultipartFile[] file = (MultipartFile[]) object;
+            if(file != null) {
+                Map data = Collections.singletonMap(file.length == 0 ? "" : file[0].getName(), object);
+                super.encode(data, MAP_STRING_WILDCARD, template);
+                return;
+            }
+        }
+        super.encode(object, bodyType, template);
+    }
+}

+ 21 - 0
src/main/java/com/pavis/ai/app/cr/common/config/MybatisPlusConfig.java

@@ -0,0 +1,21 @@
+package com.pavis.ai.app.cr.common.config;
+
+import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableTransactionManagement
+public class MybatisPlusConfig {
+
+    @Bean
+    public PaginationInterceptor paginationInterceptor() {
+        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+        // 设置请求的页面大于最大页后操作,true调回到首页,false 继续请求  默认false
+        paginationInterceptor.setOverflow(false);
+        // 设置最大单页限制数量,默认 500 条,-1 不受限制
+        paginationInterceptor.setLimit(-1);
+        return paginationInterceptor;
+    }
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/common/config/PasswordEncoderConfig.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.common.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+
+@Configuration
+public class PasswordEncoderConfig {
+
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+}

+ 48 - 0
src/main/java/com/pavis/ai/app/cr/common/config/RabbitMqConfig.java

@@ -0,0 +1,48 @@
+package com.pavis.ai.app.cr.common.config;// package com.pavis.ai.app.cr.common.config;
+//
+// import com.pavis.ai.app.fjs_ocr.common.config.constants.Constants;
+// import org.springframework.amqp.core.Binding;
+// import org.springframework.amqp.core.BindingBuilder;
+// import org.springframework.amqp.core.DirectExchange;
+// import org.springframework.amqp.core.Queue;
+// import org.springframework.context.annotation.Bean;
+// import org.springframework.context.annotation.Configuration;
+//
+// @Configuration
+// public class RabbitMqConfig {
+//
+//     @Bean
+//     public DirectExchange directExchange() {
+//         return new DirectExchange(Constants.EXCHANGE_NAME, true, false);
+//     }
+//
+//     @Bean
+//     public Queue jqasOpQueue() {
+//         return new Queue(Constants.QUEUE_OP_NAME, true);
+//     }
+//
+//     @Bean
+//     public Binding bindingOpQueue() {
+//         return BindingBuilder
+//                 .bind(jqasOpQueue())
+//                 .to(directExchange())
+//                 .with(Constants.ROUTING_OP_KEY);
+//     }
+//
+//     @Bean
+//     public Queue jqasOpResultQueue() {
+//         return new Queue(Constants.QUEUE_OP_RESULT_NAME, true);
+//     }
+//
+//     @Bean
+//     public Binding bindingOpResultQueue() {
+//         return BindingBuilder
+//                 .bind(jqasOpResultQueue())
+//                 .to(directExchange())
+//                 .with(Constants.ROUTING_OP_RESULT_KEY);
+//     }
+//
+//
+//
+//
+// }

+ 27 - 0
src/main/java/com/pavis/ai/app/cr/common/config/ResourceServerConfig.java

@@ -0,0 +1,27 @@
+package com.pavis.ai.app.cr.common.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+
+@Configuration
+@EnableResourceServer
+public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+        http
+                .csrf()
+                .disable()
+                .authorizeRequests()
+                .antMatchers("/swagger-resources/**",
+                        "/swagger-ui.html",
+                        "/v2/**",
+                        "/webjars/**",
+                        "/doc.html")
+                .permitAll()
+                .anyRequest()
+                .authenticated();
+    }
+}

+ 37 - 0
src/main/java/com/pavis/ai/app/cr/common/config/Swagger2Config.java

@@ -0,0 +1,37 @@
+package com.pavis.ai.app.cr.common.config;
+
+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.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class Swagger2Config {
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("com.pavis.ai.app.cr.controller"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("合同审核平台")
+                .description("带权限版接口文档说明")
+                .contact(new Contact("管慧娟", "", "ghj@s-privacy.com"))
+                .version("1.0")
+                .build();
+    }
+}
+

+ 24 - 0
src/main/java/com/pavis/ai/app/cr/common/config/WebMvcConfig.java

@@ -0,0 +1,24 @@
+package com.pavis.ai.app.cr.common.config;
+
+import com.pavis.ai.app.cr.common.config.properties.CommonProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+    @Autowired
+    private CommonProperties commonProperties;
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+        // 对已上传的文件地址做映射访问
+        registry.addResourceHandler("/upload/file_down/**").addResourceLocations("file:" + commonProperties.getDir().getDown());
+
+    }
+
+
+}

+ 27 - 0
src/main/java/com/pavis/ai/app/cr/common/config/WebSecurityConfig.java

@@ -0,0 +1,27 @@
+package com.pavis.ai.app.cr.common.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+
+@Configuration
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                .authorizeRequests()
+                .antMatchers("/swagger-resources/**",
+                        "/swagger-ui.html",
+                        "/v2/**",
+                        "/webjars/**",
+                        "/doc.html")
+                .permitAll()
+                .anyRequest()
+                .authenticated()
+                .and()
+                .csrf()
+                .disable();
+    }
+
+}

+ 58 - 0
src/main/java/com/pavis/ai/app/cr/common/config/constants/Constants.java

@@ -0,0 +1,58 @@
+package com.pavis.ai.app.cr.common.config.constants;
+
+/**
+ * 通用常量
+ */
+public class Constants {
+
+    public static final String DEFAULT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
+    public static final String DATE_FORMAT_1 = "yyyy-MM-dd";
+    public static final String DATE_FORMAT_2 = "yyyyMMdd";
+
+    /**
+     * AK、SK
+     */
+    public static final String APPID = "10573741";
+    public static final String ACCESS_KEY = "586d2b8ac25045b88edecda8bd9ad07a";
+    public static final String SECRET_KEY = "2bbb5de5c63444a7b18709e03d5fb60a";
+
+
+    /**
+     * 身份证AK、SK
+     */
+    public static final String IDCARD_APPID = "18764902";
+    public static final String IDCARD_ACCESS_KEY = "0yLOIGW1Hhp2xNa8oG3uXjm0";
+    public static final String IDCARD_SECRET_KEY = "P7bXgLxGQ4g4YTY1t0AA82dmRE8IRKVP";
+
+
+    //
+    /**
+     * type 第一版本。
+     */
+    // public static final String TYPE_ONE = "5dd218cef11102bd6785862b904432da";
+    // public static final String TYPE_TWO = "134fd3c02c27a9353f672b12461ed5be";
+    // public static final String TYPE_THREE = "8b4d8b1408c0d1e64e32f6ca269a8e11";
+    // public static final String TYPE_FOUR = "dc63d1c842beba8db23b050b7af5c2ea";
+    // public static final String TYPE_FIVE = "f63bb922d55caf08551ab639ee51e68e";
+    // public static final String TYPE_SIX = "b65745f96abb50ea09780114eed3d8cb";
+    // public static final String TYPE_SEVEN = "899a17b0e64df13b55e550438b66c797";
+    // public static final String TYPE_EIGHT = "750db0bef26cad2872257ad311bcac2c";
+    // public static final String TYPE_NINE = "8b120b0836573b9ddeb601a289027c69";
+    // public static final String TYPE_TWELVE = "5d232b5e73e42348dcdf3017bfd1b232";
+
+    /**
+     * todo 0312 增删字段后的模板文件。
+     */
+
+    public static final String TYPE_ONE = "5dd218cef11102bd6785862b904432da";
+    public static final String TYPE_TWO = "33277f2cb0cece3844d585ad9261e38c";
+    public static final String TYPE_THREE = "716a19c9a509ea181460aef4b8e030e9";
+    public static final String TYPE_FOUR = "db9a268e1d7f6d9530227b626a14eb48";
+    public static final String TYPE_FIVE = "8e38dee03d67e48627119b609137d1a5";
+    public static final String TYPE_SIX = "acee24224b0de72bb00f3977a54c5c65";
+    public static final String TYPE_SEVEN = "0c7da5d93e6ae75ea275c80156280ba1";
+    public static final String TYPE_EIGHT = "750db0bef26cad2872257ad311bcac2c";
+    public static final String TYPE_NINE = "8232f6caca8afec26e0c5de18384ac72";
+    public static final String TYPE_TWELVE = "5d232b5e73e42348dcdf3017bfd1b232";
+
+}

+ 103 - 0
src/main/java/com/pavis/ai/app/cr/common/config/constants/ErrorCode.java

@@ -0,0 +1,103 @@
+package com.pavis.ai.app.cr.common.config.constants;
+
+/**
+ * 自定义返回码
+ */
+
+public enum ErrorCode {
+    /**
+     * 成功
+     */
+    OK(0, "success"),
+    FAIL(1000, "fail"),
+    ALERT(1001, "alert"),
+
+    /**
+     * oauth2返回码
+     */
+    INVALID_TOKEN(2000, "invalid_token"),
+    INVALID_SCOPE(2001, "invalid_scope"),
+    INVALID_REQUEST(2002, "invalid_request"),
+    INVALID_CLIENT(2003, "invalid_client"),
+    INVALID_GRANT(2004, "invalid_grant"),
+    REDIRECT_URI_MISMATCH(2005, "redirect_uri_mismatch"),
+    UNAUTHORIZED_CLIENT(2006, "unauthorized_client"),
+    EXPIRED_TOKEN(2007, "expired_token"),
+    UNSUPPORTED_GRANT_TYPE(2008, "unsupported_grant_type"),
+    UNSUPPORTED_RESPONSE_TYPE(2009, "unsupported_response_type"),
+    UNAUTHORIZED(2012, "unauthorized"),
+    SIGNATURE_DENIED(2013, "signature_denied"),
+
+    ACCESS_DENIED(4030, "access_denied"),
+    ACCESS_DENIED_BLACK_LIMITED(4031, "access_denied_black_limited"),
+    ACCESS_DENIED_WHITE_LIMITED(4032, "access_denied_white_limited"),
+    ACCESS_DENIED_AUTHORITY_EXPIRED(4033, "access_denied_authority_expired"),
+    ACCESS_DENIED_UPDATING(4034, "access_denied_updating"),
+    ACCESS_DENIED_DISABLED(4035, "access_denied_disabled"),
+    ACCESS_DENIED_NOT_OPEN(4036, "access_denied_not_open"),
+    /**
+     * 账号错误
+     */
+    BAD_CREDENTIALS(3000, "bad_credentials"),
+    ACCOUNT_DISABLED(3001, "account_disabled"),
+    ACCOUNT_EXPIRED(3002, "account_expired"),
+    CREDENTIALS_EXPIRED(3003, "credentials_expired"),
+    ACCOUNT_LOCKED(3004, "account_locked"),
+    USERNAME_NOT_FOUND(3005, "username_not_found"),
+
+    /**
+     * 请求错误
+     */
+    BAD_REQUEST(4000, "bad_request"),
+    NOT_FOUND(4004, "not_found"),
+    METHOD_NOT_ALLOWED(4005, "method_not_allowed"),
+    MEDIA_TYPE_NOT_ACCEPTABLE(4006, "media_type_not_acceptable"),
+    TOO_MANY_REQUESTS(4029, "too_many_requests"),
+    /**
+     * 系统错误
+     */
+    ERROR(5000, "error"),
+    GATEWAY_TIMEOUT(5004, "gateway_timeout"),
+    SERVICE_UNAVAILABLE(5003, "service_unavailable");
+
+
+    private int code;
+    private String message;
+
+    ErrorCode() {
+    }
+
+    private ErrorCode(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public static ErrorCode getResultEnum(int code) {
+        for (ErrorCode type : ErrorCode.values()) {
+            if (type.getCode() == code) {
+                return type;
+            }
+        }
+        return ERROR;
+    }
+
+    public static ErrorCode getResultEnum(String message) {
+        for (ErrorCode type : ErrorCode.values()) {
+            if (type.getMessage().equals(message)) {
+                return type;
+            }
+        }
+        return ERROR;
+    }
+
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+
+}

+ 21 - 0
src/main/java/com/pavis/ai/app/cr/common/config/constants/ResourceType.java

@@ -0,0 +1,21 @@
+package com.pavis.ai.app.cr.common.config.constants;
+
+/**
+ * 资源类型
+ */
+public enum ResourceType {
+
+    /**
+     * 菜单资源
+     */
+    menu,
+    /**
+     * 操作资源
+     */
+    action,
+    /**
+     * API接口资源
+     */
+    api
+
+}

+ 17 - 0
src/main/java/com/pavis/ai/app/cr/common/config/properties/CommonProperties.java

@@ -0,0 +1,17 @@
+package com.pavis.ai.app.cr.common.config.properties;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@ConfigurationProperties(prefix = "cr.common")
+public class CommonProperties {
+    private Dir dir;
+    private Url url;
+}

+ 16 - 0
src/main/java/com/pavis/ai/app/cr/common/config/properties/Dir.java

@@ -0,0 +1,16 @@
+package com.pavis.ai.app.cr.common.config.properties;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class Dir {
+    private String base;
+    private String upload;
+    private String down;
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/common/config/properties/Url.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.common.config.properties;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class Url {
+    private String base;
+    private String path;
+}

+ 22 - 0
src/main/java/com/pavis/ai/app/cr/common/exception/AlertException.java

@@ -0,0 +1,22 @@
+package com.pavis.ai.app.cr.common.exception;
+
+/**
+ * 消息提示异常
+ */
+public class AlertException extends BaseException {
+
+    public AlertException() {
+    }
+
+    public AlertException(String msg) {
+        super(msg);
+    }
+
+    public AlertException(int code, String msg) {
+        super(code, msg);
+    }
+
+    public AlertException(int code, String msg, Throwable cause) {
+        super(code, msg, cause);
+    }
+}

+ 36 - 0
src/main/java/com/pavis/ai/app/cr/common/exception/BaseException.java

@@ -0,0 +1,36 @@
+package com.pavis.ai.app.cr.common.exception;
+
+import com.pavis.ai.app.cr.common.http.ErrorCode;
+
+/**
+ * 基础错误异常
+ */
+public class BaseException extends RuntimeException {
+
+    private int code = ErrorCode.ERROR.getCode();
+
+    public BaseException() {
+    }
+
+    public BaseException(String msg) {
+        super(msg);
+    }
+
+    public BaseException(int code, String msg) {
+        super(msg);
+        this.code = code;
+    }
+
+    public BaseException(int code, String msg, Throwable cause) {
+        super(msg, cause);
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+}

+ 179 - 0
src/main/java/com/pavis/ai/app/cr/common/exception/GlobalExceptionHandler.java

@@ -0,0 +1,179 @@
+package com.pavis.ai.app.cr.common.exception;
+
+
+import com.alibaba.fastjson.JSON;
+import com.pavis.ai.app.cr.common.http.ErrorCode;
+import com.pavis.ai.app.cr.common.http.ResultBody;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
+import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Objects;
+
+/**
+ * 统一异常处理器
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    /**
+     * 统一异常处理
+     * AuthenticationException
+     */
+    @ExceptionHandler({AuthenticationException.class})
+    public static ResultBody authenticationException(Exception ex, HttpServletRequest request, HttpServletResponse response) {
+        ResultBody resultBody = resolveException(ex, request.getRequestURI());
+        response.setStatus(resultBody.getHttpStatus());
+        return resultBody;
+    }
+
+    /**
+     * OAuth2Exception
+     */
+    @ExceptionHandler({OAuth2Exception.class, InvalidTokenException.class})
+    public static ResultBody oauth2Exception(Exception ex, HttpServletRequest request, HttpServletResponse response) {
+        ResultBody resultBody = resolveException(ex, request.getRequestURI());
+        response.setStatus(resultBody.getHttpStatus());
+        return resultBody;
+    }
+
+    /**
+     * 其他异常
+     */
+    @ExceptionHandler({Exception.class})
+    public static ResultBody exception(Exception ex, HttpServletRequest request, HttpServletResponse response) {
+        ResultBody resultBody = resolveException(ex, request.getRequestURI());
+        response.setStatus(resultBody.getHttpStatus());
+        return resultBody;
+    }
+
+    /**
+     * 静态解析异常,可以直接调用
+     */
+    public static ResultBody resolveException(Exception ex, String path) {
+        ErrorCode code = ErrorCode.ERROR;
+        int httpStatus = HttpStatus.INTERNAL_SERVER_ERROR.value();
+        String message = ex.getMessage();
+        String className = ex.getClass().getName();
+        log.info("exception class name:{}", className);
+        if (className.contains("UsernameNotFoundException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.USERNAME_NOT_FOUND;
+        } else if (className.contains("BadCredentialsException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.BAD_CREDENTIALS;
+        } else if (className.contains("AccountExpiredException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.ACCOUNT_EXPIRED;
+        } else if (className.contains("LockedException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.ACCOUNT_LOCKED;
+        } else if (className.contains("DisabledException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.ACCOUNT_DISABLED;
+        } else if (className.contains("CredentialsExpiredException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.CREDENTIALS_EXPIRED;
+        } else if (className.contains("InvalidClientException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.INVALID_CLIENT;
+        } else if (className.contains("UnauthorizedClientException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.UNAUTHORIZED_CLIENT;
+        } else if (className.contains("InsufficientAuthenticationException") || className.contains("AuthenticationCredentialsNotFoundException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.UNAUTHORIZED;
+        } else if (className.contains("InvalidGrantException")) {
+            code = ErrorCode.ALERT;
+            if ("Bad credentials".contains(message)) {
+                code = ErrorCode.BAD_CREDENTIALS;
+            } else if ("User is disabled".contains(message)) {
+                code = ErrorCode.ACCOUNT_DISABLED;
+            } else if ("User account is locked".contains(message)) {
+                code = ErrorCode.ACCOUNT_LOCKED;
+            }
+        } else if (className.contains("InvalidScopeException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.INVALID_SCOPE;
+        } else if (className.contains("InvalidTokenException")) {
+            httpStatus = HttpStatus.UNAUTHORIZED.value();
+            code = ErrorCode.INVALID_TOKEN;
+        } else if (className.contains("InvalidRequestException")) {
+            httpStatus = HttpStatus.BAD_REQUEST.value();
+            code = ErrorCode.INVALID_REQUEST;
+        } else if (className.contains("RedirectMismatchException")) {
+            code = ErrorCode.REDIRECT_URI_MISMATCH;
+        } else if (className.contains("UnsupportedGrantTypeException")) {
+            code = ErrorCode.UNSUPPORTED_GRANT_TYPE;
+        } else if (className.contains("UnsupportedResponseTypeException")) {
+            code = ErrorCode.UNSUPPORTED_RESPONSE_TYPE;
+        } else if (className.contains("UserDeniedAuthorizationException")) {
+            code = ErrorCode.ACCESS_DENIED;
+        } else if (className.contains("AccessDeniedException")) {
+            code = ErrorCode.ACCESS_DENIED;
+            httpStatus = HttpStatus.FORBIDDEN.value();
+            if (ErrorCode.ACCESS_DENIED_BLACK_LIMITED.getMessage().contains(message)) {
+                code = ErrorCode.ACCESS_DENIED_BLACK_LIMITED;
+            } else if (ErrorCode.ACCESS_DENIED_WHITE_LIMITED.getMessage().contains(message)) {
+                code = ErrorCode.ACCESS_DENIED_WHITE_LIMITED;
+            } else if (ErrorCode.ACCESS_DENIED_AUTHORITY_EXPIRED.getMessage().contains(message)) {
+                code = ErrorCode.ACCESS_DENIED_AUTHORITY_EXPIRED;
+            } else if (ErrorCode.ACCESS_DENIED_UPDATING.getMessage().contains(message)) {
+                code = ErrorCode.ACCESS_DENIED_UPDATING;
+            } else if (ErrorCode.ACCESS_DENIED_DISABLED.getMessage().contains(message)) {
+                code = ErrorCode.ACCESS_DENIED_DISABLED;
+            } else if (ErrorCode.ACCESS_DENIED_NOT_OPEN.getMessage().contains(message)) {
+                code = ErrorCode.ACCESS_DENIED_NOT_OPEN;
+            }
+        } else if (className.contains("HttpMessageNotReadableException")
+                || className.contains("TypeMismatchException")
+                || className.contains("MissingServletRequestParameterException")) {
+            httpStatus = HttpStatus.BAD_REQUEST.value();
+            code = ErrorCode.BAD_REQUEST;
+        } else if (className.contains("NoHandlerFoundException")) {
+            httpStatus = HttpStatus.NOT_FOUND.value();
+            code = ErrorCode.NOT_FOUND;
+        } else if (className.contains("HttpRequestMethodNotSupportedException")) {
+            httpStatus = HttpStatus.METHOD_NOT_ALLOWED.value();
+            code = ErrorCode.METHOD_NOT_ALLOWED;
+        } else if (className.contains("HttpMediaTypeNotAcceptableException")) {
+            httpStatus = HttpStatus.BAD_REQUEST.value();
+            code = ErrorCode.MEDIA_TYPE_NOT_ACCEPTABLE;
+        } else if (className.contains("MethodArgumentNotValidException")) {
+            BindingResult bindingResult = ((MethodArgumentNotValidException) ex).getBindingResult();
+            code = ErrorCode.ALERT;
+            return ResultBody.failed().code(code.getCode()).msg(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage());
+        } else if (className.contains("IllegalArgumentException")) {
+            // 参数错误
+            code = ErrorCode.ALERT;
+            httpStatus = HttpStatus.BAD_REQUEST.value();
+        } else if (className.contains("AlertException")) {
+            code = ErrorCode.ALERT;
+        } else if (message.equalsIgnoreCase(ErrorCode.TOO_MANY_REQUESTS.name())) {
+            code = ErrorCode.TOO_MANY_REQUESTS;
+        }
+        return buildBody(ex, code, path, httpStatus);
+    }
+
+    /**
+     * 构建返回结果对象
+     */
+    private static ResultBody buildBody(Exception exception, ErrorCode resultCode, String path, int httpStatus) {
+        if (resultCode == null) {
+            resultCode = ErrorCode.ERROR;
+        }
+        ResultBody resultBody = ResultBody.failed().code(resultCode.getCode()).msg(exception.getMessage()).path(path).httpStatus(httpStatus);
+        log.error("==> error:{} exception:{}", JSON.toJSONString(resultBody), exception);
+        return resultBody;
+    }
+
+}

+ 106 - 0
src/main/java/com/pavis/ai/app/cr/common/http/ErrorCode.java

@@ -0,0 +1,106 @@
+package com.pavis.ai.app.cr.common.http;
+
+/**
+ * 自定义返回码
+ */
+
+public enum ErrorCode {
+
+    /**
+     * 成功
+     */
+    OK(0, "success"),
+    FAIL(1000, "fail"),
+    ALERT(1001, "alert"),
+
+    /**
+     * oauth2返回码
+     */
+    INVALID_TOKEN(2000, "invalid_token"),
+    INVALID_SCOPE(2001, "invalid_scope"),
+    INVALID_REQUEST(2002, "invalid_request"),
+    INVALID_CLIENT(2003, "invalid_client"),
+    INVALID_GRANT(2004, "invalid_grant"),
+    REDIRECT_URI_MISMATCH(2005, "redirect_uri_mismatch"),
+    UNAUTHORIZED_CLIENT(2006, "unauthorized_client"),
+    EXPIRED_TOKEN(2007, "expired_token"),
+    UNSUPPORTED_GRANT_TYPE(2008, "unsupported_grant_type"),
+    UNSUPPORTED_RESPONSE_TYPE(2009, "unsupported_response_type"),
+    UNAUTHORIZED(2012, "unauthorized"),
+    SIGNATURE_DENIED(2013, "signature_denied"),
+
+    ACCESS_DENIED(4030, "access_denied"),
+    ACCESS_DENIED_BLACK_LIMITED(4031, "access_denied_black_limited"),
+    ACCESS_DENIED_WHITE_LIMITED(4032, "access_denied_white_limited"),
+    ACCESS_DENIED_AUTHORITY_EXPIRED(4033, "access_denied_authority_expired"),
+    ACCESS_DENIED_UPDATING(4034, "access_denied_updating"),
+    ACCESS_DENIED_DISABLED(4035, "access_denied_disabled"),
+    ACCESS_DENIED_NOT_OPEN(4036, "access_denied_not_open"),
+
+    /**
+     * 账号错误
+     */
+    BAD_CREDENTIALS(3000, "bad_credentials"),
+    ACCOUNT_DISABLED(3001, "account_disabled"),
+    ACCOUNT_EXPIRED(3002, "account_expired"),
+    CREDENTIALS_EXPIRED(3003, "credentials_expired"),
+    ACCOUNT_LOCKED(3004, "account_locked"),
+    USERNAME_NOT_FOUND(3005, "username_not_found"),
+
+    /**
+     * 请求错误
+     */
+    BAD_REQUEST(4000, "bad_request"),
+    NOT_FOUND(4004, "not_found"),
+    METHOD_NOT_ALLOWED(4005, "method_not_allowed"),
+    MEDIA_TYPE_NOT_ACCEPTABLE(4006, "media_type_not_acceptable"),
+    TOO_MANY_REQUESTS(4029, "too_many_requests"),
+
+    /**
+     * 系统错误
+     */
+    ERROR(5000, "error"),
+    GATEWAY_TIMEOUT(5004, "gateway_timeout"),
+    SERVICE_UNAVAILABLE(5003, "service_unavailable");
+
+
+    private int code;
+    private String message;
+
+    ErrorCode() {
+    }
+
+    private ErrorCode(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public static ErrorCode getResultEnum(int code) {
+        for (ErrorCode type : ErrorCode.values()) {
+            if (type.getCode() == code) {
+                return type;
+            }
+        }
+        return ERROR;
+    }
+
+    public static ErrorCode getResultEnum(String message) {
+        for (ErrorCode type : ErrorCode.values()) {
+            if (type.getMessage().equals(message)) {
+                return type;
+            }
+        }
+        return ERROR;
+    }
+
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+
+}

+ 155 - 0
src/main/java/com/pavis/ai/app/cr/common/http/ResultBody.java

@@ -0,0 +1,155 @@
+package com.pavis.ai.app.cr.common.http;
+
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.common.collect.Maps;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Map;
+import java.util.ResourceBundle;
+
+@ApiModel(value = "响应结果")
+public class ResultBody {
+
+    /**
+     * 响应编码
+     */
+    @ApiModelProperty(value = "响应编码:0-请求处理成功")
+    private int code = 0;
+
+    /**
+     * 提示消息
+     */
+    @ApiModelProperty(value = "提示消息")
+    private String message;
+
+    /**
+     * 请求路径
+     */
+    @ApiModelProperty(value = "请求路径")
+    private String path;
+
+    /**
+     * 响应数据
+     */
+    @ApiModelProperty(value = "响应数据")
+    private Object data;
+
+    /**
+     * http状态码
+     */
+    private int httpStatus;
+
+    /**
+     * 附加数据
+     */
+    @ApiModelProperty(value = "附加数据")
+    private Map<String, Object> extra;
+
+    /**
+     * 响应时间
+     */
+    @ApiModelProperty(value = "响应时间")
+    private long timestamp = System.currentTimeMillis();
+
+    public ResultBody() {
+
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public Map<String, Object> getExtra() {
+        return extra;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    @JSONField(serialize = false, deserialize = false)
+    @JsonIgnore
+    public int getHttpStatus() {
+        return httpStatus;
+    }
+
+    @JSONField(serialize = false, deserialize = false)
+    @JsonIgnore
+    public boolean isOk() {
+        return this.code == ErrorCode.OK.getCode();
+    }
+
+
+    public static ResultBody ok() {
+        return new ResultBody().code(ErrorCode.OK.getCode()).msg(ErrorCode.OK.getMessage());
+    }
+
+    public static ResultBody failed() {
+        return new ResultBody().code(ErrorCode.FAIL.getCode()).msg(ErrorCode.FAIL.getMessage());
+    }
+
+    public ResultBody code(int code) {
+        this.code = code;
+        return this;
+    }
+
+    public ResultBody msg(String message) {
+        this.message = i18n(ErrorCode.getResultEnum(this.code).getMessage(), message);
+        return this;
+    }
+
+    public ResultBody data(Object data) {
+        this.data = data;
+        return this;
+    }
+
+    public ResultBody path(String path) {
+        this.path = path;
+        return this;
+    }
+
+    public ResultBody httpStatus(int httpStatus) {
+        this.httpStatus = httpStatus;
+        return this;
+    }
+
+    public ResultBody put(String key, Object value) {
+        if (this.extra == null) {
+            this.extra = Maps.newHashMap();
+        }
+        this.extra.put(key, value);
+        return this;
+    }
+
+    /**
+     * 错误信息配置
+     */
+    @JSONField(serialize = false, deserialize = false)
+    @JsonIgnore
+    private static ResourceBundle resourceBundle = ResourceBundle.getBundle("error");
+
+    /**
+     * 提示信息国际化
+     */
+    @JSONField(serialize = false, deserialize = false)
+    @JsonIgnore
+    private static String i18n(String message, String defaultMessage) {
+        return resourceBundle.containsKey(message) ? resourceBundle.getString(message) : defaultMessage;
+    }
+
+}

+ 27 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/AuthenticationUtils.java

@@ -0,0 +1,27 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+import java.util.Collection;
+
+public class AuthenticationUtils {
+
+    public static String getCurrentUsername() {
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        if (null != authentication) {
+            return authentication.getName();
+        }
+        return "";
+    }
+
+    public static Collection<? extends GrantedAuthority> getCurrentUserAuthorities() {
+        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+        if (null != authentication) {
+            return authentication.getAuthorities();
+        }
+        return null;
+    }
+
+}

+ 93 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/BeanConvertUtils.java

@@ -0,0 +1,93 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+
+public class BeanConvertUtils {
+
+    /**
+     * 方法说明:将bean转化为另一种bean实体
+     */
+    public static <T> T convertBean(Object object, Class<T> entityClass) {
+        if (null == object) {
+            return null;
+        }
+        return JSON.parseObject(JSON.toJSONString(object), entityClass);
+    }
+
+
+    /**
+     * 方法说明:对象转换
+     *  
+     *
+     * @param source           原对象
+     * @param target           目标对象
+     * @param ignoreProperties 排除要copy的属性
+     */
+    public static <T> T copy(Object source, Class<T> target, String... ignoreProperties) {
+        T targetInstance = null;
+        try {
+            targetInstance = target.newInstance();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (ArrayUtils.isEmpty(ignoreProperties)) {
+            assert targetInstance != null;
+            BeanUtils.copyProperties(source, targetInstance);
+        } else {
+            assert targetInstance != null;
+            BeanUtils.copyProperties(source, targetInstance, ignoreProperties);
+        }
+        return targetInstance;
+
+    }
+
+    /**
+     * 方法说明:对象转换(List)
+     *  
+     *
+     * @param list             原对象
+     * @param target           目标对象
+     * @param ignoreProperties 排除要copy的属性
+     */
+    public static <T, E> List<T> copyList(List<E> list, Class<T> target, String... ignoreProperties) {
+        List<T> targetList = new ArrayList<>();
+        if (CollectionUtils.isEmpty(list)) {
+            return targetList;
+        }
+        for (E e : list) {
+            targetList.add(copy(e, target, ignoreProperties));
+        }
+        return targetList;
+    }
+
+    /**
+     * 方法说明:map转化为对象
+     *  
+     */
+    public static <T> T mapToObject(Map<String, Object> map, Class<T> t) {
+        try {
+            T instance = t.newInstance();
+            org.apache.commons.beanutils.BeanUtils.populate(instance, map);
+            return instance;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 方法说明:对象转化为Map
+     *  
+     */
+    public static Map<?, ?> objectToMap(Object object) {
+        return convertBean(object, Map.class);
+    }
+
+}

+ 11 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/DateUtils.java

@@ -0,0 +1,11 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import com.pavis.ai.app.cr.common.config.constants.Constants;
+import org.joda.time.DateTime;
+
+public class DateUtils {
+
+    public static String now() {
+        return DateTime.now().toString(Constants.DEFAULT_DATETIME_FORMAT);
+    }
+}

+ 110 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/EncodeUtils.java

@@ -0,0 +1,110 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+/**
+ * 封装各种格式的编码解码工具类.
+ * 1.Commons-Codec的 hex/base64 编码
+ * 2.自制的base62 编码
+ * 3.Commons-Lang的xml/html escape
+ * 4.JDK提供的URLEncoder
+ */
+public class EncodeUtils {
+
+    private static final String ENCODING = "UTF-8";
+    private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+
+    /**
+     * Hex编码.
+     */
+    public static String encodeHex(byte[] input) {
+        return new String(Hex.encodeHex(input));
+    }
+
+    /**
+     * Hex解码.
+     */
+    public static byte[] decodeHex(String input) {
+        try {
+            return Hex.decodeHex(input.toCharArray());
+        } catch (DecoderException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Base64编码.
+     */
+    public static String encodeBase64(byte[] input) {
+        return new String(Base64.encodeBase64(input));
+    }
+
+    /**
+     * Base64编码.
+     */
+    public static String encodeBase64(String input) {
+        try {
+            return new String(Base64.encodeBase64(input.getBytes(ENCODING)));
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Base64解码.
+     */
+    public static byte[] decodeBase64(String input) {
+        return Base64.decodeBase64(input.getBytes());
+    }
+
+    /**
+     * Base64解码.
+     */
+    public static String decodeBase64String(String input) {
+        try {
+            return new String(Base64.decodeBase64(input.getBytes()), ENCODING);
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Base62编码。
+     */
+    public static String encodeBase62(byte[] input) {
+        char[] chars = new char[input.length];
+        for (int i = 0; i < input.length; i++) {
+            chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
+        }
+        return new String(chars);
+    }
+
+    /**
+     * URL 编码, Encode默认为UTF-8.
+     */
+    public static String encodeUrl(String part) {
+        try {
+            return URLEncoder.encode(part, ENCODING);
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+    /**
+     * URL 解码, Encode默认为UTF-8.
+     */
+    public static String decodeUrl(String part) {
+        try {
+            return URLDecoder.decode(part, ENCODING);
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+    }
+
+}

+ 24 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/IgnoreUtils.java

@@ -0,0 +1,24 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+
+import java.beans.PropertyDescriptor;
+import java.util.HashSet;
+import java.util.Set;
+
+public class IgnoreUtils {
+    public static String[] getNullPropertyNames(Object source) {
+        BeanWrapper src = new BeanWrapperImpl(source);
+        PropertyDescriptor[] pds = src.getPropertyDescriptors();
+        Set<String> emptyNames = new HashSet<>();
+        for (PropertyDescriptor pd : pds) {
+            Object srcValue = src.getPropertyValue(pd.getName());
+            if (srcValue == null){
+                emptyNames.add(pd.getName());
+            }
+        }
+        return emptyNames.toArray(new String[emptyNames.size()]);
+    }
+
+}

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 29 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/RandomValueUtils.java


+ 83 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/SpringContextHolder.java

@@ -0,0 +1,83 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 yadu.liu
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+package com.pavis.ai.app.cr.common.utils;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ * 以静态变量保存Spring ApplicationContext,可在任何代码任何地方任何时候中取出ApplicaitonContext.
+ */
+public class SpringContextHolder implements ApplicationContextAware {
+
+    private static ApplicationContext applicationContext;
+
+    /**
+     * 实现ApplicationContextAware接口的context注入函数,将其存入静态变量.
+     */
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) {
+        SpringContextHolder.applicationContext = applicationContext;
+    }
+
+    /**
+     * 取得存储在静态变量中的ApplicationContext.
+     */
+    public static ApplicationContext getApplicationContext() {
+        checkApplicationContext();
+        return applicationContext;
+    }
+
+    /**
+     * 从静态变量ApplicationContext中取得Bean,自动转型为所赋值对象的类型.
+     */
+    public static <T> T getBean(String name) {
+        checkApplicationContext();
+        return (T) applicationContext.getBean(name);
+    }
+
+    /**
+     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
+     */
+    public static <T> T getBean(Class<T> clazz) {
+        checkApplicationContext();
+        return (T) applicationContext.getBean(clazz);
+    }
+
+    /**
+     * 清除applicationContext静态变量.
+     */
+    public static void cleanApplicationContext() {
+        applicationContext = null;
+    }
+
+    private static void checkApplicationContext() {
+        if (applicationContext == null) {
+            throw new IllegalStateException(
+                    "applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");
+        }
+    }
+}  

+ 540 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/StrUtils.java

@@ -0,0 +1,540 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.StringEscapeUtils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
+ */
+public class StrUtils extends StringUtils {
+
+    private static final char SEPARATOR = '_';
+    private static final String CHARSET = "UTF-8";
+
+    /**
+     * 转换为字节数组
+     */
+    public static byte[] getBytes(String str) {
+        if (str != null) {
+            try {
+                return str.getBytes(CHARSET);
+            } catch (UnsupportedEncodingException e) {
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * 转换为字节数组
+     */
+    public static String toString(byte[] bytes) {
+        try {
+            return new String(bytes, CHARSET);
+        } catch (UnsupportedEncodingException e) {
+            return EMPTY;
+        }
+    }
+
+    /**
+     * 转换为Boolean类型
+     * 'true', 'on', 'y', 't', 'yes' or '1' (case insensitive) will return true. Otherwise, false is returned.
+     */
+    public static Boolean toBoolean(final Object val) {
+        if (val == null) {
+            return false;
+        }
+        return BooleanUtils.toBoolean(val.toString()) || "1".equals(val.toString());
+    }
+
+
+    /**
+     * 如果对象为空,则使用defaultVal值
+     * see: ObjectUtils.toString(obj, defaultVal)
+     */
+    public static String toString(final Object obj, final String defaultVal) {
+        return obj == null ? defaultVal : obj.toString();
+    }
+
+    /**
+     * 是否包含字符串
+     *
+     * @param str  验证字符串
+     * @param strs 字符串组
+     * @return 包含返回true
+     */
+    public static boolean inString(String str, String... strs) {
+        if (str != null) {
+            for (String s : strs) {
+                if (str.equals(trim(s))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 转换为Double类型
+     */
+    public static Double toDouble(Object val) {
+        if (val == null) {
+            return 0D;
+        }
+        try {
+            return Double.valueOf(trim(val.toString()));
+        } catch (Exception e) {
+            return 0D;
+        }
+    }
+
+    /**
+     * 转换为Float类型
+     */
+    public static Float toFloat(Object val) {
+        return toDouble(val).floatValue();
+    }
+
+    /**
+     * 转换为Long类型
+     */
+    public static Long toLong(Object val) {
+        return toDouble(val).longValue();
+    }
+
+    /**
+     * 转换为Integer类型
+     */
+    public static Integer toInteger(Object val) {
+        return toLong(val).intValue();
+    }
+
+    /**
+     * 缩略字符串(不区分中英文字符)
+     *
+     * @param str    目标字符串
+     * @param length 截取长度
+     */
+    public static String ellipsis(String str, int length) {
+        if (str == null) {
+            return "";
+        }
+        try {
+            StringBuilder sb = new StringBuilder();
+            int currentLength = 0;
+            for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) {
+                currentLength += String.valueOf(c).getBytes("GBK").length;
+                if (currentLength <= length - 3) {
+                    sb.append(c);
+                } else {
+                    sb.append("...");
+                    break;
+                }
+            }
+            return sb.toString();
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+    /**
+     * 替换掉HTML标签方法
+     */
+    public static String replaceHtml(String html) {
+        if (isBlank(html)) {
+            return "";
+        }
+        String regEx = "<.+?>";
+        Pattern p = Pattern.compile(regEx);
+        Matcher m = p.matcher(html);
+        return m.replaceAll("");
+    }
+
+    /**
+     * Html 转码.
+     */
+    public static String escapeHtml(String html) {
+        return StringEscapeUtils.escapeHtml4(html);
+    }
+
+    /**
+     * Html 解码.
+     */
+    public static String unescapeHtml(String htmlEscaped) {
+        return StringEscapeUtils.unescapeHtml4(htmlEscaped);
+    }
+
+    /**
+     * Xml 转码.
+     */
+    public static String escapeXml(String xml) {
+        return StringEscapeUtils.escapeXml11(xml);
+    }
+
+    /**
+     * Xml 解码.
+     */
+    public static String unescapeXml(String xmlEscaped) {
+        return StringEscapeUtils.unescapeXml(xmlEscaped);
+    }
+
+    /**
+     * url追加参数
+     *
+     * @param url   传入的url ex:"http://exp.kunnr.com/so/index.html?kunnrId=16&userProfile=16#/app/home"
+     * @param name  参数名
+     * @param value 参数值
+     */
+    public static String appendURIParam(String url, String name, String value) {
+        url += (url.indexOf('?') == -1 ? '?' : '&');
+        url += EncodeUtils.encodeUrl(name) + '=' + EncodeUtils.encodeUrl(value);
+        return url;
+    }
+
+    /**
+     * 组装新的URL
+     */
+    public static String appendURIParam(String url, Map<String, String> map) {
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            url = appendURIParam(url, entry.getKey(), entry.getValue());
+        }
+        return url;
+    }
+
+
+    /**
+     * 驼峰转下划线
+     * createTime > create_time
+     */
+    public static String camelToUnderline(String param) {
+        if (param == null || "".equals(param.trim())) {
+            return "";
+        }
+        int len = param.length();
+        StringBuilder sb = new StringBuilder(len);
+        for (int i = 0; i < len; i++) {
+            char c = param.charAt(i);
+            if (Character.isUpperCase(c)) {
+                sb.append(SEPARATOR);
+                sb.append(Character.toLowerCase(c));
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 下划线转驼峰
+     * create_time > createTime
+     */
+    public static String underlineToCamel(String param) {
+        if (param == null || "".equals(param.trim())) {
+            return "";
+        }
+        StringBuilder sb = new StringBuilder(param);
+        Matcher mc = Pattern.compile(String.valueOf(SEPARATOR)).matcher(param);
+        int i = 0;
+        while (mc.find()) {
+            int position = mc.end() - (i++);
+            sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 格式化存储单位
+     */
+    public static String formatBytes(long size) {
+        // 如果字节数少于1024,则直接以B为单位,否则先除于1024,后3位因太少无意义
+        int bytes = 1024;
+        if (size < bytes) {
+            return String.valueOf(size) + "Byte";
+        } else {
+            size = size / bytes;
+        }
+        // 如果原字节数除于1024之后,少于1024,则可以直接以KB作为单位 //因为还没有到达要使用另一个单位的时候 //接下去以此类推
+        if (size < bytes) {
+            return String.valueOf(size) + "K";
+        } else {
+            size = size / bytes;
+        }
+        if (size < bytes) {
+            // 因为如果以MB为单位的话,要保留最后1位小数, //因此,把此数乘以100之后再取余
+            size = size * 100;
+            return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "M";
+        } else { // 否则如果要以GB为单位的,先除于1024再作同样的处理
+            size = size * 100 / bytes;
+            return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "G";
+        }
+    }
+
+    /**
+     * 匿名手机号
+     *
+     * @param mobile 手机号
+     * @return 152****4799
+     */
+    public static String formatMobile(String mobile) {
+
+        if (isEmpty(mobile)) {
+            return null;
+        }
+        return mobile.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
+    }
+
+    /**
+     * 匿名银行卡号
+     */
+    public static String formatBankCard(String bankCard) {
+        if (isEmpty(bankCard)) {
+            return null;
+        }
+        return bankCard.replaceAll("(\\d{5})\\d{5}\\d{2}(\\d{4})", "$1****$2");
+    }
+
+    /**
+     * 匿名身份证
+     *
+     * @return 4304*****7733
+     */
+    public static String formatIdCard(String idCard) {
+
+        if (isEmpty(idCard)) {
+            return null;
+        }
+        return idCard.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1*****$2");
+    }
+
+    /**
+     * 检测是否未手机号
+     * 中国电信号段
+     * 133、149、153、173、177、180、181、189、199
+     * 中国联通号段
+     * 130、131、132、145、155、156、166、175、176、185、186
+     * 中国移动号段
+     * 134(0-8)、135、136、137、138、139、147、150、151、152、157、158、159、178、182、183、184、187、188、198
+     * 其他号段
+     * 14号段以前为上网卡专属号段,如中国联通的是145,中国移动的是147等等。
+     * 虚拟运营商
+     * 电信:1700、1701、1702
+     * 移动:1703、1705、1706
+     * 联通:1704、1707、1708、1709、171
+     */
+    public static boolean matchMobile(String mobile) {
+        if (StringUtils.isBlank(mobile)) {
+            return false;
+        }
+        String regex = "^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$";
+        return Pattern.matches(regex, mobile);
+    }
+
+    /**
+     * 检测Email
+     */
+    public static boolean matchEmail(String email) {
+        if (StringUtils.isBlank(email)) {
+            return false;
+        }
+        String regex = "\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?";
+        return Pattern.matches(regex, email);
+    }
+
+
+    /**
+     * 检测域名
+     */
+    public static boolean matchDomain(String domain) {
+        if (domain == null) {
+            return false;
+        }
+        String regex = "^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$";
+        return Pattern.matches(regex, domain);
+    }
+
+    /**
+     * 检测IP
+     */
+    public static boolean matchIp(String ip) {
+        if (ip == null) {
+            return false;
+        }
+        String regex = "^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])$";
+        return Pattern.matches(regex, ip);
+    }
+
+    /**
+     * 检测HttpUrl
+     */
+    public static boolean matchHttpUrl(String url) {
+        if (url == null) {
+            return false;
+        }
+        String regex = "^(?=^.{3,255}$)(http(s)?:\\/\\/)?(www\\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\\d+)*(\\/\\w+\\.\\w+)*([\\?&]\\w+=\\w*)*$";
+        return Pattern.matches(regex, url);
+    }
+
+    /**
+     * 校验银行卡卡号
+     * 校验过程:
+     * 1、从卡号最后一位数字开始,逆向将奇数位(1、3、5等等)相加。
+     * 2、从卡号最后一位数字开始,逆向将偶数位数字,先乘以2(如果乘积为两位数,将个位十位数字相加,即将其减去9),再求和。
+     * 3、将奇数位总和加上偶数位总和,结果应该可以被10整除。
+     */
+    public static boolean matchBankCard(String bankCard) {
+        if (bankCard == null) {
+            return false;
+        }
+        if (bankCard.length() < 15 || bankCard.length() > 19) {
+            return false;
+        }
+        char bit = getBankCardCheckCode(bankCard.substring(0, bankCard.length() - 1));
+        if (bit == 'N') {
+            return false;
+        }
+        return bankCard.charAt(bankCard.length() - 1) == bit;
+    }
+
+    /**
+     * 从不含校验位的银行卡卡号采用 Luhm 校验算法获得校验位
+     */
+    public static char getBankCardCheckCode(String nonCheckCodeBankCard) {
+        if (nonCheckCodeBankCard == null || nonCheckCodeBankCard.trim().length() == 0
+                || !nonCheckCodeBankCard.matches("\\d+")) {
+            //如果传的不是数据返回N
+            return 'N';
+        }
+        char[] chs = nonCheckCodeBankCard.trim().toCharArray();
+        int luhmSum = 0;
+        for (int i = chs.length - 1, j = 0; i >= 0; i--, j++) {
+            int k = chs[i] - '0';
+            if (j % 2 == 0) {
+                k *= 2;
+                k = k / 10 + k % 10;
+            }
+            luhmSum += k;
+        }
+        return (luhmSum % 10 == 0) ? '0' : (char) ((10 - luhmSum % 10) + '0');
+    }
+
+
+    /**
+     * 处理非法字符
+     */
+    private static List<Pattern> patterns = null;
+
+    private static List<Object[]> getXssPatternList() {
+        List<Object[]> ret = new ArrayList<Object[]>();
+        ret.add(new Object[]{"<(no)?script[^>]*>.*?</(no)?script>", Pattern.CASE_INSENSITIVE});
+        ret.add(new Object[]{"eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
+        ret.add(new Object[]{"expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
+        ret.add(new Object[]{"(javascript:|vbscript:|view-source:)*", Pattern.CASE_INSENSITIVE});
+        ret.add(new Object[]{"<(\"[^\"]*\"|\'[^\']*\'|[^\'\">])*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
+        ret.add(new Object[]{"(window\\.location|window\\.|\\.location|document\\.cookie|document\\.|alert\\(.*?\\)|window\\.open\\()*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
+        ret.add(new Object[]{"<+\\s*\\w*\\s*(oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondblclick|ondeactivate|ondrag|ondragend|ondragenter|ondragleave|ondragover|ondragstart|ondrop|onerror=|onerroupdate|onfilterchange|onfinish|onfocus|onfocusin|onfocusout|onhelp|onkeydown|onkeypress|onkeyup|onlayoutcomplete|onload|onlosecapture|onmousedown|onmouseenter|onmouseleave|onmousemove|onmousout|onmouseover|onmouseup|onmousewheel|onmove|onmoveend|onmovestart|onabort|onactivate|onafterprint|onafterupdate|onbefore|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onblur|onbounce|oncellchange|onchange|onclick|oncontextmenu|onpaste|onpropertychange|onreadystatuschange|onreset|onresize|onresizend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onselect|onselectionchange|onselectstart|onstart|onstop|onsubmit|onunload)+\\s*=+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL});
+        return ret;
+    }
+
+    private static List<Pattern> getPatterns() {
+
+        if (patterns == null) {
+
+            List<Pattern> list = new ArrayList<Pattern>();
+
+            String regex = null;
+            Integer flag = null;
+            int arrLength = 0;
+
+            for (Object[] arr : getXssPatternList()) {
+                arrLength = arr.length;
+                for (int i = 0; i < arrLength; i++) {
+                    regex = (String) arr[0];
+                    flag = (Integer) arr[1];
+                    list.add(Pattern.compile(regex, flag));
+                }
+            }
+
+            patterns = list;
+        }
+
+        return patterns;
+    }
+
+    public static String stripXss(String value) {
+        if (StringUtils.isNotBlank(value)) {
+            Matcher matcher = null;
+            for (Pattern pattern : getPatterns()) {
+                matcher = pattern.matcher(value);
+                if (matcher.find()) {
+                    value = matcher.replaceAll("");
+                }
+            }
+            value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
+        }
+        return value;
+    }
+
+    /**
+     * 密码强度
+     *
+     * @return Z = 字母 S = 数字 T = 特殊字符
+     */
+    public static String checkPassword(String passwordStr) {
+        String regexZ = "\\d*";
+        String regexS = "[a-zA-Z]+";
+        String regexT = "\\W+$";
+        String regexZT = "\\D*";
+        String regexST = "[\\d\\W]*";
+        String regexZS = "\\w*";
+        String regexZST = "[\\w\\W]*";
+
+        if (passwordStr.matches(regexZ)) {
+            return "弱";
+        }
+        if (passwordStr.matches(regexS)) {
+            return "弱";
+        }
+        if (passwordStr.matches(regexT)) {
+            return "弱";
+        }
+        if (passwordStr.matches(regexZT)) {
+            return "中";
+        }
+        if (passwordStr.matches(regexST)) {
+            return "中";
+        }
+        if (passwordStr.matches(regexZS)) {
+            return "中";
+        }
+        if (passwordStr.matches(regexZST)) {
+            return "强";
+        }
+        return passwordStr;
+    }
+
+
+    /**
+     * 将 Exception 转化为 String
+     */
+    public static String getExceptionToString(Throwable e) {
+        if (e == null) {
+            return "";
+        }
+        StringWriter stringWriter = new StringWriter();
+        e.printStackTrace(new PrintWriter(stringWriter));
+        return stringWriter.toString();
+    }
+
+}

+ 469 - 0
src/main/java/com/pavis/ai/app/cr/common/utils/WebUtils.java

@@ -0,0 +1,469 @@
+package com.pavis.ai.app.cr.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.google.common.net.HttpHeaders;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.http.MediaType;
+import org.springframework.util.Assert;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * Http与Servlet工具类.
+ */
+public class WebUtils {
+
+    private final static String staticSuffix = ".css,.js,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.htm,.html,.crx,.xpi,.exe,.ipa,.apk,.woff2,.ico,.swf,.ttf,.otf,.svg,.woff";
+
+    /**
+     * 静态文件后缀
+     */
+    private final static String[] staticFiles = StringUtils.split(staticSuffix, ",");
+
+    /**
+     * 动态映射URL后缀
+     */
+    private final static String urlSuffix = ".html";
+
+    public static String[] getStaticFiles() {
+        return staticFiles;
+    }
+
+    /**
+     * 设置 Cookie(生成时间为1天)
+     *
+     * @param name  名称
+     * @param value 值
+     */
+    public static void setCookie(HttpServletResponse response, String name, String value) {
+        setCookie(response, name, value, 60 * 60 * 24);
+    }
+
+    /**
+     * 设置 Cookie
+     *
+     * @param name  名称
+     * @param value 值
+     */
+    public static void setCookie(HttpServletResponse response, String name, String value, String path) {
+        setCookie(response, name, value, path, 60 * 60 * 24);
+    }
+
+    /**
+     * 设置 Cookie
+     *
+     * @param name   名称
+     * @param value  值
+     * @param maxAge 生存时间(单位秒)
+     */
+    public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) {
+        setCookie(response, name, value, "/", maxAge);
+    }
+
+    /**
+     * 设置 Cookie
+     *
+     * @param name   名称
+     * @param value  值
+     * @param maxAge 生存时间(单位秒)
+     * @param path   路径
+     */
+    public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge) {
+        Cookie cookie = new Cookie(name, null);
+        cookie.setPath(path);
+        cookie.setMaxAge(maxAge);
+        try {
+            cookie.setValue(URLEncoder.encode(value, "utf-8"));
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        }
+        response.addCookie(cookie);
+    }
+
+    /**
+     * 移除cookie
+     */
+    public static void removeCookie(HttpServletResponse response, String name) {
+        Cookie cookie = new Cookie(name, null);
+        cookie.setPath("/");
+        cookie.setMaxAge(0);
+        cookie.setValue(null);
+        response.addCookie(cookie);
+    }
+
+    /**
+     * 获得指定Cookie的值
+     *
+     * @param name 名称
+     * @return 值
+     */
+    public static String getCookie(HttpServletRequest request, String name) {
+        return getCookie(request, null, name, false);
+    }
+
+    /**
+     * 获得指定Cookie的值,并删除。
+     *
+     * @param name 名称
+     * @return 值
+     */
+    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) {
+        return getCookie(request, response, name, true);
+    }
+
+    /**
+     * 获得指定Cookie的值
+     *
+     * @param request  请求对象
+     * @param response 响应对象
+     * @param name     名字
+     * @param isRemove 是否移除
+     * @return 值
+     */
+    public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, boolean isRemove) {
+        String value = null;
+        Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (Cookie cookie : cookies) {
+                if (cookie.getName().equals(name)) {
+                    try {
+                        value = URLDecoder.decode(cookie.getValue(), "utf-8");
+                    } catch (UnsupportedEncodingException e) {
+                        e.printStackTrace();
+                    }
+                    if (isRemove) {
+                        cookie.setMaxAge(0);
+                        response.addCookie(cookie);
+                    }
+                }
+            }
+        }
+        return value;
+    }
+
+    /**
+     * 设置客户端缓存过期时间 的Header.
+     */
+    public static void setExpiresHeader(HttpServletResponse response, long expiresSeconds) {
+        // Http 1.0 header, set model fix expires date.
+        response.setDateHeader(HttpHeaders.EXPIRES, System.currentTimeMillis() + expiresSeconds * 1000);
+        // Http 1.1 header, set model time after now.
+        response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=" + expiresSeconds);
+    }
+
+
+    /**
+     * 设置禁止客户端缓存的Header.
+     */
+    public static void setNoCacheHeader(HttpServletResponse response) {
+        // Http 1.0 header
+        response.setDateHeader(HttpHeaders.EXPIRES, 1L);
+        response.addHeader(HttpHeaders.PRAGMA, "no-cache");
+        // Http 1.1 header
+        response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0");
+    }
+
+    /**
+     * 设置LastModified Header.
+     */
+    public static void setLastModifiedHeader(HttpServletResponse response, long lastModifiedDate) {
+        response.setDateHeader(HttpHeaders.LAST_MODIFIED, lastModifiedDate);
+    }
+
+    /**
+     * 设置Etag Header.
+     */
+    public static void setEtag(HttpServletResponse response, String etag) {
+        response.setHeader(HttpHeaders.ETAG, etag);
+    }
+
+    /**
+     * 根据浏览器If-Modified-Since Header, 计算文件是否已被修改.
+     * <p>
+     * 如果无修改, checkIfModify返回false ,设置304 not modify status.
+     *
+     * @param lastModified 内容的最后修改时间.
+     */
+    public static boolean checkIfModifiedSince(HttpServletRequest request, HttpServletResponse response,
+                                               long lastModified) {
+        long ifModifiedSince = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
+        if ((ifModifiedSince != -1) && (lastModified < ifModifiedSince + 1000)) {
+            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 根据浏览器 If-None-Match Header, 计算Etag是否已无效.
+     * <p>
+     * 如果Etag有效, checkIfNoneMatch返回false, 设置304 not modify status.
+     *
+     * @param etag 内容的ETag.
+     */
+    public static boolean checkIfNoneMatchEtag(HttpServletRequest request, HttpServletResponse response, String etag) {
+        String headerValue = request.getHeader(HttpHeaders.IF_NONE_MATCH);
+        if (headerValue != null) {
+            boolean conditionSatisfied = false;
+            if (!"*".equals(headerValue)) {
+                StringTokenizer commaTokenizer = new StringTokenizer(headerValue, ",");
+
+                while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) {
+                    String currentToken = commaTokenizer.nextToken();
+                    if (currentToken.trim().equals(etag)) {
+                        conditionSatisfied = true;
+                    }
+                }
+            } else {
+                conditionSatisfied = true;
+            }
+
+            if (conditionSatisfied) {
+                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                response.setHeader(HttpHeaders.ETAG, etag);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 设置让浏览器弹出下载对话框的Header.
+     *
+     * @param fileName 下载后的文件名.
+     */
+    public static void setFileDownloadHeader(HttpServletResponse response, String fileName) {
+        try {
+            // 中文文件名支持
+            String encodedfileName = new String(fileName.getBytes(), "ISO8859-1");
+            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedfileName + "\"");
+        } catch (UnsupportedEncodingException e) {
+            e.getMessage();
+        }
+    }
+
+    /**
+     * 取得带相同前缀的Request Parameters, copy from spring WebUtils.
+     * <p>
+     * 返回的结果的Parameter名已去除前缀.
+     */
+    @SuppressWarnings("rawtypes")
+    public static Map<String, Object> getParametersWith(ServletRequest request, String prefix) {
+        Assert.notNull(request, "Request must not be null");
+        Enumeration paramNames = request.getParameterNames();
+        Map<String, Object> params = new TreeMap<String, Object>();
+        String pre = prefix;
+        if (pre == null) {
+            pre = "";
+        }
+        while (paramNames != null && paramNames.hasMoreElements()) {
+            String paramName = (String) paramNames.nextElement();
+            if ("".equals(pre) || paramName.startsWith(pre)) {
+                String unprefixed = paramName.substring(pre.length());
+                String[] values = request.getParameterValues(paramName);
+                if (values == null || values.length == 0) {
+                    values = new String[]{};
+                    // Do nothing, no values found at all.
+                } else if (values.length > 1) {
+                    params.put(unprefixed, values);
+                } else {
+                    params.put(unprefixed, values[0]);
+                }
+            }
+        }
+        return params;
+    }
+
+    /**
+     * 获取请求Body
+     */
+    public static String getBodyString(final ServletRequest request) {
+        StringBuilder sb = new StringBuilder();
+        InputStream inputStream = null;
+        BufferedReader reader = null;
+        try {
+            inputStream = cloneInputStream(request.getInputStream());
+            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+            String line = "";
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 复制输入流
+     */
+    public static InputStream cloneInputStream(ServletInputStream inputStream) {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int len;
+        try {
+            while ((len = inputStream.read(buffer)) > -1) {
+                byteArrayOutputStream.write(buffer, 0, len);
+            }
+            byteArrayOutputStream.flush();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
+    }
+
+
+    /**
+     * 组合Parameters生成Query String的Parameter部分,并在paramter name上加上prefix.
+     */
+    public static String encodeParameterWithPrefix(Map<String, Object> params, String prefix) {
+        StringBuilder queryStringBuilder = new StringBuilder();
+
+        String pre = prefix;
+        if (pre == null) {
+            pre = "";
+        }
+        Iterator<Entry<String, Object>> it = params.entrySet().iterator();
+        while (it.hasNext()) {
+            Entry<String, Object> entry = it.next();
+            queryStringBuilder.append(pre).append(entry.getKey()).append("=").append(entry.getValue());
+            if (it.hasNext()) {
+                queryStringBuilder.append("&");
+            }
+        }
+        return queryStringBuilder.toString();
+    }
+
+    /**
+     * 客户端对Http Basic验证的 Header进行编码.
+     */
+    public static String encodeHttpBasic(String userName, String password) {
+        String encode = userName + ":" + password;
+        return "Basic " + EncodeUtils.encodeBase64(encode.getBytes());
+    }
+
+    /**
+     * 是否是Ajax异步请求
+     */
+    public static boolean isAjaxRequest(HttpServletRequest request) {
+        return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With").toString())) || (request.getHeader("Content-Type") != null && request.getHeader("Content-Type").startsWith("application/json"));
+    }
+
+    /**
+     * 获取IP地址
+     */
+    public static String getRemoteAddress(HttpServletRequest request) {
+        String unknown = "unknown";
+        String ip = request.getHeader("X-Forwarded-For");
+        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_CLIENT_IP");
+        }
+        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+        }
+        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Real-IP");
+        }
+        if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+        // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
+        if (ip != null && ip.length() > 0) {
+            String[] ips = ip.split(",");
+            if (ips.length > 0) {
+                ip = ips[0];
+            }
+        }
+        return ip;
+    }
+
+
+    /**
+     * 判断访问URI是否是静态文件请求
+     */
+    public static boolean isStaticFile(String uri) {
+        return StringUtils.endsWithAny(uri, staticFiles) && !StringUtils.endsWithAny(uri, new String[]{urlSuffix})
+                && !StringUtils.endsWithAny(uri, new String[]{".jsp"}) && !StringUtils.endsWithAny(uri, new String[]{".java"});
+    }
+
+    /**
+     * 客户端返回JSON字符串
+     */
+    public static void writeJson(HttpServletResponse response, Object object) throws IOException {
+        writeJson(response, JSON.toJSONString(object), MediaType.APPLICATION_JSON_UTF8_VALUE);
+    }
+
+    /**
+     * 客户端返回字符串
+     */
+    public static void writeJson(HttpServletResponse response, String string, String type) throws IOException {
+        response.setContentType(type);
+        response.setCharacterEncoding("utf-8");
+        response.getWriter().print(string);
+        response.getWriter().flush();
+        response.getWriter().close();
+    }
+
+    public static String getServerUrl(HttpServletRequest request) {
+        return request.getScheme() + "://" + request.getServerName()
+                + ":" + request.getServerPort() + request.getContextPath();
+    }
+
+
+    public static String getContextPath(HttpServletRequest request) {
+        return request.getContextPath();
+    }
+
+    public static HttpServletRequest getHttpServletRequest() {
+        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+    }
+
+    public static Map<String, String> getHttpHeaders(HttpServletRequest request) {
+        Map<String, String> map = new LinkedHashMap<>();
+        if (request != null) {
+            Enumeration<String> enumeration = request.getHeaderNames();
+            if (enumeration != null) {
+                while (enumeration.hasMoreElements()) {
+                    String key = enumeration.nextElement();
+                    String value = request.getHeader(key);
+                    map.put(key, value);
+                }
+            }
+        }
+        return map;
+    }
+
+}

+ 43 - 0
src/main/java/com/pavis/ai/app/cr/controller/Controller.java

@@ -0,0 +1,43 @@
+package com.pavis.ai.app.cr.controller;
+
+import com.pavis.ai.app.cr.common.http.ResultBody;
+import com.pavis.ai.app.cr.service.UploadService;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestPart;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-17 13:49
+ * @desc Controller
+ **/
+@Slf4j
+@RestController
+@RequestMapping("/api")
+public class Controller {
+
+    @Autowired
+    private UploadService uploadService;
+
+    @ApiOperation("合同审核上传接口")
+    @PostMapping(value = "/cr/uplaod", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "file", value = "合同文件,支持docx/doc", required = true, dataType = "file", paramType = "formData")
+    })
+    public ResultBody uplaod(@RequestPart("file") MultipartFile file) {
+        System.out.println(file.getOriginalFilename());
+        if (file.isEmpty()){
+            return ResultBody.failed().path("/api/cr/uplaod").data(uploadService.upload(file)).msg("文件参数不能为空,请选择文件后重试。");
+        }else {
+            return ResultBody.ok().path("/api/cr/uplaod").data(uploadService.upload(file));
+        }
+    }
+}

+ 59 - 0
src/main/java/com/pavis/ai/app/cr/controller/TestController.java

@@ -0,0 +1,59 @@
+package com.pavis.ai.app.cr.controller;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.pavis.ai.app.cr.common.http.ResultBody;
+import com.pavis.ai.app.cr.common.utils.IgnoreUtils;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 14:03
+ * @desc
+ **/
+@Slf4j
+@RestController
+@RequestMapping("/api")
+public class TestController {
+
+    // @Autowired
+    // private SendService sendService;
+
+    @ApiOperation("测试接口1")
+    @GetMapping("/cr")
+    public ResultBody get()  {
+        // ResData resData = new ResData();
+        // resData.setReqId("01");
+        // sendService.send(resData);
+        return ResultBody.ok().data(System.currentTimeMillis());
+    }
+
+    @ApiOperation("测试接口1")
+    @PostMapping("/cr/test/{id}")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "id", value = "唯一标识id", required = false, dataType = "string", paramType = "path")
+    })
+    public ResultBody testOne(@PathVariable("id") String id)  {
+        // ResData resData = new ResData();
+        // resData.setReqId("01");
+        // sendService.send(resData);
+        return ResultBody.ok().data(id);
+    }
+
+    @ApiOperation("测试接口2")
+    @PostMapping("/cr/data")
+    public ResultBody testTwo(@RequestBody ResultBody resultBody)  {
+        System.err.println("tes<>"+ JSON.toJSONString(resultBody));
+        return ResultBody.ok().data(resultBody);
+    }
+
+
+}

+ 27 - 0
src/main/java/com/pavis/ai/app/cr/form/ResData.java

@@ -0,0 +1,27 @@
+package com.pavis.ai.app.cr.form;
+
+import lombok.*;
+
+import java.io.Serializable;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 16:53
+ * @desc 返回信息
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ResData<T> implements Serializable {
+    private String fileUrl;
+    private T locations;
+    private T person;
+    private T times;
+    private T amount;
+    private T orgs_info;
+    private T phone_numbers;
+    private T classification;
+    private T disclaimer;
+}

+ 17 - 0
src/main/java/com/pavis/ai/app/cr/form/SendUrl.java

@@ -0,0 +1,17 @@
+package com.pavis.ai.app.cr.form;
+
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-21 15:38
+ * @desc SendUrl
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class SendUrl {
+    private String fileUrl;
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractAddressMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractAddress;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractAddressMapper
+ **/
+@Component
+public interface ContractAddressMapper extends BaseMapper<ContractAddress> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractAmountCheckMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractAmountCheck;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractAmountCheckMapper
+ **/
+@Component
+public interface ContractAmountCheckMapper extends BaseMapper<ContractAmountCheck> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractClassificationMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractClassification;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractClassificationMapper
+ **/
+@Component
+public interface ContractClassificationMapper extends BaseMapper<ContractClassification> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractEnterpriseMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractEnterprise;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractEnterpriseMapper
+ **/
+@Component
+public interface ContractEnterpriseMapper extends BaseMapper<ContractEnterprise> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractSubjectDateMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractSubjectDate;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractSubjectDateMapper
+ **/
+@Component
+public interface ContractSubjectDateMapper extends BaseMapper<ContractSubjectDate> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractSubjectMobileMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractSubjectMobile;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractSubjectMobileMapper
+ **/
+@Component
+public interface ContractSubjectMobileMapper extends BaseMapper<ContractSubjectMobile> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/ContractSubjectNameMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.ContractSubjectName;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc ContractSubjectNameMapper
+ **/
+@Component
+public interface ContractSubjectNameMapper extends BaseMapper<ContractSubjectName> {
+    
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/mapper/UploadMapper.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.pavis.ai.app.cr.model.Upload;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-09 12:37
+ * @desc UploadMapper
+ **/
+@Component
+public interface UploadMapper extends BaseMapper<Upload> {
+    
+}

+ 29 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractAddress.java

@@ -0,0 +1,29 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractAddress
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractAddress {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String locationParagraph;
+    private String locationPosition;
+    private String address;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 32 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractAmountCheck.java

@@ -0,0 +1,32 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractAmountCheck
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractAmountCheck {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String locationParagraph;
+    private String locationPosition;
+    private String capital;
+    private String lower;
+    private String unit;
+    private String result;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 28 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractClassification.java

@@ -0,0 +1,28 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractClassification
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractClassification {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String contractClassification;
+    private String disclaimer;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 31 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractEnterprise.java

@@ -0,0 +1,31 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractEnterprise
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractEnterprise {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String agency;
+    private String locationParagraph;
+    private String locationPosition;
+    private String enterpriseName;
+    private String result;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 29 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractSubjectDate.java

@@ -0,0 +1,29 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractSubjectDate
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractSubjectDate {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String dateLocationParagraph;
+    private String dateLocationPosition;
+    private String subjectDate;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 29 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractSubjectMobile.java

@@ -0,0 +1,29 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractSubjectMobile
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractSubjectMobile {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String mobileLocationParagraph;
+    private String mobileLocationPosition;
+    private String subjectMobile;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 29 - 0
src/main/java/com/pavis/ai/app/cr/model/ContractSubjectName.java

@@ -0,0 +1,29 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc ContractSubjectName
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ContractSubjectName {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String cId;
+    private String nameLocationParagraph;
+    private String nameLocationPosition;
+    private String subjectName;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 26 - 0
src/main/java/com/pavis/ai/app/cr/model/Upload.java

@@ -0,0 +1,26 @@
+package com.pavis.ai.app.cr.model;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.*;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-04 15:12
+ * @desc Upload
+ **/
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class Upload {
+    @TableId(type = IdType.ID_WORKER_STR)
+    private String id;
+    private String fileName;
+    private String operator;
+    private String operatorId;
+    private String operateTime;
+    private String operateIp;
+    private String remarks;
+}

+ 47 - 0
src/main/java/com/pavis/ai/app/cr/service/SendService.java

@@ -0,0 +1,47 @@
+package com.pavis.ai.app.cr.service;
+
+import com.pavis.ai.app.cr.common.config.FeignMultipartSupportConfig;
+import feign.codec.Encoder;
+import feign.form.spring.SpringFormEncoder;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-10 13:19
+ * @desc SendService
+ **/
+@FeignClient(value = "cr-ocr-server",url = "http://180.76.156.164:9955" ,configuration = FeignMultipartSupportConfig.class)
+// @FeignClient(value = "cr-ocr-server",url = "http://192.168.1.73:10084" ,configuration = FeignMultipartSupportConfig.class)
+public interface SendService {
+
+    // @PostMapping(value = "/api/cr/uplaod",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    // @PostMapping(value = "/api/cr/uplaod")
+    // @Headers("Content-Type: multipart/form-data")
+    // @PostMapping(value = "/handel",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    // @PostMapping(value = "/handel",consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+    @RequestMapping(method = RequestMethod.POST, value = "/handel",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    // @RequestMapping(method = RequestMethod.POST, value = "/api/cr/file",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    @ResponseBody
+    public String send(@RequestPart(value = "file") MultipartFile file);
+    // public String send(File file);
+
+    @ResponseBody
+    @PostMapping(value = "/handel_v1",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},consumes = "application/json")
+    // @RequestMapping(method = RequestMethod.POST, value = "/handel",produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+    String sendUrl(String fileUrl);
+
+
+    @Configuration
+    class MultipartSupportConfig {
+        @Bean
+        public Encoder feignFormEncoder() {
+            return new SpringFormEncoder();
+        }
+    }
+
+}

+ 15 - 0
src/main/java/com/pavis/ai/app/cr/service/UploadService.java

@@ -0,0 +1,15 @@
+package com.pavis.ai.app.cr.service;
+
+import com.pavis.ai.app.cr.form.ResData;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-16 15:41
+ * @desc UploadService
+ **/
+public interface UploadService {
+
+    ResData upload(MultipartFile file);
+
+}

+ 595 - 0
src/main/java/com/pavis/ai/app/cr/service/impl/UploadServiceImpl.java

@@ -0,0 +1,595 @@
+package com.pavis.ai.app.cr.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.pavis.ai.app.cr.common.config.properties.CommonProperties;
+import com.pavis.ai.app.cr.common.utils.DateUtils;
+import com.pavis.ai.app.cr.form.ResData;
+import com.pavis.ai.app.cr.form.SendUrl;
+import com.pavis.ai.app.cr.mapper.*;
+import com.pavis.ai.app.cr.model.*;
+import com.pavis.ai.app.cr.service.SendService;
+import com.pavis.ai.app.cr.service.UploadService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author guanhuijuan
+ * @create 2020-03-16 15:42
+ * @desc UploadServiceImpl
+ **/
+@Slf4j
+@Service
+@Transactional(rollbackFor = Exception.class)
+public class UploadServiceImpl implements UploadService {
+
+    @Autowired
+    private CommonProperties commonProperties;
+
+    @Autowired
+    private SendService sendService;
+
+    @Autowired
+    private UploadMapper uploadMapper;
+
+    @Autowired
+    private ContractAddressMapper contractAddressMapper;
+
+    @Autowired
+    private ContractAmountCheckMapper contractAmountCheckMapper;
+
+    @Autowired
+    private ContractClassificationMapper contractClassificationMapper;
+
+    @Autowired
+    private ContractEnterpriseMapper contractEnterpriseMapper;
+
+    @Autowired
+    private ContractSubjectNameMapper contractSubjectNameMapper;
+
+    @Autowired
+    private ContractSubjectMobileMapper contractSubjectMobileMapper;
+
+    @Autowired
+    private ContractSubjectDateMapper contractSubjectDateMapper;
+
+    @Override
+    public ResData upload(MultipartFile file) {
+        String fileUrl = commonProperties.getDir().getUpload();
+        String uuid = UUID.randomUUID().toString();
+        String suffix = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
+        String pathName = uuid + "." + suffix;
+        String parsedFilePath = fileUrl + pathName;
+        File f = new File(parsedFilePath);
+        try {
+            file.transferTo(new File(parsedFilePath));
+        } catch (IllegalStateException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        // 上传文件入库
+        String upload = save(file);
+        if (!upload.equals("")) {
+            // todo 调用算法,获取解析结果。
+            // 文件路径方式
+            SendUrl sendUrl = SendUrl.builder()
+                    // 上线时用
+                    // .fileUrl(fileUrl + pathName)
+                    // 线下测试时用
+                    // .fileUrl("/mnt/text-extract/file_down/jpg/广告公司合同范本.docx")
+                    .fileUrl(parsedFilePath)
+                    .build();
+
+            // String resStr2 = "";
+            String resStr2 = sendService.sendUrl(JSON.toJSONString(sendUrl));
+            System.err.println("resStr2>" + resStr2);
+            // okhttp远程发送文件,formdata形式
+            // String resStr = ocrByFormData(f,file.getOriginalFilename());
+
+            // 测试用
+            // int rd = Math.random() > 0.5 ? 1 : 0;
+            // String resStr = "";
+            // if (rd == 0){
+            //     resStr = OcrUtils.getStrEmptyFinal();
+            // }else {
+            //     resStr = OcrUtils.getStrFinal();
+            // }
+            // 将解析结果入库,判断是否有结果。
+            // return parseRes(resStr2, upload, uuid + ".pdf");
+            return parseRes(resStr2, upload, "广告公司合同范本" + ".pdf");
+
+        }
+        return new ResData();
+    }
+
+    /**
+     * 文件上传入库。
+     *
+     * @param file
+     * @return
+     */
+    public String save(MultipartFile file) {
+        Upload upload = Upload.builder()
+                // .fileName(file.getOriginalFilename())
+                .fileName(file.getOriginalFilename())
+                .operator("")
+                .operatorId("")
+                .operateIp("")
+                .operateTime(DateUtils.now())
+                .remarks("")
+                .build();
+        uploadMapper.insert(upload);
+        return upload.getId();
+    }
+
+    public ResData parseRes(String resStr, String upload, String fileName) {
+        JSONObject strJson = JSONObject.parseObject(resStr);
+        if (strJson.get("code").toString().equals("1")) {
+            // 解析成功
+            JSONObject dataJson = JSONObject.parseObject(strJson.get("data").toString());
+
+            // 地址解析
+            JSONArray addressJa = JSONArray.parseArray(dataJson.get("locations").toString());
+            List<ContractAddress> contractAddresss = parseAddress(addressJa, upload);
+            // 合同主体解析
+            JSONArray subjectPersonJa = JSONArray.parseArray(dataJson.get("person").toString());
+            List<ContractSubjectName> contractSubjectNames = parseSubjectName(subjectPersonJa, upload);
+            JSONArray subjectTimesJa = JSONArray.parseArray(dataJson.get("times").toString());
+            List<ContractSubjectDate> contractSubjectDates = parseSubjectDate(subjectTimesJa, upload);
+            JSONArray subjectPhoneJa = JSONArray.parseArray(dataJson.get("phone_numbers").toString());
+            List<ContractSubjectMobile> contractSubjectMobiles = parseSubjectMobile(subjectPhoneJa, upload);
+
+            // 金额核验解析
+            JSONArray amountCheckJa = JSONArray.parseArray(dataJson.get("amount").toString());
+            List<ContractAmountCheck> contractAmountChecks = parseAmountCheck(amountCheckJa, upload);
+
+            // 企业名称解析
+            JSONArray enterpriseJa = JSONArray.parseArray(dataJson.get("orgs_info").toString());
+            List<ContractEnterprise> contractEnterprises = parseEnterprise(enterpriseJa, upload);
+
+            // 合同分类、免责声明解析
+            List<ContractClassification> contractClassifications = parseClassification(dataJson, upload);
+
+            // 返回结果封装。
+            ResData resData = ResData.builder()
+                    .fileUrl(commonProperties.getUrl().getPath() + strJson.get("pdffilename").toString())
+                    .locations(contractAddresss.size() > 0 ? resCa(contractAddresss) : getEmpty())
+                    .person(contractSubjectNames.size() > 0 ? resCsn(contractSubjectNames) : getEmpty())
+                    .times(contractSubjectDates.size() > 0 ? resCsd(contractSubjectDates) : getEmpty())
+                    .amount(contractAmountChecks.size() > 0 ? resCac(contractAmountChecks) : getEmpty())
+                    .orgs_info(contractEnterprises.size() > 0 ? resCe(contractEnterprises) : getEmpty())
+                    .phone_numbers(contractSubjectMobiles.size() > 0 ? resCsm(contractSubjectMobiles) : getEmpty())
+                    .classification(contractClassifications.size() > 0 ? contractClassifications.get(0).getContractClassification() : "无")
+                    .disclaimer(contractClassifications.size() > 0 ? resCcd(contractClassifications) : getEmpty())
+                    .build();
+            System.err.println(JSON.toJSONString(resData));
+            return resData;
+        } else {
+            // 解析失败。
+            return new ResData();
+        }
+    }
+
+
+    public List<ContractClassification> parseClassification(JSONObject dataJson, String upload) {
+        String classification = dataJson.get("classification").toString();
+        List<ContractClassification> contractClassifications = new ArrayList<>();
+        JSONArray classificationJa = JSONArray.parseArray(dataJson.get("disclaimer").toString());
+        if (classificationJa.size() >= 1) {
+            ContractClassification contractClassification;
+            for (int i = 0; i < classificationJa.size(); i++) {
+                if (!classificationJa.get(i).toString().equals("") || !classificationJa.get(i).toString().equals("[]")) {
+                    contractClassification = ContractClassification.builder()
+                            .cId(upload)
+                            .contractClassification(classification)
+                            .disclaimer(classificationJa.get(i).toString())
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractClassificationMapper.insert(contractClassification);
+                    contractClassifications.add(contractClassification);
+                } else {
+                    contractClassification = ContractClassification.builder()
+                            .cId(upload)
+                            .contractClassification("无")
+                            .disclaimer("无")
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractClassificationMapper.insert(contractClassification);
+                    contractClassifications.add(contractClassification);
+                }
+            }
+        }
+        return contractClassifications;
+    }
+
+    public List<ContractAddress> parseAddress(JSONArray addressJa, String upload) {
+        List<ContractAddress> contractAddresss = new ArrayList<>();
+        System.err.println("size>" + addressJa.size());
+        if (addressJa.size() > 0) {
+            ContractAddress contractAddress;
+            for (int i = 0; i < addressJa.size(); i++) {
+                System.err.println(addressJa.get(i).toString());
+                if (!addressJa.get(i).toString().equals("") || !addressJa.get(i).toString().equals("[]")) {
+                    System.err.println("if");
+                    JSONArray address = JSONArray.parseArray(addressJa.get(i).toString());
+                    String[] arr = StringUtils.remove(StringUtils.remove(address.toString(), "["), "]").split(",");
+                    contractAddress = ContractAddress.builder()
+                            .cId(upload)
+                            .locationParagraph(StringUtils.remove(arr[0], "\""))
+                            .locationPosition(StringUtils.remove(arr[1], "\""))
+                            .address(StringUtils.remove(arr[2], "\""))
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractAddressMapper.insert(contractAddress);
+                    contractAddresss.add(contractAddress);
+                } else {
+                    System.err.println("else");
+                    contractAddresss.add(new ContractAddress());
+                }
+            }
+        } else {
+            System.err.println("else insert");
+            ContractAddress contractAddress = ContractAddress.builder()
+                    .cId(upload)
+                    .locationParagraph("无")
+                    .locationPosition("无")
+                    .address("无")
+                    .operator("")
+                    .operatorId("")
+                    .operateIp("")
+                    .operateTime(DateUtils.now())
+                    .remarks("")
+                    .build();
+            contractAddressMapper.insert(contractAddress);
+        }
+        return contractAddresss;
+    }
+
+    public List<ContractSubjectName> parseSubjectName(JSONArray subjectPersonJa, String upload) {
+        List<ContractSubjectName> contractSubjectNames = new ArrayList<>();
+        if (subjectPersonJa.size() > 0) {
+            ContractSubjectName contractSubjectName;
+            for (int i = 0; i < subjectPersonJa.size(); i++) {
+                if (!subjectPersonJa.get(i).toString().equals("") || !subjectPersonJa.get(i).toString().equals("[]")) {
+                    JSONArray address = JSONArray.parseArray(subjectPersonJa.get(i).toString());
+                    String[] arr = StringUtils.remove(StringUtils.remove(address.toString(), "["), "]").split(",");
+                    contractSubjectName = ContractSubjectName.builder()
+                            .cId(upload)
+                            .nameLocationParagraph(StringUtils.remove(arr[0], "\""))
+                            .nameLocationPosition(StringUtils.remove(arr[1], "\""))
+                            .subjectName(StringUtils.remove(arr[2], "\""))
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractSubjectNameMapper.insert(contractSubjectName);
+                    contractSubjectNames.add(contractSubjectName);
+                } else {
+
+                    contractSubjectNames.add(new ContractSubjectName());
+                }
+
+            }
+        } else {
+            ContractSubjectName contractSubjectName = ContractSubjectName.builder()
+                    .cId(upload)
+                    .nameLocationParagraph("无")
+                    .nameLocationPosition("无")
+                    .subjectName("无")
+                    .operator("")
+                    .operatorId("")
+                    .operateIp("")
+                    .operateTime(DateUtils.now())
+                    .remarks("")
+                    .build();
+            contractSubjectNameMapper.insert(contractSubjectName);
+        }
+        return contractSubjectNames;
+    }
+
+    public List<ContractSubjectDate> parseSubjectDate(JSONArray subjectDateJa, String upload) {
+        List<ContractSubjectDate> contractSubjectDates = new ArrayList<>();
+        if (subjectDateJa.size() > 0) {
+            ContractSubjectDate contractSubjectDate;
+            for (int i = 0; i < subjectDateJa.size(); i++) {
+                if (!subjectDateJa.get(i).toString().equals("") || !subjectDateJa.get(i).toString().equals("[]")) {
+                    JSONArray address = JSONArray.parseArray(subjectDateJa.get(i).toString());
+                    String[] arr = StringUtils.remove(StringUtils.remove(address.toString(), "["), "]").split(",");
+                    contractSubjectDate = ContractSubjectDate.builder()
+                            .cId(upload)
+                            .dateLocationParagraph(StringUtils.remove(arr[0], "\""))
+                            .dateLocationPosition(StringUtils.remove(arr[1], "\""))
+                            .subjectDate(StringUtils.remove(arr[2], "\""))
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractSubjectDateMapper.insert(contractSubjectDate);
+                    contractSubjectDates.add(contractSubjectDate);
+                } else {
+                    contractSubjectDates.add(new ContractSubjectDate());
+                }
+            }
+        } else {
+            ContractSubjectDate contractSubjectDate = ContractSubjectDate.builder()
+                    .cId(upload)
+                    .dateLocationParagraph("无")
+                    .dateLocationPosition("无")
+                    .subjectDate("无")
+                    .operator("")
+                    .operatorId("")
+                    .operateIp("")
+                    .operateTime(DateUtils.now())
+                    .remarks("")
+                    .build();
+            contractSubjectDateMapper.insert(contractSubjectDate);
+        }
+        return contractSubjectDates;
+    }
+
+    public List<ContractSubjectMobile> parseSubjectMobile(JSONArray subjectMobileJa, String upload) {
+        List<ContractSubjectMobile> contractSubjectMobiles = new ArrayList<>();
+        if (subjectMobileJa.size() > 0) {
+            ContractSubjectMobile contractSubjectMobile;
+            for (int i = 0; i < subjectMobileJa.size(); i++) {
+                if (!subjectMobileJa.get(i).toString().equals("") || !subjectMobileJa.get(i).toString().equals("[]")) {
+                    JSONArray address = JSONArray.parseArray(subjectMobileJa.get(i).toString());
+                    String[] arr = StringUtils.remove(StringUtils.remove(address.toString(), "["), "]").split(",");
+                    contractSubjectMobile = ContractSubjectMobile.builder()
+                            .cId(upload)
+                            .mobileLocationParagraph(StringUtils.remove(arr[0], "\""))
+                            .mobileLocationPosition(StringUtils.remove(arr[1], "\""))
+                            .subjectMobile(StringUtils.remove(arr[2], "\""))
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractSubjectMobileMapper.insert(contractSubjectMobile);
+                    contractSubjectMobiles.add(contractSubjectMobile);
+                } else {
+                    contractSubjectMobiles.add(new ContractSubjectMobile());
+                }
+
+            }
+        } else {
+            ContractSubjectMobile contractSubjectMobile = ContractSubjectMobile.builder()
+                    .cId(upload)
+                    .mobileLocationParagraph("无")
+                    .mobileLocationPosition("无")
+                    .subjectMobile("无")
+                    .operator("")
+                    .operatorId("")
+                    .operateIp("")
+                    .operateTime(DateUtils.now())
+                    .remarks("")
+                    .build();
+            contractSubjectMobileMapper.insert(contractSubjectMobile);
+        }
+        return contractSubjectMobiles;
+    }
+
+    public List<ContractAmountCheck> parseAmountCheck(JSONArray amountCheckJa, String upload) {
+        List<ContractAmountCheck> contractAmountChecks = new ArrayList<>();
+        if (amountCheckJa.size() > 0) {
+
+            ContractAmountCheck contractAmountCheck;
+            for (int i = 0; i < amountCheckJa.size(); i++) {
+                if (!amountCheckJa.get(i).toString().equals("") || !amountCheckJa.get(i).toString().equals("[]")) {
+                    JSONArray address = JSONArray.parseArray(amountCheckJa.get(i).toString());
+                    String[] arr = StringUtils.remove(StringUtils.remove(address.toString(), "["), "]").split(",");
+                    contractAmountCheck = ContractAmountCheck.builder()
+                            .cId(upload)
+                            .locationParagraph(StringUtils.remove(arr[0], "\""))
+                            .locationPosition(StringUtils.remove(arr[1], "\""))
+                            .capital(StringUtils.remove(arr[2], "\""))
+                            .lower(StringUtils.remove(arr[3], "\""))
+                            .unit(StringUtils.remove(arr[4], "\""))
+                            .result(StringUtils.remove(arr[5], "\""))
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractAmountCheckMapper.insert(contractAmountCheck);
+                    contractAmountChecks.add(contractAmountCheck);
+                } else {
+                    contractAmountChecks.add(new ContractAmountCheck());
+                }
+
+            }
+        } else {
+            ContractAmountCheck contractAmountCheck = ContractAmountCheck.builder()
+                    .cId(upload)
+                    .locationParagraph("无")
+                    .locationPosition("无")
+                    .capital("无")
+                    .lower("无")
+                    .unit("无")
+                    .result("无")
+                    .operatorId("")
+                    .operateIp("")
+                    .operateTime(DateUtils.now())
+                    .remarks("")
+                    .build();
+            contractAmountCheckMapper.insert(contractAmountCheck);
+        }
+        return contractAmountChecks;
+    }
+
+    public List<ContractEnterprise> parseEnterprise(JSONArray enterpriseJa, String upload) {
+        List<ContractEnterprise> contractEnterprises = new ArrayList<>();
+        if (enterpriseJa.size() > 0) {
+
+            ContractEnterprise contractEnterprise;
+            for (int i = 0; i < enterpriseJa.size(); i++) {
+                if (!enterpriseJa.get(i).toString().equals("") || !enterpriseJa.get(i).toString().equals("[]")) {
+                    JSONArray address = JSONArray.parseArray(enterpriseJa.get(i).toString());
+                    String[] arr = StringUtils.remove(StringUtils.remove(address.toString(), "["), "]").split(",");
+                    contractEnterprise = ContractEnterprise.builder()
+                            .cId(upload)
+                            .agency(StringUtils.remove(arr[0], "\""))
+                            .locationParagraph(StringUtils.remove(arr[1], "\""))
+                            .locationPosition(StringUtils.remove(arr[2], "\""))
+                            .enterpriseName(StringUtils.remove(arr[3], "\""))
+                            .result(StringUtils.remove(arr[4], "\""))
+                            .operator("")
+                            .operatorId("")
+                            .operateIp("")
+                            .operateTime(DateUtils.now())
+                            .remarks("")
+                            .build();
+                    contractEnterpriseMapper.insert(contractEnterprise);
+                    contractEnterprises.add(contractEnterprise);
+                } else {
+                    contractEnterprises.add(new ContractEnterprise());
+                }
+            }
+        } else {
+            ContractEnterprise contractEnterprise = ContractEnterprise.builder()
+                    .cId(upload)
+                    .agency("无")
+                    .locationParagraph("无")
+                    .locationPosition("无")
+                    .enterpriseName("无")
+                    .result("无")
+                    .operator("")
+                    .operatorId("")
+                    .operateIp("")
+                    .operateTime(DateUtils.now())
+                    .remarks("")
+                    .build();
+            contractEnterpriseMapper.insert(contractEnterprise);
+        }
+        return contractEnterprises;
+    }
+
+
+    public List<List<String>> getEmpty() {
+        List<String> resList = new ArrayList<>();
+        resList.add("无");
+        List<List<String>> res = new ArrayList<>();
+        res.add(resList);
+        return res;
+    }
+
+    public List<List<String>> resCa(List<ContractAddress> contractAddresss) {
+        List<List<String>> res = new ArrayList<>();
+        for (ContractAddress addresss : contractAddresss) {
+            List<String> data = new ArrayList<>();
+            data.add(addresss.getLocationParagraph());
+            data.add(addresss.getLocationPosition());
+            data.add(addresss.getAddress());
+            res.add(data);
+        }
+
+        return res;
+    }
+
+    public List<List<String>> resCsn(List<ContractSubjectName> contractSubjectNames) {
+        List<List<String>> res = new ArrayList<>();
+        for (ContractSubjectName subjectName : contractSubjectNames) {
+            List<String> data = new ArrayList<>();
+            data.add(subjectName.getNameLocationParagraph());
+            data.add(subjectName.getNameLocationPosition());
+            data.add(subjectName.getSubjectName());
+            res.add(data);
+        }
+        return res;
+    }
+
+    public List<List<String>> resCsd(List<ContractSubjectDate> contractSubjectDates) {
+        List<List<String>> res = new ArrayList<>();
+        for (ContractSubjectDate subjectDate : contractSubjectDates) {
+            List<String> data = new ArrayList<>();
+            data.add(subjectDate.getDateLocationParagraph());
+            data.add(subjectDate.getDateLocationPosition());
+            data.add(subjectDate.getSubjectDate());
+            res.add(data);
+        }
+        return res;
+    }
+
+    public List<List<String>> resCac(List<ContractAmountCheck> contractAmountChecks) {
+        List<List<String>> res = new ArrayList<>();
+        for (ContractAmountCheck amountCheck : contractAmountChecks) {
+            List<String> data = new ArrayList<>();
+            data.add(amountCheck.getLocationParagraph());
+            data.add(amountCheck.getLocationPosition());
+            data.add(amountCheck.getCapital());
+            data.add(amountCheck.getLower());
+            data.add(amountCheck.getUnit());
+            data.add(amountCheck.getResult());
+            res.add(data);
+        }
+        return res;
+    }
+
+    public List<List<String>> resCe(List<ContractEnterprise> contractEnterprises) {
+        List<List<String>> res = new ArrayList<>();
+        for (ContractEnterprise enterprise : contractEnterprises) {
+            List<String> data = new ArrayList<>();
+            data.add(enterprise.getAgency());
+            data.add(enterprise.getLocationParagraph());
+            data.add(enterprise.getLocationPosition());
+            data.add(enterprise.getEnterpriseName());
+            data.add(enterprise.getResult());
+            res.add(data);
+        }
+        return res;
+    }
+
+    public List<List<String>> resCsm(List<ContractSubjectMobile> contractSubjectMobiles) {
+        List<List<String>> res = new ArrayList<>();
+        for (ContractSubjectMobile mobile : contractSubjectMobiles) {
+            List<String> data = new ArrayList<>();
+            data.add(mobile.getMobileLocationParagraph());
+            data.add(mobile.getMobileLocationPosition());
+            data.add(mobile.getSubjectMobile());
+            res.add(data);
+        }
+        return res;
+    }
+
+    public List<String> resCcd(List<ContractClassification> contractClassifications) {
+        List<List<String>> res = new ArrayList<>();
+        List<String> data = new ArrayList<>();
+        for (ContractClassification contractClassification : contractClassifications) {
+            data.add(contractClassification.getDisclaimer());
+            res.add(data);
+        }
+        return data;
+    }
+
+}

+ 49 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,49 @@
+spring:
+  datasource:
+#    url: jdbc:mysql://192.168.1.73/fjs_ocr?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
+    url: jdbc:mysql://192.168.1.73/cr?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: root
+#  rabbitmq:
+#    host: 192.168.1.73
+#    port: 5672
+#    username: fjs
+#    password: fjs20200310
+#    virtual-host: fjs
+#    publisher-confirms: true
+#    publisher-returns: true
+cr:
+  common:
+    dir:
+      base: D:\proooject\prooooject\home\privacy\projects\cr
+      # 上传文件存储文件夹
+      upload: ${cr.common.dir.base}\upload\rec\
+      down: ${cr.common.dir.base}\upload\file_down\
+    url:
+      # ip
+      base: http://192.168.1.73:10084
+      path: ${cr.common.url.base}/down/
+logging:
+  level:
+    org.springframework.cloud: debug
+    org.springframework.boot: debug
+    com.pavis.ai.app.cr.mapper: trace
+#security:
+#  oauth2:
+#    client:
+#      client-id: pavis-upms
+#      client-secret: pavis@2019*
+#      access-token-uri: http://localhost:8090/oauth/token
+#      user-authorization-uri: http://localhost:8090/oauth/authorize
+#    resource:
+#      token-info-uri: http://localhost:8090/oauth/check_token
+security:
+  oauth2:
+    client:
+      client-id: iGKpGQXmPYNfj6XvXuiQtlSO
+      client-secret: tm6p3xq4zQOgJlCeIyeYYHMPNGAXuQVx
+      access-token-uri: http://192.168.1.23:8090/oauth/token
+      user-authorization-uri: http://192.168.1.23:8090/oauth/authorize
+    resource:
+      token-info-uri: http://192.168.1.23:8090/oauth/check_token

+ 24 - 0
src/main/resources/application-prod.yml

@@ -0,0 +1,24 @@
+spring:
+  datasource:
+    url: jdbc:mysql://180.76.146.227/cr?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    username: root
+    password: Semi.1001
+#  rabbitmq:
+#    host: 180.76.146.227
+#    port: 5672
+#    username: fjs
+#    password: fjshoyiu7
+#    virtual-host: /
+#    publisher-confirms: true
+#    publisher-returns: true
+cr:
+  common:
+    dir:
+      # 上传文件存储文件夹
+      upload: /cr/upload/
+logging:
+  level:
+    org.springframework.cloud: debug
+    org.springframework.boot: debug
+    com.pavis.ai.app.fjs_ocr.mapper: trace

+ 17 - 0
src/main/resources/application.yml

@@ -0,0 +1,17 @@
+server:
+  port: 10085
+#  port: 8000
+spring:
+  application:
+    name: pavis-portal-server
+  profiles:
+    active: dev
+#    active: prod
+  servlet:
+    multipart:
+      max-file-size: 50MB
+      max-request-size: 20MB
+mybatis-plus:
+  mapper-locations: classpath*:/mapper/*Mapper.xml
+  typeAliasesPackage: com.pavis.ai.app.cr.model
+

+ 22 - 0
src/main/resources/error.properties

@@ -0,0 +1,22 @@
+credentials_expired=\u51ED\u8BC1\u5DF2\u8FC7\u671F!
+bad_request=\u65E0\u6548\u7684\u8BF7\u6C42!
+not_found=\u65E0\u6548\u7684\u8BBF\u95EE\u5730\u5740\uFF01
+service_unavailable=\u670D\u52A1\u6682\u65F6\u65E0\u6CD5\u8BBF\u95EE\uFF01
+method_not_allowed=\u8BF7\u6C42\u65B9\u5F0F\u4E0D\u652F\u6301!
+media_type_not_acceptable=\u5A92\u4F53\u7C7B\u578B\u4E0D\u652F\u6301!
+username_not_found=\u8D26\u53F7\u4E0D\u5B58\u5728!
+bad_credentials=\u8D26\u53F7\u6216\u5BC6\u7801\u9519\u8BEF!
+account_disabled=\u8D26\u53F7\u5DF2\u88AB\u7981\u7528!
+account_expired=\u8D26\u53F7\u5DF2\u8FC7\u671F!
+account_locked=\u8D26\u53F7\u5DF2\u88AB\u9501\u5B9A!
+error=\u670D\u52A1\u5668\u7E41\u5FD9,\u8BF7\u7A0D\u540E\u518D\u8BD5!
+unauthorized=\u8BA4\u8BC1\u5931\u8D25,\u8BF7\u91CD\u65B0\u767B\u5F55!
+too_many_requests=\u8BBF\u95EE\u592A\u8FC7\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5!
+access_denied=\u6743\u9650\u4E0D\u8DB3,\u62D2\u7EDD\u8BBF\u95EE!
+access_denied_black_limited=IP\u6216\u57DF\u540D\u62D2\u7EDD\u8BBF\u95EE!
+access_denied_white_limited=IP\u6216\u57DF\u540D\u4E0D\u5728\u767D\u540D\u5355\u5185,\u62D2\u7EDD\u8BBF\u95EE!
+access_denied_authority_expired=\u6388\u6743\u5DF2\u8FC7\u671F,\u62D2\u7EDD\u8BBF\u95EE!
+access_denied_updating=\u6B63\u5728\u5347\u7EA7\u7EF4\u62A4\u4E2D,\u8BF7\u7A0D\u540E\u518D\u8BD5!
+access_denied_disabled=\u8BF7\u6C42\u5730\u5740,\u7981\u6B62\u8BBF\u95EE!
+access_denied_not_open=\u8BF7\u6C42\u5730\u5740,\u62D2\u7EDD\u8BBF\u95EE!
+invalid_token=\u65E0\u6548\u7684\u8BBF\u95EE\u4EE4\u724C!

+ 16 - 0
src/test/java/com/pavis/ai/app/cr/CrApplicationTests.java

@@ -0,0 +1,16 @@
+package com.pavis.ai.app.cr;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class CrApplicationTests {
+
+    @Test
+    public void contextLoads() {
+    }
+
+}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott