Browse Source

项目构建,基础功能完善配置

liuchanglan 4 years ago
commit
76f75d691f
100 changed files with 5854 additions and 0 deletions
  1. 33 0
      .gitignore
  2. 117 0
      .mvn/wrapper/MavenWrapperDownloader.java
  3. BIN
      .mvn/wrapper/maven-wrapper.jar
  4. 2 0
      .mvn/wrapper/maven-wrapper.properties
  5. 310 0
      mvnw
  6. 182 0
      mvnw.cmd
  7. 131 0
      pom.xml
  8. 13 0
      src/main/java/com/gz/GuihuaArchivesApplication.java
  9. 130 0
      src/main/java/com/gz/aop/WebLogAspect.java
  10. 21 0
      src/main/java/com/gz/common/DataGlobalVariable.java
  11. 29 0
      src/main/java/com/gz/config/ErrorPageConfig.java
  12. 61 0
      src/main/java/com/gz/config/FilterConfig.java
  13. 14 0
      src/main/java/com/gz/config/MapperScanConfig.java
  14. 88 0
      src/main/java/com/gz/controller/system/AdminController.java
  15. 73 0
      src/main/java/com/gz/controller/system/AuthController.java
  16. 114 0
      src/main/java/com/gz/controller/system/DictController.java
  17. 39 0
      src/main/java/com/gz/controller/system/FileController.java
  18. 75 0
      src/main/java/com/gz/controller/system/LogController.java
  19. 99 0
      src/main/java/com/gz/controller/system/MenuController.java
  20. 113 0
      src/main/java/com/gz/controller/system/RoleController.java
  21. 43 0
      src/main/java/com/gz/core/BaseDTO.java
  22. 21 0
      src/main/java/com/gz/core/annotation/Controller.java
  23. 32 0
      src/main/java/com/gz/core/annotation/TraceLog.java
  24. 39 0
      src/main/java/com/gz/core/exception/BusinessException.java
  25. 27 0
      src/main/java/com/gz/core/exception/CustomExceptionEnum.java
  26. 62 0
      src/main/java/com/gz/core/exception/CustomExceptionEnumHandler.java
  27. 16 0
      src/main/java/com/gz/core/mybatis/UUIDGenId.java
  28. 11 0
      src/main/java/com/gz/core/response/CustomResponsInterface.java
  29. 48 0
      src/main/java/com/gz/core/response/GlobalResponseHandler.java
  30. 24 0
      src/main/java/com/gz/core/response/ResponseEnum.java
  31. 31 0
      src/main/java/com/gz/core/response/ResponseResult.java
  32. 38 0
      src/main/java/com/gz/dto/system/AdminDTO.java
  33. 27 0
      src/main/java/com/gz/dto/system/DictDTO.java
  34. 20 0
      src/main/java/com/gz/dto/system/FileDTO.java
  35. 40 0
      src/main/java/com/gz/dto/system/LogDTO.java
  36. 33 0
      src/main/java/com/gz/dto/system/MenuDTO.java
  37. 25 0
      src/main/java/com/gz/dto/system/MenuRoleDTO.java
  38. 21 0
      src/main/java/com/gz/dto/system/RoleDTO.java
  39. 111 0
      src/main/java/com/gz/filter/AuthFilter.java
  40. 27 0
      src/main/java/com/gz/filter/CorsFilter.java
  41. 39 0
      src/main/java/com/gz/jwt/JwtConfig.java
  42. 26 0
      src/main/java/com/gz/jwt/JwtPayload.java
  43. 13 0
      src/main/java/com/gz/mapper/system/AdminMapper.java
  44. 20 0
      src/main/java/com/gz/mapper/system/DictMapper.java
  45. 7 0
      src/main/java/com/gz/mapper/system/FileMapper.java
  46. 28 0
      src/main/java/com/gz/mapper/system/LogMapper.java
  47. 25 0
      src/main/java/com/gz/mapper/system/MenuMapper.java
  48. 13 0
      src/main/java/com/gz/mapper/system/MenuRoleMapper.java
  49. 13 0
      src/main/java/com/gz/mapper/system/RoleMapper.java
  50. 23 0
      src/main/java/com/gz/rvo/system/FileUploadRVO.java
  51. 22 0
      src/main/java/com/gz/rvo/system/InitialHomeRVO.java
  52. 43 0
      src/main/java/com/gz/rvo/system/LogRVO.java
  53. 16 0
      src/main/java/com/gz/rvo/system/LoginRVO.java
  54. 35 0
      src/main/java/com/gz/rvo/system/RoleMenuRVO.java
  55. 19 0
      src/main/java/com/gz/rvo/system/TreeRVO.java
  56. 57 0
      src/main/java/com/gz/service/system/AdminService.java
  57. 52 0
      src/main/java/com/gz/service/system/AuthService.java
  58. 83 0
      src/main/java/com/gz/service/system/DictService.java
  59. 24 0
      src/main/java/com/gz/service/system/FileService.java
  60. 50 0
      src/main/java/com/gz/service/system/LogService.java
  61. 58 0
      src/main/java/com/gz/service/system/MenuService.java
  62. 60 0
      src/main/java/com/gz/service/system/RoleService.java
  63. 98 0
      src/main/java/com/gz/service/system/impl/AdminServiceImpl.java
  64. 201 0
      src/main/java/com/gz/service/system/impl/AuthServiceImpl.java
  65. 148 0
      src/main/java/com/gz/service/system/impl/DictServiceImpl.java
  66. 85 0
      src/main/java/com/gz/service/system/impl/FileServiceImpl.java
  67. 51 0
      src/main/java/com/gz/service/system/impl/LogServiceImpl.java
  68. 87 0
      src/main/java/com/gz/service/system/impl/MenuServiceImpl.java
  69. 152 0
      src/main/java/com/gz/service/system/impl/RoleServiceImpl.java
  70. 92 0
      src/main/java/com/gz/utils/JwtUtils.java
  71. 29 0
      src/main/java/com/gz/utils/PasswordUtils.java
  72. 36 0
      src/main/java/com/gz/utils/RequestUtils.java
  73. 153 0
      src/main/java/com/gz/utils/TableUtils.java
  74. 23 0
      src/main/java/com/gz/vo/PageVO.java
  75. 12 0
      src/main/java/com/gz/vo/system/AdminVO.java
  76. 11 0
      src/main/java/com/gz/vo/system/DictVO.java
  77. 17 0
      src/main/java/com/gz/vo/system/LogVO.java
  78. 16 0
      src/main/java/com/gz/vo/system/LoginVO.java
  79. 11 0
      src/main/java/com/gz/vo/system/MenuVO.java
  80. 15 0
      src/main/java/com/gz/vo/system/RoleMenuVO.java
  81. 12 0
      src/main/java/com/gz/vo/system/RoleVO.java
  82. 14 0
      src/main/java/com/gz/vo/system/UpdatePasswordVO.java
  83. 85 0
      src/main/resources/application-dev.yml
  84. 26 0
      src/main/resources/application.yml
  85. 7 0
      src/main/resources/banner.txt
  86. 4 0
      src/main/resources/log4j.properties
  87. 6 0
      src/main/resources/mapper/FileMapper.xml
  88. 8 0
      src/main/resources/mapper/dictMapper.xml
  89. 65 0
      src/main/resources/mapper/logMapper.xml
  90. 33 0
      src/main/resources/mapper/menuMapper.xml
  91. 118 0
      src/main/resources/static/404.html
  92. 4 0
      src/main/resources/static/api/clear.json
  93. 77 0
      src/main/resources/static/api/init.json
  94. 927 0
      src/main/resources/static/css/layuimini.css
  95. 70 0
      src/main/resources/static/css/public.css
  96. 95 0
      src/main/resources/static/css/themes/default.css
  97. BIN
      src/main/resources/static/images/bg.png
  98. BIN
      src/main/resources/static/images/captcha.jpg
  99. BIN
      src/main/resources/static/images/favicon.ico
  100. 0 0
      src/main/resources/static/images/jcqk.png

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 117 - 0
.mvn/wrapper/MavenWrapperDownloader.java

@@ -0,0 +1,117 @@
+/*
+ * Copyright 2007-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    private static final String WRAPPER_VERSION = "0.5.6";
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+        + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+            ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+            ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main(String args[]) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+        String url = DEFAULT_DOWNLOAD_URL;
+        if(mavenWrapperPropertyFile.exists()) {
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
+            try {
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+                Properties mavenWrapperProperties = new Properties();
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            } catch (IOException e) {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            } finally {
+                try {
+                    if(mavenWrapperPropertyFileInputStream != null) {
+                        mavenWrapperPropertyFileInputStream.close();
+                    }
+                } catch (IOException e) {
+                    // Ignore ...
+                }
+            }
+        }
+        System.out.println("- Downloading from: " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if(!outputFile.getParentFile().exists()) {
+            if(!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                        "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+            String username = System.getenv("MVNW_USERNAME");
+            char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+            Authenticator.setDefault(new Authenticator() {
+                @Override
+                protected PasswordAuthentication getPasswordAuthentication() {
+                    return new PasswordAuthentication(username, password);
+                }
+            });
+        }
+        URL website = new URL(urlString);
+        ReadableByteChannel rbc;
+        rbc = Channels.newChannel(website.openStream());
+        FileOutputStream fos = new FileOutputStream(destination);
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        fos.close();
+        rbc.close();
+    }
+
+}

BIN
.mvn/wrapper/maven-wrapper.jar


+ 2 - 0
.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

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

+ 131 - 0
pom.xml

@@ -0,0 +1,131 @@
+<?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.2.2.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.gz</groupId>
+    <artifactId>guihua-archives</artifactId>
+    <version>1.0.0</version>
+    <name>guihua-archives</name>
+    <description>规划档案</description>
+    <properties>
+        <java.version>1.8</java.version>
+        <druid.version>1.1.17</druid.version>
+        <mysql.connector.version>8.0.15</mysql.connector.version>
+        <log4j.version>1.2.16</log4j.version>
+        <lombok.version>1.18.12</lombok.version>
+        <fast.json.version>1.2.47</fast.json.version>
+        <tk.mapper.version>2.1.5</tk.mapper.version>
+        <japidocs.version>1.4</japidocs.version>
+        <pagehelper.spring.boot.version>1.2.3</pagehelper.spring.boot.version>
+        <java.jwt.vetsion>3.7.0</java.jwt.vetsion>
+        <apache.poi.version>3.17</apache.poi.version>
+        <hutool.version>5.4.0</hutool.version>
+        <screw.version>1.0.3</screw.version>
+        <aliyun.sdk.version>4.5.3</aliyun.sdk.version>
+        <aliyun.oss.sdk.version>3.10.2</aliyun.oss.sdk.version>
+        <!-- 跳过打包测试 -->
+        <skipTests>true</skipTests>
+    </properties>
+
+    <dependencies>
+        <!--        aop-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <!--        mybatis-->
+        <dependency>
+            <groupId>tk.mybatis</groupId>
+            <artifactId>mapper-spring-boot-starter</artifactId>
+            <version>${tk.mapper.version}</version>
+        </dependency>
+        <!--        Mysql驱动-->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+            <version>${mysql.connector.version}</version>
+        </dependency>
+        <!--            druid连接池-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>${druid.version}</version>
+        </dependency>
+        <!--            log4j-->
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+        <!--            lombok-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>${lombok.version}</version>
+        </dependency>
+        <!--            fastJson-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fast.json.version}</version>
+        </dependency>
+        <!--            分页插件-->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>${pagehelper.spring.boot.version}</version>
+        </dependency>
+        <!--        JWT-->
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>${java.jwt.vetsion}</version>
+        </dependency>
+        <!--        Hutool-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+        <!--        spring-web-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- redis依赖包 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <!--        单元测试模块-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 13 - 0
src/main/java/com/gz/GuihuaArchivesApplication.java

@@ -0,0 +1,13 @@
+package com.gz;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class GuihuaArchivesApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(GuihuaArchivesApplication.class, args);
+    }
+
+}

+ 130 - 0
src/main/java/com/gz/aop/WebLogAspect.java

@@ -0,0 +1,130 @@
+package com.gz.aop;
+
+import com.alibaba.fastjson.JSONObject;
+import com.gz.common.DataGlobalVariable;
+import com.gz.core.annotation.TraceLog;
+import com.gz.dto.system.LogDTO;
+import com.gz.mapper.system.LogMapper;
+import com.gz.utils.JwtUtils;
+import com.gz.utils.RequestUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 纪录日志
+ * @author LiuchangLan
+ * @date 2020/7/23 14:48
+ */
+@Aspect
+@Component
+public class WebLogAspect {
+
+    /**
+     * 切入点
+     */
+    public static final String POINTCUT = "execution(* com.gz.controller..*Controller.*(..))";
+
+    @Resource
+    private LogMapper logMapper;
+
+    /**
+     * @description 纪录操作日志
+     * @author LiuChangLan
+     * @since 2020/7/24 16:53
+     * @Before 前置增强
+     */
+    @Before(POINTCUT)
+    public void doBefore(JoinPoint joinPoint) throws Throwable {
+        LogDTO logDTO = loadLogDto(joinPoint);
+        if (logDTO == null){
+            return;
+        }
+        logMapper.insertSelective(logDTO);
+    }
+
+    /**
+     * @description 纪录错误日志
+     * @author LiuChangLan
+     * @since 2020/7/24 16:53
+     */
+    @AfterThrowing(pointcut = POINTCUT, throwing = "e")
+    @Transactional
+    public void afterThrowing(JoinPoint joinPoint, Throwable e) {
+        LogDTO logDTO = loadLogDto(joinPoint);
+        if (logDTO != null){
+            // 查询已经记录过的操作日志
+            LogDTO selectOne = logMapper.selectOne(logDTO);
+            // 修改日志类型
+            selectOne.setLogType(DataGlobalVariable.ERROR_LOG_CODE);
+            // 修改错误消息
+            selectOne.setErrorMsg(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
+            // 修改日志
+            logMapper.updateByPrimaryKeySelective(selectOne);
+        }
+    }
+
+
+    /**
+     * * 转换异常信息为字符串
+     * * @param exceptionName    异常名称
+     * * @param exceptionMessage 异常信息
+     * * @param elements         堆栈信息
+     */
+    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
+        StringBuffer strbuff = new StringBuffer();
+        for (StackTraceElement stet : elements) {
+            strbuff.append(stet + "\n");
+        }
+        String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
+        return message;
+    }
+
+
+    /**
+     * @description 根据连接点载体日志dto
+     * @author LiuChangLan
+     * @since 2020/7/23 15:55
+     */
+    private LogDTO loadLogDto(JoinPoint joinPoint) {
+        // 获取自定义注解
+        TraceLog traceLog = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(TraceLog.class);
+        // 跳过没有注解的方法
+        if(traceLog == null){
+            return null;
+        }
+        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+        HttpServletRequest request = sra.getRequest();
+        // 反射读取类名
+        String className = joinPoint.getTarget().getClass().getName();
+        // 构造日志对象
+        LogDTO logDTO = new LogDTO();
+        logDTO.setExecMethod(className + "." + joinPoint.getSignature().getName());
+        //判断是否是上传文件
+        // 参数
+        logDTO.setParamsJson(JSONObject.toJSONString(joinPoint.getArgs()));
+        // 操作者
+        logDTO.setExecBy(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 日志类别
+        logDTO.setLogType(DataGlobalVariable.OPERATE_LOG_CODE);
+        // 操作ip
+        logDTO.setExecIp(RequestUtils.getIpAddress(request));
+        // 操作模块
+        logDTO.setModule(traceLog.module());
+        // 操作业务
+        logDTO.setBusiness(traceLog.business());
+        return logDTO;
+    }
+
+}

+ 21 - 0
src/main/java/com/gz/common/DataGlobalVariable.java

@@ -0,0 +1,21 @@
+package com.gz.common;
+
+/**
+ * 全局常量
+ * @author LiuchangLan
+ * @date 2020/7/14 15:00
+ */
+public class DataGlobalVariable {
+
+    /** 用户激活状态码*/
+    public static final Integer USER_STATUS_DISABLE = 1;
+
+    /** 操作日志的code*/
+    public static final String OPERATE_LOG_CODE = "OPERATION_LOG";
+
+    /** 错误日志的code*/
+    public static final String ERROR_LOG_CODE = "ERROR_LOG";
+
+    /** 登录日志的code*/
+    public static final String LOGIN_LOG_CODE = "LOGIN_LOG";
+}

+ 29 - 0
src/main/java/com/gz/config/ErrorPageConfig.java

@@ -0,0 +1,29 @@
+package com.gz.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.web.server.ConfigurableWebServerFactory;
+import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
+
+/**
+ *
+ * @author LiuchangLan
+ * @date 2021/2/22 14:44
+ */
+@Slf4j
+@Configuration
+public class ErrorPageConfig {
+
+    @Bean
+    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
+        log.info("配置自定义404页面");
+        return (factory -> {
+            ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404.html");
+            factory.addErrorPages(errorPage404);
+        });
+    }
+
+}

+ 61 - 0
src/main/java/com/gz/config/FilterConfig.java

@@ -0,0 +1,61 @@
+package com.gz.config;
+
+import com.gz.filter.AuthFilter;
+import com.gz.filter.CorsFilter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.util.AntPathMatcher;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+
+/**
+ * @author LiuchangLan
+ * @date 2021/1/15 13:28
+ */
+@Configuration
+@Slf4j
+public class FilterConfig {
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Value("${auth.login.force-urls}")
+    private String forceUrls;
+
+    @Value("${auth.login.skip-urls}")
+    private String skipUrls;
+
+
+
+    @Bean
+    public FilterRegistrationBean registCorsFilter(){
+        log.info("注册跨域过滤器");
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new CorsFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("crosFilter");
+        registration.setOrder(1);
+        return registration;
+    }
+
+    @Bean
+    public FilterRegistrationBean registAuthFilter() {
+        log.info("注册登录验证过滤器");
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        AuthFilter authFilter = new AuthFilter();
+        authFilter.setStringRedisTemplate(stringRedisTemplate);
+        authFilter.setSkipUrls(skipUrls);
+        authFilter.setForceUrls(forceUrls);
+        registration.setFilter(authFilter);
+        registration.addUrlPatterns("/*");
+        registration.setName("authFilter");
+        registration.setOrder(2);
+        return registration;
+    }
+
+}
+

+ 14 - 0
src/main/java/com/gz/config/MapperScanConfig.java

@@ -0,0 +1,14 @@
+package com.gz.config;
+
+import org.springframework.context.annotation.Configuration;
+import tk.mybatis.spring.annotation.MapperScan;
+
+/**
+ * mapper扫描
+ * @author LiuchangLan
+ * @date 2020/7/12 19:42
+ */
+@Configuration
+@MapperScan("com.gz.mapper")
+public class MapperScanConfig {
+}

+ 88 - 0
src/main/java/com/gz/controller/system/AdminController.java

@@ -0,0 +1,88 @@
+package com.gz.controller.system;
+
+import com.github.pagehelper.PageInfo;
+import com.gz.core.annotation.TraceLog;
+import com.gz.dto.system.AdminDTO;
+import com.gz.service.system.AdminService;
+import com.gz.vo.system.AdminVO;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 14:41
+ */
+@RestController
+@RequestMapping("system/admin")
+public class AdminController {
+
+    @Resource
+    private AdminService adminService;
+
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("insert")
+    @TraceLog(module = "管理员管理",business = "新增管理员")
+    public Integer insert(@RequestBody AdminDTO adminDTO){
+        return adminService.insert(adminDTO);
+    }
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @DeleteMapping("delete")
+    @TraceLog(module = "管理员管理",business = "删除管理员")
+    public Integer delete( Integer id){
+        return adminService.delete(id);
+    }
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("update")
+    @TraceLog(module = "管理员管理",business = "修改管理员")
+    public Integer update(@RequestBody AdminDTO adminDTO){
+        return adminService.update(adminDTO);
+    }
+
+    /**
+     * @description 查(分页)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @GetMapping("select")
+    @TraceLog(module = "管理员管理",business = "查询管理员列表")
+    public PageInfo<AdminDTO> select(AdminVO adminVO){
+        return adminService.select(adminVO);
+    }
+
+    @GetMapping("selectByPrimaryKey")
+    @TraceLog(module = "管理员管理",business = "查询管理员详细信息")
+    public AdminDTO selectByPrimaryKey(Integer id){
+        return adminService.selectByPrimaryKey(id);
+    }
+
+    @PostMapping("updateStatus")
+    @TraceLog(module = "管理员管理",business = "修改管理员状态")
+    Integer updateStatus(@RequestBody Integer id){
+        return adminService.updateStatus(id);
+    }
+
+    @PostMapping("resetPassword")
+    @TraceLog(module = "管理员管理",business = "重置管理员密码")
+    Integer resetPassword(@RequestBody Integer id){
+        return adminService.resetPassword(id);
+    }
+
+
+
+}

+ 73 - 0
src/main/java/com/gz/controller/system/AuthController.java

@@ -0,0 +1,73 @@
+package com.gz.controller.system;
+
+import com.gz.core.annotation.TraceLog;
+import com.gz.core.exception.BusinessException;
+import com.gz.dto.system.MenuDTO;
+import com.gz.jwt.JwtPayload;
+import com.gz.rvo.system.InitialHomeRVO;
+import com.gz.rvo.system.LoginRVO;
+import com.gz.service.system.AuthService;
+import com.gz.utils.JwtUtils;
+import com.gz.vo.system.LoginVO;
+import com.gz.vo.system.UpdatePasswordVO;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 登录授权控制器
+ * @author LiuchangLan
+ * @date 2020/7/16 14:34
+ */
+@RestController
+@RequestMapping("system/auth")
+public class AuthController {
+
+    @Resource
+    private AuthService authService;
+
+    @PostMapping("login")
+    public LoginRVO login(@RequestBody LoginVO loginVO) throws BusinessException, NoSuchMethodException {
+        return authService.login(loginVO);
+    }
+
+    @PostMapping("refreshToken")
+    public LoginRVO refreshToken(String accessToken){
+        return authService.refreshToken(accessToken);
+    }
+
+    /**
+     * @description 获取登录的用户名
+     * @author LiuChangLan
+     * @since 2020/9/25 15:43
+     */
+    @GetMapping("getLoginUserName")
+    public JwtPayload getLoginUserName(){
+        return JwtUtils.getCurrentUserJwtPayload();
+    }
+
+    /**
+     * @description 获取有权限的菜单
+     * @author LiuChangLan
+     * @since 2020/9/25 15:43
+     */
+    @GetMapping("getLoginMenus")
+    public InitialHomeRVO getLoginMenus(){ return authService.getLoginMenus(); }
+
+    @PostMapping("updatePassword")
+    public Integer updatePassword(@RequestBody UpdatePasswordVO vo) throws BusinessException {
+        return authService.updatePassword(vo);
+    }
+
+    /**
+     * @description 获取有权限的按钮
+     * @author LiuChangLan
+     * @since 2020/9/25 15:43
+     */
+    @GetMapping("getLoginButtons")
+    public List<MenuDTO> getLoginButtons(Integer menuId){
+        return authService.getLoginButtons(menuId);
+    }
+
+}

+ 114 - 0
src/main/java/com/gz/controller/system/DictController.java

@@ -0,0 +1,114 @@
+package com.gz.controller.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.github.pagehelper.PageInfo;
+import com.gz.core.annotation.TraceLog;
+import com.gz.core.exception.BusinessException;
+import com.gz.dto.system.DictDTO;
+import com.gz.service.system.DictService;
+import com.gz.vo.system.DictVO;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 10:21
+ */
+@RestController
+@RequestMapping("system/dict")
+public class DictController {
+
+    @Resource
+    private DictService dictService;
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("insert")
+    @TraceLog(module = "字典管理",business = "新增字典")
+    public Integer insert(@RequestBody DictDTO dictDTO) throws BusinessException {
+        return dictService.insert(dictDTO);
+    }
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @DeleteMapping("delete")
+    @TraceLog(module = "字典管理",business = "删除字典")
+    public Integer delete(Integer id){
+        return dictService.delete(id);
+    }
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("update")
+    @TraceLog(module = "字典管理",business = "修改字典")
+    public Integer update(@RequestBody DictDTO dictDTO) throws BusinessException {
+        return dictService.update(dictDTO);
+    }
+
+    /**
+     * @description 查(给分页参数查分页 没给查全部)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @GetMapping("selectByPage")
+    @TraceLog(module = "字典管理",business = "查找字典列表")
+    public PageInfo<DictDTO> select(DictVO dictVO){
+        return dictService.selectByPage(dictVO);
+    }
+
+    /**
+     * @description 根据主键查询
+     * @author LiuChangLan
+     * @since 2020/9/4 16:36
+     */
+    @GetMapping("selectByPrimaryKey")
+    @TraceLog(module = "字典管理",business = "查询字典详细信息")
+    public DictDTO selectByPrimaryKey(Integer id){
+        return dictService.selectByPrimaryKey(id);
+    }
+
+    /**
+     * @description 查
+     * @author LiuChangLan
+     * @since 2020/9/7 10:28
+     */
+    @GetMapping("select")
+    @TraceLog(module = "字典管理",business = "查询素有字典")
+    public List<DictDTO> select(){
+        return dictService.select();
+    }
+
+    /**
+     * @description 获取字典树
+     * @author LiuChangLan
+     * @since 2020/9/7 14:36
+     */
+    @GetMapping("getDictTree")
+    @TraceLog(module = "字典管理",business = "查询字典树列表")
+    List<Tree<String>> getDictTree(){
+        return dictService.getDictTree();
+    }
+
+    /**
+     * @description 根据code查询所有选项
+     * @author LiuChangLan
+     * @since 2020/9/7 16:57
+     */
+    @GetMapping("selectDictByCode")
+    @TraceLog(module = "字典管理",business = "查询固定code的子字典")
+    List<DictDTO> selectDictByCode(String code){
+        return dictService.selectDictByCode(code);
+    }
+
+}

+ 39 - 0
src/main/java/com/gz/controller/system/FileController.java

@@ -0,0 +1,39 @@
+package com.gz.controller.system;
+
+import com.gz.core.exception.BusinessException;
+import com.gz.dto.system.FileDTO;
+import com.gz.rvo.system.FileUploadRVO;
+import com.gz.service.system.FileService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/9 11:23
+ */
+@RestController
+@RequestMapping("system/file")
+public class FileController {
+
+    @Resource
+    private FileService fileService;
+
+    @PostMapping("upload")
+    public FileUploadRVO upload(@RequestBody MultipartFile file, String fileId) throws IOException, BusinessException {
+        return fileService.upload(file, fileId);
+    }
+
+    @GetMapping("selectByFileId")
+    public List<FileDTO> selectByPrimaryKey(String fileId) {
+        return fileService.selectByFileId(fileId);
+    }
+
+    @DeleteMapping("delete")
+    Integer delete(Integer id){
+        return fileService.delete(id);
+    }
+}

+ 75 - 0
src/main/java/com/gz/controller/system/LogController.java

@@ -0,0 +1,75 @@
+package com.gz.controller.system;
+
+import com.github.pagehelper.PageInfo;
+import com.gz.rvo.system.LogRVO;
+import com.gz.service.system.LogService;
+import com.gz.vo.system.LogVO;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 20:15
+ */
+@RestController
+@RequestMapping("system/log")
+public class LogController {
+
+    @Resource
+    private LogService logService;
+
+    /**
+     * @description 查询日志
+     * @author LiuChangLan
+     * @since 2020/9/7 20:44
+     */
+    @GetMapping("selectByPage")
+    PageInfo<LogRVO> selectByPage(LogVO logVO){
+        return logService.selectByPage(logVO);
+    }
+
+    /**
+     * @description 查询日志模块
+     * @author LiuChangLan
+     * @since 2020/9/7 20:44
+     */
+    @GetMapping("selectLogModule")
+    List<String> selectLogModule(){
+        return logService.selectLogModule();
+    }
+
+    /**
+     * @description 查询日志具体操作
+     * @author LiuChangLan
+     * @since 2020/9/7 20:45
+     */
+    @GetMapping("selectLogBusiness")
+    List<String> selectLogBusiness(String module){
+        return logService.selectLogBusiness(module);
+    }
+
+
+    /**
+     * @description 查询日志具体操作
+     * @author LiuChangLan
+     * @since 2020/9/7 20:45
+     */
+    @GetMapping("clearAll")
+    public Integer clearAll() {
+        return logService.clearAll();
+    }
+
+    /**
+     * @description 查询日志具体操作
+     * @author LiuChangLan
+     * @since 2020/9/7 20:45
+     */
+    @GetMapping("clearThirtyOut")
+    public Integer clearThirtyOut() {
+        return logService.clearThirtyOut();
+    }
+}

+ 99 - 0
src/main/java/com/gz/controller/system/MenuController.java

@@ -0,0 +1,99 @@
+package com.gz.controller.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.gz.core.annotation.TraceLog;
+import com.gz.dto.system.MenuDTO;
+import com.gz.service.system.MenuService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 16:00
+ */
+@RestController
+@RequestMapping("system/menu")
+public class MenuController {
+
+    @Resource
+    private MenuService menuService;
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("insert")
+    @TraceLog(module = "菜单管理",business = "新增菜单")
+    public Integer insert(@RequestBody MenuDTO menuDTO){
+        return menuService.insert(menuDTO);
+    }
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @DeleteMapping("delete")
+    @TraceLog(module = "菜单管理",business = "删除菜单")
+    public Integer delete(Integer id){
+        return menuService.delete(id);
+    }
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("update")
+    @TraceLog(module = "菜单管理",business = "修改菜单")
+    public Integer update(@RequestBody MenuDTO menuDTO){
+        return menuService.update(menuDTO);
+    }
+
+    /**
+     * @description 查(给分页参数查分页 没给查全部)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @GetMapping("select")
+    @TraceLog(module = "菜单管理",business = "查询所有菜单")
+    public List<MenuDTO> select(){
+        return menuService.select();
+    }
+
+    /**
+     * @description 根据主键查询
+     * @author LiuChangLan
+     * @since 2020/9/4 16:36
+     */
+    @GetMapping("selectByPrimaryKey")
+    @TraceLog(module = "菜单管理",business = "查询菜单详细信息")
+    public MenuDTO selectByPrimaryKey(Integer id){
+        return menuService.selectByPrimaryKey(id);
+    }
+
+    /**
+     * @description 查询菜单按照排序
+     * @author LiuChangLan
+     * @since 2020/9/7 16:47
+     */
+    @GetMapping("selectByOrder")
+    @TraceLog(module = "菜单管理",business = "根据排序查询菜单")
+    public List<MenuDTO> selectByOrder(){
+        return menuService.selectByOrder();
+    }
+
+    /**
+     * @description 查询菜单树
+     * @author LiuChangLan
+     * @since 2020/9/7 16:49
+     */
+    @GetMapping("getMenuTree")
+    @TraceLog(module = "菜单管理",business = "查询菜单树")
+    List<Tree<String>> getMenuTree(){
+        return menuService.getMenuTree();
+    }
+}

+ 113 - 0
src/main/java/com/gz/controller/system/RoleController.java

@@ -0,0 +1,113 @@
+package com.gz.controller.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.github.pagehelper.PageInfo;
+import com.gz.core.annotation.TraceLog;
+import com.gz.dto.system.RoleDTO;
+import com.gz.service.system.RoleService;
+import com.gz.vo.system.RoleMenuVO;
+import com.gz.vo.system.RoleVO;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 20:44
+ */
+@RestController
+@RequestMapping("system/role")
+public class RoleController {
+    @Resource
+    private RoleService roleService;
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("insert")
+    @TraceLog(module = "权限管理",business = "新增权限")
+    public Integer insert(@RequestBody RoleDTO roleDTO){
+        return roleService.insert(roleDTO);
+    }
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @DeleteMapping("delete")
+    @TraceLog(module = "权限管理",business = "删除权限")
+    public Integer delete(Integer id){
+        return roleService.delete(id);
+    }
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @PostMapping("update")
+    @TraceLog(module = "权限管理",business = "修改权限")
+    public Integer update(@RequestBody RoleDTO roleDTO){
+        return roleService.update(roleDTO);
+    }
+
+    /**
+     * @description 查(分页)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    @GetMapping("select")
+    @TraceLog(module = "权限管理",business = "获取权限列表")
+    public PageInfo<RoleDTO> select(RoleVO roleVO){
+        return roleService.select(roleVO);
+    }
+
+    /**
+     * @description 根据主键查询
+     * @author LiuChangLan
+     * @since 2020/9/4 16:36
+     */
+    @GetMapping("selectByPrimaryKey")
+    @TraceLog(module = "权限管理",business = "查询权限详细信息")
+    public RoleDTO selectByPrimaryKey(Integer id){
+        return roleService.selectByPrimaryKey(id);
+    }
+
+    /**
+     * @description 设置权限菜单
+     * @author LiuChangLan
+     * @since 2020/9/22 11:52
+     */
+    @PostMapping("setRole")
+    @TraceLog(module = "权限管理",business = "修改权限可访问菜单")
+    public Integer setRole(@RequestBody RoleMenuVO vo) {
+        return roleService.setRole(vo);
+    }
+
+    /**
+     * @description 查询权限菜单列表
+     * @author LiuChangLan
+     * @since 2020/9/22 11:52
+     */
+    @GetMapping("selectRoleList")
+    @TraceLog(module = "权限管理",business = "查询权限可访问的菜单")
+    public List<Tree<String>> selectRoleList(Integer roleId) {
+        return roleService.selectRoleList(roleId);
+    }
+
+    /**
+     * @description 查询所有权限
+     * @author LiuChangLan
+     * @since 2020/9/22 11:54
+     */
+    @GetMapping("selectAllRole")
+    @TraceLog(module = "权限管理",business = "获取所有权限")
+    public List<RoleDTO> selectAllRole(){
+        return roleService.selectAllRole();
+    }
+
+}

+ 43 - 0
src/main/java/com/gz/core/BaseDTO.java

@@ -0,0 +1,43 @@
+package com.gz.core;
+
+import lombok.Data;
+import tk.mybatis.mapper.annotation.KeySql;
+
+import javax.persistence.Column;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * DTO公共部分抽取
+ * @author LiuchangLan
+ * @date 2021/1/26 22:41
+ */
+@Data
+public class BaseDTO {
+    /**
+     * 主键id
+     */
+    @Id
+    @GeneratedValue(generator = "JDBC")
+    private Integer id;
+    /**
+     * 创建时间
+     */
+    @Column(name = "create_time")
+    private String createTime;
+    /**
+     * 修改时间
+     */
+    @Column(name = "update_time")
+    private String updateTime;
+    /**
+     * 创建人
+     */
+    @Column(name = "created")
+    private Integer created;
+    /**
+     * 修改人
+     */
+    @Column(name = "updated")
+    private Integer updated;
+}

+ 21 - 0
src/main/java/com/gz/core/annotation/Controller.java

@@ -0,0 +1,21 @@
+package com.gz.core.annotation;
+
+
+import org.springframework.core.annotation.AliasFor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@org.springframework.stereotype.Controller
+@ResponseBody
+@Validated
+public @interface Controller{
+    @AliasFor(
+            annotation = org.springframework.stereotype.Controller.class
+    )
+    String value() default "";
+}

+ 32 - 0
src/main/java/com/gz/core/annotation/TraceLog.java

@@ -0,0 +1,32 @@
+package com.gz.core.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义日志注解
+ * @author LiuchangLan
+ * @date 2020/7/23 18:49
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+public @interface TraceLog {
+
+    /**
+     * @description 业务
+     * @author LiuChangLan
+     * @since 2020/7/23 18:49
+     */
+    public String business() default "";
+
+    /**
+     * @description 模块
+     * @author LiuChangLan
+     * @since 2020/7/23 18:49
+     */
+    public String module() default "";
+
+}

+ 39 - 0
src/main/java/com/gz/core/exception/BusinessException.java

@@ -0,0 +1,39 @@
+package com.gz.core.exception;
+
+import com.gz.core.response.CustomResponsInterface;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * 业务异常
+ * @author LiuchangLan
+ * @date 2020/6/27 22:23
+ */
+@RequiredArgsConstructor
+@Getter
+public class BusinessException extends RuntimeException{
+    private Integer errorCode;
+    private String errorMsg;
+
+    /**
+     * @description 枚举抛出异常
+     * @author LiuChangLan
+     * @since 2021/1/26 22:32
+     */
+    public BusinessException(CustomResponsInterface customResponseInterface){
+        super("业务异常 - " + customResponseInterface.getMsg());
+        this.errorCode = customResponseInterface.getCode();
+        this.errorMsg =customResponseInterface.getMsg();
+    }
+
+    /**
+     * @description 自定义抛出异常
+     * @author LiuChangLan
+     * @since 2021/1/26 22:32
+     */
+    public BusinessException(Integer errorCode, String errorMsg){
+        super("业务异常 - " + errorMsg);
+        this.errorCode = errorCode;
+        this.errorMsg = errorMsg;
+    }
+}

+ 27 - 0
src/main/java/com/gz/core/exception/CustomExceptionEnum.java

@@ -0,0 +1,27 @@
+package com.gz.core.exception;
+
+import com.gz.core.response.CustomResponsInterface;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @description 自定义异常枚举
+ * @author LiuChangLan
+ * @since 2021/1/26 22:23
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomExceptionEnum implements CustomResponsInterface {
+
+    ACCOUNT_OR_PASSWORD_INCORRECT(1000,"用户名不存在、或者密码不正确!"),
+    ACCOUNT_DISABLE(1001,"用户已禁用"),
+    LOGIN_TIMEOUT(1002,"登录已过期"),
+    DICT_CODE_EXISTS(1004,"字典编码已存在,请更换"),
+    File_NOT_EXISTS(1005,"请选择一个文件"),
+    PASSWORD_NO_INCORRECT(1006,"密码不正确");
+    ;
+
+
+    private Integer code;
+    private String msg;
+}

+ 62 - 0
src/main/java/com/gz/core/exception/CustomExceptionEnumHandler.java

@@ -0,0 +1,62 @@
+package com.gz.core.exception;
+
+import com.gz.core.response.ResponseEnum;
+import com.gz.core.response.ResponseResult;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.ValidationException;
+import java.util.stream.Collectors;
+
+/**
+ * 全局异常捕获
+ *
+ * @author LiuchangLan
+ * @date 2020/6/27 22:19
+ */
+@Slf4j
+@RestControllerAdvice
+public class CustomExceptionEnumHandler {
+    @ExceptionHandler(Exception.class)
+    public ResponseResult exceptionHandler(Exception e) {
+        // 控制台打印错误
+        log.error(e.getMessage(), e);
+        ResponseResult result = new ResponseResult();
+        if (e instanceof BusinessException) {
+            // 自定义错误处理
+            BusinessException businessException = (BusinessException) e;
+            result.setCode(businessException.getErrorCode());
+            result.setMsg(businessException.getErrorMsg());
+//        } else if (e instanceof NoHandlerFoundException) {
+//            // 404
+//            result.setCode(ResponseEnum.NOT_FOUND.getCode());
+//            result.setMsg(ResponseEnum.NOT_FOUND.getMsg());
+        } else if (e instanceof HttpRequestMethodNotSupportedException) {
+            // 请求方式不对
+            result.setCode(ResponseEnum.METHOD_ERROR.getCode());
+            result.setMsg(ResponseEnum.METHOD_ERROR.getMsg());
+        } else if (e instanceof ValidationException) {
+            // 请求入参错误拦截
+            result.setCode(400);
+            String message = ((ConstraintViolationException) e).getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
+            result.setMsg(message);
+        } else if (e instanceof MethodArgumentNotValidException) {
+            // 对象入参错误拦截
+            result.setCode(400);
+            String message = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
+            result.setMsg(message);
+        } else {
+            // 其他错误
+            result.setCode(500);
+            result.setMsg(e.getMessage());
+        }
+        return result;
+    }
+}

+ 16 - 0
src/main/java/com/gz/core/mybatis/UUIDGenId.java

@@ -0,0 +1,16 @@
+package com.gz.core.mybatis;
+
+import cn.hutool.core.util.IdUtil;
+import tk.mybatis.mapper.genid.GenId;
+
+/**
+ * Mybatis 自定义UUID主键生成规则
+ * @author LiuchangLan
+ * @date 2021/1/12 15:25
+ */
+public class UUIDGenId implements GenId<String> {
+    @Override
+    public String genId(String s, String s1) {
+        return IdUtil.simpleUUID();
+    }
+}

+ 11 - 0
src/main/java/com/gz/core/response/CustomResponsInterface.java

@@ -0,0 +1,11 @@
+package com.gz.core.response;
+
+/**
+ * @description 自定义响应接口
+ * @author LiuChangLan
+ * @since 2021/1/26 22:20
+ */
+public interface CustomResponsInterface {
+    Integer getCode();
+    String getMsg();
+}

+ 48 - 0
src/main/java/com/gz/core/response/GlobalResponseHandler.java

@@ -0,0 +1,48 @@
+package com.gz.core.response;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+/**
+ * 处理返回结果
+ * @author LiuchangLan
+ * @date 2020/6/27 22:05
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalResponseHandler implements ResponseBodyAdvice<Object> {
+
+    @Override
+    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
+        //判断支持的类型,因为data可能是任何类型,这里就不判断统一放过
+        //如果你想对执行的返回体进行操作,可将上方的Object换成你自己的类型
+        return true;
+    }
+
+    @Override
+    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
+        ResponseResult result = null;
+        // 已经是该响应类型
+        if (body instanceof ResponseResult){
+            result = (ResponseResult) body;
+        }else {
+            // 非默认转换类型 进行转换
+            result = new ResponseResult();
+            result.setCode(ResponseEnum.SUCCESS.getCode());
+            result.setMsg(ResponseEnum.SUCCESS.getMsg());
+            result.setData(body == null ? "" : body);
+        }
+        //处理返回值是String的情况
+        if (body instanceof String) {
+            return JSON.toJSONString(result);
+        }
+        return result;
+    }
+}

+ 24 - 0
src/main/java/com/gz/core/response/ResponseEnum.java

@@ -0,0 +1,24 @@
+package com.gz.core.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @description 响应结果枚举
+ * @author LiuChangLan
+ * @since 2021/1/26 22:23
+ */
+@Getter
+@AllArgsConstructor
+public enum ResponseEnum implements CustomResponsInterface{
+    SUCCESS(200,"请求成功"),
+    ILLEGAL_TOKEN(302,"非法Token"),
+    TOKEN_EXPIRED(303,"Token过期"),
+    OTHER_CLIENTS_LOGGED_IN(304,"在其他地方登录"),
+    METHOD_ERROR(405,"请求方式错误"),
+    NOT_FOUND(404,"请求地址不存在"),
+    ;
+
+    private Integer code;
+    private String msg;
+}

+ 31 - 0
src/main/java/com/gz/core/response/ResponseResult.java

@@ -0,0 +1,31 @@
+package com.gz.core.response;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 返回结果DTO
+ * @author LiuchangLan
+ * @date 2020/6/27 22:00
+ */
+@Data
+@NoArgsConstructor
+public class ResponseResult {
+    /**
+     * 返回的代码,200表示成功,其他表示失败
+     */
+    private Integer code;
+    /**
+     * 成功或失败时返回的错误信息
+     */
+    private String msg;
+    /**
+     * 成功时返回的数据信息
+     */
+    private Object data;
+
+    public ResponseResult(CustomResponsInterface customResponsInterface){
+        this.code = customResponsInterface.getCode();
+        this.msg = customResponsInterface.getMsg();
+    }
+}

+ 38 - 0
src/main/java/com/gz/dto/system/AdminDTO.java

@@ -0,0 +1,38 @@
+package com.gz.dto.system;
+
+import com.gz.core.BaseDTO;
+import lombok.Data;
+
+import javax.persistence.Table;
+
+/**
+ * 系统管理员dto
+ * @author LiuchangLan
+ * @date 2020/9/4 11:25
+ */
+@Data
+@Table(name = "tab_admin")
+public class AdminDTO extends BaseDTO {
+    // 管理员姓名
+    private String adminName;
+
+    // 登录名
+    private String account;
+
+    // 密码
+    private String password;
+
+    // 加密盐
+    private String salt;
+
+    // 手机
+    private String phone;
+
+    // 邮箱
+    private String email;
+
+    // 状态(0正常 1禁用)
+    private Integer status;
+
+    private Integer roleId;
+}

+ 27 - 0
src/main/java/com/gz/dto/system/DictDTO.java

@@ -0,0 +1,27 @@
+package com.gz.dto.system;
+
+import com.gz.core.BaseDTO;
+import lombok.Data;
+
+import javax.persistence.Table;
+
+/**
+ * 字典dto
+ * @author LiuchangLan
+ * @date 2020/9/4 11:34
+ */
+@Data
+@Table(name = "tab_dict")
+public class DictDTO extends BaseDTO {
+    // 字典名称
+    private String dictName;
+
+    // 字典标识(唯一,一般为字典拼音)
+    private String dictCode;
+
+    // 父级字典
+    private Integer parentId;
+
+    // 备注
+    private String remarks;
+}

+ 20 - 0
src/main/java/com/gz/dto/system/FileDTO.java

@@ -0,0 +1,20 @@
+package com.gz.dto.system;
+
+import com.gz.core.BaseDTO;
+import lombok.Data;
+
+import javax.persistence.Table;
+
+@Data
+@Table(name = "tab_file")
+public class FileDTO extends BaseDTO {
+    // 文件id
+    private String fileId;
+
+    // 源文件名
+    private String originalFileName;
+
+    // 下载路径
+    private String downloadPath;
+
+}

+ 40 - 0
src/main/java/com/gz/dto/system/LogDTO.java

@@ -0,0 +1,40 @@
+package com.gz.dto.system;
+
+import lombok.Data;
+
+import javax.persistence.Table;
+
+/**
+ * 系统日志dto
+ * @author LiuchangLan
+ * @date 2020/9/4 11:53
+ */
+@Data
+@Table(name = "tab_log")
+public class LogDTO {
+    // 日志类型(字典表关联)
+    private String logType;
+
+    // 操作模块
+    private String module;
+
+    // 操作业务
+    private String business;
+
+    // 操作方法
+    private String execMethod;
+
+    // 操作传参Json
+    private String paramsJson;
+
+    // 错误信息
+    private String errorMsg;
+
+    // 操作ip
+    private String execIp;
+
+    // 操作人
+    private Integer execBy;
+
+    private String execTime;
+}

+ 33 - 0
src/main/java/com/gz/dto/system/MenuDTO.java

@@ -0,0 +1,33 @@
+package com.gz.dto.system;
+
+import com.gz.core.BaseDTO;
+import lombok.Data;
+
+import javax.persistence.Table;
+
+/**
+ * 后台菜单dto
+ * @author LiuchangLan
+ * @date 2020/9/4 11:55
+ */
+@Data
+@Table(name = "tab_menu")
+public class MenuDTO extends BaseDTO {
+    // 菜单名称
+    private String title;
+
+    // 父级菜单(顶级为-1)
+    private Integer parentId;
+
+    // 菜单排序
+    private Integer sort;
+
+    // 菜单类型(0菜单 1 按钮)
+    private Integer type;
+
+    // 菜单地址(菜单时 页面地址)
+    private String href;
+
+    // 图标
+    private String icon;
+}

+ 25 - 0
src/main/java/com/gz/dto/system/MenuRoleDTO.java

@@ -0,0 +1,25 @@
+package com.gz.dto.system;
+
+import lombok.Data;
+
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * 用户权限关联dto
+ * @author LiuchangLan
+ * @date 2020/9/4 11:57
+ */
+@Data
+@Table(name = "tab_menu_role")
+public class MenuRoleDTO {
+
+    @Id
+    @GeneratedValue(generator = "JDBC")
+    private Integer id;
+    // 权限表id
+    private Integer roleId;
+    // 菜单表id
+    private Integer menuId;
+}

+ 21 - 0
src/main/java/com/gz/dto/system/RoleDTO.java

@@ -0,0 +1,21 @@
+package com.gz.dto.system;
+
+import com.gz.core.BaseDTO;
+import lombok.Data;
+
+import javax.persistence.Table;
+
+/**
+ * 权限dto
+ * @author LiuchangLan
+ * @date 2020/9/4 12:02
+ */
+@Data
+@Table(name = "tab_role")
+public class RoleDTO extends BaseDTO {
+    // 权限名称
+    private String roleName;
+
+    // 备注
+    private String remark;
+}

+ 111 - 0
src/main/java/com/gz/filter/AuthFilter.java

@@ -0,0 +1,111 @@
+package com.gz.filter;
+
+import com.alibaba.fastjson.JSON;
+import com.auth0.jwt.exceptions.JWTDecodeException;
+import com.auth0.jwt.exceptions.TokenExpiredException;
+import com.gz.core.response.ResponseEnum;
+import com.gz.core.response.ResponseResult;
+import com.gz.jwt.JwtConfig;
+import com.gz.jwt.JwtPayload;
+import com.gz.utils.JwtUtils;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2021/1/28 22:06
+ */
+@Slf4j
+@Setter
+public class AuthFilter implements Filter {
+
+    private StringRedisTemplate stringRedisTemplate;
+
+    private String skipUrls;
+
+    private String forceUrls;
+
+    private AntPathMatcher matcher = new AntPathMatcher();
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+
+        HttpServletRequest req = (HttpServletRequest) servletRequest;
+        HttpServletResponse resp = (HttpServletResponse) servletResponse;
+
+        // 设置请求字符集
+        servletRequest.setCharacterEncoding("UTF-8");
+        // 设置返回格式
+        servletResponse.setContentType("application/json;charset=UTF-8");
+        String uri = req.getRequestURI();
+        String url = uri.replace(req.getContextPath(), "");
+
+        boolean force = Arrays.stream(forceUrls.split(",")).anyMatch(e -> matcher.match(e, url));
+        // 验证路径是否跳过
+        boolean skip = Arrays.stream(skipUrls.split(",")).anyMatch(e -> matcher.match(e, url));
+
+        if (!force || skip) {
+            // 不进行token验证
+            filterChain.doFilter(servletRequest, servletResponse);
+        } else {
+            // token验证
+            String token = req.getHeader(JwtConfig.HEADER_ACCCESS_TOKEN);
+            // token黑名单
+            String BlackListKey = String.format(JwtConfig.BLACKLIST_KEY_FORMAT, token);
+            // token为空
+            if (StringUtils.isEmpty(token) || "undefined".equals(token)) {
+                // 返回
+                PrintWriter writer = servletResponse.getWriter();
+                log.warn("token为空,禁止访问");
+                ResponseResult result = new ResponseResult(ResponseEnum.ILLEGAL_TOKEN);
+                writer.println(JSON.toJSONString(result));
+            } else {
+                // 在黑名单中
+                if (stringRedisTemplate.opsForValue().get(BlackListKey) != null) {
+                    // 返回
+                    PrintWriter writer = servletResponse.getWriter();
+                    log.warn("该token在黑名单中");
+                    ResponseResult result = new ResponseResult(ResponseEnum.ILLEGAL_TOKEN);
+                    writer.println(JSON.toJSONString(result));
+                    return;
+                }
+                // 验证token
+                boolean verifier = false;
+                try {
+                    verifier = JwtUtils.verifier(token);
+                } catch (TokenExpiredException e) {
+                    PrintWriter writer = servletResponse.getWriter();
+                    log.warn("token验证失败,禁止访问");
+                    ResponseResult result = new ResponseResult(ResponseEnum.TOKEN_EXPIRED);
+                    writer.println(JSON.toJSONString(result));
+                } catch (JWTDecodeException e){
+                    PrintWriter writer = servletResponse.getWriter();
+                    log.warn("token验证失败,禁止访问");
+                    ResponseResult result = new ResponseResult(ResponseEnum.ILLEGAL_TOKEN);
+                    writer.println(JSON.toJSONString(result));
+                }
+                // 验证成功
+                if (verifier){
+                    // 根据token获取载体
+                    JwtPayload jwtPayload = JwtUtils.decrypt(token);
+                    // 放到请求中
+                    req.setAttribute(JwtConfig.HEADER_AUTHORIZATION_USER, jwtPayload);
+                    log.info("token验证成功");
+                    filterChain.doFilter(servletRequest, servletResponse);
+                }
+            }
+            log.info("请求的url:{},请求的Token{}", url, token);
+        }
+    }
+}

+ 27 - 0
src/main/java/com/gz/filter/CorsFilter.java

@@ -0,0 +1,27 @@
+package com.gz.filter;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * @author LiuchangLan
+ * @date 2021/1/29 9:49
+ */
+public class CorsFilter implements Filter {
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
+        // 允许跨域的地址为所有
+        httpResponse.setHeader("Access-Control-Allow-Origin", "*");
+        // 允许的请求头
+        httpResponse.setHeader("Access-Control-Allow-Headers", "*");
+        // 允许请求的方法
+        httpResponse.setHeader("Access-Control-Allow-Methods", "*");
+        // 非简单请求,只要第一次通过OPTIONS检查 在1小时之内不会在调用OPTIONS进行检测
+        httpResponse.addHeader("Access-Control-Max-Age", "3600");
+        // 带有Cookie的跨域请求,此值必须设置为true。
+        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
+        filterChain.doFilter(servletRequest, httpResponse);
+    }
+}

+ 39 - 0
src/main/java/com/gz/jwt/JwtConfig.java

@@ -0,0 +1,39 @@
+package com.gz.jwt;
+
+/**
+ * @author LiuchangLan
+ * @date 2021/1/27 10:38
+ */
+public class JwtConfig {
+    /** 用户禁用状态码*/
+    public static final Integer USER_STATUS_DISABLE = 1;
+
+    /** redis 中 JWT 刷新 token 使用的key */
+    public static final String REFRESH_TOKEN_KEY_FORMAT = "JWT_REFRESH_TOKEN:%s";
+
+    /** redis 中 JWT 黑名单 token 使用的key */
+    public static final String BLACKLIST_KEY_FORMAT = "JWT_BLACKLIST:%s";
+
+    /** redis 中 JWT token 使用的key */
+    public static final String REDIS_JWT_TOKEN_KEY = "ACCESS_TOKEN";
+
+    /** redis 中 JWT 生成 token 载体使用的key */
+    public static final String REDIS_JWT_PAYLOAD_KEY = "payload";
+
+    /**
+     * 载体在服务间传递时,header 中使用的名称
+     */
+    public static final String HEADER_AUTHORIZATION_USER = "AUTHORIZATION_USER";
+
+    /** 载体在服务间传递时,header 中使用的名称*/
+    public static final String HEADER_ACCCESS_TOKEN = "accessToken";
+
+    /** JWT加密密钥*/
+    public static final String TOKEN_SECRET = "A5D833ABE7685BA6AB2E30BD8156E6E";
+
+    /** refresh token 过期时间-单位秒 7天 */
+    public static Long REFRESH_TOKEN_EXPIRE_TIME = 7 * 24 * 60 * 60L;
+
+    /** accessToken有效期 单位秒*/
+    public static final long ACCESS_TOKEN_EFFECTIVE = 30 * 60L;
+}

+ 26 - 0
src/main/java/com/gz/jwt/JwtPayload.java

@@ -0,0 +1,26 @@
+package com.gz.jwt;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/7/16 15:05
+ */
+@Data
+@AllArgsConstructor
+public class JwtPayload {
+
+    /** 用户 Id */
+    private Integer id;
+
+    /** 用户名 */
+    private String account;
+
+    /** 昵称 */
+    private String adminName;
+
+    /** 权限id*/
+    private Integer roleId;
+
+}

+ 13 - 0
src/main/java/com/gz/mapper/system/AdminMapper.java

@@ -0,0 +1,13 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.AdminDTO;
+import tk.mybatis.mapper.common.Mapper;
+
+/**
+ * 系统管理员Mapper
+ * @author LiuchangLan
+ * @date 2020/9/4 11:25
+ */
+public interface AdminMapper extends Mapper<AdminDTO> {
+
+}

+ 20 - 0
src/main/java/com/gz/mapper/system/DictMapper.java

@@ -0,0 +1,20 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.DictDTO;
+import tk.mybatis.mapper.common.Mapper;
+
+import java.util.List;
+
+/**
+ * 字典Mapper
+ * @author LiuchangLan
+ * @date 2020/9/4 11:34
+ */
+public interface DictMapper extends Mapper<DictDTO> {
+    /**
+     * @description 根据code查询子项
+     * @author LiuChangLan
+     * @since 2020/9/27 14:28
+     */
+    List<DictDTO> selectDictByCode(String code);
+}

+ 7 - 0
src/main/java/com/gz/mapper/system/FileMapper.java

@@ -0,0 +1,7 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.FileDTO;
+import tk.mybatis.mapper.common.Mapper;
+
+public interface FileMapper extends Mapper<FileDTO> {
+}

+ 28 - 0
src/main/java/com/gz/mapper/system/LogMapper.java

@@ -0,0 +1,28 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.LogDTO;
+import com.gz.rvo.system.LogRVO;
+import com.gz.vo.system.LogVO;
+import tk.mybatis.mapper.common.Mapper;
+
+import java.util.List;
+
+/**
+ * 系统日志Mapper
+ * @author LiuchangLan
+ * @date 2020/9/4 11:53
+ */
+public interface LogMapper extends Mapper<LogDTO> {
+
+    List<LogRVO> selectByTime(LogVO logVO);
+
+    List<String> selectLogModule();
+
+    List<String> selectLogBusiness(String module);
+
+    Integer clearAll();
+
+    Integer clearThirtyOut();
+
+    Integer selectCountByTime(LogVO logVO);
+}

+ 25 - 0
src/main/java/com/gz/mapper/system/MenuMapper.java

@@ -0,0 +1,25 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.MenuDTO;
+import tk.mybatis.mapper.common.Mapper;
+
+import java.util.List;
+
+
+/**
+ * 后台菜单Mapper
+ * @author LiuchangLan
+ * @date 2020/9/4 11:55
+ */
+public interface MenuMapper extends Mapper<MenuDTO> {
+    /**
+     * @description 查询列表(按照排序)
+     * @author LiuChangLan
+     * @since 2020/8/19 16:43
+     */
+    List<MenuDTO> getMenusOrder();
+
+    List<MenuDTO> getRoleMenu(Integer roleId);
+
+    List<MenuDTO> getRoleButtle(Integer roleId,Integer menuId);
+}

+ 13 - 0
src/main/java/com/gz/mapper/system/MenuRoleMapper.java

@@ -0,0 +1,13 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.MenuRoleDTO;
+import tk.mybatis.mapper.common.Mapper;
+
+/**
+ * 用户权限关联Mapper
+ * @author LiuchangLan
+ * @date 2020/9/4 11:57
+ */
+public interface MenuRoleMapper extends Mapper<MenuRoleDTO> {
+
+}

+ 13 - 0
src/main/java/com/gz/mapper/system/RoleMapper.java

@@ -0,0 +1,13 @@
+package com.gz.mapper.system;
+
+import com.gz.dto.system.RoleDTO;
+import tk.mybatis.mapper.common.Mapper;
+
+/**
+ * 权限Mapper
+ * @author LiuchangLan
+ * @date 2020/9/4 12:02
+ */
+public interface RoleMapper extends Mapper<RoleDTO> {
+
+}

+ 23 - 0
src/main/java/com/gz/rvo/system/FileUploadRVO.java

@@ -0,0 +1,23 @@
+package com.gz.rvo.system;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/9 14:20
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class FileUploadRVO {
+    // 关联id
+    private String fileId;
+    // 原文件名
+    private String originalFileName;
+    // 现文件名
+    private String fileName;
+    // 文件位置
+    private String path;
+}

+ 22 - 0
src/main/java/com/gz/rvo/system/InitialHomeRVO.java

@@ -0,0 +1,22 @@
+package com.gz.rvo.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.Data;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/8/25 9:52
+ */
+@Data
+public class InitialHomeRVO {
+
+    private HashMap<String,Object> homeInfo = new HashMap<>();
+
+    private HashMap<String,Object> logoInfo = new HashMap<>();
+
+    private List<Tree<String>> menuInfo;
+
+}

+ 43 - 0
src/main/java/com/gz/rvo/system/LogRVO.java

@@ -0,0 +1,43 @@
+package com.gz.rvo.system;
+
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 20:57
+ */
+@Data
+public class LogRVO {
+    // 日志类型(字典表关联)
+    private String logType;
+
+    // 操作模块
+    private String module;
+
+    // 操作业务
+    private String business;
+
+    // 操作方法
+    private String execMethod;
+
+    // 操作传参Json
+    private String paramsJson;
+
+    // 错误信息
+    private String errorMsg;
+
+    // 操作ip
+    private String execIp;
+
+    // 操作人
+    private Integer execBy;
+
+    // 操作时间
+    private String execTime;
+
+    // 操作人
+    private String adminName;
+
+    // 日志类型
+    private String dictName;
+}

+ 16 - 0
src/main/java/com/gz/rvo/system/LoginRVO.java

@@ -0,0 +1,16 @@
+package com.gz.rvo.system;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/7/16 14:36
+ */
+@Data
+@AllArgsConstructor
+public class LoginRVO {
+    private String accessToken;    // jwt token
+    private String refreshToken;   // 用户刷新 jwt 的 token
+    private Long createTime;       // 创建时间
+}

+ 35 - 0
src/main/java/com/gz/rvo/system/RoleMenuRVO.java

@@ -0,0 +1,35 @@
+package com.gz.rvo.system;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 20:05
+ */
+@Data
+public class RoleMenuRVO {
+    // 主键
+    private Integer id;
+
+    // 菜单标题
+    private String title;
+
+    // 菜单图标
+    private String icon;
+
+    // 菜单地址
+    private String href;
+
+    // 子菜单
+    private List<RoleMenuRVO> children;
+
+    private List<RoleMenuRVO> child;
+
+    // 是否默认选中
+    private boolean checked;
+
+    // 父菜单id
+    private Integer parentId;
+}

+ 19 - 0
src/main/java/com/gz/rvo/system/TreeRVO.java

@@ -0,0 +1,19 @@
+package com.gz.rvo.system;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 13:16
+ */
+@Data
+public class TreeRVO {
+
+    private Integer id;
+    private String name;
+    private boolean open;
+    private List<TreeRVO> children;
+
+}

+ 57 - 0
src/main/java/com/gz/service/system/AdminService.java

@@ -0,0 +1,57 @@
+package com.gz.service.system;
+
+import com.github.pagehelper.PageInfo;
+import com.gz.dto.system.AdminDTO;
+import com.gz.vo.system.AdminVO;
+
+public interface AdminService {
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public Integer insert(AdminDTO adminDTO);
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public Integer delete(Integer id);
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public Integer update(AdminDTO adminDTO);
+
+    /**
+     * @description 查(给分页参数查分页 没给查全部)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public PageInfo<AdminDTO> select(AdminVO adminVO);
+
+    /**
+     * @description
+     * @author LiuChangLan
+     * @since 2020/9/4 15:05
+     */
+    public AdminDTO selectByPrimaryKey(Integer id);
+
+    /**
+     * @description 修改状态
+     * @author LiuChangLan
+     * @since 2020/9/22 11:38
+     */
+    Integer updateStatus(Integer id);
+
+    /**
+     * @description 重置密码
+     * @author LiuChangLan
+     * @since 2021/2/19 17:13
+     */
+    Integer resetPassword(Integer id);
+}

+ 52 - 0
src/main/java/com/gz/service/system/AuthService.java

@@ -0,0 +1,52 @@
+package com.gz.service.system;
+
+
+import com.gz.core.exception.BusinessException;
+import com.gz.dto.system.AdminDTO;
+import com.gz.dto.system.MenuDTO;
+import com.gz.rvo.system.InitialHomeRVO;
+import com.gz.rvo.system.LoginRVO;
+import com.gz.vo.system.LoginVO;
+import com.gz.vo.system.UpdatePasswordVO;
+
+import java.util.List;
+
+public interface AuthService {
+
+    /**
+     * @description 登录
+     * @author LiuChangLan
+     * @since 2021/1/23 0:26
+     */
+    LoginRVO login(LoginVO param);
+
+    /**
+     * @description 刷新Token
+     * @author LiuChangLan
+     * @since 2021/1/23 1:41
+     */
+    LoginRVO refreshToken(String refreshToken);
+
+    /**
+     * @description 获取登录的信息
+     * @author LiuChangLan
+     * @since 2021/1/28 22:04
+     */
+    AdminDTO getLoginInfo();
+
+    /**
+     * @description 退出登录
+     * @author LiuChangLan
+     * @since 2021/1/30 14:27
+     */
+    void logout(String refreshToken);
+
+
+    Integer updatePassword(UpdatePasswordVO vo) throws BusinessException;
+
+
+    InitialHomeRVO getLoginMenus();
+
+    List<MenuDTO> getLoginButtons(Integer menuId);
+
+}

+ 83 - 0
src/main/java/com/gz/service/system/DictService.java

@@ -0,0 +1,83 @@
+package com.gz.service.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.github.pagehelper.PageInfo;
+import com.gz.core.exception.BusinessException;
+import com.gz.dto.system.DictDTO;
+import com.gz.vo.system.DictVO;
+
+import java.util.List;
+
+public interface DictService {
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    Integer insert(DictDTO dictDTO) throws BusinessException;
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    Integer delete(Integer id);
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    Integer update(DictDTO dictDTO) throws BusinessException;
+
+    /**
+     * @description 查(分页)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    PageInfo<DictDTO> selectByPage(DictVO dictVO);
+
+    /**
+     * @description 根据主键查询
+     * @author LiuChangLan
+     * @since 2020/9/4 16:35
+     */
+    DictDTO selectByPrimaryKey(Integer id);
+
+    /**
+     * @description 查
+     * @author LiuChangLan
+     * @since 2020/9/7 10:25
+     */
+    List<DictDTO> select();
+
+    /**
+     * @description 获取字典树
+     * @author LiuChangLan
+     * @since 2020/9/7 14:46
+     */
+    List<Tree<String>> getDictTree();
+
+    /**
+     * @description 根据code查询所有选项
+     * @author LiuChangLan
+     * @since 2020/9/7 16:57
+     */
+    List<DictDTO> selectDictByCode(String code);
+
+
+    /**
+     * 获取字典Code
+     * @param chineseName 中文
+     * @return 字典Code
+     */
+    String getDictCode(String chineseName);
+
+    /**
+     * @description 根据code获取名称
+     * @author LiuChangLan
+     * @since 2020/10/28 14:16
+     */
+    String getDictName(String code);
+}

+ 24 - 0
src/main/java/com/gz/service/system/FileService.java

@@ -0,0 +1,24 @@
+package com.gz.service.system;
+
+import com.gz.core.exception.BusinessException;
+import com.gz.dto.system.FileDTO;
+import com.gz.rvo.system.FileUploadRVO;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+public interface FileService {
+
+    /**
+     * @description 上传文件
+     * @author LiuChangLan
+     * @since 2020/9/9 11:25
+     * @return
+     */
+    FileUploadRVO upload(MultipartFile files, String fileId) throws BusinessException, IOException;
+
+    List<FileDTO> selectByFileId(String fileId);
+
+    Integer delete(Integer id);
+}

+ 50 - 0
src/main/java/com/gz/service/system/LogService.java

@@ -0,0 +1,50 @@
+package com.gz.service.system;
+
+import com.github.pagehelper.PageInfo;
+import com.gz.rvo.system.LogRVO;
+import com.gz.vo.system.LogVO;
+
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 20:16
+ */
+public interface LogService {
+
+    /**
+     * @description 查询日志
+     * @author LiuChangLan
+     * @since 2020/9/7 20:44
+     */
+    PageInfo<LogRVO> selectByPage(LogVO logVO);
+
+    /**
+     * @description 查询日志模块
+     * @author LiuChangLan
+     * @since 2020/9/7 20:44
+     */
+    List<String> selectLogModule();
+
+    /**
+     * @description 查询日志具体操作
+     * @author LiuChangLan
+     * @since 2020/9/7 20:45
+     */
+    List<String> selectLogBusiness(String module);
+
+    /**
+     * @description 清除所有日志
+     * @author LiuChangLan
+     * @since 2020/9/7 21:07
+     */
+    Integer clearAll();
+
+    /**
+     * @description 清除三十天之外的日志
+     * @author LiuChangLan
+     * @since 2020/9/7 21:07
+     */
+    Integer clearThirtyOut();
+
+}

+ 58 - 0
src/main/java/com/gz/service/system/MenuService.java

@@ -0,0 +1,58 @@
+package com.gz.service.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.gz.dto.system.MenuDTO;
+
+import java.util.List;
+
+public interface MenuService {
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    Integer insert(MenuDTO menuDTO);
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    Integer delete(Integer id);
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    Integer update(MenuDTO menuDTO);
+
+    /**
+     * @description 查(给分页参数查分页 没给查全部)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    List<MenuDTO> select();
+
+    /**
+     * @description 根据主键查询
+     * @author LiuChangLan
+     * @since 2020/9/4 16:36
+     */
+    MenuDTO selectByPrimaryKey(Integer id);
+
+    /**
+     * @description 查询菜单按照排序
+     * @author LiuChangLan
+     * @since 2020/9/7 16:46
+     */
+    List<MenuDTO> selectByOrder();
+
+    /**
+     * @description 获取菜单(树结构)
+     * @author LiuChangLan
+     * @since 2020/9/7 16:51
+     */
+    List<Tree<String>> getMenuTree();
+}

+ 60 - 0
src/main/java/com/gz/service/system/RoleService.java

@@ -0,0 +1,60 @@
+package com.gz.service.system;
+
+import cn.hutool.core.lang.tree.Tree;
+import com.github.pagehelper.PageInfo;
+import com.gz.dto.system.RoleDTO;
+import com.gz.vo.system.RoleMenuVO;
+import com.gz.vo.system.RoleVO;
+
+import java.util.List;
+
+public interface RoleService {
+
+    /**
+     * @description 增
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public Integer insert(RoleDTO roleDTO);
+
+    /**
+     * @description 删
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public Integer delete(Integer id);
+
+    /**
+     * @description 改
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public Integer update(RoleDTO roleDTO);
+
+    /**
+     * @description 查(给分页参数查分页 没给查全部)
+     * @author LiuChangLan
+     * @since 2020/9/4 14:46
+     */
+    public PageInfo<RoleDTO> select(RoleVO roleVO);
+
+    /**
+     * @description 根据主键查询
+     * @author LiuChangLan
+     * @since 2020/9/4 16:35
+     */
+    public RoleDTO selectByPrimaryKey(Integer id);
+
+    /**
+     * @description 设置权限
+     * @author LiuChangLan
+     * @since 2020/9/22 9:51
+     */
+    public Integer setRole(RoleMenuVO vo);
+
+
+    public List<Tree<String>> selectRoleList(Integer roleId);
+
+    List<RoleDTO> selectAllRole();
+
+}

+ 98 - 0
src/main/java/com/gz/service/system/impl/AdminServiceImpl.java

@@ -0,0 +1,98 @@
+package com.gz.service.system.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.IdUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.gz.common.DataGlobalVariable;
+import com.gz.dto.system.AdminDTO;
+import com.gz.mapper.system.AdminMapper;
+import com.gz.service.system.AdminService;
+import com.gz.utils.JwtUtils;
+import com.gz.utils.PasswordUtils;
+import com.gz.vo.system.AdminVO;
+import org.springframework.stereotype.Service;
+import sun.net.util.IPAddressUtil;
+
+import javax.annotation.Resource;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 14:42
+ */
+@Service
+public class AdminServiceImpl implements AdminService {
+
+    @Resource
+    private AdminMapper adminMapper;
+
+    @Override
+    public Integer insert(AdminDTO adminDTO) {
+        // 盐
+        adminDTO.setSalt(IdUtil.simpleUUID());
+        // 加密后密码
+        adminDTO.setPassword(PasswordUtils.encryption(adminDTO.getPassword(), adminDTO.getSalt()));
+        // 创建人
+        adminDTO.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 执行入库
+        return adminMapper.insertSelective(adminDTO);
+    }
+
+    @Override
+    public Integer delete(Integer id) {
+        return adminMapper.deleteByPrimaryKey(id);
+    }
+
+    @Override
+    public Integer update(AdminDTO adminDTO) {
+        // 修改人
+        adminDTO.setUpdated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 修改时间
+        adminDTO.setUpdateTime(DateUtil.now());
+        // 执行入库
+        return adminMapper.updateByPrimaryKeySelective(adminDTO);
+    }
+
+    @Override
+    public PageInfo<AdminDTO> select(AdminVO adminVO) {
+        // 包含分页参数执行分页
+        if (adminVO.getPageNum() != null && adminVO.getPageSize() != null){
+            PageHelper.startPage(adminVO.getPageNum(),adminVO.getPageSize());
+        }
+        // 查询条件转换
+        AdminDTO adminDTO = BeanUtil.copyProperties(adminVO, AdminDTO.class);
+        // 查询未删除的数据
+        return new PageInfo<>(adminMapper.select(adminDTO));
+    }
+
+    @Override
+    public AdminDTO selectByPrimaryKey(Integer id) {
+        AdminDTO adminDTO = new AdminDTO();
+        adminDTO.setId(id);
+        return adminMapper.selectOne(adminDTO);
+    }
+
+    @Override
+    public Integer updateStatus(Integer id) {
+        AdminDTO adminDTOd = new AdminDTO();
+        adminDTOd.setId(id);
+        AdminDTO adminDTO = adminMapper.selectOne(adminDTOd);
+        if (adminDTO.getStatus().equals(0)){
+            adminDTO.setStatus(1);
+        }else {
+            adminDTO.setStatus(0);
+        }
+        return adminMapper.updateByPrimaryKeySelective(adminDTO);
+    }
+
+    @Override
+    public Integer resetPassword(Integer id) {
+        AdminDTO adminDTO = selectByPrimaryKey(id);
+        // 盐
+        adminDTO.setSalt(IdUtil.simpleUUID());
+        // 加密后密码
+        adminDTO.setPassword(PasswordUtils.encryption("123456", adminDTO.getSalt()));
+        return update(adminDTO);
+    }
+}

+ 201 - 0
src/main/java/com/gz/service/system/impl/AuthServiceImpl.java

@@ -0,0 +1,201 @@
+package com.gz.service.system.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.gz.common.DataGlobalVariable;
+import com.gz.core.exception.BusinessException;
+import com.gz.core.exception.CustomExceptionEnum;
+import com.gz.dto.system.AdminDTO;
+import com.gz.dto.system.MenuDTO;
+import com.gz.jwt.JwtConfig;
+import com.gz.jwt.JwtPayload;
+import com.gz.mapper.system.AdminMapper;
+import com.gz.mapper.system.MenuMapper;
+import com.gz.rvo.system.InitialHomeRVO;
+import com.gz.rvo.system.LoginRVO;
+import com.gz.service.system.AuthService;
+import com.gz.utils.JwtUtils;
+import com.gz.utils.PasswordUtils;
+import com.gz.vo.system.LoginVO;
+import com.gz.vo.system.UpdatePasswordVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 身份验证Service
+ * @author LiuchangLan
+ * @date 2021/1/28 12:55
+ */
+@Slf4j
+@Service
+public class AuthServiceImpl implements AuthService {
+
+    @Resource
+    private AdminMapper adminMapper;
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    @Resource
+    private MenuMapper menuMapper;
+
+    @Override
+    public LoginRVO login(LoginVO vo) {
+        // 查询用户参数
+        AdminDTO param = new AdminDTO();
+
+        // 根据用户名查
+        param.setAccount(vo.getAccount());
+        AdminDTO loginDTO = adminMapper.selectOne(param);
+        // 用户名没查到
+        if (loginDTO == null){
+            throw new BusinessException(CustomExceptionEnum.ACCOUNT_OR_PASSWORD_INCORRECT);
+        }
+
+        // 用户禁用
+        if (loginDTO.getStatus().equals(DataGlobalVariable.USER_STATUS_DISABLE)) {
+            log.warn("账号{}已禁用 无法登录", vo.getAccount());
+            throw new BusinessException(CustomExceptionEnum.ACCOUNT_DISABLE);
+        }
+        // 密码不正确
+        if (!PasswordUtils.verification(vo.getPassword(), loginDTO.getSalt(), loginDTO.getPassword())){
+            throw new BusinessException(CustomExceptionEnum.ACCOUNT_OR_PASSWORD_INCORRECT);
+        }
+        // 生成jwt载体
+        JwtPayload jwtPayload = new JwtPayload(loginDTO.getId(), loginDTO.getAccount(), loginDTO.getAdminName(),loginDTO.getRoleId());
+        // token
+        String token = JwtUtils.createToken(jwtPayload, JwtConfig.ACCESS_TOKEN_EFFECTIVE);
+        // refreshToken
+        String refreshToken = IdUtil.simpleUUID();
+        // 存储token的key
+        String refreshTokenKey = String.format(JwtConfig.REFRESH_TOKEN_KEY_FORMAT, refreshToken);
+        // 设置当前有效的Token
+        stringRedisTemplate.opsForHash().put(refreshTokenKey, JwtConfig.REDIS_JWT_TOKEN_KEY, token);
+        // 存储载体
+        stringRedisTemplate.opsForHash().put(refreshTokenKey, JwtConfig.REDIS_JWT_PAYLOAD_KEY, JSONObject.toJSONString(jwtPayload));
+        // refresh token 设置过期时间
+        stringRedisTemplate.expire(refreshTokenKey, JwtConfig.REFRESH_TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);
+        log.info("账号:{}  密码:{} 登录成功",vo.getAccount(),vo.getPassword());
+        return new LoginRVO(token, refreshToken, System.currentTimeMillis());
+    }
+
+    @Override
+    public LoginRVO refreshToken(String refreshToken) {
+        String refreshTokenKey = String.format(JwtConfig.REFRESH_TOKEN_KEY_FORMAT, refreshToken);
+        String payload = (String)stringRedisTemplate.opsForHash().get(refreshTokenKey, JwtConfig.REDIS_JWT_PAYLOAD_KEY);
+
+        if (StringUtils.isEmpty(payload)) { // refreshtoken 已经过期
+            throw new BusinessException(CustomExceptionEnum.LOGIN_TIMEOUT);
+        }
+
+        JwtPayload JwtPayload = JSONObject.parseObject(payload, JwtPayload.class);
+        String newAccessToken = JwtUtils.createToken(JwtPayload, JwtConfig.ACCESS_TOKEN_EFFECTIVE);
+
+        String oldAccessToken = (String)stringRedisTemplate.opsForHash().get(refreshTokenKey, JwtConfig.REDIS_JWT_TOKEN_KEY);
+        stringRedisTemplate.opsForHash().put(refreshTokenKey, JwtConfig.REDIS_JWT_TOKEN_KEY, newAccessToken);
+
+        // 旧 token 放入黑名单,防止超过 10s 后被再次使用
+        String blacklistKey = String.format(JwtConfig.BLACKLIST_KEY_FORMAT, oldAccessToken);
+        stringRedisTemplate.opsForValue()
+                .set(blacklistKey, oldAccessToken, JwtConfig.ACCESS_TOKEN_EFFECTIVE, TimeUnit.SECONDS);
+
+        return new LoginRVO(newAccessToken,refreshToken,System.currentTimeMillis());
+    }
+
+
+    @Override
+    public AdminDTO getLoginInfo() {
+        AdminDTO adminDTO = adminMapper.selectByPrimaryKey(JwtUtils.getCurrentUserJwtPayload().getId());
+        adminDTO.setPassword(null);
+        adminDTO.setSalt(null);
+        return adminDTO;
+    }
+
+    @Override
+    public void logout(String refreshToken) {
+        String refreshTokenKey = String.format(JwtConfig.REFRESH_TOKEN_KEY_FORMAT, refreshToken);
+        String oldAccessToken = (String)stringRedisTemplate.opsForHash().get(refreshTokenKey, JwtConfig.REDIS_JWT_TOKEN_KEY);
+        if (!StringUtils.isEmpty(oldAccessToken)) {
+            // 旧 token 放入黑名单,防止再次被调用
+            String blacklistKey = String.format(JwtConfig.BLACKLIST_KEY_FORMAT, oldAccessToken); // 被黑名单的 key
+            stringRedisTemplate.opsForValue()
+                    .set(blacklistKey, "", JwtConfig.ACCESS_TOKEN_EFFECTIVE, TimeUnit.SECONDS);
+        }
+        stringRedisTemplate.delete(refreshTokenKey);
+    }
+
+
+    @Override
+    public InitialHomeRVO getLoginMenus() {
+        InitialHomeRVO initialHomeRVO = new InitialHomeRVO();
+        // 设置首页信息
+        initialHomeRVO.getHomeInfo().put("title","首页");
+        initialHomeRVO.getHomeInfo().put("href","page/home/welcome.html?t=1");
+        // logo信息
+        initialHomeRVO.getLogoInfo().put("title","南京市纪委监委派驻监督管理信息系统");
+        initialHomeRVO.getLogoInfo().put("image","images/logo.png");
+        initialHomeRVO.getLogoInfo().put("href","");
+
+        // 获取所有菜单
+        List<MenuDTO> menusOrder = menuMapper.getRoleMenu(JwtUtils.getCurrentUserJwtPayload().getRoleId());
+        //配置
+        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
+        // 自定义属性名 都要默认值的
+        treeNodeConfig.setIdKey("id");
+        treeNodeConfig.setNameKey("title");
+        treeNodeConfig.setChildrenKey("child");
+        // 最大递归深度
+        treeNodeConfig.setDeep(100);
+
+        //转换器
+        List<Tree<String>> treeNodes = TreeUtil.build(menusOrder, "-1", treeNodeConfig,
+                (treeNode, tree) -> {
+                    tree.setId(treeNode.getId().toString());
+                    tree.setParentId(treeNode.getParentId().toString());
+                    tree.setName(treeNode.getTitle());
+                    tree.putExtra("href",treeNode.getHref());
+                    tree.putExtra("icon",treeNode.getIcon());
+                });
+        initialHomeRVO.setMenuInfo(treeNodes);
+
+        return initialHomeRVO;
+    }
+
+
+    @Override
+    public Integer updatePassword(UpdatePasswordVO vo) throws BusinessException {
+        Integer id = JwtUtils.getCurrentUserJwtPayload().getId();
+        AdminDTO adminDTO = adminMapper.selectByPrimaryKey(id);
+        String salt = adminDTO.getSalt();
+        String password = adminDTO.getPassword();
+
+        // 密码不正确
+        if (!PasswordUtils.verification(vo.getOldPassword(),salt,password)) {
+            throw new BusinessException(CustomExceptionEnum.PASSWORD_NO_INCORRECT);
+        }
+
+        salt = IdUtil.simpleUUID();
+        password = PasswordUtils.encryption(vo.getNewPassword(), salt);
+        adminDTO.setSalt(salt);
+        adminDTO.setPassword(password);
+        adminDTO.setUpdateTime(DateUtil.now());
+
+        return adminMapper.updateByPrimaryKey(adminDTO);
+    }
+
+    @Override
+    public List<MenuDTO> getLoginButtons(Integer menuId) {
+        return menuMapper.getRoleButtle(JwtUtils.getCurrentUserJwtPayload().getRoleId(),menuId);
+    }
+
+}

+ 148 - 0
src/main/java/com/gz/service/system/impl/DictServiceImpl.java

@@ -0,0 +1,148 @@
+package com.gz.service.system.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.gz.common.DataGlobalVariable;
+import com.gz.core.exception.BusinessException;
+import com.gz.core.exception.CustomExceptionEnum;
+import com.gz.dto.system.DictDTO;
+import com.gz.mapper.system.DictMapper;
+import com.gz.service.system.DictService;
+import com.gz.utils.JwtUtils;
+import com.gz.vo.system.DictVO;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 10:17
+ */
+@Service
+public class DictServiceImpl implements DictService {
+    @Resource
+    private DictMapper dictMapper;
+
+    @Override
+    public Integer insert(DictDTO dictDTO) throws BusinessException {
+        DictDTO codeIsExist = new DictDTO();
+        codeIsExist.setDictCode(dictDTO.getDictCode());
+        List<DictDTO> select = dictMapper.select(codeIsExist);
+        if (select != null && select.size() > 0){
+            throw new BusinessException(CustomExceptionEnum.DICT_CODE_EXISTS);
+        }
+        // 创建人
+        dictDTO.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 执行入库
+        return dictMapper.insertSelective(dictDTO);
+    }
+
+    @Override
+    public Integer delete(Integer id) {
+        return dictMapper.deleteByPrimaryKey(id);
+    }
+
+    @Override
+    public Integer update(DictDTO dictDTO) throws BusinessException {
+        DictDTO codeIsExist = new DictDTO();
+        codeIsExist.setDictCode(dictDTO.getDictCode());
+        List<DictDTO> select = dictMapper.select(codeIsExist);
+        Integer count = select.size();
+        // 除了自己原来的code
+        for (DictDTO dto : select) {
+            if (dictDTO.getId().equals(dto.getId())){
+                count --;
+            }
+        }
+        // code已经重复
+        if (select != null && count > 0){
+            throw new BusinessException(CustomExceptionEnum.DICT_CODE_EXISTS);
+        }
+        // 修改人
+        dictDTO.setUpdated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 修改时间
+        dictDTO.setUpdateTime(DateUtil.now());
+        // 执行入库
+        return dictMapper.updateByPrimaryKeySelective(dictDTO);
+    }
+
+    @Override
+    public PageInfo<DictDTO> selectByPage(DictVO dictVO) {
+        if (dictVO.getPageNum() != null && dictVO.getPageSize() != null){
+            PageHelper.startPage(dictVO.getPageNum(),dictVO.getPageSize());
+        }
+        // 查询条件转换
+        DictDTO dictDTO = BeanUtil.copyProperties(dictVO, DictDTO.class);
+        // 查询未删除的数据
+        return new PageInfo<>(dictMapper.select(dictDTO));
+    }
+
+    @Override
+    public DictDTO selectByPrimaryKey(Integer id) {
+        DictDTO adminDTO = new DictDTO();
+        adminDTO.setId(id);
+        return dictMapper.selectOne(adminDTO);
+    }
+
+    @Override
+    public List<DictDTO> select() {
+        // 查询条件转换
+        DictDTO dictDTO = new DictDTO();
+        // 查询未删除的数据
+        return dictMapper.select(dictDTO);
+    }
+
+    @Override
+    public List<Tree<String>> getDictTree() {
+        List<DictDTO> select = select();
+        //配置
+        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
+        // 自定义属性名 都要默认值的
+        treeNodeConfig.setIdKey("id");
+        // 最大递归深度
+        treeNodeConfig.setDeep(3);
+
+        //转换器
+        List<Tree<String>> treeNodes = TreeUtil.build(select, "-1", treeNodeConfig,
+                (treeNode, tree) -> {
+                    tree.setId(treeNode.getId().toString());
+                    tree.setParentId(treeNode.getParentId().toString());
+                    tree.setName(treeNode.getDictName());
+                });
+        return treeNodes;
+    }
+
+    @Override
+    public List<DictDTO> selectDictByCode(String code) {
+        return dictMapper.selectDictByCode(code);
+    }
+
+    /**
+     * @description 根据中文名查询字典
+     * @author LiuChangLan
+     * @since 2020/9/18 10:20
+     */
+    @Override
+    public String getDictCode(String chineseName) {
+        if (chineseName != null && !"".equals(chineseName)) {
+            DictDTO dictDTO = new DictDTO();
+            dictDTO.setDictName(chineseName);
+            return dictMapper.selectOne(dictDTO).getDictCode();
+        }
+        return "";
+    }
+
+    @Override
+    public String getDictName(String code) {
+        DictDTO dictDTO = new DictDTO();
+        dictDTO.setDictCode(code);
+        DictDTO dictDTO1 = dictMapper.selectOne(dictDTO);
+        return dictDTO1.getDictName();
+    }
+}

+ 85 - 0
src/main/java/com/gz/service/system/impl/FileServiceImpl.java

@@ -0,0 +1,85 @@
+package com.gz.service.system.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.IdUtil;
+import com.gz.common.DataGlobalVariable;
+import com.gz.core.exception.BusinessException;
+import com.gz.core.exception.CustomExceptionEnum;
+import com.gz.dto.system.FileDTO;
+import com.gz.mapper.system.FileMapper;
+import com.gz.rvo.system.FileUploadRVO;
+import com.gz.service.system.FileService;
+import com.gz.utils.JwtUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ClassUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/9 11:24
+ */
+@Service
+@Slf4j
+public class FileServiceImpl implements FileService {
+    @Resource
+    private FileMapper fileMapper;
+
+    @Override
+    @Transactional
+    public FileUploadRVO upload(MultipartFile file, String fileId) throws BusinessException, IOException {
+
+            if (file.isEmpty()) {
+                throw new BusinessException(CustomExceptionEnum.File_NOT_EXISTS);
+            }
+            String fileName = file.getOriginalFilename();
+            // 上传路径
+            String filePath = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static/upload/" + DateUtil.format(new Date(), "yyyyMMdd") + "/";
+            File file1 = new File(filePath);
+            // 判断上传是否存在
+            if (!file1.exists()) {
+                file1.mkdirs();
+            }
+            if ("null".equals(fileId) || fileId == null || "".equals(fileId)) {
+                fileId = IdUtil.simpleUUID();
+            }
+        // 现文件名
+            String fn = IdUtil.simpleUUID() + fileName.substring(fileName.indexOf("."));
+            File dest = new File(filePath + fn);
+            // 上传
+            file.transferTo(dest);
+            // 数据库插入
+            FileDTO fileDTO = new FileDTO();
+            fileDTO.setFileId(fileId);
+            fileDTO.setOriginalFileName(fileName);
+            fileDTO.setDownloadPath("upload/" + DateUtil.format(new Date(), "yyyyMMdd") + "/" + fn);
+            fileDTO.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
+            fileMapper.insertSelective(fileDTO);
+
+            FileUploadRVO fileUploadRVO = new FileUploadRVO(fileId,fileName, fn, "upload/" + DateUtil.format(new Date(), "yyyyMMdd") + "/" + fn);
+            return fileUploadRVO;
+
+    }
+
+    @Override
+    public List<FileDTO> selectByFileId(String fileId) {
+        FileDTO fileDTO = new FileDTO();
+        fileDTO.setFileId(fileId);
+        List<FileDTO> select = fileMapper.select(fileDTO);
+        return select;
+    }
+
+    @Override
+    public Integer delete(Integer id) {
+        return fileMapper.deleteByPrimaryKey(id);
+    }
+
+
+}

+ 51 - 0
src/main/java/com/gz/service/system/impl/LogServiceImpl.java

@@ -0,0 +1,51 @@
+package com.gz.service.system.impl;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.gz.mapper.system.LogMapper;
+import com.gz.rvo.system.LogRVO;
+import com.gz.service.system.LogService;
+import com.gz.vo.system.LogVO;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 20:17
+ */
+@Service
+public class LogServiceImpl implements LogService {
+
+    @Resource
+    private LogMapper logMapper;
+
+    @Override
+    public PageInfo<LogRVO> selectByPage(LogVO logVO) {
+        if (logVO.getPageNum() != null && logVO.getPageSize() != null){
+            PageHelper.startPage(logVO.getPageNum(),logVO.getPageSize());
+        }
+        return new PageInfo<>(logMapper.selectByTime(logVO));
+    }
+
+    @Override
+    public List<String> selectLogModule() {
+        return logMapper.selectLogModule();
+    }
+
+    @Override
+    public List<String> selectLogBusiness(String module) {
+        return logMapper.selectLogBusiness(module);
+    }
+
+    @Override
+    public Integer clearAll() {
+        return logMapper.clearAll();
+    }
+
+    @Override
+    public Integer clearThirtyOut() {
+        return logMapper.clearThirtyOut();
+    }
+}

+ 87 - 0
src/main/java/com/gz/service/system/impl/MenuServiceImpl.java

@@ -0,0 +1,87 @@
+package com.gz.service.system.impl;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import com.gz.common.DataGlobalVariable;
+import com.gz.dto.system.MenuDTO;
+import com.gz.mapper.system.MenuMapper;
+import com.gz.service.system.MenuService;
+import com.gz.utils.JwtUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 菜单业务层
+ * @author LiuchangLan
+ * @date 2020/9/4 15:54
+ */
+@Service
+public class MenuServiceImpl implements MenuService {
+
+    @Resource
+    private MenuMapper menuMapper;
+
+    @Override
+    public Integer insert(MenuDTO menuDTO) {
+        // 创建人
+        menuDTO.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 执行入库
+        return menuMapper.insertSelective(menuDTO);
+    }
+
+    @Override
+    public Integer delete(Integer id) {
+        return menuMapper.deleteByPrimaryKey(id);
+    }
+
+    @Override
+    public Integer update(MenuDTO menuDTO) {
+        // 修改人
+        menuDTO.setUpdated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 修改时间
+        menuDTO.setUpdateTime(DateUtil.now());
+        // 执行入库
+        return menuMapper.updateByPrimaryKeySelective(menuDTO);
+    }
+
+    @Override
+    public List<MenuDTO> select() {
+        return menuMapper.selectAll();
+    }
+
+    @Override
+    public MenuDTO selectByPrimaryKey(Integer id) {
+        return menuMapper.selectByPrimaryKey(id);
+    }
+
+    @Override
+    public List<Tree<String>> getMenuTree() {
+        List<MenuDTO> menuDTOS = selectByOrder();
+        //配置
+        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
+        // 自定义属性名 都要默认值的
+        treeNodeConfig.setIdKey("id");
+        // 最大递归深度
+        treeNodeConfig.setDeep(3);
+
+        //转换器
+        List<Tree<String>> treeNodes = TreeUtil.build(menuDTOS, "-1", treeNodeConfig,
+                (treeNode, tree) -> {
+                    tree.setId(treeNode.getId().toString());
+                    tree.setParentId(treeNode.getParentId().toString());
+                    tree.setName(treeNode.getTitle());
+                });
+        return treeNodes;
+    }
+
+    @Override
+    public List<MenuDTO> selectByOrder() {
+        return menuMapper.getMenusOrder();
+    }
+
+
+}

+ 152 - 0
src/main/java/com/gz/service/system/impl/RoleServiceImpl.java

@@ -0,0 +1,152 @@
+package com.gz.service.system.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.lang.tree.TreeNodeConfig;
+import cn.hutool.core.lang.tree.TreeUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.gz.common.DataGlobalVariable;
+import com.gz.dto.system.MenuDTO;
+import com.gz.dto.system.MenuRoleDTO;
+import com.gz.dto.system.RoleDTO;
+import com.gz.mapper.system.MenuRoleMapper;
+import com.gz.mapper.system.RoleMapper;
+import com.gz.service.system.MenuService;
+import com.gz.service.system.RoleService;
+import com.gz.utils.JwtUtils;
+import com.gz.vo.system.RoleMenuVO;
+import com.gz.vo.system.RoleVO;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 14:42
+ */
+@Service
+public class RoleServiceImpl implements RoleService {
+
+    @Resource
+    private RoleMapper roleMapper;
+
+    @Resource
+    private MenuRoleMapper menuRoleMapper;
+
+    @Resource
+    private MenuService menuService;
+
+    @Override
+    public Integer insert(RoleDTO roleDTO) {
+        // 创建人
+        roleDTO.setCreated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 执行入库
+        return roleMapper.insertSelective(roleDTO);
+    }
+
+    @Override
+    public Integer delete(Integer id) {
+        return roleMapper.deleteByPrimaryKey(id);
+    }
+
+    @Override
+    public Integer update(RoleDTO roleDTO) {
+        // 修改人
+        roleDTO.setUpdated(JwtUtils.getCurrentUserJwtPayload().getId());
+        // 修改时间
+        roleDTO.setUpdateTime(DateUtil.now());
+        // 执行入库
+        return roleMapper.updateByPrimaryKeySelective(roleDTO);
+    }
+
+    @Override
+    public PageInfo<RoleDTO> select(RoleVO roleVO) {
+        if (roleVO.getPageNum() != null && roleVO.getPageSize() != null){
+            PageHelper.startPage(roleVO.getPageNum(),roleVO.getPageSize());
+        }
+        // 查询条件转换
+        RoleDTO roleDTO = BeanUtil.copyProperties(roleVO, RoleDTO.class);
+        // 查询未删除的数据
+        return new PageInfo<>(roleMapper.select(roleDTO));
+    }
+
+    @Override
+    public RoleDTO selectByPrimaryKey(Integer id) {
+        RoleDTO roleDTO = new RoleDTO();
+        roleDTO.setId(id);
+        return roleMapper.selectOne(roleDTO);
+    }
+
+    @Override
+    @Transactional
+    public Integer setRole(RoleMenuVO vo) {
+        String[] menuIds = vo.getMenuId().split(",");
+        // 删除已有的权限
+        MenuRoleDTO deleteDTO = new MenuRoleDTO();
+        deleteDTO.setRoleId(vo.getRoleId());
+        Integer i = menuRoleMapper.delete(deleteDTO);
+        if (vo.getMenuId() == null || "".equals(vo.getMenuId())){
+            return i;
+        }
+        // 重新添加权限
+        for (String menuId : menuIds) {
+            MenuRoleDTO menuRoleDTO = new MenuRoleDTO();
+            menuRoleDTO.setRoleId(vo.getRoleId());
+            menuRoleDTO.setMenuId(Integer.parseInt(menuId));
+            i = menuRoleMapper.insert(menuRoleDTO);
+        }
+        return i;
+    }
+
+    @Override
+    public List<Tree<String>> selectRoleList(Integer roleId) {
+        List<MenuDTO> menuDTOS = menuService.selectByOrder();
+
+        MenuRoleDTO dto = new MenuRoleDTO();
+        dto.setRoleId(roleId);
+        List<MenuRoleDTO> select = menuRoleMapper.select(dto);
+        //配置
+        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
+        // 自定义属性名 都要默认值的
+        treeNodeConfig.setIdKey("id");
+        // 最大递归深度
+        treeNodeConfig.setDeep(3);
+
+        //转换器
+        List<Tree<String>> treeNodes = TreeUtil.build(menuDTOS, "-1", treeNodeConfig,
+                (treeNode, tree) -> {
+                    tree.setId(treeNode.getId().toString());
+                    tree.setParentId(treeNode.getParentId().toString());
+                    tree.setName(treeNode.getTitle());
+                    tree.putExtra("title",treeNode.getTitle());
+
+                    for (MenuRoleDTO menuRoleDTO : select) {
+                        boolean flag = false;
+                        // 判断是否有子元素
+                        for (MenuDTO menuDTO1 : menuDTOS) {
+                            if (menuDTO1.getParentId().equals(treeNode.getId())){
+                                flag = true;
+                                break;
+                            }
+                        }
+                        // 有权限 并且没有子元素的默认选中
+                        if(menuRoleDTO.getMenuId().equals(treeNode.getId()) && !flag){
+                            flag = true;
+                            tree.putExtra("checked",true);
+                            break;
+                        }
+                    }
+                });
+        return treeNodes;
+    }
+
+    @Override
+    public List<RoleDTO> selectAllRole() {
+        RoleDTO roleDTO = new RoleDTO();
+        return roleMapper.select(roleDTO);
+    }
+}

+ 92 - 0
src/main/java/com/gz/utils/JwtUtils.java

@@ -0,0 +1,92 @@
+package com.gz.utils;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.gz.jwt.JwtConfig;
+import com.gz.jwt.JwtPayload;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/7/16 15:04
+ */
+@Slf4j
+public class JwtUtils {
+
+
+
+    /**
+     * @description 创建token
+     * @author LiuChangLan
+     * @since 2020/7/16 15:19
+     * @param jwtPayload jwt载体
+     * @param expireTimeInSecond 过期时间 秒
+     */
+    public static String createToken(JwtPayload jwtPayload, Long expireTimeInSecond){
+        Algorithm alg = Algorithm.HMAC256(JwtConfig.TOKEN_SECRET);
+        Date currentTime = new Date();
+        String token = JWT.create()
+                // 签发时间
+                .withIssuedAt(currentTime)
+                // 过期时间
+                .withExpiresAt(new Date(currentTime.getTime() + expireTimeInSecond * 1000))
+                // 分配JWT的ID
+                .withJWTId(IdUtil.simpleUUID())
+                // 定义公共域信息
+                .withClaim("loginUser", JSON.toJSONString(jwtPayload))
+                // 加密的密钥
+                .sign(alg);
+        return token;
+    }
+
+    /**
+     * @description 验证token
+     * @author LiuChangLan
+     * @since 2020/6/29 15:53
+     */
+    public static boolean verifier(String token){
+        Algorithm alg = Algorithm.HMAC256(JwtConfig.TOKEN_SECRET);
+        // 2 验证Token
+        JWTVerifier verifier = JWT.require(alg)
+                .build();
+            verifier.verify(token);
+            log.info("token验证成功!");
+            return true;
+
+    }
+
+    /**
+     * @description 获取token的内容
+     * @author LiuChangLan
+     * @since 2020/6/29 15:57
+     */
+    public static JwtPayload decrypt(String token){
+        DecodedJWT originToken = JWT.decode(token);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        log.info(String.format("token签发时间%s",DateUtil.formatDateTime(originToken.getIssuedAt())));
+        String publicClaimExample = originToken.getClaim("loginUser").asString();
+        JwtPayload jwtPayload = JSON.parseObject(publicClaimExample, JwtPayload.class);
+        return jwtPayload;
+    }
+
+    /**
+     * 获取当前登录用户的JwtPayload
+     */
+    public static JwtPayload getCurrentUserJwtPayload() {
+        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+        return (JwtPayload) request.getAttribute(JwtConfig.HEADER_AUTHORIZATION_USER);
+    }
+
+
+}

+ 29 - 0
src/main/java/com/gz/utils/PasswordUtils.java

@@ -0,0 +1,29 @@
+package com.gz.utils;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.crypto.SecureUtil;
+
+/**
+ * 密码utils
+ * @author LiuchangLan
+ * @date 2021/1/27 10:24
+ */
+public class PasswordUtils {
+
+    public static String encryption(String password,String salt){
+        return SecureUtil.md5(password + salt);
+    }
+
+    public static boolean verification(String inputPassword,String salt,String password){
+        return encryption(inputPassword,salt).equals(password);
+    }
+
+
+    public static void main(String[] args) {
+        String password = "123456";
+        String salt = IdUtil.simpleUUID();
+
+        System.out.println(encryption(password,salt));
+        System.out.println(salt);
+    }
+}

+ 36 - 0
src/main/java/com/gz/utils/RequestUtils.java

@@ -0,0 +1,36 @@
+package com.gz.utils;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 请求工具类
+ * @author LiuchangLan
+ * @date 2020/7/23 15:31
+ */
+public class RequestUtils {
+
+    /**
+     * @description 获取ip
+     * @author LiuChangLan
+     * @since 2020/7/23 15:31
+     */
+    public static String getIpAddress(HttpServletRequest request) {
+        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.getRemoteAddr();
+        }
+        return ip;
+    }
+}

+ 153 - 0
src/main/java/com/gz/utils/TableUtils.java

@@ -0,0 +1,153 @@
+package com.gz.utils;
+
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import java.util.Scanner;
+
+/**
+ * DTO生成工具类
+ * @author LiuchangLan
+ * @date 2020/6/28 10:32
+ */
+public class TableUtils {
+
+    private static String yml;
+    private static String url;
+    private static String user;
+    private static String password;
+    private static String drive;
+
+    static {
+        // 读取yml
+        yml = (String) getYml("spring.profiles.active");
+        if (yml != null && !"".equals(yml)) {
+            yml = "-" + yml;
+        } else {
+            yml = "";
+        }
+        url = String.valueOf(getYml("spring.datasource.url"));
+        user = String.valueOf(getYml("spring.datasource.username"));
+        password = String.valueOf(getYml("spring.datasource.password"));
+        drive = String.valueOf(getYml("spring.datasource.driver-class-name"));
+
+        //1.加载驱动程序
+        try {
+            Class.forName(drive);
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void main(String[] args) throws SQLException {
+        // 跳过固定字段
+        List<String> cloumns = new ArrayList<String>(){{
+            add("create_time");
+            add("update_time");
+            add("created");
+            add("updated");
+            add("id");
+        }};
+        Connection connection = DriverManager.getConnection(url, user , password);
+        Scanner scanner = new Scanner(System.in);
+        String tableName = scanner("表名");
+        String tableSql = "select COLUMN_NAME,column_comment,data_type  from INFORMATION_SCHEMA.Columns where table_name='" + tableName + "'  ";
+        PreparedStatement ps = connection.prepareStatement(tableSql);
+        ResultSet resultSet = ps.executeQuery();
+        while (resultSet.next()){
+            String clumn = resultSet.getString("COLUMN_NAME");
+            if(cloumns.indexOf(clumn) != -1){
+                continue;
+            }
+            String comment = resultSet.getString("column_comment");
+            String type = "";
+            switch (resultSet.getString("data_type")){
+                case "varchar":
+                    type = "String";
+                    break;
+                case "datetime":
+                    type = "String";
+                    break;
+                case "date":
+                    type = "String";
+                    break;
+                case "decimal":
+                    type = "Double";
+                    break;
+                case "int":
+                    type = "Integer";
+                    break;
+            }
+            int index = clumn.indexOf("_");
+            while (index != -1){
+                clumn = clumn.substring(0,index) + clumn.substring(index + 1,index + 2).toUpperCase() + clumn.substring(index + 2);
+                index = clumn.indexOf("_");
+            }
+            System.out.println("// " + comment);
+            System.out.println("private " + type + " " + clumn + ";");
+            System.out.println();
+        }
+    }
+
+
+    /**
+     * 根据传入的yml获取yml中key的属性值
+     *
+     * @param key
+     * @param yml
+     * @return
+     */
+    public static Object getYml(Object key, String yml) {
+        Resource resource = new ClassPathResource(yml);
+        Properties properties;
+        try {
+            YamlPropertiesFactoryBean yamlFactory = new YamlPropertiesFactoryBean();
+            yamlFactory.setResources(resource);
+            properties = yamlFactory.getObject();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+        return properties.get(key);
+    }
+
+    /**
+     * 自动根据 application中激活的配置文件,选择对应的yml读取属性
+     *
+     * @param key
+     * @return
+     */
+    public static Object getYml(Object key) {
+        Object value = getYml(key, "application.yml");
+        if (value != null) {
+            return value;
+        }
+        if (!yml.contains("application")) {
+            yml = "application" + yml + ".yml";
+        }
+        return getYml(key, yml);
+    }
+
+
+    /**
+     * 读取控制台输入
+     * @author WangJixin
+     * @since 2019/9/24 11:53
+     */
+    public static String scanner(String tip) {
+        Scanner scanner = new Scanner(System.in);
+        StringBuilder help = new StringBuilder();
+        help.append("请输入" + tip + ":");
+        System.out.println(help.toString());
+        if (scanner.hasNext()) {
+            return scanner.next();
+        }
+        throw new RuntimeException("输入有误");
+    }
+
+}

+ 23 - 0
src/main/java/com/gz/vo/PageVO.java

@@ -0,0 +1,23 @@
+package com.gz.vo;
+
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 分页入参VO
+ * @author LiuchangLan
+ * @date 2021/1/26 22:41
+ */
+@Data
+public class PageVO {
+    // 页数
+    @Min(value = 1,message = "页数最少为第1页")
+    @NotNull(message = "页数不能为空")
+    private Integer pageNum;
+    // 每页显示数量
+    @NotNull(message = "每页数量不能为空")
+    @Min(value = 1,message = "每页数量最少为1")
+    private Integer pageSize;
+}

+ 12 - 0
src/main/java/com/gz/vo/system/AdminVO.java

@@ -0,0 +1,12 @@
+package com.gz.vo.system;
+
+import com.gz.vo.PageVO;
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 15:00
+ */
+@Data
+public class AdminVO extends PageVO {
+}

+ 11 - 0
src/main/java/com/gz/vo/system/DictVO.java

@@ -0,0 +1,11 @@
+package com.gz.vo.system;
+
+
+import com.gz.vo.PageVO;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 10:19
+ */
+public class DictVO extends PageVO {
+}

+ 17 - 0
src/main/java/com/gz/vo/system/LogVO.java

@@ -0,0 +1,17 @@
+package com.gz.vo.system;
+
+import com.gz.vo.PageVO;
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/7 20:17
+ */
+@Data
+public class LogVO extends PageVO {
+    private String startTime;
+    private String endTime;
+    private String logType;
+    private String module;
+    private String business;
+}

+ 16 - 0
src/main/java/com/gz/vo/system/LoginVO.java

@@ -0,0 +1,16 @@
+package com.gz.vo.system;
+
+import lombok.Data;
+
+/**
+ * 登录入参
+ * @author LiuchangLan
+ * @date 2020/7/16 14:35
+ */
+@Data
+public class LoginVO {
+    // 用户名
+    private String account;
+    // 密码
+    private String password;
+}

+ 11 - 0
src/main/java/com/gz/vo/system/MenuVO.java

@@ -0,0 +1,11 @@
+package com.gz.vo.system;
+
+
+import com.gz.vo.PageVO;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 15:59
+ */
+public class MenuVO extends PageVO {
+}

+ 15 - 0
src/main/java/com/gz/vo/system/RoleMenuVO.java

@@ -0,0 +1,15 @@
+package com.gz.vo.system;
+
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/22 9:33
+ */
+@Data
+public class RoleMenuVO {
+
+    private Integer roleId;
+    private String menuId;
+
+}

+ 12 - 0
src/main/java/com/gz/vo/system/RoleVO.java

@@ -0,0 +1,12 @@
+package com.gz.vo.system;
+
+import com.gz.vo.PageVO;
+import lombok.Data;
+
+/**
+ * @author LiuchangLan
+ * @date 2020/9/4 20:42
+ */
+@Data
+public class RoleVO extends PageVO {
+}

+ 14 - 0
src/main/java/com/gz/vo/system/UpdatePasswordVO.java

@@ -0,0 +1,14 @@
+package com.gz.vo.system;
+
+import lombok.Data;
+
+/**
+ * 修改密码入参vo
+ * @author LiuchangLan
+ * @date 2020/9/25 15:45
+ */
+@Data
+public class UpdatePasswordVO {
+    private String oldPassword;
+    private String newPassword;
+}

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

@@ -0,0 +1,85 @@
+server:
+  port: 9091
+spring:
+  servlet:
+    multipart:
+      # 单个文件大小
+      max-file-size: 100MB
+      # 设置总上传的数据大小
+      max-request-size: 100MB
+      # 开启
+      enabled: true
+  # 数据源配置
+  datasource:
+    # 连接池类型
+    type: com.alibaba.druid.pool.DruidDataSource
+    # MYSQL 5 驱动:com.mysql.jdbc.Driver,MYSQL 6+ 驱动:com.mysql.cj.jdbc.Driver
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://115.159.38.225:3306/guihua_archives?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+    username: root
+    password: abcd123456!@#
+    # 连接池配置
+    druid:
+      # 初始化大小,最小,最大
+      initial-size: 5
+      min-idle: 5
+      max-active: 20
+      # 配置获取连接等待超时的时间
+      max-wait: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
+      time-between-eviction-runs-millis: 60000
+      # 配置一个连接在池中最小生存时间
+      min-evictable-idle-time-millis: 300000
+      validation-query: SELECT 1
+      test-while-idle: true
+      test-on-borrow: false
+      test-on-return: false
+      # 打开 PSCache,并且指定每个连接上 PSCache 的大小
+      pool-prepared-statements: true
+      max-pool-prepared-statement-per-connection-size: 20
+      # 配置监控统计拦截的 Filter,去掉后监控界面 SQL 无法统计,wall 用于防火墙
+      filters: stat,wall,log4j
+      # 通过 connection-properties 属性打开 mergeSql 功能;慢 SQL 记录
+      connection-properties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
+      # 配置 DruidStatFilter
+      web-stat-filter:
+        enabled: true
+        url-pattern: /*
+        exclusions: .js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*
+      # 配置 DruidStatViewServlet
+      stat-view-servlet:
+        # 开启监控页面
+        enabled: true
+        # 页面地址
+        url-pattern: /druid/*
+        # IP 白名单,没有配置或者为空,则允许所有访问
+        allow: 127.0.0.1
+        # IP 黑名单,若白名单也存在,则优先使用
+        deny: 192.168.31.253
+        # 禁用 HTML 中 Reset All 按钮
+        reset-enable: false
+        # 登录用户名/密码
+        # login-username: admin
+        # login-password: 123456
+  # redis配置
+  redis:
+    # redis地址
+    host: 127.0.0.1
+    # redis端口
+    port: 6379
+    # redis库
+    database: 0
+    jedis:
+      pool:
+        # 连接池最大连接数(使用负值表示没有限制,对应maxTotal)
+        max-active: 50
+        # 连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3000
+        # 连接池中的最大空闲连接
+        max-idle: 20
+        # 连接池中的最小空闲连接
+        min-idle: 2
+    # 密码
+#    password: 123456
+    # 连接超时时间(毫秒)
+    timeout: 30000

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

@@ -0,0 +1,26 @@
+spring:
+#  mvc:
+#    throw-exception-if-no-handler-found: false
+#  resources:
+#    add-mappings: true
+  profiles:
+    active: dev
+mybatis:
+  #注册Mapper.xml配置文件
+  mapper-locations: classpath:mapper/*.xml
+  configuration:
+    #配置下划线转驼峰
+    map-underscore-to-camel-case: true
+#分页配置
+pagehelper:
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql
+auth:
+  login:
+    # 进行登录验证的地址
+    force-urls: /**
+    # 跳过验证地址
+    skip-urls: /,/**/*.png,/**/*.jpg,/**/*.html,/**/*.ico,/**/*.css,/**/*.js,/webSocket/**,/**/*.woff2,/system/auth/login,/system/auth/refreshToken
+

+ 7 - 0
src/main/resources/banner.txt

@@ -0,0 +1,7 @@
+   ___       _            _   _      _                      _
+  |_  |     (_)          | \ | |    | |                    | |
+    | |_   _ _  ___ ___  |  \| | ___| |___      _____  _ __| | __
+    | | | | | |/ __/ _ \ | . ` |/ _ \ __\ \ /\ / / _ \| '__| |/ /
+/\__/ / |_| | | (_|  __/ | |\  |  __/ |_ \ V  V / (_) | |  |   <
+\____/ \__,_|_|\___\___| \_| \_/\___|\__| \_/\_/ \___/|_|  |_|\_\
+                        :: Spring Boot ::        (v2.2.2.RELEASE)

+ 4 - 0
src/main/resources/log4j.properties

@@ -0,0 +1,4 @@
+log4j.rootLogger=DEBUG, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

+ 6 - 0
src/main/resources/mapper/FileMapper.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.gz.archives.mapper.system.FileMapper">
+
+
+</mapper>

+ 8 - 0
src/main/resources/mapper/dictMapper.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.gz.mapper.system.DictMapper">
+
+    <select id="selectDictByCode" resultType="com.gz.dto.system.DictDTO">
+        select * from tab_dict where parent_id = (select id from tab_dict where dict_code = #{code})
+    </select>
+</mapper>

+ 65 - 0
src/main/resources/mapper/logMapper.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.gz.mapper.system.LogMapper">
+
+    <select id="selectByTime" resultType="com.gz.rvo.system.LogRVO" parameterType="com.gz.vo.system.LogVO">
+        SELECT
+        l.*,
+        d.dict_name,
+        u.admin_name
+        FROM
+        `tab_log` l
+        LEFT JOIN `tab_admin` u ON l.exec_by = u.id
+        LEFT JOIN `tab_dict` d ON l.log_type = d.dict_code
+        <where>
+            <if test="logType != null and logType != ''">
+                and l.log_type = #{logType}
+            </if>
+            <if test="module != null and module != ''">
+                and l.module = #{module}
+            </if>
+            <if test="business != null and business != ''">
+                and l.business = #{business}
+            </if>
+            <if test="startTime != null and startTime != ''">
+                and l.exec_time <![CDATA[>=]]> #{startTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                and l.exec_time <![CDATA[<=]]> #{endTime}
+            </if>
+        </where>
+        ORDER BY l.exec_time DESC
+    </select>
+
+    <select id="selectLogModule" resultType="string">
+        select module from tab_log group by module
+    </select>
+
+    <select id="selectLogBusiness" resultType="string" parameterType="string">
+        select business from tab_log where module = #{module} group by business
+    </select>
+
+    <select id="clearAll" resultType="integer">
+        TRUNCATE TABLE `tab_log`;
+    </select>
+
+    <select id="clearThirtyOut" resultType="integer">
+        delete from tab_log where DATE_FORMAT(exec_time,'%Y-%m-%d') <![CDATA[<]]> DATE_SUB(curdate(),interval 30 day)
+    </select>
+
+
+    <select id="selectCountByTime" resultType="integer">
+        select count(id) from tab_log l
+        <where>
+            <if test="logType != null and logType != ''">
+                and l.log_type = #{logType}
+            </if>
+            <if test="startTime != null and startTime != ''">
+                and l.exec_time <![CDATA[>=]]> #{startTime}
+            </if>
+            <if test="endTime != null and endTime != ''">
+                and l.exec_time <![CDATA[<=]]> #{endTime}
+            </if>
+        </where>
+    </select>
+</mapper>

+ 33 - 0
src/main/resources/mapper/menuMapper.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.gz.mapper.system.MenuMapper">
+    <select id="getMenusOrder" resultType="com.gz.dto.system.MenuDTO">
+        select * from tab_menu order by `sort` asc
+    </select>
+
+    <select id="getRoleMenu" resultType="com.gz.dto.system.MenuDTO">
+        SELECT
+            m.*
+        FROM
+            tab_menu m
+            LEFT JOIN tab_menu_role mr ON m.id = mr.menu_id
+        WHERE
+             mr.role_id = #{roleId}
+            AND m.type != 2
+        order by m.`sort` asc
+    </select>
+
+    <select id="getRoleButtle" resultType="com.gz.dto.system.MenuDTO">
+        SELECT
+            m.*
+        FROM
+            tab_menu m
+            LEFT JOIN tab_menu_role mr ON m.id = mr.menu_id
+        WHERE
+             mr.role_id = #{roleId}
+            AND m.parent_id = #{menuId}
+            AND m.type = 2
+        order by m.`sort` asc
+    </select>
+
+</mapper>

+ 118 - 0
src/main/resources/static/404.html

@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>404</title>
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta http-equiv="Access-Control-Allow-Origin" content="*">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
+    <meta name="apple-mobile-web-app-status-bar-style" content="black">
+    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="format-detection" content="telephone=no">
+    <link rel="stylesheet" href="lib/layui-v2.5.5/css/layui.css" media="all">
+    <style>
+        .error .clip .shadow {height:180px;}
+        .error .clip:nth-of-type(2) .shadow {width:130px;}
+        .error .clip:nth-of-type(1) .shadow,.error .clip:nth-of-type(3) .shadow {width:250px;}
+        .error .digit {width:150px;height:150px;line-height:150px;font-size:120px;font-weight:bold;}
+        .error h2 {font-size:32px;}
+        .error .msg {top:-190px;left:30%;width:80px;height:80px;line-height:80px;font-size:32px;}
+        .error span.triangle {top:70%;right:0%;border-left:20px solid #535353;border-top:15px solid transparent;border-bottom:15px solid transparent;}
+        .error .container-error-404 {top: 50%;margin-top: 250px;position:relative;height:250px;padding-top:40px;}
+        .error .container-error-404 .clip {display:inline-block;transform:skew(-45deg);}
+        .error .clip .shadow {overflow:hidden;}
+        .error .clip:nth-of-type(2) .shadow {overflow:hidden;position:relative;box-shadow:inset 20px 0px 20px -15px rgba(150,150,150,0.8),20px 0px 20px -15px rgba(150,150,150,0.8);}
+        .error .clip:nth-of-type(3) .shadow:after,.error .clip:nth-of-type(1) .shadow:after {content:"";position:absolute;right:-8px;bottom:0px;z-index:9999;height:100%;width:10px;background:linear-gradient(90deg,transparent,rgba(173,173,173,0.8),transparent);border-radius:50%;}
+        .error .clip:nth-of-type(3) .shadow:after {left:-8px;}
+        .error .digit {position:relative;top:8%;color:white;background:#1E9FFF;border-radius:50%;display:inline-block;transform:skew(45deg);}
+        .error .clip:nth-of-type(2) .digit {left:-10%;}
+        .error .clip:nth-of-type(1) .digit {right:-20%;}
+        .error .clip:nth-of-type(3) .digit {left:-20%;}
+        .error h2 {font-size:24px;color:#A2A2A2;font-weight:bold;padding-bottom:20px;}
+        .error .tohome {font-size:16px;color:#07B3F9;}
+        .error .msg {position:relative;z-index:9999;display:block;background:#535353;color:#A2A2A2;border-radius:50%;font-style:italic;}
+        .error .triangle {position:absolute;z-index:999;transform:rotate(45deg);content:"";width:0;height:0;}
+        @media(max-width:767px) {.error .clip .shadow {height:100px;}
+            .error .clip:nth-of-type(2) .shadow {width:80px;}
+            .error .clip:nth-of-type(1) .shadow,.error .clip:nth-of-type(3) .shadow {width:100px;}
+            .error .digit {width:80px;height:80px;line-height:80px;font-size:52px;}
+            .error h2 {font-size:18px;}
+            .error .msg {top:-110px;left:15%;width:40px;height:40px;line-height:40px;font-size:18px;}
+            .error span.triangle {top:70%;right:-3%;border-left:10px solid #535353;border-top:8px solid transparent;border-bottom:8px solid transparent;}
+            .error .container-error-404 {height:150px;}
+        }
+    </style>
+</head>
+<body>
+<div class="error">
+    <div class="container-floud">
+        <div style="text-align: center">
+            <div class="container-error-404">
+                <div class="clip">
+                    <div class="shadow">
+                        <span class="digit thirdDigit"></span>
+                    </div>
+                </div>
+                <div class="clip">
+                    <div class="shadow">
+                        <span class="digit secondDigit"></span>
+                    </div>
+                </div>
+                <div class="clip">
+                    <div class="shadow">
+                        <span class="digit firstDigit"></span>
+                    </div>
+                </div>
+                <div class="msg">OH!
+                    <span class="triangle"></span>
+                </div>
+            </div>
+            <h2 class="h1">很抱歉,你访问的页面找不到了</h2>
+<!--            <h2 class="h1" id="dj">3秒后自动跳转      <a href="/index.html" style="color: #1e9fff;text-decoration:underline">点击跳转</a></h2>-->
+        </div>
+    </div>
+</div>
+<script src="lib/layui-v2.5.5/layui.js" charset="utf-8"></script>
+<script>
+    function randomNum() {
+        return Math.floor(Math.random() * 9) + 1;
+    }
+
+    var loop1, loop2, loop3, time = 30, i = 0, number;
+    loop3 = setInterval(function () {
+        if (i > 40) {
+            clearInterval(loop3);
+            document.querySelector('.thirdDigit').textContent = 4;
+        } else {
+            document.querySelector('.thirdDigit').textContent = randomNum();
+            i++;
+        }
+    }, time);
+    loop2 = setInterval(function () {
+        if (i > 80) {
+            clearInterval(loop2);
+            document.querySelector('.secondDigit').textContent = 0;
+        } else {
+            document.querySelector('.secondDigit').textContent = randomNum();
+            i++;
+        }
+    }, time);
+    loop1 = setInterval(function () {
+        if (i > 100) {
+            clearInterval(loop1);
+            document.querySelector('.firstDigit').textContent = 4;
+        } else {
+            document.querySelector('.firstDigit').textContent = randomNum();
+            i++;
+        }
+    }, time);
+    // let ms = 2;
+    // setInterval(function () {
+    //     document.getElementById('dj').innerHTML = (ms --) + '秒后自动跳转      <a href="/index.html" style="color: #1e9fff;text-decoration:underline">点击跳转</a>'
+    //     if (ms == -1){
+    //         window.location = '/index.html'
+    //     }
+    // },1000)
+</script>
+</body>
+</html>

+ 4 - 0
src/main/resources/static/api/clear.json

@@ -0,0 +1,4 @@
+{
+  "code": 1,
+  "msg": "服务端清理缓存成功"
+}

+ 77 - 0
src/main/resources/static/api/init.json

@@ -0,0 +1,77 @@
+{
+  "homeInfo": {
+    "title": "首页",
+    "href": "page/home/welcome.html?t=1"
+  },
+  "logoInfo": {
+    "title": "考试系统",
+    "image": "images/logo.png",
+    "href": ""
+  },
+  "menuInfo": [
+    {
+      "title": "常规管理",
+      "icon": "fa fa-address-book",
+      "href": "",
+      "target": "_self",
+      "child": [
+        {
+          "title": "系统设置",
+          "href": "",
+          "icon": "fa fa-gears",
+          "target": "_self",
+          "child": [
+            {
+              "title": "日志管理",
+              "href": "page/log/logsList.html",
+              "icon": "fa fa-cube",
+              "target": "_self"
+            },
+            {
+              "title": "用户管理",
+              "href": "page/user/userList.html",
+              "icon": "fa fa-user",
+              "target": "_self"
+            },
+            {
+              "title": "数据源监听",
+              "href": "/druid/index.html",
+              "icon": "fa fa-database",
+              "target": "_self"
+            }
+          ]
+        },
+        {
+          "title": "字典管理",
+          "href": "page/dict/dictList.html",
+          "icon": "fa fa-window-maximize",
+          "target": "_self"
+        },
+        {
+          "title": "试卷管理",
+          "href": "page/paper/paperList.html",
+          "icon": "fa fa-window-maximize",
+          "target": "_self"
+        },
+        {
+          "title": "题目管理",
+          "href": "page/question/questionList.html",
+          "icon": "fa fa-lightbulb-o",
+          "target": "_self"
+        },
+        {
+          "title": "菜单管理",
+          "href": "page/menu/menuList.html",
+          "icon": "fa fa-window-maximize",
+          "target": "_self"
+        },
+        {
+          "title": "权限管理",
+          "href": "page/role/list.html",
+          "icon": "fa fa-window-maximize",
+          "target": "_self"
+        }
+      ]
+    }
+  ]
+}

+ 927 - 0
src/main/resources/static/css/layuimini.css

@@ -0,0 +1,927 @@
+/**
+配色方案(如有需要,请自行配置)
+ */
+/**头部-配色*/
+.layui-layout-admin .layui-header {
+    background-color: #1aa094 !important;
+}
+
+.layui-header > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover {
+    background-color: #197971 !important;
+}
+
+.layui-header .layuimini-header-content > ul > .layui-nav-item.layui-this, .layuimini-tool i:hover {
+    background-color: #197971 !important;
+}
+
+/**logo-配色*/
+.layui-layout-admin .layuimini-logo {
+    background-color: #243346 !important;
+}
+
+/**左侧-配色*/
+.layui-side.layui-bg-black, .layui-side.layui-bg-black > .layuimini-menu-left > ul {
+    background-color: #2f4056 !important;
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-child a:hover:not(.layui-this) {
+    background-color: #3b3f4b;
+}
+
+/**左侧菜单选中-配色*/
+.layui-layout-admin .layui-nav-tree .layui-this, .layui-layout-admin .layui-nav-tree .layui-this > a, .layui-layout-admin .layui-nav-tree .layui-nav-child dd.layui-this, .layui-layout-admin .layui-nav-tree .layui-nav-child dd.layui-this a {
+    background-color: #1aa094 !important;
+}
+
+
+/**头部样式 */
+.layui-layout-admin .header {
+    position: fixed;
+    left: 0;
+    right: 0;
+    top: 0;
+    bottom: 0;
+}
+
+.layuimini-header-menu, .layui-header {
+    height: 60px !important;
+}
+
+.layuimini-header-menu > .layui-nav-item {
+    color: #1b1d21;
+    height: 60px !important;
+    line-height: 60px !important;
+}
+
+.layui-header > .layui-layout-right > .layui-nav-item {
+    height: 60px !important;
+    line-height: 60px !important;
+}
+
+.layui-layout-left {
+    left: 295px !important;
+}
+
+.layui-nav.layui-layout-left.layuimini-header-menu.layuimini-pc-show {
+    font-weight: bold;
+    transition: all .2s;
+}
+
+
+/**logo演示(通用) */
+.layui-layout-admin .layuimini-logo {
+    font-weight: bold;
+    color: #ffffff !important;
+    height: 60px !important;
+    line-height: 60px !important;
+    overflow: hidden;
+    line-height: 64px;
+    transition: all .2s !important;
+}
+
+.layui-layout-admin .layuimini-logo img {
+    display: inline-block;
+    height: 40px;
+    vertical-align: middle;
+}
+
+.layui-layout-admin .layuimini-logo h1 {
+    display: inline-block;
+    margin: 0 0 0 12px;
+    color: #ffffff;
+    font-weight: 600;
+    font-size: 20px;
+    font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+    vertical-align: middle;
+}
+
+/**缩放工具(通用) */
+.layuimini-tool {
+    position: absolute !important;
+    top: 0;
+    left: 235px;
+    width: 60px;
+    height: 100%;
+    line-height: 60px;
+    text-align: center;
+    color: #ffffff !important;
+    transition: all .2s;
+}
+
+/**缩放工具(缩放) */
+.layuimini-tool i {
+    display: block;
+    color: #bbe3df;
+    width: 32px;
+    height: 32px;
+    line-height: 32px;
+    border-radius: 3px;
+    text-align: center;
+    margin-top: 15px;
+    cursor: pointer;
+}
+
+/**tab选项卡 */
+.layuimini-tab {
+    margin: 0px;
+    overflow: hidden;
+    height: 100% !important;
+}
+
+.layuimini-tab .layui-tab-content {
+    height: calc(100% - 37px) !important;
+}
+
+.layuimini-tab .layui-tab-content .layui-tab-item {
+    height: 100%;
+}
+
+.layuimini-tab .layui-tab-content {
+    padding: 0px;
+}
+
+.layuimini-tab .layui-tab-title {
+    border: none;
+    border: 1px solid whitesmoke;
+    background-color: white;
+}
+
+.layuimini-tab .layui-tab-title li {
+    border-right: 1px solid whitesmoke;
+    color: dimgray;
+}
+
+.layuimini-tab .layui-tab-title .layui-tab-bar {
+    display: none;
+}
+
+.layuimini-tab .layui-tab-title .layui-this:after {
+    display: none;
+}
+
+.layuimini-tab .layui-tab-title .layuimini-tab-active {
+    display: inline-block;
+    background-color: lightgray;
+    width: 9px;
+    height: 9px;
+    border-radius: 30px;
+    margin-right: 5px;
+}
+
+.layuimini-tab .layui-tab-title .layui-this .layuimini-tab-active {
+    background-color: #1aa094;
+}
+
+.layuimini-tab > .layui-tab-title, .layuimini-tab > .close-box {
+    height: 35px !important;
+}
+
+.layuimini-tab > .layui-tab-title li, .layuimini-tab > .close-box li {
+    line-height: 35px !important;
+}
+
+.layuimini-tab .layui-tab-title span {
+    color: #acafb1;
+}
+
+.layuimini-tab .layui-tab-title .layui-this span {
+    color: dimgray;
+}
+
+.layuimini-tab .layui-tab-title .layui-tab-close {
+    font-size: 12px !important;
+    width: 14px !important;
+    height: 14px !important;
+    line-height: 16px !important;
+}
+
+.layuimini-tab .layui-tab-title .layui-tab-close:hover {
+    border-radius: 4em;
+    background: #ff5722;
+}
+
+.layuimini-tab .layui-tab-title .disable-close + .layui-tab-close {
+    display: none;
+}
+
+.layuimini-tab .layui-tab-title .able-close + .layui-tab-close {
+    display: inline-block;
+}
+
+.layuimini-tab .layui-tab-control > li {
+    position: absolute;
+    top: 0px;
+    height: 35px;
+    line-height: 35px;
+    width: 35px;
+    text-align: center;
+    background-color: white;
+    border-top: whitesmoke 1px solid;
+    border-bottom: whitesmoke 1px solid;
+}
+
+.layuimini-tab .layuimini-tab-roll-left {
+    left: 0px;
+    border-right: whitesmoke 1px solid;
+    border-left: whitesmoke 1px solid;
+}
+
+.layuimini-tab .layuimini-tab-roll-right {
+    right: 35px;
+    border-left: 1px solid whitesmoke;
+}
+
+.layuimini-tab .layui-tab-tool {
+    right: 0px;
+    border-left: 1px solid whitesmoke;
+}
+
+.layuimini-tab .layui-tab-control .layui-tab-tool,
+.layuimini-tab .layui-tab-control .layuimini-tab-roll-left,
+.layuimini-tab .layui-tab-control .layuimini-tab-roll-right {
+    display: none;
+}
+
+.layuimini-tab.layui-tab-roll .layui-tab-control .layuimini-tab-roll-left,
+.layuimini-tab.layui-tab-roll .layui-tab-control .layuimini-tab-roll-right {
+    display: block;
+}
+
+.layuimini-tab.layui-tab-roll .layui-tab-control .layuimini-tab-roll-right {
+    right: 0px;
+    border-right: 1px solid whitesmoke;
+}
+
+.layuimini-tab.layui-tab-roll .layui-tab-title {
+    padding-left: 35px;
+    padding-right: 35px;
+}
+
+
+.layuimini-tab.layui-tab-tool .layui-tab-control .layui-tab-tool {
+    display: block;
+}
+
+.layuimini-tab.layui-tab-tool .layui-tab-title {
+    padding-left: 0px;
+    padding-right: 35px;
+}
+
+
+.layuimini-tab.layui-tab-rollTool .layui-tab-title {
+    padding-left: 35px;
+    padding-right: 80px;
+}
+
+.layuimini-tab.layui-tab-rollTool .layui-tab-control .layuimini-tab-roll-left,
+.layuimini-tab.layui-tab-rollTool .layui-tab-control .layuimini-tab-roll-right,
+.layuimini-tab.layui-tab-rollTool .layui-tab-control .layui-tab-tool {
+    display: block;
+}
+
+.layuimini-tab .layui-tab-tool .layui-nav {
+    position: absolute;
+    height: 43px !important;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    padding: 0;
+    background: 0 0;
+}
+
+.layuimini-tab .layui-tab-tool .layui-nav-item {
+    height: 35px;
+}
+
+.layuimini-tab .layui-tab-tool .layui-nav-bar {
+    display: none;
+}
+
+.layuimini-tab .layui-tab-tool .layui-nav-child {
+    left: auto;
+    top: 45px;
+    right: 3px;
+    width: 120px;
+    border: 1px solid whitesmoke;
+}
+
+.layuimini-tab .layui-tab-tool .layui-this a {
+    background-color: #009688;
+}
+
+.layuimini-tab-loading {
+    position: absolute;
+    display: none;
+    width: 100%;
+    height: calc(100% - 37px);
+    top: 37px;
+    z-index: 19;
+    background-color: #fff
+}
+
+.layuimini-tab-loading.close {
+    animation: close 1s;
+    -webkit-animation: close 1s;
+    animation-fill-mode: forwards;
+}
+
+/**左侧菜单栏 (通用) */
+.layui-side.layui-bg-black {
+    transition: all .2s;
+}
+
+.layui-side.layui-bg-black > .layuimini-menu-left > ul {
+    transition: all .2s;
+}
+
+.layui-side.layui-bg-black > .layuimini-menu-left > ul > .layui-nav-item:first-child {
+    border-top: 1px solid #4b5461;
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-item a {
+    height: 40px;
+    line-height: 40px;
+    padding-right: 30px;
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-item > a {
+    padding-top: 5px;
+    padding-bottom: 5px;
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child {
+    background: 0 0 !important
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-more {
+    right: 15px;
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-item a:hover {
+    background-color: transparent !important;
+}
+
+.layuimini-menu-left .layui-nav {
+    background-color: transparent !important;
+}
+
+
+/**左侧菜单栏 (正常) */
+.layui-layout-body .layui-nav-itemed .layui-nav-child a, .layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child a {
+    padding-left: 35px;
+}
+
+.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child a {
+    padding-left: 45px;
+}
+
+.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child .layui-nav-child a {
+    padding-left: 55px;
+}
+
+.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-child .layui-nav-child .layui-nav-child .layui-nav-child a {
+    padding-left: 65px;
+}
+
+.layui-layout-body .layuimini-menu-left .layui-nav .layui-nav-itemed > .layui-nav-child {
+    padding: 5px 0;
+}
+
+/**内容主体(通用) */
+.layui-layout-admin .layui-body {
+    overflow: hidden;
+    bottom: 0px !important;
+    top: 60px !important;
+    transition: all .2s;
+}
+
+/**选择配色方案 */
+.layuimini-color .color-title {
+    padding: 10px 0 10px 20px;
+    border-bottom: 1px solid #d9dada;
+    margin-bottom: 8px;
+}
+
+.layuimini-color .color-content {
+    padding: 10px 5px 0 5px;
+}
+
+.layuimini-color .color-content ul {
+    list-style: none;
+    text-align: center;
+}
+
+.layuimini-color .color-content ul li {
+    position: relative;
+    display: inline-block;
+    vertical-align: top;
+    width: 80px;
+    height: 50px;
+    margin: 0 15px 15px 0;
+    padding: 2px 2px 4px 2px;
+    background-color: #f2f2f2;
+    cursor: pointer;
+    font-size: 12px;
+    color: #666;
+}
+
+.layuimini-color .color-content li.layui-this:after, .layuimini-color .color-content li:hover:after {
+    width: 100%;
+    height: 100%;
+    padding: 4px;
+    top: -5px;
+    left: -5px;
+    border-color: #d8d8d8;
+    opacity: 1;
+}
+
+.layuimini-color .color-content li:after {
+    content: '';
+    position: absolute;
+    z-index: 20;
+    top: 50%;
+    left: 50%;
+    width: 1px;
+    height: 0;
+    border: 1px solid #f2f2f2;
+    transition: all .3s;
+    -webkit-transition: all .3s;
+    opacity: 0;
+}
+
+
+/**其它 */
+.layui-tab-item {
+    width: 100% !important;
+    height: 100% !important;
+}
+
+.layui-nav-item.layui-this {
+    background-color: #1b1d21;
+}
+
+.layui-width-height {
+    width: 100%;
+    height: 95%;
+}
+
+.layui-tab {
+    margin: 0 0 0 0;
+    z-index: 99999;
+}
+
+.text-center {
+    height: 30px !important;
+    line-height: 30px !important;
+    text-align: center !important;
+}
+
+.layui-nav {
+    padding: 0 !important;
+}
+
+.layui-nav .layui-this:after, .layui-nav-bar, .layui-nav-tree .layui-nav-itemed:after {
+    width: 0 !important;
+    height: 0 !important;
+}
+
+.layui-layout-admin .layui-side {
+    top: 60px !important;
+}
+
+.layui-tab-card {
+    box-shadow: 0px 0px 0px #888888;
+    border-bottom: 0;
+}
+
+
+/**自定义滚动条样式 */
+::-webkit-scrollbar {
+    display: none
+}
+
+
+/*移动端遮罩层*/
+.layuimini-make {
+    position: fixed;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    top: 0;
+    z-index: 1000;
+    background: rgba(0, 0, 0, .5);
+    display: none;
+}
+
+.layuimini-mini .layui-header {
+    z-index: 1001;
+}
+
+/**初始化加载层*/
+.layuimini-loader {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: #ffffff;
+    z-index: 999999;
+}
+
+.layuimini-loader .layuimini-loader-inner {
+    display: block;
+    position: relative;
+    left: 50%;
+    top: 50%;
+    width: 150px;
+    height: 150px;
+    margin: -75px 0 0 -75px;
+    border-radius: 50%;
+    border: 3px solid transparent;
+    border-top-color: #1E9FFF;
+    animation: spin 2s linear infinite;
+}
+
+.layuimini-loader .layuimini-loader-inner:before {
+    content: "";
+    position: absolute;
+    top: 5px;
+    left: 5px;
+    right: 5px;
+    bottom: 5px;
+    border-radius: 50%;
+    border: 3px solid transparent;
+    border-top-color: #1E9FFF;
+    animation: spin 3s linear infinite;
+}
+
+.layuimini-loader .layuimini-loader-inner:after {
+    content: "";
+    position: absolute;
+    top: 15px;
+    left: 15px;
+    right: 15px;
+    bottom: 15px;
+    border-radius: 50%;
+    border: 3px solid transparent;
+    border-top-color: #1E9FFF;
+    animation: spin 1.5s linear infinite;
+}
+
+@keyframes spin {
+    0% {
+        transform: rotate(0deg);
+    }
+    to {
+        transform: rotate(1turn);
+    }
+}
+
+/*系统设置*/
+
+.layuimini-color .layui-word-aux {
+    position: absolute;
+    left: 60px;
+    top: 12px;
+    font-size: 12px;
+}
+
+.layuimini-color .layui-input-block {
+    margin-left: 15px;
+    min-height: 36px;
+}
+
+.layuimini-color .more-menu-list {
+    width: 100%;
+    margin-top: 30px;
+}
+
+
+.layuimini-color .more-menu-item:first-child {
+    border-top: 1px solid #e8e8e8;
+}
+
+.layuimini-color .more-menu-item .layui-icon {
+    font-size: 18px;
+    padding-right: 10px;
+}
+
+.layuimini-color .more-menu-item {
+    color: #595959;
+    height: 50px;
+    line-height: 50px;
+    font-size: 16px;
+    padding: 0 25px;
+    border-bottom: 1px solid #e8e8e8;
+    font-style: normal;
+    display: block;
+}
+
+.layuimini-color .more-menu-item:hover {
+    background-color: whitesmoke;
+}
+
+.layuimini-color .more-menu-item:after {
+    color: #8c8c8c;
+    right: 16px;
+    content: "\e602";
+    position: absolute;
+    font-family: layui-icon !important;
+}
+
+/**
+鼠标右键
+ */
+.layuimini-tab-mousedown {
+    display: none;
+    width: 80px;
+    position: absolute;
+    top: 0px !important;
+    left: 0px !important;
+}
+
+.layuimini-tab-mousedown dd a {
+    padding: 0 15px;
+    color: #484545;
+}
+
+.layuimini-tab-make{
+    position: absolute;
+    top: 36px;
+    bottom: 0px;
+    width: 100%;
+    background: rgb(255, 255, 255,0);
+    padding: 0px;
+    overflow: hidden;
+}
+
+/**
+菜单缩放
+ */
+.popup-tips .layui-layer-TipsG{
+    display: none;
+}
+.popup-tips.layui-layer-tips .layui-layer-content{
+    padding: 0;
+}
+.popup-tips .layui-nav-tree{
+    width: 150px;
+    border-radius: 10px;
+}
+
+/**左侧菜单字体间距*/
+.layuimini-menu-left .layui-nav-item a span {
+    letter-spacing: 1px;
+}
+
+/**头部菜单字体间距*/
+.layui-layout-admin .layui-header .layuimini-header-menu.layuimini-pc-show,.layui-layout-admin .layui-header .layuimini-header-menu.layuimini-mobile-show {
+    letter-spacing: 1px;
+}
+
+
+/**左侧菜单更多下拉样式*/
+.layuimini-menu-left .layui-nav-more,.layuimini-menu-left-zoom .layui-nav-more {
+    font-family: layui-icon !important;
+    font-size: 12px;
+    font-style: normal;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    overflow: hidden;
+    width: auto;
+    height: auto;
+    line-height: normal;
+    border: none;
+    display: inline-block;
+    margin-top: -6px !important;
+}
+
+.layuimini-menu-left .layui-nav-child .layui-nav-more {
+    margin-top: -6px !important;
+}
+
+.layuimini-menu-left .layui-nav .layui-nav-mored,.layuimini-menu-left .layui-nav-itemed>a .layui-nav-more{
+    margin-top: -9px!important;
+}
+
+.layuimini-menu-left-zoom.layui-nav .layui-nav-mored,.layuimini-menu-left-zoom.layui-nav-itemed>a .layui-nav-more{
+    margin-top: -9px!important;
+}
+
+.layuimini-menu-left .layui-nav-more:before,.layuimini-menu-left-zoom .layui-nav-more:before {
+    content: "\e61a";
+}
+.layuimini-menu-left .layui-nav-itemed > a > .layui-nav-more,.layuimini-menu-left-zoom .layui-nav-itemed > a > .layui-nav-more {
+    transform: rotate(180deg);
+    -ms-transform: rotate(180deg);
+    -moz-transform: rotate(180deg);
+    -webkit-transform: rotate(180deg);
+    -o-transform: rotate(180deg);
+    width: 12px;
+    text-align: center;
+    border-style:none;
+}
+
+.layuimini-menu-left .layui-nav-itemed > a > .layui-nav-more:before,.layuimini-menu-left-zoom .layui-nav-itemed > a > .layui-nav-more:before {
+    content: '\e61a';
+    background-color: transparent;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+/**修复左侧菜单字体不对齐的问题*/
+.layuimini-menu-left .layui-nav-item a .fa,.layuimini-menu-left .layui-nav-item a .layui-icon{
+    width: 20px;
+}
+
+
+/**
+ PC版样式
+ */
+@media screen and (min-width: 1025px) {
+    /**头部样式(缩放) */
+    .layuimini-mini .layui-layout-left.layuimini-header-menu.layuimini-pc-show {
+        left: 155px !important;
+    }
+
+    /**logo演示(缩放) */
+    .layuimini-mini .layui-layout-admin .layuimini-logo {
+        width: 60px !important;
+    }
+
+    .layuimini-mini .layui-layout-admin .layuimini-logo h1 {
+        display: none;
+    }
+
+    /**左侧菜单栏(缩放) */
+    .layuimini-mini .layuimini-menu-left {
+        width: 80px !important;
+    }
+
+    .layuimini-mini .layui-side.layui-bg-black, .layuimini-mini .layuimini-menu-left > ul, .layuimini-mini .layuimini-menu-left > ul li i {
+        width: 60px !important;
+    }
+
+    .layuimini-mini .layuimini-menu-left > ul li span:first-child {
+        display: none;
+    }
+
+    .layuimini-mini .layuimini-menu-left > ul li span:last-child {
+        float: right;
+        right: 7px;
+    }
+
+    .layuimini-mini .layuimini-menu-left .layui-nav .layui-nav-item a {
+        height: 40px;
+        line-height: 40px;
+        padding-right: 0px !important;
+    }
+
+    /**内容主体(缩放) */
+    .layuimini-mini .layui-layout-admin .layui-body {
+        left: 60px !important;
+    }
+
+    .layuimini-mini .layuimini-tool {
+        left: 95px !important;
+    }
+
+    .layuimini-pc-show{
+        display: block;
+    }
+    .layuimini-mobile-show{
+        display: none;
+    }
+
+    /**菜单缩放*/
+    .layuimini-mini .layuimini-menu-left .layui-nav-more,.layuimini-mini .layuimini-menu-left .layui-nav-child{
+        display: none;!important;
+    }
+}
+
+/**
+ 手机自适应样式
+*/
+@media screen and (max-width: 1024px) {
+
+    /**
+    todo 修复低版本IOS不能滑动问题, 但还是有问题, 低版本IOS部分情况下子页面无法自适应
+     */
+    .layuimini-tab .layui-tab-content .layui-tab-item {
+        -webkit-overflow-scrolling: touch;
+        overflow: scroll;
+        width: 100%;
+        height: 100%;
+    }
+
+    .layuimini-tab .layui-tab-content .layui-tab-item iframe {
+        height: 100%;
+        width: 100%;
+    }
+
+    .layuimini-pc-show{
+        display: none;
+    }
+    .layuimini-mobile-show{
+        display: block;
+    }
+    .layuimini-header-content {
+        left: 0;
+    }
+
+    .layui-layout-admin .layui-body .layui-tab-item.layui-show {
+        border-top: 1px solid #e2e2e2;
+    }
+
+    .layuimini-all .layui-layout-left.layuimini-header-menu {
+        left: 15px !important
+    }
+
+    .layuimini-mini .layui-layout-left.layuimini-header-menu {
+        left: 205px !important
+    }
+
+    .layui-layout-admin .layui-nav.layui-layout-right > li:not(.layuimini-setting) {
+        width: 40px !important;
+    }
+
+    .layui-layout-admin .layui-nav.layui-layout-right > li:not(.layuimini-setting) a {
+        padding: 0 15px;
+    }
+
+    .layuimini-all .layui-layout-admin .layui-body {
+        left: 0px !important;
+    }
+
+    .layuimini-mini .layui-layout-admin .layuimini-menu-left, .layuimini-mini .layui-header .layuimini-logo {
+        left: 0;
+        transition: left .2s;
+        z-index: 1001 !important;
+    }
+
+    .layuimini-all .layui-layout-admin .layuimini-menu-left, .layuimini-all .layui-header .layuimini-logo {
+        left: -200px;
+        transition: left .2s;
+        top: 0;
+        z-index: 1002;
+    }
+
+    .layuimini-mini .layui-layout-admin .layui-body {
+        left: 0!important;
+        transition: left .2s;
+        top: 0;
+        z-index: 998;
+    }
+
+    .layuimini-mini .layuimini-make {
+        display: block;
+    }
+
+    .layuimini-multi-module .layuimini-header-content .layuimini-tool {
+        display: none;
+    }
+
+    .layuimini-single-module .layuimini-header-content .layuimini-tool {
+        left: 15px;
+    }
+
+    .layuimini-mini .layuimini-site-mobile {
+        display: none !important;
+    }
+
+    .layuimini-site-mobile {
+        display: block !important;
+        position: fixed;
+        z-index: 100000;
+        bottom: 15px;
+        left: 15px;
+        width: 40px;
+        height: 40px;
+        line-height: 40px;
+        border-radius: 2px;
+        text-align: center;
+        background-color: rgba(0, 0, 0, .7);
+        color: #fff;
+    }
+
+    .layuimini-header-content {
+        z-index: 997;
+    }
+
+    /*修复UC之类的浏览器点击无效*/
+    .layuimini-make {
+        cursor: pointer;
+    }
+
+    .layuimini-site-mobile {
+        cursor: pointer;
+    }
+}
+
+@media screen and (max-width: 550px){
+
+    /**头部右侧数据*/
+    .layuimini-multi-module.layuimini-mini .layuimini-header-content .layui-layout-right {
+        display: none;
+    }
+}

+ 70 - 0
src/main/resources/static/css/public.css

@@ -0,0 +1,70 @@
+body {
+    margin: 15px 15px 15px 15px;
+    background: #f2f2f2;
+}
+
+.layuimini-container {
+    border: 1px solid #f2f2f2;
+    border-radius: 5px;
+    background-color: #ffffff
+}
+
+.layuimini-main {
+    margin: 10px 10px 10px 10px;
+}
+
+/**必填红点 */
+.layuimini-form > .layui-form-item > .required:after {
+    content: '*';
+    color: red;
+    position: absolute;
+    margin-left: 4px;
+    font-weight: bold;
+    line-height: 1.8em;
+    top: 6px;
+    right: 5px;
+}
+
+.layuimini-form > .layui-form-item > .layui-form-label {
+    width: 120px !important;
+}
+
+.layuimini-form > .layui-form-item > .layui-input-block {
+    margin-left: 150px !important;
+}
+
+.layuimini-form > .layui-form-item > .layui-input-block > tip {
+    display: inline-block;
+    margin-top: 10px;
+    line-height: 10px;
+    font-size: 10px;
+    color: #a29c9c;
+}
+
+/**搜索框*/
+.layuimini-container .table-search-fieldset {
+    margin: 0;
+    border: 1px solid #e6e6e6;
+    padding: 10px 20px 5px 20px;
+    color: #6b6b6b;
+}
+
+/**自定义滚动条样式 */
+::-webkit-scrollbar {
+    width: 6px;
+    height: 6px
+}
+
+::-webkit-scrollbar-track {
+    background-color: transparent;
+    -webkit-border-radius: 2em;
+    -moz-border-radius: 2em;
+    border-radius: 2em;
+}
+
+::-webkit-scrollbar-thumb {
+    background-color: #9c9da0;
+    -webkit-border-radius: 2em;
+    -moz-border-radius: 2em;
+    border-radius: 2em
+}

File diff suppressed because it is too large
+ 95 - 0
src/main/resources/static/css/themes/default.css


BIN
src/main/resources/static/images/bg.png


BIN
src/main/resources/static/images/captcha.jpg


BIN
src/main/resources/static/images/favicon.ico


+ 0 - 0
src/main/resources/static/images/jcqk.png


Some files were not shown because too many files changed in this diff