Browse Source

first commit

hellohaidie 6 months ago
commit
524189f0ff
86 changed files with 7715 additions and 0 deletions
  1. 34 0
      .gitignore
  2. BIN
      .mvn/wrapper/maven-wrapper.jar
  3. 2 0
      .mvn/wrapper/maven-wrapper.properties
  4. 308 0
      mvnw
  5. 205 0
      mvnw.cmd
  6. 154 0
      pom.xml
  7. 6 0
      src/main/java/com/lqkj/link/APIVersion.java
  8. 28 0
      src/main/java/com/lqkj/link/GlobalAsyncExceptionHandler.java
  9. 25 0
      src/main/java/com/lqkj/link/GlobalExceptionHandler.java
  10. 23 0
      src/main/java/com/lqkj/link/LinkServerApplication.java
  11. 53 0
      src/main/java/com/lqkj/link/config/JwtAuthFilter.java
  12. 53 0
      src/main/java/com/lqkj/link/config/JwtTokenAdminInterceptor.java
  13. 19 0
      src/main/java/com/lqkj/link/config/LimitRequest/LimitRequest.java
  14. 74 0
      src/main/java/com/lqkj/link/config/LimitRequest/LimitRequestAspect.java
  15. 133 0
      src/main/java/com/lqkj/link/config/OpenApiConfig.java
  16. 136 0
      src/main/java/com/lqkj/link/config/PropertyDeploy.java
  17. 75 0
      src/main/java/com/lqkj/link/config/WebMvcConfig.java
  18. 72 0
      src/main/java/com/lqkj/link/config/WebSecurityConfig.java
  19. 47 0
      src/main/java/com/lqkj/link/config/auth/LoginAuthenticationProvider.java
  20. 130 0
      src/main/java/com/lqkj/link/config/auth/OauthAuthorizationConfig.java
  21. 24 0
      src/main/java/com/lqkj/link/config/auth/OauthResourceConfig.java
  22. 112 0
      src/main/java/com/lqkj/link/message/MessageBaseBean.java
  23. 59 0
      src/main/java/com/lqkj/link/message/MessageBean.java
  24. 68 0
      src/main/java/com/lqkj/link/message/MessageListBean.java
  25. 102 0
      src/main/java/com/lqkj/link/module/audit/controller/AuditRecordController.java
  26. 47 0
      src/main/java/com/lqkj/link/module/audit/domain/AuditRecord.java
  27. 57 0
      src/main/java/com/lqkj/link/module/audit/repository/AuditRecordRepository.java
  28. 109 0
      src/main/java/com/lqkj/link/module/audit/service/AuditRecordService.java
  29. 113 0
      src/main/java/com/lqkj/link/module/authority/controller/RoleInfoController.java
  30. 197 0
      src/main/java/com/lqkj/link/module/authority/controller/UserInfoController.java
  31. 16 0
      src/main/java/com/lqkj/link/module/authority/domain/LoginBody.java
  32. 40 0
      src/main/java/com/lqkj/link/module/authority/domain/RoleInfo.java
  33. 119 0
      src/main/java/com/lqkj/link/module/authority/domain/UserInfo.java
  34. 126 0
      src/main/java/com/lqkj/link/module/authority/repository/RoleInfoRepository.java
  35. 106 0
      src/main/java/com/lqkj/link/module/authority/repository/UserInfoRepository.java
  36. 101 0
      src/main/java/com/lqkj/link/module/authority/service/DatabaseUserDetailService.java
  37. 103 0
      src/main/java/com/lqkj/link/module/authority/service/RoleInfoService.java
  38. 178 0
      src/main/java/com/lqkj/link/module/authority/service/UserInfoService.java
  39. 77 0
      src/main/java/com/lqkj/link/module/base/service/BaseService.java
  40. 63 0
      src/main/java/com/lqkj/link/module/bulletin/controller/BulletinInfoController.java
  41. 50 0
      src/main/java/com/lqkj/link/module/bulletin/controller/NoticeInfoController.java
  42. 35 0
      src/main/java/com/lqkj/link/module/bulletin/domain/BulletinInfo.java
  43. 48 0
      src/main/java/com/lqkj/link/module/bulletin/domain/NoticeInfo.java
  44. 9 0
      src/main/java/com/lqkj/link/module/bulletin/repository/BulletinInfoRepository.java
  45. 60 0
      src/main/java/com/lqkj/link/module/bulletin/repository/NoticeInfoRepository.java
  46. 45 0
      src/main/java/com/lqkj/link/module/bulletin/service/BulletinInfoService.java
  47. 26 0
      src/main/java/com/lqkj/link/module/bulletin/service/NoticeInfoService.java
  48. 87 0
      src/main/java/com/lqkj/link/module/config/controller/ConfigInfoController.java
  49. 30 0
      src/main/java/com/lqkj/link/module/config/domain/ConfigInfo.java
  50. 9 0
      src/main/java/com/lqkj/link/module/config/repository/ConfigInfoRepository.java
  51. 50 0
      src/main/java/com/lqkj/link/module/config/service/ConfigInfoService.java
  52. 47 0
      src/main/java/com/lqkj/link/module/encrypt/controller/EncryptController.java
  53. 96 0
      src/main/java/com/lqkj/link/module/jwt/controller/JwtController.java
  54. 80 0
      src/main/java/com/lqkj/link/module/jwt/service/JwtService.java
  55. 112 0
      src/main/java/com/lqkj/link/module/zone/controller/GeomInfoController.java
  56. 39 0
      src/main/java/com/lqkj/link/module/zone/controller/LayerInfoController.java
  57. 233 0
      src/main/java/com/lqkj/link/module/zone/controller/ResourceController.java
  58. 337 0
      src/main/java/com/lqkj/link/module/zone/controller/ZoneInfoController.java
  59. 67 0
      src/main/java/com/lqkj/link/module/zone/domain/GeomInfo.java
  60. 30 0
      src/main/java/com/lqkj/link/module/zone/domain/LayerInfo.java
  61. 50 0
      src/main/java/com/lqkj/link/module/zone/domain/ModelCategory.java
  62. 51 0
      src/main/java/com/lqkj/link/module/zone/domain/ModelInfo.java
  63. 18 0
      src/main/java/com/lqkj/link/module/zone/domain/OneZoneGeomInfos.java
  64. 14 0
      src/main/java/com/lqkj/link/module/zone/domain/TemplateInfo.java
  65. 62 0
      src/main/java/com/lqkj/link/module/zone/domain/ZoneInfo.java
  66. 73 0
      src/main/java/com/lqkj/link/module/zone/repository/GeomInfoRepository.java
  67. 50 0
      src/main/java/com/lqkj/link/module/zone/repository/LayerInfoRepository.java
  68. 60 0
      src/main/java/com/lqkj/link/module/zone/repository/ModelCategoryRepository.java
  69. 43 0
      src/main/java/com/lqkj/link/module/zone/repository/ModelInfoRepository.java
  70. 189 0
      src/main/java/com/lqkj/link/module/zone/repository/ZoneInfoRepository.java
  71. 80 0
      src/main/java/com/lqkj/link/module/zone/service/GeomInfoService.java
  72. 20 0
      src/main/java/com/lqkj/link/module/zone/service/LayerInfoService.java
  73. 173 0
      src/main/java/com/lqkj/link/module/zone/service/ResourceService.java
  74. 324 0
      src/main/java/com/lqkj/link/module/zone/service/ZoneInfoService.java
  75. 91 0
      src/main/java/com/lqkj/link/util/AESUtils.java
  76. 182 0
      src/main/java/com/lqkj/link/util/FileUtils.java
  77. 26 0
      src/main/java/com/lqkj/link/util/GeometryDeserializer.java
  78. 26 0
      src/main/java/com/lqkj/link/util/GeometrySerializer.java
  79. 58 0
      src/main/java/com/lqkj/link/util/JwtUtil.java
  80. 127 0
      src/main/java/com/lqkj/link/util/RSAUtils.java
  81. 232 0
      src/main/java/com/lqkj/link/util/Unzipper.java
  82. 98 0
      src/main/resources/application-install.yml
  83. 0 0
      src/main/resources/db/migration/V1__INIT.sql
  84. 728 0
      src/main/resources/db/migration/V2__1.0.0.sql
  85. 43 0
      src/main/resources/log4j2.xml
  86. 13 0
      src/test/java/com/lqkj/link/LinkServerApplicationTests.java

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
1
+HELP.md
2
+target/
3
+!.mvn/wrapper/maven-wrapper.jar
4
+!**/src/main/**/target/
5
+!**/src/test/**/target/
6
+
7
+### STS ###
8
+.apt_generated
9
+.classpath
10
+.factorypath
11
+.project
12
+.settings
13
+.springBeans
14
+.sts4-cache
15
+
16
+### IntelliJ IDEA ###
17
+.idea
18
+*.iws
19
+*.iml
20
+*.ipr
21
+
22
+### NetBeans ###
23
+/nbproject/private/
24
+/nbbuild/
25
+/dist/
26
+/nbdist/
27
+/.nb-gradle/
28
+build/
29
+!**/src/main/**/build/
30
+!**/src/test/**/build/
31
+
32
+### VS Code ###
33
+.vscode/
34
+/config/application.yml

BIN
.mvn/wrapper/maven-wrapper.jar


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

@@ -0,0 +1,2 @@
1
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
2
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar

+ 308 - 0
mvnw

@@ -0,0 +1,308 @@
1
+#!/bin/sh
2
+# ----------------------------------------------------------------------------
3
+# Licensed to the Apache Software Foundation (ASF) under one
4
+# or more contributor license agreements.  See the NOTICE file
5
+# distributed with this work for additional information
6
+# regarding copyright ownership.  The ASF licenses this file
7
+# to you under the Apache License, Version 2.0 (the
8
+# "License"); you may not use this file except in compliance
9
+# with the License.  You may obtain a copy of the License at
10
+#
11
+#    https://www.apache.org/licenses/LICENSE-2.0
12
+#
13
+# Unless required by applicable law or agreed to in writing,
14
+# software distributed under the License is distributed on an
15
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+# KIND, either express or implied.  See the License for the
17
+# specific language governing permissions and limitations
18
+# under the License.
19
+# ----------------------------------------------------------------------------
20
+
21
+# ----------------------------------------------------------------------------
22
+# Apache Maven Wrapper startup batch script, version 3.2.0
23
+#
24
+# Required ENV vars:
25
+# ------------------
26
+#   JAVA_HOME - location of a JDK home dir
27
+#
28
+# Optional ENV vars
29
+# -----------------
30
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
31
+#     e.g. to debug Maven itself, use
32
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34
+# ----------------------------------------------------------------------------
35
+
36
+if [ -z "$MAVEN_SKIP_RC" ] ; then
37
+
38
+  if [ -f /usr/local/etc/mavenrc ] ; then
39
+    . /usr/local/etc/mavenrc
40
+  fi
41
+
42
+  if [ -f /etc/mavenrc ] ; then
43
+    . /etc/mavenrc
44
+  fi
45
+
46
+  if [ -f "$HOME/.mavenrc" ] ; then
47
+    . "$HOME/.mavenrc"
48
+  fi
49
+
50
+fi
51
+
52
+# OS specific support.  $var _must_ be set to either true or false.
53
+cygwin=false;
54
+darwin=false;
55
+mingw=false
56
+case "$(uname)" in
57
+  CYGWIN*) cygwin=true ;;
58
+  MINGW*) mingw=true;;
59
+  Darwin*) darwin=true
60
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
61
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
62
+    if [ -z "$JAVA_HOME" ]; then
63
+      if [ -x "/usr/libexec/java_home" ]; then
64
+        JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
65
+      else
66
+        JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
67
+      fi
68
+    fi
69
+    ;;
70
+esac
71
+
72
+if [ -z "$JAVA_HOME" ] ; then
73
+  if [ -r /etc/gentoo-release ] ; then
74
+    JAVA_HOME=$(java-config --jre-home)
75
+  fi
76
+fi
77
+
78
+# For Cygwin, ensure paths are in UNIX format before anything is touched
79
+if $cygwin ; then
80
+  [ -n "$JAVA_HOME" ] &&
81
+    JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
82
+  [ -n "$CLASSPATH" ] &&
83
+    CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
84
+fi
85
+
86
+# For Mingw, ensure paths are in UNIX format before anything is touched
87
+if $mingw ; then
88
+  [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
89
+    JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
90
+fi
91
+
92
+if [ -z "$JAVA_HOME" ]; then
93
+  javaExecutable="$(which javac)"
94
+  if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
95
+    # readlink(1) is not available as standard on Solaris 10.
96
+    readLink=$(which readlink)
97
+    if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
98
+      if $darwin ; then
99
+        javaHome="$(dirname "\"$javaExecutable\"")"
100
+        javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
101
+      else
102
+        javaExecutable="$(readlink -f "\"$javaExecutable\"")"
103
+      fi
104
+      javaHome="$(dirname "\"$javaExecutable\"")"
105
+      javaHome=$(expr "$javaHome" : '\(.*\)/bin')
106
+      JAVA_HOME="$javaHome"
107
+      export JAVA_HOME
108
+    fi
109
+  fi
110
+fi
111
+
112
+if [ -z "$JAVACMD" ] ; then
113
+  if [ -n "$JAVA_HOME"  ] ; then
114
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
115
+      # IBM's JDK on AIX uses strange locations for the executables
116
+      JAVACMD="$JAVA_HOME/jre/sh/java"
117
+    else
118
+      JAVACMD="$JAVA_HOME/bin/java"
119
+    fi
120
+  else
121
+    JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
122
+  fi
123
+fi
124
+
125
+if [ ! -x "$JAVACMD" ] ; then
126
+  echo "Error: JAVA_HOME is not defined correctly." >&2
127
+  echo "  We cannot execute $JAVACMD" >&2
128
+  exit 1
129
+fi
130
+
131
+if [ -z "$JAVA_HOME" ] ; then
132
+  echo "Warning: JAVA_HOME environment variable is not set."
133
+fi
134
+
135
+# traverses directory structure from process work directory to filesystem root
136
+# first directory with .mvn subdirectory is considered project base directory
137
+find_maven_basedir() {
138
+  if [ -z "$1" ]
139
+  then
140
+    echo "Path not specified to find_maven_basedir"
141
+    return 1
142
+  fi
143
+
144
+  basedir="$1"
145
+  wdir="$1"
146
+  while [ "$wdir" != '/' ] ; do
147
+    if [ -d "$wdir"/.mvn ] ; then
148
+      basedir=$wdir
149
+      break
150
+    fi
151
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
152
+    if [ -d "${wdir}" ]; then
153
+      wdir=$(cd "$wdir/.." || exit 1; pwd)
154
+    fi
155
+    # end of workaround
156
+  done
157
+  printf '%s' "$(cd "$basedir" || exit 1; pwd)"
158
+}
159
+
160
+# concatenates all lines of a file
161
+concat_lines() {
162
+  if [ -f "$1" ]; then
163
+    # Remove \r in case we run on Windows within Git Bash
164
+    # and check out the repository with auto CRLF management
165
+    # enabled. Otherwise, we may read lines that are delimited with
166
+    # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
167
+    # splitting rules.
168
+    tr -s '\r\n' ' ' < "$1"
169
+  fi
170
+}
171
+
172
+log() {
173
+  if [ "$MVNW_VERBOSE" = true ]; then
174
+    printf '%s\n' "$1"
175
+  fi
176
+}
177
+
178
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
179
+if [ -z "$BASE_DIR" ]; then
180
+  exit 1;
181
+fi
182
+
183
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
184
+log "$MAVEN_PROJECTBASEDIR"
185
+
186
+##########################################################################################
187
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
188
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
189
+##########################################################################################
190
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
191
+if [ -r "$wrapperJarPath" ]; then
192
+    log "Found $wrapperJarPath"
193
+else
194
+    log "Couldn't find $wrapperJarPath, downloading it ..."
195
+
196
+    if [ -n "$MVNW_REPOURL" ]; then
197
+      wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
198
+    else
199
+      wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
200
+    fi
201
+    while IFS="=" read -r key value; do
202
+      # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
203
+      safeValue=$(echo "$value" | tr -d '\r')
204
+      case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
205
+      esac
206
+    done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
207
+    log "Downloading from: $wrapperUrl"
208
+
209
+    if $cygwin; then
210
+      wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
211
+    fi
212
+
213
+    if command -v wget > /dev/null; then
214
+        log "Found wget ... using wget"
215
+        [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
216
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
217
+            wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
218
+        else
219
+            wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
220
+        fi
221
+    elif command -v curl > /dev/null; then
222
+        log "Found curl ... using curl"
223
+        [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
224
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
225
+            curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
226
+        else
227
+            curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
228
+        fi
229
+    else
230
+        log "Falling back to using Java to download"
231
+        javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
232
+        javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
233
+        # For Cygwin, switch paths to Windows format before running javac
234
+        if $cygwin; then
235
+          javaSource=$(cygpath --path --windows "$javaSource")
236
+          javaClass=$(cygpath --path --windows "$javaClass")
237
+        fi
238
+        if [ -e "$javaSource" ]; then
239
+            if [ ! -e "$javaClass" ]; then
240
+                log " - Compiling MavenWrapperDownloader.java ..."
241
+                ("$JAVA_HOME/bin/javac" "$javaSource")
242
+            fi
243
+            if [ -e "$javaClass" ]; then
244
+                log " - Running MavenWrapperDownloader.java ..."
245
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
246
+            fi
247
+        fi
248
+    fi
249
+fi
250
+##########################################################################################
251
+# End of extension
252
+##########################################################################################
253
+
254
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
255
+wrapperSha256Sum=""
256
+while IFS="=" read -r key value; do
257
+  case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
258
+  esac
259
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
260
+if [ -n "$wrapperSha256Sum" ]; then
261
+  wrapperSha256Result=false
262
+  if command -v sha256sum > /dev/null; then
263
+    if echo "$wrapperSha256Sum  $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
264
+      wrapperSha256Result=true
265
+    fi
266
+  elif command -v shasum > /dev/null; then
267
+    if echo "$wrapperSha256Sum  $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
268
+      wrapperSha256Result=true
269
+    fi
270
+  else
271
+    echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
272
+    echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
273
+    exit 1
274
+  fi
275
+  if [ $wrapperSha256Result = false ]; then
276
+    echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
277
+    echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
278
+    echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
279
+    exit 1
280
+  fi
281
+fi
282
+
283
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
284
+
285
+# For Cygwin, switch paths to Windows format before running java
286
+if $cygwin; then
287
+  [ -n "$JAVA_HOME" ] &&
288
+    JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
289
+  [ -n "$CLASSPATH" ] &&
290
+    CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
291
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
292
+    MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
293
+fi
294
+
295
+# Provide a "standardized" way to retrieve the CLI args that will
296
+# work with both Windows and non-Windows executions.
297
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
298
+export MAVEN_CMD_LINE_ARGS
299
+
300
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
301
+
302
+# shellcheck disable=SC2086 # safe args
303
+exec "$JAVACMD" \
304
+  $MAVEN_OPTS \
305
+  $MAVEN_DEBUG_OPTS \
306
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
307
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
308
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 205 - 0
mvnw.cmd

@@ -0,0 +1,205 @@
1
+@REM ----------------------------------------------------------------------------
2
+@REM Licensed to the Apache Software Foundation (ASF) under one
3
+@REM or more contributor license agreements.  See the NOTICE file
4
+@REM distributed with this work for additional information
5
+@REM regarding copyright ownership.  The ASF licenses this file
6
+@REM to you under the Apache License, Version 2.0 (the
7
+@REM "License"); you may not use this file except in compliance
8
+@REM with the License.  You may obtain a copy of the License at
9
+@REM
10
+@REM    https://www.apache.org/licenses/LICENSE-2.0
11
+@REM
12
+@REM Unless required by applicable law or agreed to in writing,
13
+@REM software distributed under the License is distributed on an
14
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+@REM KIND, either express or implied.  See the License for the
16
+@REM specific language governing permissions and limitations
17
+@REM under the License.
18
+@REM ----------------------------------------------------------------------------
19
+
20
+@REM ----------------------------------------------------------------------------
21
+@REM Apache Maven Wrapper startup batch script, version 3.2.0
22
+@REM
23
+@REM Required ENV vars:
24
+@REM JAVA_HOME - location of a JDK home dir
25
+@REM
26
+@REM Optional ENV vars
27
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
28
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
29
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
30
+@REM     e.g. to debug Maven itself, use
31
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
32
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
33
+@REM ----------------------------------------------------------------------------
34
+
35
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
36
+@echo off
37
+@REM set title of command window
38
+title %0
39
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
40
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
41
+
42
+@REM set %HOME% to equivalent of $HOME
43
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
44
+
45
+@REM Execute a user defined script before this one
46
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
47
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
48
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
49
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
50
+:skipRcPre
51
+
52
+@setlocal
53
+
54
+set ERROR_CODE=0
55
+
56
+@REM To isolate internal variables from possible post scripts, we use another setlocal
57
+@setlocal
58
+
59
+@REM ==== START VALIDATION ====
60
+if not "%JAVA_HOME%" == "" goto OkJHome
61
+
62
+echo.
63
+echo Error: JAVA_HOME not found in your environment. >&2
64
+echo Please set the JAVA_HOME variable in your environment to match the >&2
65
+echo location of your Java installation. >&2
66
+echo.
67
+goto error
68
+
69
+:OkJHome
70
+if exist "%JAVA_HOME%\bin\java.exe" goto init
71
+
72
+echo.
73
+echo Error: JAVA_HOME is set to an invalid directory. >&2
74
+echo JAVA_HOME = "%JAVA_HOME%" >&2
75
+echo Please set the JAVA_HOME variable in your environment to match the >&2
76
+echo location of your Java installation. >&2
77
+echo.
78
+goto error
79
+
80
+@REM ==== END VALIDATION ====
81
+
82
+:init
83
+
84
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
85
+@REM Fallback to current working directory if not found.
86
+
87
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
88
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
89
+
90
+set EXEC_DIR=%CD%
91
+set WDIR=%EXEC_DIR%
92
+:findBaseDir
93
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
94
+cd ..
95
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
96
+set WDIR=%CD%
97
+goto findBaseDir
98
+
99
+:baseDirFound
100
+set MAVEN_PROJECTBASEDIR=%WDIR%
101
+cd "%EXEC_DIR%"
102
+goto endDetectBaseDir
103
+
104
+:baseDirNotFound
105
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
106
+cd "%EXEC_DIR%"
107
+
108
+:endDetectBaseDir
109
+
110
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
111
+
112
+@setlocal EnableExtensions EnableDelayedExpansion
113
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
114
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
115
+
116
+:endReadAdditionalConfig
117
+
118
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
119
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121
+
122
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
123
+
124
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
125
+    IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
126
+)
127
+
128
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
129
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
130
+if exist %WRAPPER_JAR% (
131
+    if "%MVNW_VERBOSE%" == "true" (
132
+        echo Found %WRAPPER_JAR%
133
+    )
134
+) else (
135
+    if not "%MVNW_REPOURL%" == "" (
136
+        SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
137
+    )
138
+    if "%MVNW_VERBOSE%" == "true" (
139
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
140
+        echo Downloading from: %WRAPPER_URL%
141
+    )
142
+
143
+    powershell -Command "&{"^
144
+		"$webclient = new-object System.Net.WebClient;"^
145
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
146
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
147
+		"}"^
148
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
149
+		"}"
150
+    if "%MVNW_VERBOSE%" == "true" (
151
+        echo Finished downloading %WRAPPER_JAR%
152
+    )
153
+)
154
+@REM End of extension
155
+
156
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
157
+SET WRAPPER_SHA_256_SUM=""
158
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
159
+    IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
160
+)
161
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
162
+    powershell -Command "&{"^
163
+       "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
164
+       "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
165
+       "  Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
166
+       "  Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
167
+       "  Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
168
+       "  exit 1;"^
169
+       "}"^
170
+       "}"
171
+    if ERRORLEVEL 1 goto error
172
+)
173
+
174
+@REM Provide a "standardized" way to retrieve the CLI args that will
175
+@REM work with both Windows and non-Windows executions.
176
+set MAVEN_CMD_LINE_ARGS=%*
177
+
178
+%MAVEN_JAVA_EXE% ^
179
+  %JVM_CONFIG_MAVEN_PROPS% ^
180
+  %MAVEN_OPTS% ^
181
+  %MAVEN_DEBUG_OPTS% ^
182
+  -classpath %WRAPPER_JAR% ^
183
+  "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
184
+  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
185
+if ERRORLEVEL 1 goto error
186
+goto end
187
+
188
+:error
189
+set ERROR_CODE=1
190
+
191
+:end
192
+@endlocal & set ERROR_CODE=%ERROR_CODE%
193
+
194
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
195
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
196
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
197
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
198
+:skipRcPost
199
+
200
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
201
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
202
+
203
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
204
+
205
+cmd /C exit /B %ERROR_CODE%

+ 154 - 0
pom.xml

@@ -0,0 +1,154 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4
+    <modelVersion>4.0.0</modelVersion>
5
+    <parent>
6
+        <groupId>org.springframework.boot</groupId>
7
+        <artifactId>spring-boot-starter-parent</artifactId>
8
+        <version>3.2.5</version>
9
+        <relativePath/> <!-- lookup parent from repository -->
10
+    </parent>
11
+    <groupId>com.lqkj</groupId>
12
+    <artifactId>link</artifactId>
13
+    <version>1.0.0.${timestamp}</version>
14
+    <name>LINK-SERVER</name>
15
+    <description>LINK-SERVER</description>
16
+    <properties>
17
+        <java.version>17</java.version>
18
+        <timestamp>${maven.build.timestamp}</timestamp>
19
+        <maven.build.timestamp.format>yyMMdd</maven.build.timestamp.format>
20
+    </properties>
21
+    <dependencies>
22
+        <dependency>
23
+            <groupId>org.springframework.boot</groupId>
24
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
25
+        </dependency>
26
+        <dependency>
27
+            <groupId>org.springframework.boot</groupId>
28
+            <artifactId>spring-boot-starter-security</artifactId>
29
+        </dependency>
30
+        <dependency>
31
+            <groupId>io.jsonwebtoken</groupId>
32
+            <artifactId>jjwt-api</artifactId>
33
+            <version>0.11.5</version>
34
+        </dependency>
35
+        <dependency>
36
+            <groupId>io.jsonwebtoken</groupId>
37
+            <artifactId>jjwt-impl</artifactId>
38
+            <version>0.11.5</version>
39
+        </dependency>
40
+        <dependency>
41
+            <groupId>io.jsonwebtoken</groupId>
42
+            <artifactId>jjwt-jackson</artifactId>
43
+            <version>0.11.5</version>
44
+        </dependency>
45
+        <dependency>
46
+            <groupId>jakarta.servlet</groupId>
47
+            <artifactId>jakarta.servlet-api</artifactId>
48
+            <version>6.1.0-M2</version>
49
+            <scope>provided</scope>
50
+        </dependency>
51
+        <dependency>
52
+            <groupId>com.alibaba.fastjson2</groupId>
53
+            <artifactId>fastjson2</artifactId>
54
+            <version>2.0.49</version>
55
+        </dependency>
56
+        <dependency>
57
+            <groupId>net.jodah</groupId>
58
+            <artifactId>expiringmap</artifactId>
59
+            <version>0.5.8</version>
60
+        </dependency>
61
+
62
+        <dependency>
63
+            <groupId>org.flywaydb</groupId>
64
+            <artifactId>flyway-core</artifactId>
65
+        </dependency>
66
+        <dependency>
67
+            <groupId>org.springframework.boot</groupId>
68
+            <artifactId>spring-boot-starter-test</artifactId>
69
+            <scope>test</scope>
70
+        </dependency>
71
+        <dependency>
72
+            <groupId>org.springframework.security</groupId>
73
+            <artifactId>spring-security-test</artifactId>
74
+            <scope>test</scope>
75
+        </dependency>
76
+        <dependency>
77
+            <groupId>org.projectlombok</groupId>
78
+            <artifactId>lombok</artifactId>
79
+            <optional>true</optional>
80
+        </dependency>
81
+        <dependency>
82
+            <groupId>org.bouncycastle</groupId>
83
+            <artifactId>bcprov-jdk18on</artifactId>
84
+            <version>1.78.1</version>
85
+        </dependency>
86
+        <dependency>
87
+            <groupId>org.apache.commons</groupId>
88
+            <artifactId>commons-lang3</artifactId>
89
+            <version>3.14.0</version>
90
+        </dependency>
91
+        <dependency>
92
+            <groupId>com.squareup.okhttp3</groupId>
93
+            <artifactId>okhttp</artifactId>
94
+            <version>4.12.0</version>
95
+        </dependency>
96
+        <dependency>
97
+            <groupId>io.undertow</groupId>
98
+            <artifactId>undertow-core</artifactId>
99
+            <version>2.3.13.Final</version>
100
+        </dependency>
101
+        <dependency>
102
+            <groupId>io.undertow</groupId>
103
+            <artifactId>undertow-servlet</artifactId>
104
+            <version>2.3.13.Final</version>
105
+        </dependency>
106
+
107
+        <dependency>
108
+            <groupId>org.hibernate.orm</groupId>
109
+            <artifactId>hibernate-spatial</artifactId>
110
+            <version>6.5.0.Final</version>
111
+        </dependency>
112
+        <dependency>
113
+            <groupId>org.postgresql</groupId>
114
+            <artifactId>postgresql</artifactId>
115
+            <version>42.7.3</version>
116
+        </dependency>
117
+        <dependency>
118
+            <groupId>org.springdoc</groupId>
119
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
120
+            <version>2.5.0</version>
121
+        </dependency>
122
+        <dependency>
123
+            <groupId>io.hypersistence</groupId>
124
+            <artifactId>hypersistence-utils-hibernate-63</artifactId>
125
+            <version>3.7.5</version>
126
+        </dependency>
127
+        <dependency>
128
+            <groupId>org.apache.commons</groupId>
129
+            <artifactId>commons-compress</artifactId>
130
+            <version>1.26.1</version>
131
+        </dependency>
132
+        <dependency>
133
+            <groupId>net.coobird</groupId>
134
+            <artifactId>thumbnailator</artifactId>
135
+            <version>0.4.20</version>
136
+        </dependency>
137
+        <dependency>
138
+            <groupId>org.apache.calcite</groupId>
139
+            <artifactId>calcite-core</artifactId>
140
+            <version>1.37.0</version>
141
+        </dependency>
142
+
143
+    </dependencies>
144
+
145
+    <build>
146
+        <plugins>
147
+            <plugin>
148
+                <groupId>org.springframework.boot</groupId>
149
+                <artifactId>spring-boot-maven-plugin</artifactId>
150
+            </plugin>
151
+        </plugins>
152
+    </build>
153
+
154
+</project>

+ 6 - 0
src/main/java/com/lqkj/link/APIVersion.java

@@ -0,0 +1,6 @@
1
+package com.lqkj.link;
2
+
3
+public class APIVersion {
4
+    public static final String VERSION_V1 = "v1";
5
+    public static final String VERSION_V2 = "v2";
6
+}

+ 28 - 0
src/main/java/com/lqkj/link/GlobalAsyncExceptionHandler.java

@@ -0,0 +1,28 @@
1
+package com.lqkj.link;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import org.slf4j.Logger;
5
+import org.slf4j.LoggerFactory;
6
+import org.springframework.web.context.request.NativeWebRequest;
7
+import org.springframework.web.context.request.async.CallableProcessingInterceptor;
8
+
9
+import java.util.concurrent.Callable;
10
+
11
+/**
12
+ * 异步全局异常处理
13
+ */
14
+public class GlobalAsyncExceptionHandler implements CallableProcessingInterceptor {
15
+
16
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
17
+
18
+    @Override
19
+    public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
20
+        return MessageBean.error("请求超时");
21
+    }
22
+
23
+    @Override
24
+    public <T> Object handleError(NativeWebRequest request, Callable<T> task, Throwable t) throws Exception {
25
+        logger.error("收到异常", t);
26
+        return MessageBean.error(t.toString());
27
+    }
28
+}

+ 25 - 0
src/main/java/com/lqkj/link/GlobalExceptionHandler.java

@@ -0,0 +1,25 @@
1
+package com.lqkj.link;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import org.slf4j.Logger;
5
+import org.slf4j.LoggerFactory;
6
+import org.springframework.web.bind.annotation.ControllerAdvice;
7
+import org.springframework.web.bind.annotation.ExceptionHandler;
8
+import org.springframework.web.bind.annotation.ResponseBody;
9
+
10
+/**
11
+ * 全局异常处理
12
+ */
13
+@ControllerAdvice
14
+public class GlobalExceptionHandler {
15
+
16
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
17
+
18
+    @ExceptionHandler
19
+    @ResponseBody
20
+    public MessageBean<String> resolveException(Exception e) {
21
+        logger.error("收到异常", e);
22
+
23
+        return MessageBean.error(e.toString());
24
+    }
25
+}

+ 23 - 0
src/main/java/com/lqkj/link/LinkServerApplication.java

@@ -0,0 +1,23 @@
1
+package com.lqkj.link;
2
+
3
+import com.lqkj.link.config.PropertyDeploy;
4
+import org.springframework.boot.Banner;
5
+import org.springframework.boot.SpringApplication;
6
+import org.springframework.boot.autoconfigure.SpringBootApplication;
7
+
8
+@SpringBootApplication
9
+public class LinkServerApplication {
10
+
11
+    public static void main(String[] args) {
12
+        // 生成配置文件
13
+        PropertyDeploy deploy=new PropertyDeploy();
14
+        deploy.deploy();
15
+
16
+        // 禁止actuator端点
17
+        SpringApplication app = new SpringApplication(LinkServerApplication.class);
18
+        app.setBannerMode(Banner.Mode.OFF);
19
+        app.setAddCommandLineProperties(false);
20
+        app.run(args);
21
+    }
22
+
23
+}

+ 53 - 0
src/main/java/com/lqkj/link/config/JwtAuthFilter.java

@@ -0,0 +1,53 @@
1
+package com.lqkj.link.config;
2
+
3
+import com.lqkj.link.module.jwt.service.JwtService;
4
+import com.lqkj.link.module.authority.service.DatabaseUserDetailService;
5
+import jakarta.servlet.FilterChain;
6
+import jakarta.servlet.ServletException;
7
+import jakarta.servlet.http.HttpServletRequest;
8
+import jakarta.servlet.http.HttpServletResponse;
9
+import org.jetbrains.annotations.NotNull;
10
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
11
+import org.springframework.security.core.context.SecurityContextHolder;
12
+import org.springframework.security.core.userdetails.UserDetails;
13
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
14
+import org.springframework.stereotype.Component;
15
+import org.springframework.web.filter.OncePerRequestFilter;
16
+
17
+import java.io.IOException;
18
+
19
+@Component
20
+public class JwtAuthFilter extends OncePerRequestFilter {
21
+
22
+    private final JwtService jwtService;
23
+    private final DatabaseUserDetailService userDetailService;
24
+
25
+    public JwtAuthFilter(JwtService jwtService, DatabaseUserDetailService userDetailService) {
26
+        this.jwtService = jwtService;
27
+        this.userDetailService = userDetailService;
28
+    }
29
+
30
+    @Override
31
+    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
32
+        String url = request.getRequestURI();
33
+        logger.info(url);
34
+
35
+        String authHeader = request.getHeader("Authorization");
36
+        String token = null;
37
+        String username = null;
38
+        if (authHeader != null && authHeader.startsWith("Bearer ")) {
39
+            token = authHeader.substring(7);
40
+            username = jwtService.extractUsername(token);
41
+        }
42
+
43
+        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
44
+            UserDetails userDetails = userDetailService.loadUserByUsername(username);
45
+            if (jwtService.validateToken(token, userDetails)) {
46
+                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
47
+                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
48
+                SecurityContextHolder.getContext().setAuthentication(authToken);
49
+            }
50
+        }
51
+        filterChain.doFilter(request, response);
52
+    }
53
+}

+ 53 - 0
src/main/java/com/lqkj/link/config/JwtTokenAdminInterceptor.java

@@ -0,0 +1,53 @@
1
+//package com.lqkj.link.config;
2
+//
3
+//import com.lqkj.link.util.JwtUtil;
4
+//import io.jsonwebtoken.Claims;
5
+//import io.jsonwebtoken.Jws;
6
+//import jakarta.servlet.http.HttpServletRequest;
7
+//import jakarta.servlet.http.HttpServletResponse;
8
+//import lombok.extern.slf4j.Slf4j;
9
+//import org.jetbrains.annotations.NotNull;
10
+//import org.springframework.beans.factory.annotation.Autowired;
11
+//import org.springframework.stereotype.Component;
12
+//import org.springframework.web.method.HandlerMethod;
13
+//import org.springframework.web.servlet.HandlerInterceptor;
14
+//@Component
15
+//@Slf4j
16
+//public class JwtTokenAdminInterceptor implements HandlerInterceptor {
17
+//
18
+//    public static final String SECRET = "zdvilXBILaMtQVtcJQ19ovIAo6GE1fEreTVYFXU1TZXg42Cc6AacW9fC1LV0u5Pc";
19
+//
20
+//    /**
21
+//     * 拦截器  校验jwt
22
+//     * @param request
23
+//     * @param response
24
+//     * @param handler
25
+//     * @return
26
+//     * @throws Exception
27
+//     */
28
+//
29
+//    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception{
30
+//        //判断当前拦截到的是Controller的方法还是其他资源
31
+//        if(!(handler instanceof HandlerMethod)){
32
+//            //当前拦截到的不是动态方法,直接放行
33
+//            return true;
34
+//        }
35
+//        //从请求头中获取令牌
36
+//        String token = request.getHeader("access_token");
37
+//        //校验令牌
38
+//        try{
39
+//            log.info("jwt校验:{}",token);
40
+//            Jws<Claims> claimsJws = JwtUtil.parseJWT(token, SECRET);
41
+//
42
+//            Long farId = Long.valueOf(claimsJws.getPayload().get(JwtClaimsConstant.FAR_ID).toString());
43
+//            log.info("当前农户id:{}",farId);
44
+//            BaseContext.setCurrentId(farId); //设置当前登录的用户id
45
+//            //放行
46
+//            return true;
47
+//        }catch (Exception e){
48
+//            //不通过,响应401状态码
49
+//            response.setStatus(HttpStatus.SC_UNAUTHORIZED);
50
+//            return false;
51
+//        }
52
+//    }
53
+//}

+ 19 - 0
src/main/java/com/lqkj/link/config/LimitRequest/LimitRequest.java

@@ -0,0 +1,19 @@
1
+package com.lqkj.link.config.LimitRequest;
2
+
3
+import java.lang.annotation.*;
4
+
5
+/**
6
+ * 限流注解
7
+ * 可以注解在controller类上和具体接口上
8
+ * 如果同时存在,以具体接口上的注解为准
9
+ * 注意:因为切面在类的注解上,所以controller上必须加注解
10
+ */
11
+
12
+@Documented
13
+@Target({ElementType.METHOD, ElementType.TYPE})
14
+@Retention(RetentionPolicy.RUNTIME)
15
+public @interface LimitRequest {
16
+    boolean limit() default true;
17
+    long time() default 1000;
18
+    int count() default 1;
19
+}

+ 74 - 0
src/main/java/com/lqkj/link/config/LimitRequest/LimitRequestAspect.java

@@ -0,0 +1,74 @@
1
+package com.lqkj.link.config.LimitRequest;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.util.RSAUtils;
5
+import jakarta.servlet.http.HttpServletRequest;
6
+import net.jodah.expiringmap.ExpirationPolicy;
7
+import net.jodah.expiringmap.ExpiringMap;
8
+import org.aspectj.lang.ProceedingJoinPoint;
9
+import org.aspectj.lang.annotation.Around;
10
+import org.aspectj.lang.annotation.Aspect;
11
+import org.aspectj.lang.annotation.Pointcut;
12
+import org.aspectj.lang.reflect.MethodSignature;
13
+import org.springframework.stereotype.Component;
14
+import org.springframework.web.context.request.RequestAttributes;
15
+import org.springframework.web.context.request.RequestContextHolder;
16
+import org.springframework.web.context.request.ServletRequestAttributes;
17
+
18
+import java.lang.reflect.Method;
19
+import java.util.concurrent.ConcurrentHashMap;
20
+import java.util.concurrent.TimeUnit;
21
+
22
+@Aspect
23
+@Component
24
+public class LimitRequestAspect {
25
+
26
+    private static final ConcurrentHashMap<String, ExpiringMap<String, Integer>> book = new ConcurrentHashMap<>();
27
+
28
+    @Pointcut(value = "@within(com.lqkj.link.config.LimitRequest.LimitRequest)")
29
+    public void excludeService() {
30
+
31
+    }
32
+
33
+    @Around(value = "excludeService()", argNames = "pjp")
34
+    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
35
+        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
36
+        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
37
+        assert sra != null;
38
+        HttpServletRequest request = sra.getRequest();
39
+
40
+        // 从header获取RSA加密后的AES KEY
41
+        String aesKey = request.getHeader("KEY");
42
+        aesKey = RSAUtils.decryptBase64(aesKey);
43
+
44
+        ExpiringMap<String, Integer> uc = book.getOrDefault(request.getRequestURI(), ExpiringMap.builder().variableExpiration().build());
45
+
46
+        Integer uCount = uc.getOrDefault(request.getRemoteAddr(), 0);
47
+
48
+        // 获取类上的注解
49
+        Class<?> clazz = pjp.getTarget().getClass();
50
+        LimitRequest limitRequest = clazz.getAnnotation(LimitRequest.class);
51
+
52
+        // 获取接口上的注解,如果有,以接口上的注解为准
53
+        MethodSignature ms = (MethodSignature) pjp.getSignature();
54
+        Method targetMethod = clazz.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
55
+
56
+        LimitRequest funLimitRequest = targetMethod.getAnnotation(LimitRequest.class);
57
+        if (funLimitRequest != null) {
58
+            limitRequest = funLimitRequest;
59
+        }
60
+
61
+        if (limitRequest.limit()) {
62
+            if (uCount >= limitRequest.count()) {
63
+                return MessageBean.error("接口请求超过次数");
64
+            } else if (uCount == 0) {
65
+                uc.put(request.getRemoteAddr(), uCount + 1, ExpirationPolicy.CREATED, limitRequest.time(), TimeUnit.MILLISECONDS);
66
+            } else {
67
+                uc.put(request.getRemoteAddr(), uCount + 1);
68
+            }
69
+            book.put(request.getRequestURI(), uc);
70
+        }
71
+
72
+        return pjp.proceed();
73
+    }
74
+}

+ 133 - 0
src/main/java/com/lqkj/link/config/OpenApiConfig.java

@@ -0,0 +1,133 @@
1
+package com.lqkj.link.config;
2
+
3
+import io.swagger.v3.oas.models.Components;
4
+import io.swagger.v3.oas.models.ExternalDocumentation;
5
+import io.swagger.v3.oas.models.OpenAPI;
6
+import io.swagger.v3.oas.models.info.Contact;
7
+import io.swagger.v3.oas.models.info.Info;
8
+import io.swagger.v3.oas.models.info.License;
9
+import io.swagger.v3.oas.models.security.SecurityRequirement;
10
+import io.swagger.v3.oas.models.security.SecurityScheme;
11
+import org.springdoc.core.models.GroupedOpenApi;
12
+import org.springframework.context.annotation.Bean;
13
+import org.springframework.context.annotation.Configuration;
14
+
15
+import java.util.List;
16
+import java.util.stream.Collectors;
17
+
18
+@Configuration
19
+public class OpenApiConfig {
20
+
21
+    @Bean
22
+    public OpenAPI customOpenAPI(){
23
+        return new OpenAPI()
24
+                .info(info())
25
+                .externalDocs(externalDocs())
26
+                .components(components())
27
+                .addSecurityItem(securityRequirement());
28
+    }
29
+
30
+    private Info info(){
31
+        return new Info()
32
+                .title("灵客空间")
33
+                .version("V1.0.0")
34
+                .description("LINK-SERVER API")
35
+                .license(new License()
36
+                        .name("Apache 2.0") // The Apache License, Version 2.0
37
+                        .url("https://www.apache.org/licenses/LICENSE-2.0.html"))
38
+                .contact(new Contact()
39
+                        .name("灵奇空间")
40
+                        .url("http://www.you07.com")
41
+                        .email("jc.top@qq.com"))
42
+                .termsOfService("http://www.you07.com")
43
+                ;
44
+    }
45
+
46
+    private ExternalDocumentation externalDocs() {
47
+        return new ExternalDocumentation()
48
+                .description("灵客空间")
49
+                .url("http://www.you07.com");
50
+    }
51
+
52
+    private Components components(){
53
+        return new Components()
54
+                .addSecuritySchemes("Bearer Authorization",
55
+                        new SecurityScheme()
56
+                                .name("Bearer 认证")
57
+                                .type(SecurityScheme.Type.HTTP)
58
+                                .scheme("bearer")
59
+                                .bearerFormat("JWT")
60
+                                .in(SecurityScheme.In.HEADER)
61
+                );
62
+
63
+    }
64
+
65
+    private SecurityRequirement securityRequirement() {
66
+        return new SecurityRequirement()
67
+                .addList("Bearer Authorization");
68
+    }
69
+
70
+    private List<SecurityRequirement> security(Components components) {
71
+        return components.getSecuritySchemes()
72
+                .keySet()
73
+                .stream()
74
+                .map(k -> new SecurityRequirement().addList(k))
75
+                .collect(Collectors.toList());
76
+    }
77
+
78
+
79
+    /**
80
+     * 通用接口
81
+     * @return
82
+     */
83
+    @Bean
84
+    public GroupedOpenApi publicApi(){
85
+        return GroupedOpenApi.builder()
86
+                .group("通用接口")
87
+                .pathsToMatch(
88
+                        "/jwt/**",
89
+                        "/encrypt/**")
90
+                .build();
91
+    }
92
+
93
+    /**
94
+     * 前端接口
95
+     * @return
96
+     */
97
+    @Bean
98
+    public GroupedOpenApi chaserApi(){
99
+        return GroupedOpenApi.builder()
100
+                .group("前端接口")
101
+                .pathsToMatch(
102
+                        "/user/v1/**",
103
+                        "/config/v1/**",
104
+                        "/zone/v1/**",
105
+                        "/geom/v1/**",
106
+                        "/audit/v1/**",
107
+                        "/notice/v1/**",
108
+                        "/layer/v1/**",
109
+                        "/resource/v1/**")
110
+                .build();
111
+    }
112
+
113
+    /**
114
+     * 管理接口
115
+     * @return
116
+     */
117
+    @Bean
118
+    public GroupedOpenApi supervisorApi(){
119
+        return GroupedOpenApi.builder()
120
+                .group("后端接口")
121
+                .pathsToMatch(
122
+                        "/user/authList",
123
+                        "/zone/template/**",
124
+                        "/resource/manage/**",
125
+                        "/audit/manage/**",
126
+                        "/user/manage/**",
127
+                        "/role/**",
128
+                        "/config/manage/**",
129
+                        "/bulletin/manage/**")
130
+                .build();
131
+    }
132
+
133
+}

+ 136 - 0
src/main/java/com/lqkj/link/config/PropertyDeploy.java

@@ -0,0 +1,136 @@
1
+package com.lqkj.link.config;
2
+
3
+import okio.BufferedSink;
4
+import okio.Okio;
5
+import org.apache.commons.lang3.StringUtils;
6
+import org.slf4j.Logger;
7
+import org.slf4j.LoggerFactory;
8
+import org.springframework.core.io.ClassPathResource;
9
+import org.yaml.snakeyaml.Yaml;
10
+
11
+import java.io.File;
12
+import java.io.IOException;
13
+import java.io.InputStream;
14
+import java.nio.file.Files;
15
+import java.nio.file.Paths;
16
+import java.util.LinkedHashMap;
17
+import java.util.Scanner;
18
+
19
+/**
20
+ * 环境文件部署
21
+ */
22
+public class PropertyDeploy {
23
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
24
+    public static final String PropertyDirPath = "./config";
25
+    public static final String PropertyFilePath = PropertyDirPath + "/application.yml";
26
+
27
+    /**
28
+     * 查询文件是否存在
29
+     *
30
+     * @return
31
+     */
32
+    private boolean isPropertyFileExist() {
33
+        return Files.exists(Paths.get(PropertyFilePath));
34
+    }
35
+
36
+    /**
37
+     * 数据库链接询问
38
+     */
39
+    private void inputDataBaseConfig() {
40
+        Scanner scanner = new Scanner(System.in);
41
+
42
+        System.out.println("请输入数据库IP:");
43
+        String ip = scanner.nextLine();
44
+
45
+        System.out.println("请输入数据库端口:");
46
+        String port = scanner.nextLine();
47
+
48
+        System.out.println("请输入数据库名称");
49
+        String dbName = scanner.nextLine();
50
+
51
+        System.out.println("请输入数据库用户名:");
52
+        String userName = scanner.nextLine();
53
+
54
+        System.out.println("请输入数据库密码");
55
+        String passWord = scanner.nextLine();
56
+
57
+        System.out.println("指定server绑定的地址");
58
+        String address = scanner.nextLine();
59
+
60
+        createConfigureFile(ip, port, dbName, userName, passWord, address);
61
+    }
62
+
63
+    /**
64
+     * 创建配置文件
65
+     */
66
+    public void createConfigureFile(String ip, String port, String dbName, String userName, String passWord, String address) {
67
+        if (StringUtils.isEmpty(ip)) {
68
+            ip = "127.0.0.1";
69
+        }
70
+        if (StringUtils.isEmpty(port)) {
71
+            port = "5432";
72
+        }
73
+        File applicationFile = new File(PropertyFilePath);
74
+
75
+        ClassPathResource resource = new ClassPathResource("application-install.yml");
76
+
77
+        Yaml yaml = new Yaml();
78
+
79
+        BufferedSink sink = null;
80
+
81
+        InputStream inputStream = null;
82
+
83
+        try {
84
+            Files.createDirectories(Paths.get(PropertyDirPath));
85
+
86
+            Files.createFile(Paths.get(PropertyFilePath));
87
+
88
+            inputStream = resource.getInputStream();
89
+
90
+            LinkedHashMap<String, LinkedHashMap> application = yaml.load(inputStream);
91
+
92
+            LinkedHashMap<String, Object> dateSource = (LinkedHashMap<String, Object>) application.get("spring").get("datasource");
93
+            LinkedHashMap<String, Object> hikari = (LinkedHashMap<String, Object>) dateSource.get("hikari");
94
+            dateSource.put("url", "jdbc:postgresql://" + ip + ":" + port + "/" + dbName);
95
+            hikari.put("username", userName);
96
+            hikari.put("password", passWord);
97
+
98
+            LinkedHashMap<String, Object> serverAddress = (LinkedHashMap<String, Object>) application.get("server");
99
+            serverAddress.put("address", address);
100
+
101
+            sink = Okio.buffer(Okio.sink(applicationFile));
102
+
103
+            sink.write(yaml.dump(application).getBytes());
104
+
105
+            sink.flush();
106
+        } catch (IOException e) {
107
+            e.printStackTrace();
108
+        } finally {
109
+            try {
110
+                if (sink != null) {
111
+                    sink.close();
112
+                }
113
+                if (inputStream != null) {
114
+                    inputStream.close();
115
+                }
116
+            } catch (Exception e) {
117
+                e.printStackTrace();
118
+            }
119
+        }
120
+    }
121
+
122
+
123
+    /**
124
+     * 部署文件
125
+     */
126
+    public void deploy() {
127
+        try {
128
+            if (!isPropertyFileExist()) {
129
+                inputDataBaseConfig();
130
+            }
131
+        } catch (Exception e) {
132
+            logger.error(e.getMessage(), e);
133
+        }
134
+
135
+    }
136
+}

+ 75 - 0
src/main/java/com/lqkj/link/config/WebMvcConfig.java

@@ -0,0 +1,75 @@
1
+package com.lqkj.link.config;
2
+
3
+import com.lqkj.link.GlobalAsyncExceptionHandler;
4
+import org.springframework.context.annotation.Bean;
5
+import org.springframework.context.annotation.Configuration;
6
+import org.springframework.http.CacheControl;
7
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
8
+import org.springframework.web.cors.CorsConfiguration;
9
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
10
+import org.springframework.web.filter.CorsFilter;
11
+import org.springframework.web.servlet.config.annotation.*;
12
+import org.springframework.web.servlet.mvc.WebContentInterceptor;
13
+
14
+import java.util.List;
15
+import java.util.concurrent.TimeUnit;
16
+
17
+@Configuration
18
+public class WebMvcConfig implements WebMvcConfigurer {
19
+
20
+    /**
21
+     * mvc异步线程池
22
+     */
23
+    @Override
24
+    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
25
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
26
+        executor.setCorePoolSize(4);
27
+        executor.setAllowCoreThreadTimeOut(false);
28
+        executor.setMaxPoolSize(200);
29
+        executor.setQueueCapacity(2000);
30
+        executor.setThreadNamePrefix("link-mvc-");
31
+        executor.initialize();
32
+        //10秒超时时间
33
+        configurer.setDefaultTimeout(1000 * 200);
34
+        configurer.registerCallableInterceptors(new GlobalAsyncExceptionHandler());
35
+        configurer.setTaskExecutor(executor);
36
+    }
37
+
38
+    /**
39
+     * 静态资源配置
40
+     */
41
+    @Override
42
+    public void addResourceHandlers(ResourceHandlerRegistry registry) {
43
+        registry.addResourceHandler("/upload/**")
44
+                .addResourceLocations("file:./upload/")
45
+                .setCacheControl(CacheControl.maxAge(0, TimeUnit.SECONDS));
46
+    }
47
+
48
+    /**
49
+     * 跨域配置
50
+     */
51
+    @Bean
52
+    public CorsFilter corsFilter() {
53
+        CorsConfiguration corsConfiguration = new CorsConfiguration();
54
+        corsConfiguration.setAllowCredentials(true);
55
+        corsConfiguration.addAllowedOriginPattern("*");
56
+        corsConfiguration.setAllowedHeaders(List.of("accept", "authorization", "content-type", "cache-control"));
57
+        corsConfiguration.setAllowedMethods(List.of("POST", "GET", "PUT", "OPTIONS", "DELETE"));
58
+        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
59
+        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
60
+        return new CorsFilter(urlBasedCorsConfigurationSource);
61
+    }
62
+
63
+    @Override
64
+    public void addInterceptors(InterceptorRegistry registry) {
65
+        WebContentInterceptor contentInterceptor = new WebContentInterceptor();
66
+        contentInterceptor.setCacheSeconds(0);
67
+        contentInterceptor.setUseExpiresHeader(true);
68
+        contentInterceptor.setUseCacheControlNoStore(false);
69
+        contentInterceptor.setUseCacheControlHeader(true);
70
+        contentInterceptor.setUseCacheControlNoStore(false);
71
+        registry.addInterceptor(contentInterceptor);
72
+    }
73
+
74
+
75
+}

+ 72 - 0
src/main/java/com/lqkj/link/config/WebSecurityConfig.java

@@ -0,0 +1,72 @@
1
+package com.lqkj.link.config;
2
+
3
+import com.lqkj.link.config.auth.LoginAuthenticationProvider;
4
+import com.lqkj.link.module.authority.service.DatabaseUserDetailService;
5
+import org.springframework.context.annotation.Bean;
6
+import org.springframework.context.annotation.Configuration;
7
+import org.springframework.security.authentication.AuthenticationManager;
8
+import org.springframework.security.authentication.AuthenticationProvider;
9
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
10
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
11
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
12
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
13
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
14
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
15
+import org.springframework.security.config.http.SessionCreationPolicy;
16
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
17
+import org.springframework.security.crypto.password.PasswordEncoder;
18
+import org.springframework.security.web.SecurityFilterChain;
19
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
20
+
21
+@Configuration
22
+@EnableWebSecurity
23
+@EnableMethodSecurity
24
+public class WebSecurityConfig {
25
+    private final JwtAuthFilter authFilter;
26
+    private final DatabaseUserDetailService userDetailService;
27
+
28
+    public WebSecurityConfig(JwtAuthFilter authFilter, DatabaseUserDetailService userDetailService) {
29
+        this.authFilter = authFilter;
30
+        this.userDetailService = userDetailService;
31
+    }
32
+
33
+    @Bean
34
+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
35
+        return http
36
+                .csrf(AbstractHttpConfigurer::disable)
37
+                .authorizeHttpRequests((requests) -> requests
38
+                        .requestMatchers(
39
+                                "/jwt/token",
40
+                                "/jwt/getAdminToken",
41
+                                "/encrypt/**",
42
+                                "/swagger-ui.html",
43
+                                "/swagger-ui/**",
44
+                                "/v3/api-docs/**",
45
+                                "/geom/all",
46
+                                "/upload/**")
47
+                        .permitAll()
48
+                        .requestMatchers("/**")
49
+                        .authenticated())
50
+                .sessionManagement((session) -> session
51
+                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS))
52
+                .authenticationProvider(authenticationProvider())
53
+                .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
54
+                .build();
55
+    }
56
+    @Bean
57
+    public PasswordEncoder passwordEncoder() {
58
+        return new BCryptPasswordEncoder();
59
+    }
60
+    @Bean
61
+    public AuthenticationProvider authenticationProvider(){
62
+        DaoAuthenticationProvider authenticationProvider=new LoginAuthenticationProvider(userDetailService, passwordEncoder());
63
+        authenticationProvider.setUserDetailsService(userDetailService);
64
+        authenticationProvider.setPasswordEncoder(passwordEncoder());
65
+        return authenticationProvider;
66
+    }
67
+    @Bean
68
+    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
69
+        return config.getAuthenticationManager();
70
+    }
71
+
72
+}

+ 47 - 0
src/main/java/com/lqkj/link/config/auth/LoginAuthenticationProvider.java

@@ -0,0 +1,47 @@
1
+package com.lqkj.link.config.auth;
2
+
3
+import com.lqkj.link.module.authority.service.DatabaseUserDetailService;
4
+import com.lqkj.link.util.RSAUtils;
5
+import org.springframework.security.authentication.BadCredentialsException;
6
+import org.springframework.security.authentication.LockedException;
7
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
8
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
9
+import org.springframework.security.core.AuthenticationException;
10
+import org.springframework.security.core.userdetails.UserDetails;
11
+import org.springframework.security.crypto.password.PasswordEncoder;
12
+
13
+/**
14
+ * oauth2验证
15
+ */
16
+public class LoginAuthenticationProvider extends DaoAuthenticationProvider {
17
+    private final PasswordEncoder passwordEncoder;
18
+    public LoginAuthenticationProvider(DatabaseUserDetailService userDetailsService, PasswordEncoder passwordEncoder) {
19
+        setUserDetailsService(userDetailsService);
20
+        this.passwordEncoder = passwordEncoder;
21
+    }
22
+
23
+    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
24
+        //在接收到符合权限的帐号密码后进行再处理
25
+        if (authentication.getCredentials() == null) {
26
+            this.logger.debug("Authentication failed: no credentials provided");
27
+            throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
28
+        } else {
29
+            String pw;
30
+            //如果位数为172则先解密
31
+            if (authentication.getCredentials().toString().length() != 172) {
32
+                this.logger.debug("Authentication failed: password length error");
33
+                throw new BadCredentialsException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
34
+            }
35
+            pw = RSAUtils.decryptBase64(authentication.getCredentials().toString());
36
+            DatabaseUserDetailService userDetailsService = (DatabaseUserDetailService) getUserDetailsService();
37
+            if (userDetailsService.isLocked(userDetails.getUsername())) {//账号是否被冻结
38
+                throw new LockedException("账号已被冻结,请稍后重试");
39
+            }
40
+            if (!passwordEncoder.matches(pw, userDetails.getPassword())) {
41
+                throw new LockedException(userDetailsService.lockedUser(userDetails.getUsername()));
42
+            }else {
43
+                userDetailsService.unlockedUser(userDetails.getUsername());
44
+            }
45
+        }
46
+    }
47
+}

+ 130 - 0
src/main/java/com/lqkj/link/config/auth/OauthAuthorizationConfig.java

@@ -0,0 +1,130 @@
1
+//package com.lqkj.link.config.auth;
2
+//
3
+//
4
+//import com.nimbusds.jose.jwk.JWKSet;
5
+//import com.nimbusds.jose.jwk.RSAKey;
6
+//import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
7
+//import com.nimbusds.jose.jwk.source.JWKSource;
8
+//import org.springframework.context.annotation.Bean;
9
+//import org.springframework.context.annotation.Configuration;
10
+//import org.springframework.core.annotation.Order;
11
+//import org.springframework.security.config.Customizer;
12
+//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
13
+//import org.springframework.security.core.userdetails.User;
14
+//import org.springframework.security.core.userdetails.UserDetails;
15
+//import org.springframework.security.core.userdetails.UserDetailsService;
16
+//import org.springframework.security.oauth2.core.AuthorizationGrantType;
17
+//import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
18
+//import org.springframework.security.oauth2.core.oidc.OidcScopes;
19
+//import org.springframework.security.oauth2.jwt.JwtDecoder;
20
+//import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
21
+//import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
22
+//import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
23
+//import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
24
+//import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
25
+//import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
26
+//import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
27
+//import org.springframework.security.provisioning.InMemoryUserDetailsManager;
28
+//import org.springframework.security.web.SecurityFilterChain;
29
+//import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
30
+//
31
+//import java.security.KeyPair;
32
+//import java.security.KeyPairGenerator;
33
+//import java.security.interfaces.RSAPrivateKey;
34
+//import java.security.interfaces.RSAPublicKey;
35
+//import java.util.UUID;
36
+//
37
+//@Configuration
38
+//public class OauthAuthorizationConfig {
39
+//    @Bean
40
+//    @Order(1)
41
+//    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
42
+//        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
43
+//        http
44
+//                .getConfigurer(OAuth2AuthorizationServerConfigurer.class)
45
+//                .oidc(Customizer.withDefaults());
46
+//
47
+//        http
48
+//                .oauth2ResourceServer(Customizer.withDefaults());
49
+//        return http.build();
50
+//    }
51
+//
52
+//    @Bean
53
+//    @Order(2)
54
+//    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
55
+//        http
56
+//                .authorizeHttpRequests((authorize) ->
57
+//                        authorize
58
+//                                .requestMatchers(
59
+//                                    new AntPathRequestMatcher("/oauth2/**"),
60
+//                                    new AntPathRequestMatcher("/**/*.html"))
61
+//                                .permitAll()
62
+//                                .anyRequest()
63
+//                                .authenticated());
64
+//
65
+//        return http.build();
66
+//    }
67
+//
68
+//    @Bean
69
+//    public UserDetailsService userDetailsService() {
70
+//        UserDetails userDetails = User.withDefaultPasswordEncoder()
71
+//                .username("test")
72
+//                .password("test")
73
+//                .roles("USER")
74
+//                .build();
75
+//
76
+//        return new InMemoryUserDetailsManager(userDetails);
77
+//    }
78
+//
79
+//    @Bean
80
+//    public RegisteredClientRepository registeredClientRepository() {
81
+//        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
82
+//                .clientId("link_server")
83
+//                .clientSecret("{noop}demo-client-secret")
84
+//                .authorizationGrantType(AuthorizationGrantType.PASSWORD)
85
+//                .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
86
+//                .scope("all")
87
+//                // 登录成功后对scope进行确认授权
88
+//                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
89
+//                .build();
90
+//
91
+//        return new InMemoryRegisteredClientRepository(registeredClient);
92
+//    }
93
+//
94
+//    @Bean
95
+//    public JWKSource jwkSource() {
96
+//        KeyPair keyPair = generateRsaKey();
97
+//        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
98
+//        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
99
+//        RSAKey rsaKey = new RSAKey
100
+//                .Builder(publicKey)
101
+//                .privateKey(privateKey)
102
+//                .keyID(UUID.randomUUID().toString())
103
+//                .build();
104
+//        JWKSet jwkSet = new JWKSet(rsaKey);
105
+//        return new ImmutableJWKSet<>(jwkSet);
106
+//    }
107
+//
108
+//    private static KeyPair generateRsaKey() {
109
+//        KeyPair keyPair;
110
+//        try {
111
+//            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
112
+//            keyPairGenerator.initialize(2048);
113
+//            keyPair = keyPairGenerator.generateKeyPair();
114
+//        }
115
+//        catch (Exception ex) {
116
+//            throw new IllegalStateException(ex);
117
+//        }
118
+//        return keyPair;
119
+//    }
120
+//
121
+//    @Bean
122
+//    public JwtDecoder jwtDecoder(JWKSource jwkSource) {
123
+//        return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
124
+//    }
125
+//
126
+//    @Bean
127
+//    public AuthorizationServerSettings authorizationServerSettings() {
128
+//        return AuthorizationServerSettings.builder().build();
129
+//    }
130
+//}

+ 24 - 0
src/main/java/com/lqkj/link/config/auth/OauthResourceConfig.java

@@ -0,0 +1,24 @@
1
+//package com.lqkj.link.config.auth;
2
+//
3
+//import org.springframework.context.annotation.Bean;
4
+//import org.springframework.context.annotation.Configuration;
5
+//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6
+//import org.springframework.security.oauth2.jwt.JwtDecoders;
7
+//import org.springframework.security.web.SecurityFilterChain;
8
+//
9
+//@Configuration
10
+//public class OauthResourceConfig {
11
+//
12
+//    @Bean
13
+//    public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception {
14
+//        return http
15
+//                .authorizeHttpRequests((authorize) -> authorize
16
+//                            .anyRequest()
17
+//                            .authenticated()
18
+//                )
19
+//                .oauth2ResourceServer(oauth2 -> oauth2
20
+//                        .jwt(jwt -> jwt.decoder(JwtDecoders.fromIssuerLocation())))
21
+//                .jwt();
22
+//
23
+//    }
24
+//}

+ 112 - 0
src/main/java/com/lqkj/link/message/MessageBaseBean.java

@@ -0,0 +1,112 @@
1
+package com.lqkj.link.message;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+
5
+import java.io.Serializable;
6
+import java.util.HashMap;
7
+import java.util.Map;
8
+
9
+/**
10
+ * 基础消息bean
11
+ * Created by free on 2017/7/27 0027.
12
+ */
13
+@Schema(description = "基础返回对象")
14
+public class MessageBaseBean implements Serializable {
15
+
16
+    public static final String NEXT_PAGE="nextPage";
17
+    /**
18
+     * 总页数
19
+     */
20
+    public static final String ALL_PAGE="allPage";
21
+    /**
22
+     * 当前页数
23
+     */
24
+    public static final String TOTAL_PAGE="totalPage";
25
+
26
+    /**
27
+     * 消息状态
28
+     */
29
+    @Schema(description = "消息状态")
30
+    private boolean status;
31
+
32
+    /**
33
+     * 消息时间戳
34
+     */
35
+    @Schema(description = "消息时间戳")
36
+    private long time;
37
+
38
+    /**
39
+     * 消息状态码
40
+     */
41
+    @Schema(description = "消息状态码")
42
+    private int code;
43
+
44
+    /**
45
+     * 提示信息
46
+     */
47
+    @Schema(description = "提示信息")
48
+    private String message;
49
+
50
+    /**
51
+     * 附加消息
52
+     */
53
+    @Schema(description = "附加消息")
54
+    private Map<String,Object> properties=new HashMap<String, Object>();
55
+
56
+    public boolean isStatus() {
57
+        return status;
58
+    }
59
+
60
+    public long getTime() {
61
+        return time;
62
+    }
63
+
64
+    public int getCode() {
65
+        return code;
66
+    }
67
+
68
+    public String getMessage() {
69
+        return message;
70
+    }
71
+
72
+    public Map<String, Object> getProperties() {
73
+        return properties;
74
+    }
75
+
76
+    public void setStatus(boolean status) {
77
+        this.status = status;
78
+    }
79
+
80
+    public void setTime(long time) {
81
+        this.time = time;
82
+    }
83
+
84
+    public void setCode(int code) {
85
+        this.code = code;
86
+    }
87
+
88
+    public void setMessage(String message) {
89
+        this.message = message;
90
+    }
91
+
92
+    public void setProperties(Map<String, Object> properties) {
93
+        this.properties = properties;
94
+    }
95
+
96
+    /**
97
+     * 增加一个附属信息
98
+     * @param key 附属信息的名称
99
+     * @param value 附属信息
100
+     */
101
+    public void addPropertie(String key,Object value){
102
+        this.properties.put(key,value);
103
+    }
104
+
105
+    /**
106
+     * 移除一个附属信息
107
+     * @param key 附属信息的名称
108
+     */
109
+    public void removePropertie(String key){
110
+        this.properties.remove(key);
111
+    }
112
+}

+ 59 - 0
src/main/java/com/lqkj/link/message/MessageBean.java

@@ -0,0 +1,59 @@
1
+package com.lqkj.link.message;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+
5
+import java.io.Serializable;
6
+
7
+/**
8
+ * 服务器单个信息bean
9
+ * Created by free on 2017/7/27 0027.
10
+ */
11
+@Schema(description = "单个实体返回对象")
12
+public class MessageBean<T> extends MessageBaseBean implements Serializable {
13
+
14
+    public MessageBean() {
15
+        this.setTime(System.currentTimeMillis());
16
+    }
17
+
18
+    public MessageBean(T data) {
19
+        this.data = data;
20
+        this.setTime(System.currentTimeMillis());
21
+    }
22
+
23
+    /**
24
+     * 被包含的消息实体
25
+     */
26
+    @Schema(description = "包含的数据")
27
+    private T data;
28
+
29
+    public T getData() {
30
+        return data;
31
+    }
32
+
33
+    public void setData(T data) {
34
+        this.data = data;
35
+    }
36
+
37
+    public static <T> MessageBean<T> ok() {
38
+        MessageBean<T> messageBean = new MessageBean<>();
39
+        messageBean.setStatus(true);
40
+        return messageBean;
41
+    }
42
+
43
+    public static <T> MessageBean<T> ok(T data, String message) {
44
+        MessageBean<T> messageBean = new MessageBean<>();
45
+        messageBean.setStatus(true);
46
+        messageBean.setData(data);
47
+        messageBean.setCode(200);
48
+        messageBean.setMessage(message);
49
+        return messageBean;
50
+    }
51
+
52
+    public static <T> MessageBean<T> error(String message) {
53
+        MessageBean<T> messageBean = new MessageBean<>();
54
+        messageBean.setStatus(false);
55
+        messageBean.setCode(-1);
56
+        messageBean.setMessage(message);
57
+        return messageBean;
58
+    }
59
+}

+ 68 - 0
src/main/java/com/lqkj/link/message/MessageListBean.java

@@ -0,0 +1,68 @@
1
+package com.lqkj.link.message;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+
5
+import java.io.Serializable;
6
+import java.util.ArrayList;
7
+import java.util.List;
8
+
9
+/**
10
+ * 服务器多个信息bean
11
+ * Created by free on 2017/7/27 0027.
12
+ */
13
+@Schema(description = "多个实体返回对象")
14
+public class MessageListBean<T> extends MessageBaseBean implements Serializable {
15
+
16
+    public MessageListBean() {
17
+        this.setTime(System.currentTimeMillis());
18
+    }
19
+
20
+    public MessageListBean(List<T> data) {
21
+        this.data = data;
22
+
23
+        this.setTime(System.currentTimeMillis());
24
+    }
25
+
26
+    /**
27
+     * 被包含的多个消息实体
28
+     */
29
+    @Schema(description = "包含的对象")
30
+    private List<T> data;
31
+
32
+    public List<T> getData() {
33
+        return data;
34
+    }
35
+
36
+    public void setData(List<T> data) {
37
+        this.data = data;
38
+    }
39
+
40
+    /**
41
+     * 增加一个数据
42
+     *
43
+     * @param data 数据
44
+     */
45
+    public void addData(T data) {
46
+        if (this.data == null) {
47
+            this.data = new ArrayList<T>(5);
48
+        }
49
+        this.data.add(data);
50
+    }
51
+
52
+    public static <T> MessageListBean<T> ok(List<T> data, String message) {
53
+        MessageListBean<T> messageListBean = new MessageListBean<>();
54
+        messageListBean.setStatus(true);
55
+        messageListBean.setData(data);
56
+        messageListBean.setCode(200);
57
+        messageListBean.setMessage(message);
58
+        return messageListBean;
59
+    }
60
+
61
+    public static <T> MessageListBean<T> error(String message) {
62
+        MessageListBean<T> messageListBean = new MessageListBean<>();
63
+        messageListBean.setStatus(false);
64
+        messageListBean.setCode(-1);
65
+        messageListBean.setMessage(message);
66
+        return messageListBean;
67
+    }
68
+}

+ 102 - 0
src/main/java/com/lqkj/link/module/audit/controller/AuditRecordController.java

@@ -0,0 +1,102 @@
1
+package com.lqkj.link.module.audit.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.module.audit.service.AuditRecordService;
5
+import com.lqkj.link.module.jwt.service.JwtService;
6
+import io.swagger.v3.oas.annotations.Operation;
7
+import io.swagger.v3.oas.annotations.Parameter;
8
+import io.swagger.v3.oas.annotations.tags.Tag;
9
+import jakarta.servlet.http.HttpServletRequest;
10
+import org.apache.commons.lang3.StringUtils;
11
+import org.springframework.data.domain.Page;
12
+import org.springframework.web.bind.annotation.PostMapping;
13
+import org.springframework.web.bind.annotation.RequestMapping;
14
+import org.springframework.web.bind.annotation.RequestParam;
15
+import org.springframework.web.bind.annotation.RestController;
16
+
17
+import java.util.List;
18
+import java.util.Map;
19
+
20
+import static com.lqkj.link.APIVersion.VERSION_V1;
21
+
22
+@RestController
23
+@RequestMapping("/audit")
24
+@Tag(name = "审核记录管理", description = "审核记录管理")
25
+public class AuditRecordController {
26
+
27
+    private final AuditRecordService auditRecordService;
28
+    private final JwtService jwtService;
29
+
30
+    public AuditRecordController(AuditRecordService auditRecordService, JwtService jwtService) {
31
+        this.auditRecordService = auditRecordService;
32
+        this.jwtService = jwtService;
33
+    }
34
+
35
+    @Operation(
36
+            summary = "5.1.3.9 审核记录分页接口",
37
+            description = "5.1.3.9 审核记录分页接口",
38
+            parameters = {
39
+                    @Parameter(name = "auditor", description = "审核员"),
40
+                    @Parameter(name = "author", description = "作者"),
41
+                    @Parameter(name = "authStatus", description = "审核状态,1待审核,2通过,3拒绝,4删除,5撤销"),
42
+                    @Parameter(name = "page", description = "页码"),
43
+                    @Parameter(name = "pageSize", description = "每页数据条数")
44
+            }
45
+    )
46
+    @PostMapping("/manage/pageQuery")
47
+    public MessageBean<Page<Map<String, Object>>> pageQuery(@RequestParam(required = false, defaultValue = "") String auditor,
48
+                                                             @RequestParam(required = false, defaultValue = "") String author,
49
+                                                             @RequestParam(required = false, defaultValue = "-1") Integer authStatus,
50
+                                                             @RequestParam(required = false, defaultValue = "0") Integer page,
51
+                                                             @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
52
+        return MessageBean.ok(auditRecordService.pageQuery(auditor, author, authStatus, page, pageSize), "审核记录分页接口");
53
+    }
54
+
55
+    @Operation(
56
+            summary = "5.1.3.10 审核记录删除接口",
57
+            description = "5.1.3.10 审核记录删除接口",
58
+            parameters = {
59
+                    @Parameter(name = "recordIds", required = true, description = "审核记录ID数组")
60
+            }
61
+    )
62
+    @PostMapping("/manage/delete")
63
+    public MessageBean delete(@RequestParam List<Integer> recordIds) {
64
+        auditRecordService.delete(recordIds);
65
+        return MessageBean.ok(null, "审核记录删除接口");
66
+    }
67
+
68
+    @Operation(
69
+            summary = "5.1.2.10 审核状态修改接口",
70
+            description = "5.1.2.10 审核状态修改接口",
71
+            parameters = {
72
+                    @Parameter(name = "recordId", description = "审核记录ID", required = true),
73
+                    @Parameter(name = "authStatus", description = "状态码,2通过,3拒绝,4删除", required = true)
74
+            }
75
+    )
76
+    @PostMapping("/" + VERSION_V1 + "/audit")
77
+    public MessageBean updateAuditStatus(@RequestParam Integer recordId,
78
+                                         @RequestParam Integer authStatus,
79
+                                         HttpServletRequest request) {
80
+        String authHeader = request.getHeader("Authorization");
81
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
82
+        String msg = auditRecordService.updateAuthStatus(recordId, authStatus, userCode);
83
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
84
+        return MessageBean.ok(null, "审核中心审核接口");
85
+    }
86
+
87
+    @Operation(
88
+            summary = "5.1.2.26 申请/撤销审核",
89
+            description = "5.1.2.26 申请/撤销审核",
90
+            parameters = {
91
+                    @Parameter(name = "zoneId", description = "作品/区域ID", required = true),
92
+                    @Parameter(name = "isApply", description = "是否是提交,true提交,false撤销", required = true)
93
+            }
94
+    )
95
+    @PostMapping("/" + VERSION_V1 + "/applyOrRevoke")
96
+    public MessageBean<String> applyOrRevoke(@RequestParam Integer zoneId,
97
+                                     @RequestParam Boolean isApply) {
98
+        String msg = auditRecordService.applyOrRevoke(zoneId, isApply);
99
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
100
+        return MessageBean.ok(null, "申请/撤销审核");
101
+    }
102
+}

+ 47 - 0
src/main/java/com/lqkj/link/module/audit/domain/AuditRecord.java

@@ -0,0 +1,47 @@
1
+package com.lqkj.link.module.audit.domain;
2
+
3
+import com.fasterxml.jackson.annotation.JsonFormat;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+import jakarta.persistence.*;
6
+import lombok.AllArgsConstructor;
7
+import lombok.Getter;
8
+import lombok.NoArgsConstructor;
9
+import lombok.Setter;
10
+
11
+import java.util.Date;
12
+
13
+@Entity
14
+@Table(name = "audit_record")
15
+@Getter
16
+@Setter
17
+@NoArgsConstructor
18
+@AllArgsConstructor
19
+public class AuditRecord {
20
+    @Id
21
+    @Column(name = "record_id")
22
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
23
+    @Schema(description = "审核记录ID")
24
+    private Integer recordId;
25
+    @Column(name = "zone_id")
26
+    @Schema(description = "区域/作品ID")
27
+    private Integer zoneId;
28
+    @Column(name = "user_id")
29
+    @Schema(description = "审核员用户ID")
30
+    private Integer userId;
31
+    @Column(name = "auth_status")
32
+    @Schema(description = "审核状态,1待审,2通过,3拒绝,4删除,5撤销")
33
+    private Integer authStatus;
34
+    @Column(name = "apply_time")
35
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
36
+    @Schema(description = "申请审核时间")
37
+    private Date applyTime;
38
+    @Column(name = "auth_time")
39
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
40
+    @Schema(description = "审核时间")
41
+    private Date authTime;
42
+    @Column(name = "delete_status")
43
+    private Boolean deleteStatus;
44
+    @Column(name = "delete_time")
45
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
46
+    private Date deleteTime;
47
+}

+ 57 - 0
src/main/java/com/lqkj/link/module/audit/repository/AuditRecordRepository.java

@@ -0,0 +1,57 @@
1
+package com.lqkj.link.module.audit.repository;
2
+
3
+import com.lqkj.link.module.audit.domain.AuditRecord;
4
+import org.springframework.data.domain.Page;
5
+import org.springframework.data.domain.Pageable;
6
+import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Modifying;
8
+import org.springframework.data.jpa.repository.Query;
9
+import org.springframework.data.repository.query.Param;
10
+import org.springframework.stereotype.Repository;
11
+
12
+import java.util.List;
13
+import java.util.Map;
14
+
15
+@Repository
16
+public interface AuditRecordRepository extends JpaRepository<AuditRecord, Integer> {
17
+
18
+    @Query(nativeQuery = true,
19
+            value = "select record_id as \"recordId\", aui.user_code as \"auditorId\", " +
20
+                        "aui.display_name as auditor, zi.zone_name as \"zoneName\", " +
21
+                        "aui1.user_code as \"authorId\", aui1.display_name as author, " +
22
+                        "to_char(ar.apply_time, 'yyyy-mm-dd hh24:mi:ss') as \"applyTime\", " +
23
+                        "to_char(ar.auth_time, 'yyyy-mm-dd hh24:mi:ss') as \"auditTime\", " +
24
+                        "ar.auth_status as \"authStatus\" " +
25
+                    "from audit_record ar " +
26
+                    "inner join zone_info zi on ar.zone_id = zi.zone_id " +
27
+                    "inner join user_info aui1 on zi.user_id = aui1.user_id " +
28
+                    "left join user_info aui on ar.user_id = aui.user_id " +
29
+                    "where (:auditor = '' or aui.display_name like concat('%', :auditor, '%')) " +
30
+                    "and (:author = '' or aui1.display_name like concat('%', :author, '%')) " +
31
+                    "and (:authStatus = -1 or ar.auth_status = :authStatus)" +
32
+                    "order by ar.auth_time desc, apply_time desc",
33
+            countQuery = "select count(*) " +
34
+                    "from audit_record ar " +
35
+                    "inner join zone_info zi on ar.zone_id = zi.zone_id " +
36
+                    "inner join user_info aui1 on zi.user_id = aui1.user_id " +
37
+                    "left join user_info aui on ar.user_id = aui.user_id " +
38
+                    "where (:auditor = '' or aui.display_name like concat('%', :auditor, '%')) " +
39
+                    "and (:author = '' or aui1.display_name like concat('%', :author, '%')) " +
40
+                    "and (:authStatus = -1 or (:authStatus = 4 and ar.delete_status is true) or ar.auth_status = :authStatus)"
41
+    )
42
+    Page<Map<String, Object>> pageQuery(@Param("auditor") String auditor,
43
+                                        @Param("author") String author,
44
+                                        @Param("authStatus") Integer authStatus,
45
+                                        Pageable pageable);
46
+
47
+    @Modifying
48
+    @Query(nativeQuery = true,
49
+        value = "update audit_record set auth_status = 4 where record_id in :recordIds"
50
+    )
51
+    void batchDelete(@Param("recordIds") List<Integer> recordIds);
52
+
53
+    @Query(nativeQuery = true,
54
+        value = "select * from audit_record where zone_id = :zoneId and auth_status = 1"
55
+    )
56
+    AuditRecord findAuditing(@Param("zoneId") Integer zoneId);
57
+}

+ 109 - 0
src/main/java/com/lqkj/link/module/audit/service/AuditRecordService.java

@@ -0,0 +1,109 @@
1
+package com.lqkj.link.module.audit.service;
2
+
3
+import com.lqkj.link.module.audit.domain.AuditRecord;
4
+import com.lqkj.link.module.audit.repository.AuditRecordRepository;
5
+import com.lqkj.link.module.authority.domain.UserInfo;
6
+import com.lqkj.link.module.authority.repository.UserInfoRepository;
7
+import com.lqkj.link.module.bulletin.repository.NoticeInfoRepository;
8
+import com.lqkj.link.module.zone.domain.ZoneInfo;
9
+import com.lqkj.link.module.zone.repository.ZoneInfoRepository;
10
+import org.springframework.data.domain.Page;
11
+import org.springframework.data.domain.PageRequest;
12
+import org.springframework.data.domain.Pageable;
13
+import org.springframework.stereotype.Service;
14
+import org.springframework.transaction.annotation.Transactional;
15
+
16
+import java.util.Date;
17
+import java.util.List;
18
+import java.util.Map;
19
+
20
+@Service
21
+public class AuditRecordService {
22
+    private final AuditRecordRepository auditRecordRepository;
23
+    private final ZoneInfoRepository zoneInfoRepository;
24
+    private final UserInfoRepository userInfoRepository;
25
+    private final NoticeInfoRepository noticeInfoRepository;
26
+
27
+    public AuditRecordService(AuditRecordRepository auditRecordRepository, ZoneInfoRepository zoneInfoRepository, UserInfoRepository userInfoRepository, NoticeInfoRepository noticeInfoRepository) {
28
+        this.auditRecordRepository = auditRecordRepository;
29
+        this.zoneInfoRepository = zoneInfoRepository;
30
+        this.userInfoRepository = userInfoRepository;
31
+        this.noticeInfoRepository = noticeInfoRepository;
32
+    }
33
+
34
+    public Page<Map<String, Object>> pageQuery(String auditor, String author, Integer authStatus, Integer page, Integer pageSize) {
35
+        Pageable pageable = PageRequest.of(page, pageSize);
36
+        return auditRecordRepository.pageQuery(auditor, author, authStatus, pageable);
37
+    }
38
+
39
+    @Transactional
40
+    public void delete(List<Integer> recordIds) {
41
+        auditRecordRepository.batchDelete(recordIds);
42
+    }
43
+
44
+    @Transactional
45
+    public String updateAuthStatus(Integer recordId, Integer authStatus, String auditor) {
46
+        if (!auditRecordRepository.existsById(recordId)) {
47
+            return "该作品已被作者删除!";
48
+        }
49
+        AuditRecord auditRecord = auditRecordRepository.findById(recordId).get();
50
+        if (auditRecord.getAuthStatus() == 5) {
51
+            return "该作品作者已撤销发布!";
52
+        }
53
+
54
+        if (authStatus == 2 || authStatus == 3) {
55
+            if (auditRecord.getAuthStatus() == 2 || auditRecord.getAuthStatus() == 3) {
56
+                return "该作品已被其他审核员完成审核,审核结果:" + (auditRecord.getAuthStatus() == 2 ? "通过" : "未通过");
57
+            }
58
+            auditRecord.setAuthStatus(authStatus);
59
+            UserInfo userInfo = userInfoRepository.findByUserCode(auditor);
60
+            auditRecord.setUserId(userInfo.getUserId());
61
+            auditRecord.setAuthTime(new Date());
62
+
63
+            // 向通知添加审核结果
64
+            ZoneInfo zoneInfo = zoneInfoRepository.findById(auditRecord.getZoneId()).get();
65
+            String content = "您的作品【" +
66
+                    zoneInfo.getZoneName() +
67
+                    "】" +
68
+                    (authStatus == 2 ? "审核已通过" : "审核未通过");
69
+            noticeInfoRepository.createAuditNotice(content, zoneInfo.getUserId());
70
+
71
+            // 同步更新到作品信息
72
+            zoneInfoRepository.updateAuthStatusWithAuditRecord(recordId, authStatus);
73
+        } else {
74
+            auditRecord.setDeleteTime(new Date());
75
+            auditRecord.setDeleteStatus(true);
76
+        }
77
+        auditRecordRepository.save(auditRecord);
78
+        return null;
79
+    }
80
+
81
+    @Transactional
82
+    public String applyOrRevoke(Integer zoneId, Boolean isApply) {
83
+        AuditRecord auditingRecord = auditRecordRepository.findAuditing(zoneId);
84
+        if (isApply) {
85
+            if (auditingRecord != null) {
86
+                return "该作品正在审核中,不能继续申请审核!";
87
+            }
88
+            AuditRecord auditRecord = new AuditRecord();
89
+            auditRecord.setZoneId(zoneId);
90
+            auditRecord.setAuthStatus(1);
91
+            auditRecord.setApplyTime(new Date());
92
+            auditRecord.setDeleteStatus(false);
93
+
94
+            auditRecordRepository.save(auditRecord);
95
+
96
+            zoneInfoRepository.updateAuthStatus(zoneId, 1);
97
+        } else {
98
+            if (auditingRecord == null) {
99
+                return "该作品未提交审核,不能撤销!";
100
+            }
101
+            auditingRecord.setAuthStatus(5);
102
+            auditRecordRepository.save(auditingRecord);
103
+
104
+            zoneInfoRepository.updateAuthStatus(zoneId, 0);
105
+        }
106
+
107
+        return null;
108
+    }
109
+}

+ 113 - 0
src/main/java/com/lqkj/link/module/authority/controller/RoleInfoController.java

@@ -0,0 +1,113 @@
1
+package com.lqkj.link.module.authority.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.message.MessageListBean;
5
+import com.lqkj.link.module.authority.domain.RoleInfo;
6
+import com.lqkj.link.module.authority.service.RoleInfoService;
7
+import com.lqkj.link.module.jwt.service.JwtService;
8
+import io.swagger.v3.oas.annotations.Operation;
9
+import io.swagger.v3.oas.annotations.Parameter;
10
+import io.swagger.v3.oas.annotations.media.Content;
11
+import io.swagger.v3.oas.annotations.media.Schema;
12
+import io.swagger.v3.oas.annotations.tags.Tag;
13
+import jakarta.servlet.http.HttpServletRequest;
14
+import org.apache.commons.lang3.StringUtils;
15
+import org.springframework.data.domain.Page;
16
+import org.springframework.web.bind.annotation.*;
17
+
18
+import java.util.List;
19
+import java.util.Map;
20
+
21
+@RestController
22
+@RequestMapping("/role")
23
+@Tag(name = "角色管理", description = "角色管理")
24
+public class RoleInfoController {
25
+    private final RoleInfoService roleInfoService;
26
+    private final JwtService jwtService;
27
+
28
+    public RoleInfoController(RoleInfoService roleInfoService, JwtService jwtService) {
29
+        this.roleInfoService = roleInfoService;
30
+        this.jwtService = jwtService;
31
+    }
32
+
33
+    @Operation(
34
+            summary = "5.3.14 角色列表接口",
35
+            description = "5.3.14 角色列表接口"
36
+    )
37
+    @PostMapping("/all")
38
+    public MessageListBean<RoleInfo> allRoles() {
39
+        return MessageListBean.ok(roleInfoService.allRoles(), "查询全部角色列表");
40
+    }
41
+
42
+    @Operation(
43
+            summary = "5.3.15 角色分页接口",
44
+            description = "5.3.15 角色分页接口",
45
+            parameters = {
46
+                    @Parameter(name = "roleName", description = "角色名称"),
47
+                    @Parameter(name = "page", description = "页码"),
48
+                    @Parameter(name = "pageSize", description = "每页数据条数")
49
+            }
50
+    )
51
+    @PostMapping("/pageQuery")
52
+    public MessageBean<Page<RoleInfo>> pageQuery(@RequestParam(required = false, defaultValue = "") String roleName,
53
+                                            @RequestParam(required = false, defaultValue = "0") Integer page,
54
+                                            @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
55
+        return MessageBean.ok(roleInfoService.pageQuery(roleName, page, pageSize), "角色分页接口");
56
+    }
57
+
58
+    @Operation(
59
+            summary = "5.1.3.29 获取角色详情接口",
60
+            description = "5.1.3.29 获取角色详情接口",
61
+            parameters = {
62
+                    @Parameter(name = "roleId", description = "角色ID", required = true)
63
+            }
64
+    )
65
+    @PostMapping("/detail")
66
+    public MessageBean<RoleInfo> detail(@RequestParam Integer roleId) {
67
+        return MessageBean.ok(roleInfoService.detail(roleId), "获取角色详情");
68
+    }
69
+
70
+    @Operation(
71
+            summary = "5.1.3.16 角色保存接口",
72
+            description = "5.1.3.16 角色保存接口",
73
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
74
+                    description = "角色信息实体",
75
+                    required = true,
76
+                    content = @Content(
77
+                            mediaType = "application/json",
78
+                            schema = @Schema(implementation = RoleInfo.class)
79
+                    )
80
+            )
81
+    )
82
+    @PostMapping("/save")
83
+    public MessageBean<String> save(@RequestBody RoleInfo roleInfo) {
84
+        String msg = roleInfoService.save(roleInfo);
85
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
86
+        return MessageBean.ok(null, "角色保存接口");
87
+    }
88
+
89
+    @Operation(
90
+            summary = "5.1.3.17 权限树接口",
91
+            description = "5.1.3.17 权限树接口"
92
+    )
93
+    @PostMapping("/authTree")
94
+    public MessageBean authTree(HttpServletRequest request) {
95
+        String authHeader = request.getHeader("Authorization");
96
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
97
+        return MessageBean.ok(roleInfoService.queryAuthTree(userCode), "获取权限树接口");
98
+    }
99
+
100
+    @Operation(
101
+            summary = "5.1.3.18 角色删除接口",
102
+            description = "5.1.3.18 角色删除接口",
103
+            parameters = {
104
+                    @Parameter(name = "roleIds", description = "角色ID列表")
105
+            }
106
+    )
107
+    @PostMapping("/delete")
108
+    public MessageBean<String> delete(@RequestParam List<Integer> roleIds) {
109
+        String msg = roleInfoService.delete(roleIds);
110
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error("角色【" + msg + "】需要先删除关联用户!");
111
+        return MessageBean.ok(null, "角色删除接口");
112
+    }
113
+}

+ 197 - 0
src/main/java/com/lqkj/link/module/authority/controller/UserInfoController.java

@@ -0,0 +1,197 @@
1
+package com.lqkj.link.module.authority.controller;
2
+
3
+import com.alibaba.fastjson2.JSON;
4
+import com.alibaba.fastjson2.JSONObject;
5
+import com.lqkj.link.message.MessageBean;
6
+import com.lqkj.link.module.authority.domain.UserInfo;
7
+import com.lqkj.link.module.authority.service.UserInfoService;
8
+import com.lqkj.link.module.base.service.BaseService;
9
+import com.lqkj.link.module.jwt.service.JwtService;
10
+import com.lqkj.link.util.AESUtils;
11
+import com.lqkj.link.util.RSAUtils;
12
+import io.swagger.v3.oas.annotations.Operation;
13
+import io.swagger.v3.oas.annotations.Parameter;
14
+import io.swagger.v3.oas.annotations.media.Content;
15
+import io.swagger.v3.oas.annotations.media.Schema;
16
+import io.swagger.v3.oas.annotations.tags.Tag;
17
+import jakarta.servlet.http.HttpServletRequest;
18
+import org.apache.commons.lang3.StringUtils;
19
+import org.springframework.data.domain.Page;
20
+import org.springframework.web.bind.annotation.*;
21
+import org.springframework.web.multipart.MultipartFile;
22
+
23
+import java.util.ArrayList;
24
+import java.util.List;
25
+import java.util.Map;
26
+
27
+import static com.lqkj.link.APIVersion.VERSION_V1;
28
+
29
+@RestController
30
+@RequestMapping("/user")
31
+@Tag(name = "用户管理", description = "用户管理")
32
+public class UserInfoController {
33
+    private final UserInfoService userInfoService;
34
+    private final JwtService jwtService;
35
+    private final BaseService baseService;
36
+
37
+    public UserInfoController(UserInfoService userInfoService, JwtService jwtService, BaseService baseService) {
38
+        this.userInfoService = userInfoService;
39
+        this.jwtService = jwtService;
40
+        this.baseService = baseService;
41
+    }
42
+
43
+    @Operation(
44
+            summary = "5.1.1.3 获取登录用户接口",
45
+            description = "5.1.1.3 获取登录用户接口"
46
+    )
47
+    @PostMapping("/" + VERSION_V1 + "/detail")
48
+    public MessageBean<UserInfo> detail(HttpServletRequest request) {
49
+        String authHeader = request.getHeader("Authorization");
50
+        String username = jwtService.decryptUsernameWithHeader(authHeader);
51
+        return MessageBean.ok(userInfoService.detailByUserCode(username), "获取登录用户");
52
+    }
53
+
54
+    @Operation(
55
+            summary = "5.1.3.24 获取管理菜单接口",
56
+            description = "5.1.3.24 获取管理菜单接口"
57
+    )
58
+    @PostMapping("/authList")
59
+    public MessageBean authList(HttpServletRequest request) {
60
+        String authHeader = request.getHeader("Authorization");
61
+        String username = jwtService.decryptUsernameWithHeader(authHeader);
62
+        return MessageBean.ok(userInfoService.findAuthListWithUserCode(username), "获取管理菜单接口");
63
+    }
64
+
65
+    @Operation(
66
+            summary = "5.1.3.11 用户分页接口",
67
+            description = "5.1.3.11 用户分页接口",
68
+            parameters = {
69
+                    @Parameter(name = "userCode", description = "用户账号"),
70
+                    @Parameter(name = "displayName", description = "用户名"),
71
+                    @Parameter(name = "page", description = "页码"),
72
+                    @Parameter(name = "pageSize", description = "每页数据条数"),
73
+                    @Parameter(name = "key", description = "RSA加密后的aesKey")
74
+            }
75
+    )
76
+    @PostMapping("/manage/pageQuery")
77
+    public MessageBean<JSONObject> pageQuery(@RequestParam(required = false, defaultValue = "") String userCode,
78
+                                                 @RequestParam(required = false, defaultValue = "") String displayName,
79
+                                                 @RequestParam(required = false, defaultValue = "0") Integer page,
80
+                                                 @RequestParam(required = false, defaultValue = "10") Integer pageSize,
81
+                                                 @RequestParam String key) throws Exception {
82
+        Page<UserInfo> userInfoPage = userInfoService.pageQuery(userCode, displayName, page, pageSize);
83
+        String aesKey = RSAUtils.decryptBase64(key);
84
+        List<UserInfo> list = new ArrayList<>();
85
+        for (UserInfo userInfo : userInfoPage.getContent()) {
86
+            list.add(AESUtils.encryptUser(userInfo, aesKey));
87
+        }
88
+        JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(userInfoPage));
89
+        jsonObject.put("content", list);
90
+        return MessageBean.ok(jsonObject, "用户分页接口");
91
+    }
92
+
93
+    @Operation(
94
+            summary = "5.1.3.28 用户详情接口",
95
+            description = "5.1.3.28 用户详情接口",
96
+            parameters = {
97
+                    @Parameter(name = "userId", required = true, description = "用户ID"),
98
+                    @Parameter(name = "key", description = "RSA加密后的aesKey")
99
+            }
100
+    )
101
+    @PostMapping("/manage/detail")
102
+    public MessageBean<UserInfo> detailById(@RequestParam Integer userId,
103
+                                            @RequestParam String key) throws Exception {
104
+        String aesKey = RSAUtils.decryptBase64(key);
105
+        return MessageBean.ok(AESUtils.encryptUser(userInfoService.detail(userId), aesKey), "用户详情接口");
106
+    }
107
+
108
+    @Operation(
109
+            summary = "5.1.3.12 保存用户接口",
110
+            description = "5.1.3.12 保存用户接口",
111
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
112
+                    description = "用户实体",
113
+                    required = true,
114
+                    content = @Content(
115
+                            mediaType = "application/json",
116
+                            schema = @Schema(implementation = UserInfo.class)
117
+                    )
118
+            )
119
+    )
120
+    @PostMapping("/manage/save")
121
+    public MessageBean save(@RequestBody UserInfo userInfo) {
122
+        userInfo.setUserCode(RSAUtils.decryptBase64(userInfo.getUserCode()));
123
+        if (StringUtils.isNotBlank(userInfo.getPassword()) && userInfo.getPassword().length() == 172) {
124
+            userInfo.setPassword(RSAUtils.decryptBase64(userInfo.getPassword()));
125
+        }
126
+        userInfo.setAuthorizationCode(RSAUtils.decryptBase64(userInfo.getAuthorizationCode()));
127
+        String message = userInfoService.save(userInfo);
128
+        if (message == null) return MessageBean.ok(null, "保存用户接口");
129
+        return MessageBean.error(message);
130
+    }
131
+
132
+    @Operation(
133
+            summary = "5.1.3.13 删除用户接口",
134
+            description = "5.1.3.13 删除用户接口",
135
+            parameters = {
136
+                    @Parameter(name = "userIds", required = true, description = "用户ID列表")
137
+            }
138
+    )
139
+    @PostMapping("/manage/delete")
140
+    public MessageBean delete(@RequestParam List<Integer> userIds) {
141
+        userInfoService.delete(userIds);
142
+        return MessageBean.ok(null, "删除用户接口");
143
+    }
144
+
145
+    @Operation(
146
+            summary = "5.1.2.12 上传头像",
147
+            description = "5.1.2.12 上传头像",
148
+            parameters = {
149
+                    @Parameter(name = "file", description = "图标文件", required = true)
150
+            }
151
+    )
152
+    @PostMapping("/" + VERSION_V1 + "/uploadHead")
153
+    public MessageBean<String> uploadImg(@RequestParam MultipartFile file) {
154
+        return baseService.uploadImg(file, "user/head/");
155
+    }
156
+
157
+    @Operation(
158
+            summary = "5.1.2.13 用户设置",
159
+            description = "5.1.2.13 用户设置",
160
+            parameters = {
161
+                    @Parameter(name = "displayName", description = "用户名称"),
162
+                    @Parameter(name = "headImgPath", description = "头像地址")
163
+            }
164
+    )
165
+    @PostMapping("/" + VERSION_V1 + "/updateInfo")
166
+    public MessageBean<String> saveUser(@RequestParam(required = false) String displayName,
167
+                                         @RequestParam(required = false) String headImgPath,
168
+                                         HttpServletRequest request) {
169
+        String authHeader = request.getHeader("Authorization");
170
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
171
+        userInfoService.updateInfo(userCode, displayName, headImgPath);
172
+        return MessageBean.ok(null, "更新用户信息");
173
+    }
174
+
175
+    @Operation(
176
+            summary = "5.1.2.38 检查是否需要刷新资源",
177
+            description = "5.1.2.38 检查是否需要刷新资源"
178
+    )
179
+    @PostMapping("/" + VERSION_V1 + "/checkRefreshResource")
180
+    public MessageBean<Boolean> checkRefreshResource(HttpServletRequest request) {
181
+        String authHeader = request.getHeader("Authorization");
182
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
183
+        return MessageBean.ok(userInfoService.checkRefreshResource(userCode), "检查是否需要刷新资源");
184
+    }
185
+
186
+    @Operation(
187
+            summary = "5.1.2.39 更新用户刷新资源状态",
188
+            description = "5.1.2.39 更新用户刷新资源状态"
189
+    )
190
+    @PostMapping("/" + VERSION_V1 + "/resourceRefreshed")
191
+    public MessageBean<String> resourceRefreshed(HttpServletRequest request) {
192
+        String authHeader = request.getHeader("Authorization");
193
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
194
+        userInfoService.resourceRefreshed(userCode);
195
+        return MessageBean.ok(null, "更新用户刷新资源状态");
196
+    }
197
+}

+ 16 - 0
src/main/java/com/lqkj/link/module/authority/domain/LoginBody.java

@@ -0,0 +1,16 @@
1
+package com.lqkj.link.module.authority.domain;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+import lombok.Getter;
5
+import lombok.Setter;
6
+
7
+@Getter
8
+@Setter
9
+public class LoginBody {
10
+    @Schema(description = "登录账号,RSA加密")
11
+    private String username;
12
+    @Schema(description = "登录密码,RSA加密")
13
+    private String password;
14
+    @Schema(description = "授权码,RSA加密")
15
+    private String authCode;
16
+}

+ 40 - 0
src/main/java/com/lqkj/link/module/authority/domain/RoleInfo.java

@@ -0,0 +1,40 @@
1
+package com.lqkj.link.module.authority.domain;
2
+
3
+import com.fasterxml.jackson.annotation.JsonFormat;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+import jakarta.persistence.*;
6
+import lombok.AllArgsConstructor;
7
+import lombok.Getter;
8
+import lombok.NoArgsConstructor;
9
+import lombok.Setter;
10
+
11
+import java.util.Date;
12
+import java.util.List;
13
+import java.util.Map;
14
+
15
+@Entity
16
+@Table(name = "role_info")
17
+@Getter
18
+@Setter
19
+@NoArgsConstructor
20
+@AllArgsConstructor
21
+public class RoleInfo {
22
+    @Id
23
+    @Column(name = "role_id")
24
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
25
+    @Schema(description = "角色ID")
26
+    private Integer roleId;
27
+    @Column(name = "role_name")
28
+    @Schema(description = "角色名称")
29
+    private String roleName;
30
+    @Column(name = "en_name")
31
+    @Schema(description = "")
32
+    private String enName;
33
+    @Column(name = "update_time")
34
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
35
+    private Date updateTime;
36
+    @Transient
37
+    private List<Integer> authorityList;
38
+    @Transient
39
+    private String auths;
40
+}

+ 119 - 0
src/main/java/com/lqkj/link/module/authority/domain/UserInfo.java

@@ -0,0 +1,119 @@
1
+package com.lqkj.link.module.authority.domain;
2
+
3
+import com.fasterxml.jackson.annotation.JsonFormat;
4
+import com.fasterxml.jackson.annotation.JsonIgnore;
5
+import com.fasterxml.jackson.annotation.JsonProperty;
6
+import io.swagger.v3.oas.annotations.media.Schema;
7
+import jakarta.persistence.*;
8
+import lombok.AllArgsConstructor;
9
+import lombok.Getter;
10
+import lombok.NoArgsConstructor;
11
+import lombok.Setter;
12
+import org.springframework.security.core.GrantedAuthority;
13
+import org.springframework.security.core.userdetails.UserDetails;
14
+
15
+import java.util.Collection;
16
+import java.util.Date;
17
+import java.util.List;
18
+
19
+@Entity
20
+@Table(name = "user_info")
21
+@Getter
22
+@Setter
23
+@NoArgsConstructor
24
+@AllArgsConstructor
25
+public class UserInfo implements UserDetails {
26
+    @Id
27
+    @Column(name = "user_id")
28
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
29
+    @Schema(description = "用户ID")
30
+    private Integer userId;
31
+    @Column(name = "user_code")
32
+    @Schema(description = "登录账号")
33
+    private String userCode;
34
+    @Column(name = "display_name")
35
+    @Schema(description = "显示名称")
36
+    private String displayName;
37
+    @Column(name = "password")
38
+    @Schema(description = "密码")
39
+    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
40
+    private String password;
41
+    @Column(name = "authorization_code")
42
+    @Schema(description = "授权码")
43
+    private String authorizationCode;
44
+    @Column(name = "head_img")
45
+    @Schema(description = "头像图片地址")
46
+    private String headImg;
47
+    @Column(name = "file_save_path")
48
+    @Schema(description = "文件存储路径")
49
+    private String fileSavePath;
50
+    @Transient
51
+    @Schema(description = "是否有审核权限")
52
+    private Boolean hasAuth;
53
+    @Column(name = "locking")
54
+    @Schema(description = "是否锁定")
55
+    @JsonIgnore
56
+    private Boolean locking;
57
+    @Column(name = "login_error_count")
58
+    @Schema(description = "登录错误次数")
59
+    @JsonIgnore
60
+    private Integer loginErrorCount;
61
+    @Column(name = "lock_time")
62
+    @Schema(description = "锁定时间")
63
+    @JsonIgnore
64
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
65
+    private Date lockTime;
66
+    @Column(name = "update_time")
67
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
68
+    @Schema(description = "更新时间")
69
+    private Date updateTime;
70
+    @Column(name = "has_manage")
71
+    @Schema(description = "是否能进入后台")
72
+    private Boolean hasManage;
73
+    @Transient
74
+    @Schema(description = "角色列表")
75
+    private List<RoleInfo> roleInfoList;
76
+    @Transient
77
+    @Schema(description = "角色ID数组")
78
+    private List<Integer> roleIds;
79
+    @Transient
80
+    private String roleNames;
81
+    @Column(name = "refresh_resource")
82
+    private Boolean refreshResource;
83
+
84
+    @Override
85
+    @JsonIgnore
86
+    public Collection<? extends GrantedAuthority> getAuthorities() {
87
+        return null;
88
+    }
89
+
90
+    @Override
91
+    @JsonIgnore
92
+    public String getUsername() {
93
+        return userCode;
94
+    }
95
+
96
+    @Override
97
+    @JsonIgnore
98
+    public boolean isAccountNonExpired() {
99
+        return true;
100
+    }
101
+
102
+    @Override
103
+    @JsonIgnore
104
+    public boolean isAccountNonLocked() {
105
+        return true;
106
+    }
107
+
108
+    @Override
109
+    @JsonIgnore
110
+    public boolean isCredentialsNonExpired() {
111
+        return true;
112
+    }
113
+
114
+    @Override
115
+    @JsonIgnore
116
+    public boolean isEnabled() {
117
+        return true;
118
+    }
119
+}

+ 126 - 0
src/main/java/com/lqkj/link/module/authority/repository/RoleInfoRepository.java

@@ -0,0 +1,126 @@
1
+package com.lqkj.link.module.authority.repository;
2
+
3
+import com.lqkj.link.module.authority.domain.RoleInfo;
4
+import org.springframework.data.domain.Page;
5
+import org.springframework.data.domain.Pageable;
6
+import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Modifying;
8
+import org.springframework.data.jpa.repository.Query;
9
+import org.springframework.data.repository.query.Param;
10
+import org.springframework.stereotype.Repository;
11
+
12
+import java.util.List;
13
+import java.util.Map;
14
+
15
+@Repository
16
+public interface RoleInfoRepository extends JpaRepository<RoleInfo, Integer> {
17
+
18
+    @Query(nativeQuery = true,
19
+        value = "select ri.* from role_info ri, user_role ur where ur.user_id = :userId and ur.role_id = ri.role_id order by ri.role_id"
20
+    )
21
+    List<RoleInfo> listWithUserId(@Param("userId") Integer userId);
22
+
23
+    @Query(nativeQuery = true,
24
+        value = "select string_agg(ri.role_name, ',') from user_role ur, role_info ri where ur.role_id = ri.role_id and ur.user_id = :userId"
25
+    )
26
+    String findRoleNames(@Param("userId") Integer userId);
27
+
28
+    @Modifying
29
+    @Query(nativeQuery = true,
30
+        value = "with t1 as(delete from user_role where user_id = :userId and role_id not in :roleIds)" +
31
+                "insert into user_role(role_id, user_id) " +
32
+                "select role_id, :userId from role_info where role_id in :roleIds " +
33
+                "on conflict (role_id, user_id) do nothing "
34
+    )
35
+    void updateUserRole(@Param("userId") Integer userId,
36
+                        @Param("roleIds") List<Integer> roleIds);
37
+
38
+    @Query(nativeQuery = true,
39
+            value = "with t1 as(select * from role_info where role_name like concat('%', :roleName, '%')), " +
40
+                    "t2 as(select ra.role_id, string_agg(distinct(authority_name), ',') as auths from role_authority ra, authority_info ai " +
41
+                        "where ra.authority_id = ai.authority_id " +
42
+                            "and ra.role_id in (select role_id from t1) " +
43
+                        "group by ra.role_id) " +
44
+                    "select t1.role_id as \"roleId\", t1.role_name as \"roleName\", t2.auths, " +
45
+                        "to_char(t1.update_time, 'yyyy-mm-dd hh24:mi:ss') as \"updateTime\" " +
46
+                    "from t1, t2 where t1.role_id = t2.role_id " +
47
+                    "order by t1.role_id")
48
+    Page<Map<String, Object>> pageQuery(@Param("roleName") String roleName,
49
+                                        Pageable pageable);
50
+
51
+    @Query(nativeQuery = true,
52
+            value = "select * from role_info where role_name like concat('%', :roleName, '%') and role_id != 1 order by role_id")
53
+    Page<RoleInfo> pageQueryV2(@Param("roleName") String roleName,
54
+                                        Pageable pageable);
55
+
56
+    @Query(nativeQuery = true,
57
+        value = "select * from role_info where role_id != 1 order by role_id"
58
+    )
59
+    List<RoleInfo> queryAll();
60
+
61
+    @Query(nativeQuery = true,
62
+        value = "select string_agg(distinct (authority_name), ',') " +
63
+                "from role_authority ra , authority_info ai " +
64
+                "where ra.role_id = :roleId and ra.authority_id = ai.authority_id"
65
+    )
66
+    String queryAuthNamesWithRole(@Param("roleId") Integer roleId);
67
+
68
+    @Query(nativeQuery = true,
69
+        value = "select ai.authority_id from authority_info ai, role_authority ra " +
70
+                "where ra.role_id = :roleId and ai.authority_id = ra.authority_id " +
71
+                "order by ai.authority_id"
72
+    )
73
+    List<Map<String, Object>> queryAuthsWithRole(@Param("roleId") Integer roleId);
74
+
75
+    @Query(nativeQuery = true,
76
+        value = "select count(*) > 0 from role_info where en_name = :enName"
77
+    )
78
+    Boolean hasSameEnName(@Param("enName") String enName);
79
+
80
+    @Query(nativeQuery = true,
81
+            value = "select count(*) > 0 from role_info where role_name = :roleName"
82
+    )
83
+    Boolean hasSameName(@Param("roleName") String roleName);
84
+
85
+    @Query(nativeQuery = true,
86
+            value = "select count(*) > 0 from role_info where en_name = :enName and role_id != :roleId"
87
+    )
88
+    Boolean hasSameEnNameWithoutOneId(@Param("enName") String enName,
89
+                                      @Param("roleId") Integer roleId);
90
+
91
+    @Query(nativeQuery = true,
92
+            value = "select count(*) > 0 from role_info where role_name = :roleName and role_id != :roleId"
93
+    )
94
+    Boolean hasSameNameWithoutOneId(@Param("roleName") String roleName,
95
+                                    @Param("roleId") Integer roleId);
96
+
97
+    @Modifying
98
+    @Query(nativeQuery = true,
99
+        value = "with t1 as (delete from role_authority where role_id = :roleId and authority_id not in :authorityIds)" +
100
+                "insert into role_authority(role_id, authority_id) " +
101
+                "select :roleId, authority_id from authority_info where authority_id in :authorityIds " +
102
+                "on conflict (role_id, authority_id) do nothing "
103
+    )
104
+    void updateRoleAuthority(@Param("roleId") Integer roleId,
105
+                             @Param("authorityIds") List<Integer> authorityIds);
106
+
107
+    @Query(nativeQuery = true,
108
+        value = "select ai.authority_id, ai.parent_id, ai.authority_name " +
109
+                "from authority_info ai, role_authority ra , user_role ur , user_info ui " +
110
+                "where ai.authority_id = ra.authority_id " +
111
+                    "and ra.role_id = ur.role_id " +
112
+                    "and ur.user_id = ui.user_id " +
113
+                    "and ui.user_code = :userCode " +
114
+                "order by ai.parent_id, ai.authority_id"
115
+    )
116
+    List<Map<String, Object>> queryAuthsByUser(String userCode);
117
+
118
+
119
+    @Modifying
120
+    @Query(nativeQuery = true,
121
+        value = "with t1 as(select distinct (role_id) as role_id from user_role where role_id in :roleIds)," +
122
+                "t2 as(delete from role_info where role_id in :roleIds and role_id not in (select role_id from t1))" +
123
+                "select string_agg(role_name, ',') from role_info where role_id in (select role_id from t1)"
124
+    )
125
+    String deleteNoUserRole(List<Integer> roleIds);
126
+}

+ 106 - 0
src/main/java/com/lqkj/link/module/authority/repository/UserInfoRepository.java

@@ -0,0 +1,106 @@
1
+package com.lqkj.link.module.authority.repository;
2
+
3
+import com.lqkj.link.module.authority.domain.UserInfo;
4
+import org.springframework.data.domain.Page;
5
+import org.springframework.data.domain.Pageable;
6
+import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Modifying;
8
+import org.springframework.data.jpa.repository.Query;
9
+import org.springframework.data.repository.query.Param;
10
+import org.springframework.stereotype.Repository;
11
+import org.springframework.transaction.annotation.Transactional;
12
+
13
+import java.util.List;
14
+import java.util.Map;
15
+
16
+@Repository
17
+public interface UserInfoRepository extends JpaRepository<UserInfo, Integer> {
18
+
19
+    @Query(nativeQuery = true,
20
+            value = "select * from user_info t where user_code = :userCode")
21
+    UserInfo findByUserCode(@Param("userCode") String userCode);
22
+
23
+    @Modifying
24
+    @Query(nativeQuery = true,
25
+            value = "update user_info set login_error_count = 0, locking = false, lock_time = null where user_id = :userId")
26
+    void cleanLockStatus(@Param("userId") Integer userId);
27
+
28
+    @Transactional
29
+    @Modifying
30
+    @Query(nativeQuery = true,
31
+        value = "INSERT INTO user_info (user_id, user_code, display_name, password, authorization_code, head_img, " +
32
+                    "file_save_path, has_auth, login_error_count, locking, lock_time, update_time, has_manage, refresh_resource) " +
33
+                "VALUES (1, 'meta-link', '灵客空间', '$2a$10$e8TpJcnGtGcagLLDaL06h.W.JFtPknOl4Kxeur22rO8m7Ihz6.uzS', '87449007', " +
34
+                "NULL, NULL, NULL, NULL, 'f', NULL, now(), 't', 'f');"
35
+    )
36
+    void initSuperAdmin();
37
+
38
+    @Transactional
39
+    @Modifying
40
+    @Query(nativeQuery = true,
41
+        value = "insert into user_role values (1, 1)"
42
+    )
43
+    void initSuperAdminRole();
44
+
45
+    @Query(nativeQuery = true,
46
+        value = "select count(*) = 1 " +
47
+                "from user_info natural join user_role natural join role_authority " +
48
+                "where user_id = :userId and authority_id = 6 "
49
+    )
50
+    Boolean hasAuth(Integer userId);
51
+
52
+    @Query(nativeQuery = true,
53
+        value = "select ai.authority_id, en_name as \"name\", route as \"path\", component, redirect, authority_name as title, icon, parent_id " +
54
+                "from authority_info ai, role_authority ra, user_role ur, user_info ui " +
55
+                "where ui.user_code = :userCode " +
56
+                    "and ur.user_id = ui.user_id " +
57
+                    "and ur.role_id = ra.role_id " +
58
+                    "and ra.authority_id = ai.authority_id " +
59
+                "order by ai.parent_id, ai.order_id"
60
+    )
61
+    List<Map<String, Object>> queryAuthWithUserCode(String userCode);
62
+
63
+    @Query(nativeQuery = true,
64
+        value = "with t1 as (select * from user_info where user_id != 1 " +
65
+                    "and (:userCode = '' or user_code like concat('%', :userCode, '%')) " +
66
+                    "and (:displayName = '' or display_name like concat('%', :displayName, '%')))," +
67
+                "t2 as (select user_id, string_agg(role_name, ',') as role_names " +
68
+                    "from user_role ur, role_info ri " +
69
+                    "where ur.user_id in (select user_id from t1) and ur.role_id = ri.role_id " +
70
+                    "group by user_id) " +
71
+                "select t1.user_id as \"userId\", t1.user_code as \"userCode\", t1.display_name as \"displayName\", " +
72
+                "t2.role_names as roles, to_char(t1.update_time, 'yyyy-mm-dd hh24:mi:ss') as \"updateTime\" " +
73
+                "from t1, t2 where t1.user_id = t2.user_id order by t1.update_time desc"
74
+    )
75
+    Page<Map<String, Object>> pageQuery(@Param("userCode") String userCode,
76
+                                        @Param("displayName") String displayName,
77
+                                        Pageable pageable);
78
+
79
+    @Query(nativeQuery = true,
80
+        value = "select * from user_info " +
81
+                "where user_id != 1 " +
82
+                "and (:userCode = '' or user_code like concat('%', :userCode, '%')) " +
83
+                "and (:displayName = '' or display_name like concat('%', :displayName, '%')) " +
84
+                "order by update_time desc"
85
+    )
86
+    Page<UserInfo> pageQueryV2(@Param("userCode") String userCode,
87
+                             @Param("displayName") String displayName,
88
+                             Pageable pageable);
89
+
90
+    @Query(nativeQuery = true,
91
+        value = "select count(*) > 0 from user_info where user_code = :userCode"
92
+    )
93
+    Boolean hasSameUserCode(@Param("userCode") String userCode);
94
+
95
+    @Modifying
96
+    @Query(nativeQuery = true,
97
+        value = "update user_info set refresh_resource = true"
98
+    )
99
+    void updateRefreshStatus();
100
+
101
+    @Modifying
102
+    @Query(nativeQuery = true,
103
+            value = "update user_info set refresh_resource = false where user_code = :userCode"
104
+    )
105
+    void resourceRefreshed();
106
+}

+ 101 - 0
src/main/java/com/lqkj/link/module/authority/service/DatabaseUserDetailService.java

@@ -0,0 +1,101 @@
1
+package com.lqkj.link.module.authority.service;
2
+
3
+import com.lqkj.link.module.authority.domain.UserInfo;
4
+import com.lqkj.link.module.authority.repository.UserInfoRepository;
5
+import com.lqkj.link.util.RSAUtils;
6
+import org.springframework.transaction.annotation.Transactional;
7
+import org.springframework.security.core.userdetails.UserDetails;
8
+import org.springframework.security.core.userdetails.UserDetailsService;
9
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
10
+import org.springframework.stereotype.Service;
11
+
12
+import java.util.Date;
13
+
14
+@Service
15
+public class DatabaseUserDetailService implements UserDetailsService {
16
+
17
+    private final UserInfoRepository userInfoRepository;
18
+
19
+    public DatabaseUserDetailService(UserInfoRepository userInfoRepository) {
20
+        this.userInfoRepository = userInfoRepository;
21
+    }
22
+
23
+    @Override
24
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
25
+        if (username.length() != 172) throw new UsernameNotFoundException("用户名错误!");
26
+        try {
27
+            username = RSAUtils.decryptBase64(username);
28
+        } catch (Exception e) {
29
+            throw new UsernameNotFoundException("用户名错误!");
30
+        }
31
+        UserInfo userInfo = userInfoRepository.findByUserCode(username);
32
+        if (userInfo == null) {
33
+            throw new UsernameNotFoundException("用户名不存在!");
34
+        }
35
+        return userInfo;
36
+    }
37
+
38
+    /**
39
+     * 账号是否锁定
40
+     * @param userCode
41
+     * @return
42
+     */
43
+    @Transactional
44
+    public boolean isLocked(String userCode) {
45
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
46
+        if (userInfo == null){
47
+            return false;
48
+        }else {
49
+            if (userInfo.getLocking()) {
50
+                if (new Date().getTime() - userInfo.getLockTime().getTime() > 1000 * 60 * 60){
51
+                    userInfoRepository.cleanLockStatus(userInfo.getUserId());
52
+                    return false;
53
+                }else{
54
+                    return true;
55
+                }
56
+            }else{
57
+                return false;
58
+            }
59
+        }
60
+    }
61
+
62
+    /**
63
+     * 更新登录错误次数
64
+     * @param userCode
65
+     * @return
66
+     */
67
+    @Transactional
68
+    public String lockedUser(String userCode){
69
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
70
+        if (userInfo == null){
71
+            return "用户名或密码错误";
72
+        }else{
73
+            int loginErrorCount = userInfo.getLoginErrorCount() == null ? 0 : userInfo.getLoginErrorCount();
74
+            loginErrorCount += 1;
75
+            userInfo.setLoginErrorCount(loginErrorCount);
76
+            if (loginErrorCount == 4){
77
+                userInfo.setLocking(true);
78
+                userInfo.setLockTime(new Date());
79
+                userInfoRepository.save(userInfo);
80
+                return "账号已被冻结,请稍后重试";
81
+            }
82
+            userInfoRepository.save(userInfo);
83
+            return "用户名或密码错误," + (4 - loginErrorCount) +"次错误后,账号将会冻结1小时";
84
+        }
85
+    }
86
+
87
+    /**
88
+     * 解锁用户
89
+     * @param userCode
90
+     */
91
+    @Transactional
92
+    public void unlockedUser(String userCode){
93
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
94
+        userInfoRepository.cleanLockStatus(userInfo.getUserId());
95
+    }
96
+
97
+    public UserInfo findByUserCode(String userCode) {
98
+        return userInfoRepository.findByUserCode(userCode);
99
+    }
100
+
101
+}

+ 103 - 0
src/main/java/com/lqkj/link/module/authority/service/RoleInfoService.java

@@ -0,0 +1,103 @@
1
+package com.lqkj.link.module.authority.service;
2
+
3
+import com.lqkj.link.module.authority.domain.RoleInfo;
4
+import com.lqkj.link.module.authority.repository.RoleInfoRepository;
5
+import org.springframework.data.domain.Page;
6
+import org.springframework.data.domain.PageRequest;
7
+import org.springframework.data.domain.Pageable;
8
+import org.springframework.data.domain.Sort;
9
+import org.springframework.stereotype.Service;
10
+import org.springframework.transaction.annotation.Transactional;
11
+
12
+import java.util.*;
13
+
14
+@Service
15
+public class RoleInfoService {
16
+    private final RoleInfoRepository roleInfoRepository;
17
+
18
+    public RoleInfoService(RoleInfoRepository roleInfoRepository) {
19
+        this.roleInfoRepository = roleInfoRepository;
20
+    }
21
+
22
+    public List<RoleInfo> allRoles() {
23
+        return roleInfoRepository.queryAll();
24
+    }
25
+
26
+    public Page<RoleInfo> pageQuery(String roleName, Integer page, Integer pageSize) {
27
+        Pageable pageable = PageRequest.of(page, pageSize);
28
+        Page<RoleInfo> roleInfoPage = roleInfoRepository.pageQueryV2(roleName, pageable);
29
+        for (RoleInfo role : roleInfoPage) {
30
+            role.setAuths(roleInfoRepository.queryAuthNamesWithRole(role.getRoleId()));
31
+        }
32
+        return roleInfoPage;
33
+    }
34
+
35
+    public RoleInfo detail(Integer roleId) {
36
+        RoleInfo roleInfo = roleInfoRepository.findById(roleId).get();
37
+        List<Integer> auths = roleInfoRepository
38
+                .queryAuthsWithRole(roleId)
39
+                .stream()
40
+                .map(v -> (Integer) v.get("authority_id"))
41
+                .toList();
42
+        roleInfo.setAuthorityList(auths);
43
+        return roleInfo;
44
+    }
45
+
46
+    @Transactional
47
+    public String save(RoleInfo roleInfo) {
48
+        List<Integer> authorityIds = roleInfo.getAuthorityList();
49
+        if (roleInfo.getRoleId() == null) {
50
+            if (roleInfoRepository.hasSameEnName(roleInfo.getEnName())) {
51
+                return "英文名重复!";
52
+            }
53
+            if (roleInfoRepository.hasSameName(roleInfo.getRoleName())) {
54
+                return "角色名称重复!";
55
+            }
56
+            roleInfo.setUpdateTime(new Date());
57
+            roleInfo = roleInfoRepository.save(roleInfo);
58
+        } else {
59
+            if (roleInfoRepository.hasSameEnNameWithoutOneId(roleInfo.getEnName(), roleInfo.getRoleId())) {
60
+                return "英文名重复!";
61
+            }
62
+            if (roleInfoRepository.hasSameNameWithoutOneId(roleInfo.getRoleName(), roleInfo.getRoleId())) {
63
+                return "角色名称重复!";
64
+            }
65
+            RoleInfo oldRole = roleInfoRepository.findById(roleInfo.getRoleId()).get();
66
+            oldRole.setRoleName(roleInfo.getRoleName());
67
+            oldRole.setEnName(roleInfo.getEnName());
68
+            oldRole.setUpdateTime(new Date());
69
+            roleInfoRepository.save(oldRole);
70
+        }
71
+
72
+        roleInfoRepository.updateRoleAuthority(roleInfo.getRoleId(), authorityIds);
73
+        return null;
74
+    }
75
+
76
+    public List<Map<String, Object>> queryAuthTree(String userCode) {
77
+        List<Map<String, Object>> resultList = new ArrayList<>();
78
+        Map<Integer, List<Map<String, Object>>> childrenMap = new HashMap<>();
79
+
80
+        List<Map<String, Object>> authList = roleInfoRepository.queryAuthsByUser(userCode);
81
+        for (Map<String, Object> auth : authList) {
82
+            Map<String, Object> result = new HashMap<>();
83
+            result.put("id", auth.get("authority_id"));
84
+            result.put("name", auth.get("authority_name"));
85
+
86
+            Integer parentId = (Integer) auth.get("parent_id");
87
+            if (parentId == null) {
88
+                result.put("children", childrenMap.get((Integer) auth.get("authority_id")));
89
+                resultList.add(result);
90
+            } else {
91
+                List<Map<String, Object>> children = childrenMap.getOrDefault(parentId, new ArrayList<>());
92
+                children.add(result);
93
+                childrenMap.put(parentId, children);
94
+            }
95
+        }
96
+
97
+        return resultList;
98
+    }
99
+
100
+    public String delete(List<Integer> roleIds) {
101
+        return roleInfoRepository.deleteNoUserRole(roleIds);
102
+    }
103
+}

+ 178 - 0
src/main/java/com/lqkj/link/module/authority/service/UserInfoService.java

@@ -0,0 +1,178 @@
1
+package com.lqkj.link.module.authority.service;
2
+
3
+import com.lqkj.link.module.authority.domain.UserInfo;
4
+import com.lqkj.link.module.authority.repository.RoleInfoRepository;
5
+import com.lqkj.link.module.authority.repository.UserInfoRepository;
6
+import jakarta.annotation.PostConstruct;
7
+import org.springframework.transaction.annotation.Transactional;
8
+import org.apache.commons.lang3.StringUtils;
9
+import org.springframework.data.domain.Page;
10
+import org.springframework.data.domain.PageRequest;
11
+import org.springframework.data.domain.Pageable;
12
+import org.springframework.security.crypto.password.PasswordEncoder;
13
+import org.springframework.stereotype.Service;
14
+
15
+import java.util.*;
16
+import java.util.regex.Matcher;
17
+import java.util.regex.Pattern;
18
+
19
+@Service
20
+public class UserInfoService {
21
+    private final UserInfoRepository userInfoRepository;
22
+    private final PasswordEncoder passwordEncoder;
23
+    private final RoleInfoRepository roleInfoRepository;
24
+
25
+    public UserInfoService(UserInfoRepository userInfoRepository, PasswordEncoder passwordEncoder, RoleInfoRepository roleInfoRepository) {
26
+        this.userInfoRepository = userInfoRepository;
27
+        this.passwordEncoder = passwordEncoder;
28
+        this.roleInfoRepository = roleInfoRepository;
29
+    }
30
+
31
+    @PostConstruct
32
+    public void initSuperUser() {
33
+        if (!userInfoRepository.existsById(1)) {
34
+            userInfoRepository.initSuperAdmin();
35
+            userInfoRepository.initSuperAdminRole();
36
+        }
37
+    }
38
+
39
+    public UserInfo detailByUserCode(String userCode) {
40
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
41
+        userInfo.setHasAuth(userInfoRepository.hasAuth(userInfo.getUserId()));
42
+        return userInfo;
43
+    }
44
+
45
+    public List<Map<String, Object>> findAuthListWithUserCode(String userCode) {
46
+        List<Map<String, Object>> resultList = new ArrayList<>();
47
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
48
+        if (userInfo.getHasManage()) {
49
+            List<Map<String, Object>> authList = userInfoRepository.queryAuthWithUserCode(userCode);
50
+
51
+            Map<Integer, List<Map<String, Object>>> childrenMap = new HashMap<>();
52
+            for (Map<String, Object> auth : authList) {
53
+                Map<String, Object> result = new HashMap<>(auth);
54
+                Map<String, Object> metaObject = new HashMap<>();
55
+                metaObject.put("icon", auth.get("icon"));
56
+                metaObject.put("title", auth.get("title"));
57
+                result.put("meta", metaObject);
58
+
59
+                if (auth.get("parent_id") == null) {
60
+                    result.put("children", childrenMap.get(auth.get("authority_id")));
61
+                    resultList.add(result);
62
+                } else {
63
+                    List<Map<String, Object>> childrenList = childrenMap.getOrDefault(auth.get("parent_id"), new ArrayList<>());
64
+                    childrenList.add(result);
65
+                    childrenMap.put((Integer) auth.get("parent_id"), childrenList);
66
+                }
67
+            }
68
+        }
69
+
70
+        return resultList;
71
+    }
72
+
73
+    public Page<UserInfo> pageQuery(String userCode, String displayName, Integer page, Integer pageSize) {
74
+        Pageable pageable = PageRequest.of(page, pageSize);
75
+        Page<UserInfo> userInfos = userInfoRepository.pageQueryV2(userCode, displayName, pageable);
76
+        for (UserInfo userInfo : userInfos.getContent()) {
77
+            userInfo.setRoleNames(roleInfoRepository.findRoleNames(userInfo.getUserId()));
78
+        }
79
+        return userInfos;
80
+    }
81
+
82
+    public UserInfo detail(Integer userId) {
83
+        UserInfo userInfo = userInfoRepository.findById(userId).get();
84
+        userInfo.setRoleInfoList(roleInfoRepository.listWithUserId(userId));
85
+        return userInfo;
86
+    }
87
+
88
+    @Transactional
89
+    public String save(UserInfo userInfo) {
90
+
91
+        // 账号判断,8位数字
92
+        String userCodeRegex = "\\d{8}";
93
+        Pattern pattern = Pattern.compile(userCodeRegex);
94
+        Matcher matcher = pattern.matcher(userInfo.getUserCode());
95
+        if (!matcher.find()) {
96
+            return "账号必须是8位数字!";
97
+        }
98
+        // 显示名称判断,2-8位中文字符
99
+        String displayNameRegex = "[\u4E00-\u9FA5]{2,8}";
100
+        pattern = Pattern.compile(displayNameRegex);
101
+        matcher = pattern.matcher(userInfo.getDisplayName());
102
+        if (!matcher.find()) {
103
+            return "名称必须是2-8位中文字符!";
104
+        }
105
+
106
+        // 授权码判断,8位数字、大写字母、小写字母
107
+        String auCodeRegex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8}$";
108
+        pattern = Pattern.compile(auCodeRegex);
109
+        matcher = pattern.matcher(userInfo.getAuthorizationCode());
110
+        if (!matcher.find()) {
111
+            return "授权码必须是8位数字、大写字母、小写字母!";
112
+        }
113
+
114
+        if (userInfo.getUserId() == null) {
115
+            // 重复判断
116
+            if (userInfoRepository.hasSameUserCode(userInfo.getUserCode())) {
117
+                return "账号与已有账号重复,请设置其他账号!";
118
+            }
119
+            // 密码判断,8-16位数字、大写字母、小写字母
120
+            String passwordRegex = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,16}$";
121
+            pattern = Pattern.compile(passwordRegex);
122
+            matcher = pattern.matcher(userInfo.getPassword());
123
+            if (!matcher.find()) {
124
+                return "密码必须是8-16位数字、大写字母、小写字母!";
125
+            }
126
+
127
+            userInfo.setLocking(false);
128
+            userInfo.setPassword(passwordEncoder.encode(userInfo.getPassword()));
129
+            userInfo.setUpdateTime(new Date());
130
+            userInfo.setRefreshResource(false);
131
+            userInfo = userInfoRepository.save(userInfo);
132
+        } else {
133
+            if (StringUtils.isNotBlank(userInfo.getPassword())) {
134
+                // 密码判断,8-16位数字、大写字母、小写字母
135
+                String passwordRegex = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,16}$";
136
+                pattern = Pattern.compile(passwordRegex);
137
+                matcher = pattern.matcher(userInfo.getPassword());
138
+                if (!matcher.find()) {
139
+                    return "密码必须是8-16位数字、大写字母、小写字母!";
140
+                }
141
+            }
142
+            UserInfo oldUser = userInfoRepository.findById(userInfo.getUserId()).get();
143
+            if (StringUtils.isNotBlank(userInfo.getPassword())) {
144
+                oldUser.setPassword(passwordEncoder.encode(userInfo.getPassword()));
145
+            }
146
+            oldUser.setDisplayName(userInfo.getDisplayName());
147
+            oldUser.setHasManage(userInfo.getHasManage());
148
+            oldUser.setAuthorizationCode(userInfo.getAuthorizationCode());
149
+            oldUser.setUpdateTime(new Date());
150
+            userInfoRepository.save(oldUser);
151
+        }
152
+        roleInfoRepository.updateUserRole(userInfo.getUserId(), userInfo.getRoleIds());
153
+        return null;
154
+    }
155
+
156
+    public void delete(List<Integer> userIds) {
157
+        userInfoRepository.deleteAllByIdInBatch(userIds);
158
+    }
159
+
160
+    public void updateInfo(String userCode, String displayName, String headImgPath) {
161
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
162
+        if (StringUtils.isNotBlank(displayName)) {
163
+            userInfo.setDisplayName(displayName);
164
+        }
165
+        if ((StringUtils.isNotBlank(headImgPath))) {
166
+            userInfo.setHeadImg(headImgPath);
167
+        }
168
+        userInfoRepository.save(userInfo);
169
+    }
170
+
171
+    public Boolean checkRefreshResource(String userCode) {
172
+        return userInfoRepository.findByUserCode(userCode).getRefreshResource();
173
+    }
174
+
175
+    public void resourceRefreshed(String userCode) {
176
+        userInfoRepository.resourceRefreshed();
177
+    }
178
+}

+ 77 - 0
src/main/java/com/lqkj/link/module/base/service/BaseService.java

@@ -0,0 +1,77 @@
1
+package com.lqkj.link.module.base.service;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.util.FileUtils;
5
+import org.springframework.stereotype.Service;
6
+import org.springframework.web.multipart.MultipartFile;
7
+
8
+import java.util.UUID;
9
+
10
+@Service
11
+public class BaseService {
12
+
13
+    public MessageBean<String> uploadImg(MultipartFile file, String path) {
14
+        String fileName = file.getOriginalFilename();
15
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
16
+        if (!suffix.equals("png") && !suffix.equals("jpg"))
17
+            return MessageBean.error("上传文件类型必须是png、jpg图片文件");
18
+        String newFileName = UUID.randomUUID() + "." + suffix;
19
+        String filePath = "./upload/" + path;
20
+        FileUtils.saveFile(file, filePath, newFileName);
21
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传图标文件");
22
+    }
23
+
24
+    public MessageBean<String> uploadVideo(MultipartFile file, String path) {
25
+        String fileName = file.getOriginalFilename();
26
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
27
+        if (!suffix.equals("mp4"))
28
+            return MessageBean.error("上传文件类型必须是mp4视频文件");
29
+        String newFileName = UUID.randomUUID() + "." + suffix;
30
+        String filePath = "./upload/" + path;
31
+        FileUtils.saveFile(file, filePath, newFileName);
32
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传视频文件");
33
+    }
34
+
35
+    public MessageBean<String> uploadAudio(MultipartFile file, String path) {
36
+        String fileName = file.getOriginalFilename();
37
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
38
+        if (!suffix.equals("mp3"))
39
+            return MessageBean.error("上传文件类型必须是mp3音频文件");
40
+        String newFileName = UUID.randomUUID() + "." + suffix;
41
+        String filePath = "./upload/" + path;
42
+        FileUtils.saveFile(file, filePath, newFileName);
43
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传音频文件");
44
+    }
45
+    public MessageBean<String> uploadModelCompress(MultipartFile file, String path) {
46
+        String fileName = file.getOriginalFilename();
47
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
48
+        if (!suffix.equals("zip"))
49
+            return MessageBean.error("上传文件类型必须是zip、rar格式的模型文件");
50
+        String newFileName = UUID.randomUUID() + "." + suffix;
51
+        String filePath = "./upload/" + path;
52
+        FileUtils.saveFile(file, filePath, newFileName);
53
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传模型压缩文件");
54
+    }
55
+
56
+    public MessageBean<String> uploadModel(MultipartFile file, String path) {
57
+        String fileName = file.getOriginalFilename();
58
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
59
+        if (!suffix.equals("obj") && !suffix.equals("fbx"))
60
+            return MessageBean.error("上传文件类型必须是obj、fbx格式的压缩文件");
61
+        String newFileName = UUID.randomUUID() + "." + suffix;
62
+        String filePath = "./upload/" + path;
63
+        FileUtils.saveFile(file, filePath, newFileName);
64
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传模型文件");
65
+    }
66
+
67
+    public MessageBean<String> uploadJsonFile(MultipartFile file, String path) {
68
+        String fileName = file.getOriginalFilename();
69
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
70
+        if (!suffix.equals("json"))
71
+            return MessageBean.error("上传文件类型必须是json格式的json文件");
72
+        String newFileName = UUID.randomUUID() + "." + suffix;
73
+        String filePath = "./upload/" + path;
74
+        FileUtils.saveFile(file, filePath, newFileName);
75
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传模型文件");
76
+    }
77
+}

+ 63 - 0
src/main/java/com/lqkj/link/module/bulletin/controller/BulletinInfoController.java

@@ -0,0 +1,63 @@
1
+package com.lqkj.link.module.bulletin.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.message.MessageListBean;
5
+import com.lqkj.link.module.bulletin.domain.BulletinInfo;
6
+import com.lqkj.link.module.bulletin.service.BulletinInfoService;
7
+import io.swagger.v3.oas.annotations.Operation;
8
+import io.swagger.v3.oas.annotations.Parameter;
9
+import io.swagger.v3.oas.annotations.media.Content;
10
+import io.swagger.v3.oas.annotations.media.Schema;
11
+import io.swagger.v3.oas.annotations.tags.Tag;
12
+import org.springframework.web.bind.annotation.*;
13
+
14
+@RestController
15
+@RequestMapping("/bulletin")
16
+@Tag(name = "通知公告接口", description = "通知公告接口")
17
+public class BulletinInfoController {
18
+    private final BulletinInfoService bulletinInfoService;
19
+
20
+    public BulletinInfoController(BulletinInfoService bulletinInfoService) {
21
+        this.bulletinInfoService = bulletinInfoService;
22
+    }
23
+
24
+    @Operation(
25
+            summary = "5.1.3.21 通知公告列表接口",
26
+            description = "5.1.3.21 通知公告列表接口"
27
+    )
28
+    @PostMapping("/manage/all")
29
+    public MessageListBean<BulletinInfo> queryAll() {
30
+        return MessageListBean.ok(bulletinInfoService.queryAll(), "通知公告列表接口");
31
+    }
32
+
33
+    @Operation(
34
+            summary = "5.1.3.22 通知公告保存接口",
35
+            description = "5.1.3.22 通知公告保存接口",
36
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
37
+                    description = "通知公告信息实体",
38
+                    required = true,
39
+                    content = @Content(
40
+                            mediaType = "application/json",
41
+                            schema = @Schema(implementation = BulletinInfo.class)
42
+                    )
43
+            )
44
+    )
45
+    @PostMapping("/manage/save")
46
+    public MessageBean save(@RequestBody BulletinInfo info) {
47
+        bulletinInfoService.save(info);
48
+        return MessageBean.ok(null, "通知公告保存接口");
49
+    }
50
+
51
+    @Operation(
52
+            summary = "5.1.3.23 通知公告删除接口",
53
+            description = "5.1.3.23 通知公告删除接口",
54
+            parameters = {
55
+                    @Parameter(name = "infoId", description = "信息ID")
56
+            }
57
+    )
58
+    @PostMapping("/manage/delete")
59
+    public MessageBean delete(@RequestParam Integer infoId) {
60
+        bulletinInfoService.delete(infoId);
61
+        return MessageBean.ok(null, "通知公告删除接口");
62
+    }
63
+}

+ 50 - 0
src/main/java/com/lqkj/link/module/bulletin/controller/NoticeInfoController.java

@@ -0,0 +1,50 @@
1
+package com.lqkj.link.module.bulletin.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.message.MessageListBean;
5
+import com.lqkj.link.module.bulletin.domain.NoticeInfo;
6
+import com.lqkj.link.module.bulletin.service.NoticeInfoService;
7
+import com.lqkj.link.module.jwt.service.JwtService;
8
+import io.swagger.v3.oas.annotations.Operation;
9
+import io.swagger.v3.oas.annotations.tags.Tag;
10
+import jakarta.servlet.http.HttpServletRequest;
11
+import org.springframework.web.bind.annotation.PostMapping;
12
+import org.springframework.web.bind.annotation.RequestMapping;
13
+import org.springframework.web.bind.annotation.RequestParam;
14
+import org.springframework.web.bind.annotation.RestController;
15
+
16
+import static com.lqkj.link.APIVersion.VERSION_V1;
17
+
18
+@RestController
19
+@RequestMapping("/notice")
20
+@Tag(name = "通知公告接口", description = "通知公告接口")
21
+public class NoticeInfoController {
22
+    private final NoticeInfoService noticeInfoService;
23
+    private final JwtService jwtService;
24
+
25
+    public NoticeInfoController(NoticeInfoService noticeInfoService, JwtService jwtService) {
26
+        this.noticeInfoService = noticeInfoService;
27
+        this.jwtService = jwtService;
28
+    }
29
+
30
+    @Operation(
31
+            summary = "5.1.2.14 我的通知",
32
+            description = "5.1.2.14 我的通知"
33
+    )
34
+    @PostMapping("/" + VERSION_V1 + "/myNotice")
35
+    public MessageListBean<NoticeInfo> myNotice(HttpServletRequest request) {
36
+        String authHeader = request.getHeader("Authorization");
37
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
38
+        return MessageListBean.ok(noticeInfoService.queryList(userCode), "我的通知");
39
+    }
40
+
41
+    @Operation(
42
+            summary = "5.1.2.15 查看通知",
43
+            description = "5.1.2.15 查看通知"
44
+    )
45
+    @PostMapping("/" + VERSION_V1 + "/view")
46
+    public MessageBean<String> view(@RequestParam Integer infoId) {
47
+        noticeInfoService.view(infoId);
48
+        return MessageBean.ok(null, "查看通知");
49
+    }
50
+}

+ 35 - 0
src/main/java/com/lqkj/link/module/bulletin/domain/BulletinInfo.java

@@ -0,0 +1,35 @@
1
+package com.lqkj.link.module.bulletin.domain;
2
+
3
+import com.fasterxml.jackson.annotation.JsonFormat;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+import jakarta.persistence.*;
6
+import lombok.AllArgsConstructor;
7
+import lombok.Getter;
8
+import lombok.NoArgsConstructor;
9
+import lombok.Setter;
10
+
11
+import java.util.Date;
12
+
13
+@Entity
14
+@Table(name = "bulletin_info")
15
+@Getter
16
+@Setter
17
+@NoArgsConstructor
18
+@AllArgsConstructor
19
+public class BulletinInfo {
20
+    @Id
21
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
22
+    @Column(name = "info_id")
23
+    @Schema(description = "信息ID")
24
+    private Integer infoId;
25
+    @Column(name = "content")
26
+    @Schema(description = "信息内容")
27
+    private String content;
28
+    @Column(name = "create_time")
29
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
30
+    @Schema(description = "创建时间")
31
+    private Date createTime;
32
+    @Column(name = "info_type")
33
+    @Schema(description = "信息类型,1更新日志,2通知公告")
34
+    private Integer infoType;
35
+}

+ 48 - 0
src/main/java/com/lqkj/link/module/bulletin/domain/NoticeInfo.java

@@ -0,0 +1,48 @@
1
+package com.lqkj.link.module.bulletin.domain;
2
+
3
+import com.fasterxml.jackson.annotation.JsonFormat;
4
+import io.swagger.v3.oas.annotations.media.Schema;
5
+import jakarta.persistence.*;
6
+import lombok.AllArgsConstructor;
7
+import lombok.Getter;
8
+import lombok.NoArgsConstructor;
9
+import lombok.Setter;
10
+
11
+import java.util.Date;
12
+
13
+@Entity
14
+@Table(name = "notice_info")
15
+@Getter
16
+@Setter
17
+@NoArgsConstructor
18
+@AllArgsConstructor
19
+public class NoticeInfo {
20
+    @Id
21
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
22
+    @Column(name = "info_id")
23
+    @Schema(description = "信息ID")
24
+    private Integer infoId;
25
+    @Column(name = "bulletin_id")
26
+    @Schema(description = "系统公告ID")
27
+    private Integer bulletinId;
28
+    @Column(name = "content")
29
+    @Schema(description = "信息内容")
30
+    private String content;
31
+    @Column(name = "create_time")
32
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
33
+    @Schema(description = "创建时间")
34
+    private Date createTime;
35
+    @Column(name = "user_id")
36
+    @Schema(description = "接收用户ID")
37
+    private Integer userId;
38
+    @Column(name = "has_view")
39
+    @Schema(description = "是否已查看")
40
+    private Boolean hasView;
41
+    @Column(name = "view_time")
42
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
43
+    @Schema(description = "查看时间")
44
+    private Date viewTime;
45
+    @Column(name = "type")
46
+    @Schema(description = "信息类型,1更新日志,2系统公告,3审核通知")
47
+    private Integer type;
48
+}

+ 9 - 0
src/main/java/com/lqkj/link/module/bulletin/repository/BulletinInfoRepository.java

@@ -0,0 +1,9 @@
1
+package com.lqkj.link.module.bulletin.repository;
2
+
3
+import com.lqkj.link.module.bulletin.domain.BulletinInfo;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.stereotype.Repository;
6
+
7
+@Repository
8
+public interface BulletinInfoRepository extends JpaRepository<BulletinInfo, Integer> {
9
+}

+ 60 - 0
src/main/java/com/lqkj/link/module/bulletin/repository/NoticeInfoRepository.java

@@ -0,0 +1,60 @@
1
+package com.lqkj.link.module.bulletin.repository;
2
+
3
+import com.lqkj.link.module.bulletin.domain.NoticeInfo;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.data.jpa.repository.Modifying;
6
+import org.springframework.data.jpa.repository.Query;
7
+import org.springframework.data.repository.query.Param;
8
+import org.springframework.stereotype.Repository;
9
+
10
+import java.util.List;
11
+
12
+@Repository
13
+public interface NoticeInfoRepository extends JpaRepository<NoticeInfo, Integer> {
14
+
15
+    @Modifying
16
+    @Query(nativeQuery = true,
17
+        value = "insert into notice_info(info_id, bulletin_id, content, create_time, user_id, has_view, type) " +
18
+                "select nextval('notice_info_info_id_seq'), :bulletinId, bi.content, bi.create_time, ui.user_id, false, bi.info_type " +
19
+                "from bulletin_info bi, user_info ui " +
20
+                "where bi.info_id = :bulletinId"
21
+    )
22
+    void addBulletin(@Param("bulletinId") Integer bulletinId);
23
+
24
+    @Modifying
25
+    @Query(nativeQuery = true,
26
+        value = "update notice_info set content = :content, create_time = now(), has_view = false, type = :type " +
27
+                "where bulletin_id = :bulletinId"
28
+    )
29
+    void updateBulletin(@Param("bulletinId") Integer bulletinId,
30
+                        @Param("content") String content,
31
+                        @Param("type") Integer type);
32
+
33
+    @Modifying
34
+    @Query(nativeQuery = true,
35
+        value = "delete from notice_info where bulletin_id = :bulletinId"
36
+    )
37
+    void deleteBulletin(@Param("bulletinId") Integer bulletinId);
38
+
39
+    @Query(nativeQuery = true,
40
+        value = "select ni.* from notice_info ni, user_info ui " +
41
+                "where ni.user_id = ui.user_id and ui.user_code = :userCode " +
42
+                "order by create_time desc"
43
+    )
44
+    List<NoticeInfo> queryWithUserCode(@Param("userCode") String userCode);
45
+
46
+    @Modifying
47
+    @Query(nativeQuery = true,
48
+        value = "insert into notice_info(info_id, bulletin_id, content, create_time, user_id, has_view, view_time, type) " +
49
+                "select nextval('notice_info_info_id_seq'), null, :content, now(), :userId, false, null, 3 "
50
+    )
51
+    void createAuditNotice(@Param("content") String content,
52
+                           @Param("userId") Integer userId);
53
+
54
+    @Modifying
55
+    @Query(nativeQuery = true,
56
+        value = "update notice_info set has_view = true where info_id = :infoId"
57
+    )
58
+    void view(@Param("infoId") Integer infoId);
59
+
60
+}

+ 45 - 0
src/main/java/com/lqkj/link/module/bulletin/service/BulletinInfoService.java

@@ -0,0 +1,45 @@
1
+package com.lqkj.link.module.bulletin.service;
2
+
3
+import com.lqkj.link.module.bulletin.domain.BulletinInfo;
4
+import com.lqkj.link.module.bulletin.repository.BulletinInfoRepository;
5
+import com.lqkj.link.module.bulletin.repository.NoticeInfoRepository;
6
+import org.springframework.transaction.annotation.Transactional;
7
+import org.springframework.data.domain.Sort;
8
+import org.springframework.stereotype.Service;
9
+
10
+import java.util.Date;
11
+import java.util.List;
12
+
13
+@Service
14
+public class BulletinInfoService {
15
+    private final BulletinInfoRepository bulletinInfoRepository;
16
+    private final NoticeInfoRepository noticeInfoRepository;
17
+
18
+    public BulletinInfoService(BulletinInfoRepository bulletinInfoRepository, NoticeInfoRepository noticeInfoRepository) {
19
+        this.bulletinInfoRepository = bulletinInfoRepository;
20
+        this.noticeInfoRepository = noticeInfoRepository;
21
+    }
22
+
23
+    public List<BulletinInfo> queryAll() {
24
+        return bulletinInfoRepository.findAll(Sort.by(Sort.Direction.DESC, "createTime"));
25
+    }
26
+
27
+    @Transactional
28
+    public void save(BulletinInfo bulletinInfo) {
29
+        if (bulletinInfo.getInfoId() == null) {
30
+            bulletinInfo.setCreateTime(new Date());
31
+            BulletinInfo newInfo = bulletinInfoRepository.save(bulletinInfo);
32
+            noticeInfoRepository.addBulletin(newInfo.getInfoId());
33
+        } else {
34
+            bulletinInfo.setCreateTime(new Date());
35
+            bulletinInfoRepository.save(bulletinInfo);
36
+            noticeInfoRepository.updateBulletin(bulletinInfo.getInfoId(), bulletinInfo.getContent(), bulletinInfo.getInfoType());
37
+        }
38
+    }
39
+
40
+    @Transactional
41
+    public void delete(Integer infoId) {
42
+        bulletinInfoRepository.deleteById(infoId);
43
+        noticeInfoRepository.deleteBulletin(infoId);
44
+    }
45
+}

+ 26 - 0
src/main/java/com/lqkj/link/module/bulletin/service/NoticeInfoService.java

@@ -0,0 +1,26 @@
1
+package com.lqkj.link.module.bulletin.service;
2
+
3
+import com.lqkj.link.module.bulletin.domain.NoticeInfo;
4
+import com.lqkj.link.module.bulletin.repository.NoticeInfoRepository;
5
+import org.springframework.transaction.annotation.Transactional;
6
+import org.springframework.stereotype.Service;
7
+
8
+import java.util.List;
9
+
10
+@Service
11
+public class NoticeInfoService {
12
+    private final NoticeInfoRepository noticeInfoRepository;
13
+
14
+    public NoticeInfoService(NoticeInfoRepository noticeInfoRepository) {
15
+        this.noticeInfoRepository = noticeInfoRepository;
16
+    }
17
+
18
+    public List<NoticeInfo> queryList(String userCode) {
19
+        return noticeInfoRepository.queryWithUserCode(userCode);
20
+    }
21
+
22
+    @Transactional
23
+    public void view(Integer infoId) {
24
+        noticeInfoRepository.view(infoId);
25
+    }
26
+}

+ 87 - 0
src/main/java/com/lqkj/link/module/config/controller/ConfigInfoController.java

@@ -0,0 +1,87 @@
1
+package com.lqkj.link.module.config.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.message.MessageListBean;
5
+import com.lqkj.link.module.base.service.BaseService;
6
+import com.lqkj.link.module.config.domain.ConfigInfo;
7
+import com.lqkj.link.module.config.service.ConfigInfoService;
8
+import com.lqkj.link.util.FileUtils;
9
+import io.swagger.v3.oas.annotations.Operation;
10
+import io.swagger.v3.oas.annotations.Parameter;
11
+import io.swagger.v3.oas.annotations.media.ArraySchema;
12
+import io.swagger.v3.oas.annotations.media.Content;
13
+import io.swagger.v3.oas.annotations.media.Schema;
14
+import io.swagger.v3.oas.annotations.tags.Tag;
15
+import org.springframework.web.bind.annotation.*;
16
+import org.springframework.web.multipart.MultipartFile;
17
+
18
+import java.util.List;
19
+import java.util.UUID;
20
+
21
+import static com.lqkj.link.APIVersion.VERSION_V1;
22
+
23
+@RestController
24
+@Tag(name = "产品配置接口", description = "产品配置接口")
25
+@RequestMapping("/config")
26
+public class ConfigInfoController {
27
+    private final ConfigInfoService configInfoService;
28
+    private final BaseService baseService;
29
+
30
+    public ConfigInfoController(ConfigInfoService configInfoService, BaseService baseService) {
31
+        this.configInfoService = configInfoService;
32
+        this.baseService = baseService;
33
+    }
34
+
35
+    @Operation(
36
+            summary = "5.1.3.19 查询全部产品配置参数接口",
37
+            description = "5.1.3.19 查询全部产品配置参数接口"
38
+    )
39
+    @PostMapping({"/manage/all", "/" + VERSION_V1 + "/all"})
40
+    public MessageListBean<ConfigInfo> all(){
41
+        return MessageListBean.ok(configInfoService.queryAll(), "全部产品配置参数");
42
+    }
43
+
44
+    @Operation(
45
+            summary = "5.1.3.20 批量保存产品配置参数接口",
46
+            description = "5.1.3.20 批量保存产品配置参数接口",
47
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
48
+                    description = "产品配置参数列表",
49
+                    required = true,
50
+                    content = @Content(
51
+                            mediaType = "application/json",
52
+                            array = @ArraySchema(
53
+                                    schema = @Schema(implementation = ConfigInfo.class)
54
+                            )
55
+                    )
56
+            )
57
+    )
58
+    @PostMapping("/manage/update")
59
+    public MessageBean update(@RequestBody List<ConfigInfo> configInfoList){
60
+        configInfoService.saveAll(configInfoList);
61
+        return MessageBean.ok(null, "批量保存产品配置参数");
62
+    }
63
+
64
+    @Operation(
65
+            summary = "5.1.3.30 产品配置上传图片文件",
66
+            description = "5.1.3.30 产品配置上传图片文件",
67
+            parameters = {
68
+                    @Parameter(name = "file", description = "图片文件", required = true)
69
+            }
70
+    )
71
+    @PostMapping("/manage/uploadImg")
72
+    public MessageBean<String> uploadImg(@RequestParam MultipartFile file) {
73
+        return baseService.uploadImg(file, "config/icon/");
74
+    }
75
+
76
+    @Operation(
77
+            summary = "5.1.2.1 获取单个产品配置参数",
78
+            description = "5.1.2.1 获取单个产品配置参数",
79
+            parameters = {
80
+                    @Parameter(name = "configKey", required = true, description = "产品配置参数key")
81
+            }
82
+    )
83
+    @PostMapping("/" + VERSION_V1 + "/getOne")
84
+    public MessageBean<ConfigInfo> getOne(@RequestParam String configKey) {
85
+        return MessageBean.ok(configInfoService.getOne(configKey), "获取单个产品配置参数");
86
+    }
87
+}

+ 30 - 0
src/main/java/com/lqkj/link/module/config/domain/ConfigInfo.java

@@ -0,0 +1,30 @@
1
+package com.lqkj.link.module.config.domain;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+import jakarta.persistence.Column;
5
+import jakarta.persistence.Entity;
6
+import jakarta.persistence.Id;
7
+import jakarta.persistence.Table;
8
+import lombok.AllArgsConstructor;
9
+import lombok.Getter;
10
+import lombok.NoArgsConstructor;
11
+import lombok.Setter;
12
+
13
+@Entity
14
+@Table(name = "config_info")
15
+@Getter
16
+@Setter
17
+@NoArgsConstructor
18
+@AllArgsConstructor
19
+public class ConfigInfo {
20
+    @Id
21
+    @Column(name = "config_key")
22
+    @Schema(description = "产品配置KEY")
23
+    private String configKey;
24
+    @Column(name = "config_value")
25
+    @Schema(description = "产品配置值")
26
+    private String configValue;
27
+    @Column(name = "content_type")
28
+    @Schema(description = "参数类型")
29
+    private String contentType;
30
+}

+ 9 - 0
src/main/java/com/lqkj/link/module/config/repository/ConfigInfoRepository.java

@@ -0,0 +1,9 @@
1
+package com.lqkj.link.module.config.repository;
2
+
3
+import com.lqkj.link.module.config.domain.ConfigInfo;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.stereotype.Repository;
6
+
7
+@Repository
8
+public interface ConfigInfoRepository extends JpaRepository<ConfigInfo, String> {
9
+}

+ 50 - 0
src/main/java/com/lqkj/link/module/config/service/ConfigInfoService.java

@@ -0,0 +1,50 @@
1
+package com.lqkj.link.module.config.service;
2
+
3
+import com.alibaba.fastjson2.JSON;
4
+import com.alibaba.fastjson2.JSONObject;
5
+import com.lqkj.link.module.config.domain.ConfigInfo;
6
+import com.lqkj.link.module.config.repository.ConfigInfoRepository;
7
+import jakarta.annotation.PostConstruct;
8
+import org.springframework.data.domain.Sort;
9
+import org.springframework.stereotype.Service;
10
+
11
+import java.util.List;
12
+
13
+@Service
14
+public class ConfigInfoService {
15
+    private final ConfigInfoRepository configInfoRepository;
16
+
17
+    public ConfigInfoService(ConfigInfoRepository configInfoRepository) {
18
+        this.configInfoRepository = configInfoRepository;
19
+    }
20
+
21
+    public List<ConfigInfo> queryAll() {
22
+        return configInfoRepository.findAll(Sort.by(Sort.Direction.ASC, "configKey"));
23
+    }
24
+
25
+    public void saveAll(List<ConfigInfo> configInfoList) {
26
+        configInfoRepository.saveAll(configInfoList);
27
+    }
28
+
29
+    public ConfigInfo getOne(String configKey) {
30
+        return configInfoRepository.findById(configKey).get();
31
+    }
32
+
33
+    @PostConstruct
34
+    public void saveVersion() {
35
+        ConfigInfo configInfo;
36
+        if (configInfoRepository.existsById("jarVersion")) {
37
+            configInfo = configInfoRepository.findById("jarVersion").get();
38
+            String configValue = configInfo.getConfigValue();
39
+            JSONObject jsonObject = JSON.parseObject(configValue);
40
+            jsonObject.put("java", "V1.0.0");
41
+            configInfo.setConfigValue(jsonObject.toJSONString());
42
+            configInfo.setContentType("application/json");
43
+        } else {
44
+            JSONObject jsonObject = new JSONObject();
45
+            jsonObject.put("java", "V1.0.0");
46
+            configInfo = new ConfigInfo("jarVersion", jsonObject.toJSONString(), "application/json");
47
+        }
48
+        configInfoRepository.save(configInfo);
49
+    }
50
+}

+ 47 - 0
src/main/java/com/lqkj/link/module/encrypt/controller/EncryptController.java

@@ -0,0 +1,47 @@
1
+package com.lqkj.link.module.encrypt.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.util.RSAUtils;
5
+import io.swagger.v3.oas.annotations.Operation;
6
+import io.swagger.v3.oas.annotations.Parameter;
7
+import io.swagger.v3.oas.annotations.tags.Tag;
8
+import org.springframework.web.bind.annotation.*;
9
+
10
+@RestController
11
+@RequestMapping("/encrypt")
12
+@Tag(name = "加密工具类", description = "加密工具类")
13
+public class EncryptController {
14
+
15
+    @Operation(
16
+            summary = "5.1.1.1 获取RSA公钥接口",
17
+            description = "5.1.1.1 获取RSA公钥接口"
18
+    )
19
+    @PostMapping("/rsaKey")
20
+    public MessageBean<String> rsaKey() {
21
+        return MessageBean.ok(RSAUtils.generateBase64PublicKey(), "获取RSA公钥");
22
+    }
23
+
24
+    @Operation(
25
+            summary = "5.1.1.5 RSA加密接口",
26
+            description = "5.1.1.5 RSA加密接口",
27
+            parameters = {
28
+                @Parameter(name = "word", description = "需加密的字符串", required = true)
29
+            }
30
+    )
31
+    @PostMapping("/rsaEncrypt")
32
+    public MessageBean<String> rsaEncrypt(String word) {
33
+        return MessageBean.ok(RSAUtils.encryptBase64(word), "RSA加密数据");
34
+    }
35
+
36
+    @Operation(
37
+            summary = "5.1.1.6 RSA解密接口",
38
+            description = "5.1.1.6 RSA解密接口",
39
+            parameters = {
40
+                    @Parameter(name = "word", description = "需解密的字符串", required = true)
41
+            }
42
+    )
43
+    @PostMapping("/rsaDecrypt")
44
+    public MessageBean<String> rsaDecrypt(String word) {
45
+        return MessageBean.ok(RSAUtils.decryptBase64(word), "RSA解密数据");
46
+    }
47
+}

+ 96 - 0
src/main/java/com/lqkj/link/module/jwt/controller/JwtController.java

@@ -0,0 +1,96 @@
1
+package com.lqkj.link.module.jwt.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.module.jwt.service.JwtService;
5
+import com.lqkj.link.module.authority.domain.LoginBody;
6
+import com.lqkj.link.module.authority.domain.UserInfo;
7
+import com.lqkj.link.module.authority.service.DatabaseUserDetailService;
8
+import com.lqkj.link.util.RSAUtils;
9
+import io.swagger.v3.oas.annotations.Operation;
10
+import io.swagger.v3.oas.annotations.media.Content;
11
+import io.swagger.v3.oas.annotations.media.Schema;
12
+import io.swagger.v3.oas.annotations.tags.Tag;
13
+import jakarta.servlet.http.HttpServletRequest;
14
+import org.springframework.security.crypto.password.PasswordEncoder;
15
+import org.springframework.web.bind.annotation.PostMapping;
16
+import org.springframework.web.bind.annotation.RequestBody;
17
+import org.springframework.web.bind.annotation.RequestMapping;
18
+import org.springframework.web.bind.annotation.RestController;
19
+
20
+@RestController
21
+@RequestMapping("/jwt")
22
+@Tag(name = "授权服务", description = "授权服务")
23
+public class JwtController {
24
+
25
+    private final DatabaseUserDetailService userDetailService;
26
+    private final JwtService jwtService;
27
+    private final PasswordEncoder passwordEncoder;
28
+
29
+    public JwtController(DatabaseUserDetailService userDetailService, JwtService jwtService, PasswordEncoder passwordEncoder) {
30
+        this.userDetailService = userDetailService;
31
+        this.jwtService = jwtService;
32
+        this.passwordEncoder = passwordEncoder;
33
+    }
34
+
35
+    @Operation(
36
+            summary = "5.1.1.2 登录接口",
37
+            description = "5.1.1.2 登录接口",
38
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
39
+                    description = "登录信息对象",
40
+                    required = true,
41
+                    content = @Content(
42
+                            mediaType = "application/json",
43
+                            schema = @Schema(implementation = LoginBody.class)
44
+                    )
45
+            ))
46
+    @PostMapping("/token")
47
+    public MessageBean<String> getToken(@RequestBody LoginBody loginBody){
48
+        String userCode = loginBody.getUsername();
49
+        String password = loginBody.getPassword();
50
+        String authCode = loginBody.getAuthCode();
51
+        if (userCode.length() != 172 || password.length() != 172 || authCode.length() != 172) {
52
+            return MessageBean.error("用户名或密码或授权码错误!");
53
+        }
54
+        userCode = RSAUtils.decryptBase64(userCode);
55
+        password = RSAUtils.decryptBase64(password);
56
+        authCode = RSAUtils.decryptBase64(authCode);
57
+
58
+        UserInfo userInfo = userDetailService.findByUserCode(userCode);
59
+        if (userInfo == null) {
60
+            return MessageBean.error("账号不存在!");
61
+        }
62
+        if (userDetailService.isLocked(userInfo.getUserCode())) {//账号是否被冻结
63
+            return MessageBean.error("账号已被冻结,请稍后重试!");
64
+        }
65
+        if (!passwordEncoder.matches(password, userInfo.getPassword())) {
66
+            return MessageBean.error(userDetailService.lockedUser(userInfo.getUserCode()));
67
+        }
68
+        if (!authCode.equals(userInfo.getAuthorizationCode())) {
69
+            return MessageBean.error("授权码错误!");
70
+        }
71
+        userDetailService.unlockedUser(userInfo.getUserCode());
72
+
73
+        return MessageBean.ok(jwtService.generateToken(userCode), "登录");
74
+    }
75
+
76
+    @Operation(
77
+            summary = "5.1.1.4 刷新token接口",
78
+            description = "5.1.1.4 刷新token接口"
79
+    )
80
+    @PostMapping("/refreshToken")
81
+    public MessageBean<String> refreshToken(HttpServletRequest request) {
82
+        String authHeader = request.getHeader("Authorization");
83
+        String username = jwtService.decryptUsernameWithHeader(authHeader);
84
+        return MessageBean.ok(jwtService.generateToken(username), "刷新token");
85
+
86
+    }
87
+
88
+    @Operation(
89
+            summary = "直接获取ADMIN-TOKEN",
90
+            description = "直接获取ADMIN-TOKEN"
91
+    )
92
+    @PostMapping("/getAdminToken")
93
+    public MessageBean<String> getAdminToken() {
94
+        return MessageBean.ok(jwtService.generateToken("meta-link"), "登录");
95
+    }
96
+}

+ 80 - 0
src/main/java/com/lqkj/link/module/jwt/service/JwtService.java

@@ -0,0 +1,80 @@
1
+package com.lqkj.link.module.jwt.service;
2
+
3
+import com.lqkj.link.util.RSAUtils;
4
+import io.jsonwebtoken.Claims;
5
+import io.jsonwebtoken.Jwts;
6
+import io.jsonwebtoken.SignatureAlgorithm;
7
+import io.jsonwebtoken.io.Decoders;
8
+import io.jsonwebtoken.security.Keys;
9
+import org.springframework.security.core.userdetails.UserDetails;
10
+import org.springframework.stereotype.Component;
11
+
12
+import java.security.Key;
13
+import java.util.Date;
14
+import java.util.HashMap;
15
+import java.util.Map;
16
+import java.util.function.Function;
17
+
18
+@Component
19
+public class JwtService {
20
+
21
+
22
+    public static final String SECRET = "zdvilXBILaMtQVtcJQ19ovIAo6GE1fEreTVYFXU1TZXg42Cc6AacW9fC1LV0u5Pc";
23
+
24
+
25
+    public String extractUsername(String token) {
26
+        return extractClaim(token, Claims::getSubject);
27
+    }
28
+
29
+    public String decryptUsernameWithHeader(String header) {
30
+        String token = header.substring(7);
31
+        return RSAUtils.decryptBase64(extractUsername(token));
32
+    }
33
+
34
+    public Date extractExpiration(String token) {
35
+        return extractClaim(token, Claims::getExpiration);
36
+    }
37
+
38
+    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
39
+        final Claims claims = extractAllClaims(token);
40
+        return claimsResolver.apply(claims);
41
+    }
42
+
43
+    private Claims extractAllClaims(String token) {
44
+        return Jwts
45
+                .parserBuilder()
46
+                .setSigningKey(getSignKey())
47
+                .build()
48
+                .parseClaimsJws(token)
49
+                .getBody();
50
+    }
51
+
52
+    private Boolean isTokenExpired(String token) {
53
+        return extractExpiration(token).before(new Date());
54
+    }
55
+
56
+    public Boolean validateToken(String token, UserDetails userDetails) {
57
+        final String username = extractUsername(token);
58
+        return (RSAUtils.decryptBase64(username).equals(userDetails.getUsername()) && !isTokenExpired(token));
59
+    }
60
+
61
+
62
+    public String generateToken(String userName){
63
+        Map<String,Object> claims=new HashMap<>();
64
+        return createToken(claims,userName);
65
+    }
66
+
67
+    private String createToken(Map<String, Object> claims, String userName) {
68
+        return Jwts.builder()
69
+                .setClaims(claims)
70
+                .setSubject(RSAUtils.encryptBase64(userName))
71
+                .setIssuedAt(new Date(System.currentTimeMillis()))
72
+                .setExpiration(new Date(System.currentTimeMillis()+1000*60*30))
73
+                .signWith(getSignKey(), SignatureAlgorithm.HS256).compact();
74
+    }
75
+
76
+    private Key getSignKey() {
77
+        byte[] keyBytes= Decoders.BASE64.decode(SECRET);
78
+        return Keys.hmacShaKeyFor(keyBytes);
79
+    }
80
+}

+ 112 - 0
src/main/java/com/lqkj/link/module/zone/controller/GeomInfoController.java

@@ -0,0 +1,112 @@
1
+package com.lqkj.link.module.zone.controller;
2
+
3
+import com.lqkj.link.message.MessageBean;
4
+import com.lqkj.link.message.MessageListBean;
5
+import com.lqkj.link.module.base.service.BaseService;
6
+import com.lqkj.link.module.zone.domain.GeomInfo;
7
+import com.lqkj.link.module.zone.domain.OneZoneGeomInfos;
8
+import com.lqkj.link.module.zone.service.GeomInfoService;
9
+import io.swagger.v3.oas.annotations.Operation;
10
+import io.swagger.v3.oas.annotations.Parameter;
11
+import io.swagger.v3.oas.annotations.media.Content;
12
+import io.swagger.v3.oas.annotations.media.Schema;
13
+import io.swagger.v3.oas.annotations.tags.Tag;
14
+import org.springframework.web.bind.annotation.*;
15
+import org.springframework.web.multipart.MultipartFile;
16
+
17
+import java.util.List;
18
+
19
+import static com.lqkj.link.APIVersion.VERSION_V1;
20
+import static com.lqkj.link.APIVersion.VERSION_V2;
21
+
22
+@RestController
23
+@RequestMapping("/geom")
24
+@Tag(name = "场景元素信息", description = "场景元素信息")
25
+public class GeomInfoController {
26
+    private final GeomInfoService geomInfoService;
27
+    private final BaseService baseService;
28
+
29
+    public GeomInfoController(GeomInfoService geomInfoService, BaseService baseService) {
30
+        this.geomInfoService = geomInfoService;
31
+        this.baseService = baseService;
32
+    }
33
+
34
+    @Operation(
35
+            summary = "5.1.2.8 下载场景信息接口",
36
+            description = "5.1.2.8 下载场景信息接口",
37
+            parameters = {
38
+                    @Parameter(name = "zoneId", required = true, description = "作品/区域ID")
39
+            }
40
+    )
41
+    @PostMapping("/" + VERSION_V1 + "/byZone")
42
+    public List<GeomInfo> findByZone(@RequestParam Integer zoneId) {
43
+        return geomInfoService.findAllByZoneId(zoneId);
44
+    }
45
+
46
+    @Operation(
47
+            summary = "5.1.2.33 下载场景信息接口V2",
48
+            description = "5.1.2.33 下载场景信息接口V2",
49
+            parameters = {
50
+                    @Parameter(name = "zoneId", required = true, description = "作品/区域ID")
51
+            }
52
+    )
53
+    @PostMapping("/" + VERSION_V2 + "/byZone")
54
+    public MessageListBean<GeomInfo> findByZoneV2(@RequestParam Integer zoneId) {
55
+        return MessageListBean.ok(geomInfoService.findAllByZoneId(zoneId), "下载场景信息接口");
56
+    }
57
+
58
+    @Operation(
59
+            summary = "5.1.2.23 保存场景信息",
60
+            description = "5.1.2.23 保存场景信息",
61
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
62
+                    description = "场景元素信息",
63
+                    required = true,
64
+                    content = @Content(
65
+                            mediaType = "application/json",
66
+                            schema = @Schema(implementation = OneZoneGeomInfos.class)
67
+                    )
68
+            )
69
+    )
70
+    @PostMapping("" + VERSION_V1 + "/saveGeom")
71
+    public MessageBean saveGeom(@RequestBody OneZoneGeomInfos geomInfos) {
72
+        geomInfoService.saveLayerByZone(geomInfos);
73
+        geomInfoService.saveGeomByZone(geomInfos);
74
+        return MessageBean.ok(null,"保存场景信息");
75
+    }
76
+
77
+    @Operation(
78
+            summary = "5.1.3.28 创作中心上传图片文件",
79
+            description = "5.1.3.28 创作中心上传图片文件",
80
+            parameters = {
81
+                    @Parameter(name = "file", description = "图标文件", required = true)
82
+            }
83
+    )
84
+    @PostMapping("/" + VERSION_V1 + "/uploadImg")
85
+    public MessageBean<String> uploadImg(MultipartFile file) {
86
+        return baseService.uploadImg(file, "zone/img/");
87
+    }
88
+
89
+    @Operation(
90
+            summary = "5.1.3.29 创作中心上传音频文件",
91
+            description = "5.1.3.29 创作中心上传音频文件",
92
+            parameters = {
93
+                    @Parameter(name = "file", description = "音频文件", required = true)
94
+            }
95
+    )
96
+    @PostMapping("/" + VERSION_V1 + "/uploadAudio")
97
+    public MessageBean<String> uploadAudio(@RequestParam MultipartFile file) {
98
+        return baseService.uploadAudio(file, "zone/audio/");
99
+    }
100
+
101
+    @Operation(
102
+            summary = "5.1.3.30 创作中心上传视频文件",
103
+            description = "5.1.3.30 创作中心上传视频文件",
104
+            parameters = {
105
+                    @Parameter(name = "file", description = "视频文件", required = true)
106
+            }
107
+    )
108
+    @PostMapping("/" + VERSION_V1 + "/uploadVideo")
109
+    public MessageBean<String> uploadVideo(@RequestParam MultipartFile file) {
110
+        return baseService.uploadVideo(file, "zone/video/");
111
+    }
112
+}

+ 39 - 0
src/main/java/com/lqkj/link/module/zone/controller/LayerInfoController.java

@@ -0,0 +1,39 @@
1
+package com.lqkj.link.module.zone.controller;
2
+
3
+import com.lqkj.link.module.zone.domain.LayerInfo;
4
+import com.lqkj.link.module.zone.service.LayerInfoService;
5
+import io.swagger.v3.oas.annotations.Operation;
6
+import io.swagger.v3.oas.annotations.Parameter;
7
+import io.swagger.v3.oas.annotations.tags.Tag;
8
+import org.springframework.web.bind.annotation.PostMapping;
9
+import org.springframework.web.bind.annotation.RequestMapping;
10
+import org.springframework.web.bind.annotation.RequestParam;
11
+import org.springframework.web.bind.annotation.RestController;
12
+
13
+import java.util.List;
14
+
15
+import static com.lqkj.link.APIVersion.VERSION_V2;
16
+
17
+@RestController
18
+@RequestMapping("/layer")
19
+@Tag(name = "图层信息", description = "图层信息")
20
+public class LayerInfoController {
21
+    private final LayerInfoService layerInfoService;
22
+
23
+    public LayerInfoController(LayerInfoService layerInfoService) {
24
+        this.layerInfoService = layerInfoService;
25
+    }
26
+
27
+    @Operation(
28
+            summary = "5.1.2.17 图层目录读取接口V2",
29
+            description = "5.1.2.17 图层目录读取接口V2",
30
+            parameters = {
31
+                    @Parameter(name = "zoneId", description = "作品ID", required = true)
32
+            }
33
+    )
34
+    @PostMapping("/" + VERSION_V2 + "/byZone")
35
+    public List<LayerInfo> queryLayersV2(@RequestParam Integer zoneId) {
36
+        return layerInfoService.queryByZoneId(zoneId);
37
+    }
38
+
39
+}

+ 233 - 0
src/main/java/com/lqkj/link/module/zone/controller/ResourceController.java

@@ -0,0 +1,233 @@
1
+package com.lqkj.link.module.zone.controller;
2
+
3
+
4
+import com.lqkj.link.message.MessageBean;
5
+import com.lqkj.link.module.authority.service.UserInfoService;
6
+import com.lqkj.link.module.base.service.BaseService;
7
+import com.lqkj.link.module.jwt.service.JwtService;
8
+import com.lqkj.link.module.zone.domain.ModelCategory;
9
+import com.lqkj.link.module.zone.domain.ModelInfo;
10
+import com.lqkj.link.module.zone.service.ResourceService;
11
+import io.swagger.v3.oas.annotations.Operation;
12
+import io.swagger.v3.oas.annotations.Parameter;
13
+import io.swagger.v3.oas.annotations.media.Content;
14
+import io.swagger.v3.oas.annotations.media.Schema;
15
+import io.swagger.v3.oas.annotations.tags.Tag;
16
+import jakarta.servlet.http.HttpServletRequest;
17
+import org.apache.commons.compress.archivers.ArchiveException;
18
+import org.apache.commons.lang3.StringUtils;
19
+import org.aspectj.bridge.Message;
20
+import org.springframework.data.domain.Page;
21
+import org.springframework.web.bind.annotation.*;
22
+import org.springframework.web.multipart.MultipartFile;
23
+
24
+import java.io.IOException;
25
+import java.util.List;
26
+import java.util.Map;
27
+
28
+import static com.lqkj.link.APIVersion.VERSION_V1;
29
+
30
+@RestController
31
+@RequestMapping("/resource")
32
+@Tag(name = "资源管理", description = "资源管理")
33
+public class ResourceController {
34
+    private final ResourceService resourceService;
35
+    private final BaseService baseService;
36
+    private final JwtService jwtService;
37
+    private final UserInfoService userInfoService;
38
+
39
+    public ResourceController(ResourceService resourceService, BaseService baseService, JwtService jwtService, UserInfoService userInfoService) {
40
+        this.resourceService = resourceService;
41
+        this.baseService = baseService;
42
+        this.jwtService = jwtService;
43
+        this.userInfoService = userInfoService;
44
+    }
45
+
46
+    @Operation(
47
+            summary = "5.1.3.5 资源分页接口",
48
+            description = "5.1.3.1 资源分页接口",
49
+            parameters = {
50
+                    @Parameter(name = "name", description = "搜索关键词"),
51
+                    @Parameter(name = "page", description = "页码"),
52
+                    @Parameter(name = "pageSize", description = "每页数据条数")
53
+            }
54
+    )
55
+    @PostMapping("/manage/pageQuery")
56
+    public MessageBean<Page<ModelCategory>> pageQueryTemplate(@RequestParam(required = false, defaultValue = "") String name,
57
+                                                              @RequestParam(required = false, defaultValue = "0") Integer page,
58
+                                                              @RequestParam(required = false, defaultValue = "10") Integer pageSize){
59
+        return MessageBean.ok(resourceService.pageQuery(name, page, pageSize), "资源分页接口");
60
+    }
61
+
62
+    @Operation(
63
+            summary = "5.1.3.25 资源详情接口",
64
+            description = "5.1.3.25 资源详情接口",
65
+            parameters = {
66
+                    @Parameter(name = "categoryId", description = "资源ID")
67
+            }
68
+    )
69
+    @PostMapping("/manage/detail")
70
+    public MessageBean<ModelCategory> detail(@RequestParam Integer categoryId) {
71
+        return MessageBean.ok(resourceService.detail(categoryId), "获取资源详情");
72
+    }
73
+
74
+    @Operation(
75
+            summary = "5.1.3.26 上传图标文件",
76
+            description = "5.1.3.26 上传图标文件",
77
+            parameters = {
78
+                    @Parameter(name = "file", description = "图标文件", required = true)
79
+            }
80
+    )
81
+    @PostMapping("/manage/uploadImg")
82
+    public MessageBean<String> uploadImg(@RequestParam MultipartFile file) {
83
+        return baseService.uploadImg(file, "resource/icon/");
84
+    }
85
+
86
+    @Operation(
87
+            summary = "5.1.3.6 资源保存接口",
88
+            description = "5.1.3.6 资源保存接口",
89
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
90
+                    description = "资源信息对象",
91
+                    required = true,
92
+                    content = @Content(
93
+                            mediaType = "application/json",
94
+                            schema = @Schema(implementation = ModelCategory.class)
95
+                    )
96
+            )
97
+    )
98
+    @PostMapping("/manage/save")
99
+    public MessageBean<Object> save(@RequestBody ModelCategory category) throws IOException, ArchiveException {
100
+        String msg = resourceService.save(category);
101
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
102
+        return MessageBean.ok(null, "资源保存接口");
103
+    }
104
+
105
+    @Operation(
106
+            summary = "5.1.3.7 模型上传接口",
107
+            description = "5.1.3.7 模型上传接口",
108
+            parameters = {
109
+                    @Parameter(name = "file", description = "模型文件", required = true)
110
+            }
111
+    )
112
+    @PostMapping({"/manage/addModel", "/" + VERSION_V1 + "/addModel"})
113
+    public MessageBean<String> addModel(MultipartFile file,
114
+                                        HttpServletRequest request) {
115
+        String authHeader = request.getHeader("Authorization");
116
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
117
+        Integer userId = userInfoService.detailByUserCode(userCode).getUserId();
118
+        return baseService.uploadModel(file, "resource/model/" + userId + "/");
119
+    }
120
+
121
+    @Operation(
122
+            summary = "5.1.3.33 空间信息json文件上传接口",
123
+            description = "5.1.3.33 空间信息json文件上传接口",
124
+            parameters = {
125
+                    @Parameter(name = "file", description = "空间信息json文件上传接口", required = true)
126
+            }
127
+    )
128
+    @PostMapping({"/" + VERSION_V1 + "/addJsonFile"})
129
+    public MessageBean<String> addJsonFile(MultipartFile file) {
130
+        return baseService.uploadJsonFile(file, "resource/model/json/");
131
+    }
132
+
133
+    @Operation(
134
+            summary = "5.1.3.7 模型压缩文件上传接口",
135
+            description = "5.1.3.7 模型压缩文件上传接口",
136
+            parameters = {
137
+                    @Parameter(name = "file", description = "模型压缩文件,只支持zip格式", required = true)
138
+            }
139
+    )
140
+    @PostMapping({"/manage/addModelCompress"})
141
+    public MessageBean<String> addModelCompress(MultipartFile file) {
142
+        return baseService.uploadModelCompress(file, "resource/model/");
143
+    }
144
+
145
+    @Operation(
146
+            summary = "5.1.3.8 资源删除接口",
147
+            description = "5.1.3.8 资源删除接口",
148
+            parameters = {
149
+                    @Parameter(name = "categoryId", description = "资源分类ID", required = true)
150
+            }
151
+    )
152
+    @PostMapping({"/manage/delete", "/" + VERSION_V1 + "/deletePersonal"})
153
+    public MessageBean<String > delete(@RequestParam List<Integer> categoryId) {
154
+        resourceService.deleteCategory(categoryId);
155
+        return MessageBean.ok(null, "删除资源");
156
+    }
157
+
158
+    @Operation(
159
+            summary = "5.1.3.27 模型删除接口",
160
+            description = "5.1.3.27 模型删除接口",
161
+            parameters = {
162
+                    @Parameter(name = "modelId", description = "模型信息ID", required = true)
163
+            }
164
+    )
165
+    @PostMapping({"/manage/deleteModel","/" + VERSION_V1 + "/deleteModel"})
166
+    public MessageBean<Object> deleteModel(@RequestParam Integer modelId) {
167
+        resourceService.deleteModel(modelId);
168
+        return MessageBean.ok(null, "模型删除接口");
169
+    }
170
+
171
+    @Operation(
172
+            summary = "5.1.2.19 资源分类列表接口",
173
+            description = "5.1.2.19 资源分类列表接口"
174
+    )
175
+    @PostMapping("/" + VERSION_V1 + "/categories")
176
+    public List<Map<String, Object>> resourceCategory(HttpServletRequest request) {
177
+        String authHeader = request.getHeader("Authorization");
178
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
179
+        return resourceService.resourceCategory(userCode);
180
+    }
181
+
182
+    @Operation(
183
+            summary = "5.1.2.20 模型列表接口",
184
+            description = "5.1.2.20 模型列表接口"
185
+    )
186
+    @PostMapping("/" + VERSION_V1 + "/models")
187
+    public List<ModelInfo> models(HttpServletRequest request) {
188
+        String authHeader = request.getHeader("Authorization");
189
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
190
+        return resourceService.models(userCode);
191
+    }
192
+
193
+    @Operation(
194
+            summary = "5.1.2.21 个人文件夹保存接口",
195
+            description = "5.1.2.21 个人文件夹保存接口",
196
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
197
+                    description = "资源信息对象",
198
+                    required = true,
199
+                    content = @Content(
200
+                            mediaType = "application/json",
201
+                            schema = @Schema(implementation = ModelCategory.class)
202
+                    )
203
+            )
204
+    )
205
+    @PostMapping("/" + VERSION_V1 + "/savePersonal")
206
+    public MessageBean<String> savePersonal(@RequestBody ModelCategory category,
207
+                                    HttpServletRequest request) {
208
+        String authHeader = request.getHeader("Authorization");
209
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
210
+        String msg = resourceService.savePersonal(category, userCode);
211
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
212
+        return MessageBean.ok(null, "个人文件夹保存接口");
213
+    }
214
+
215
+    @Operation(
216
+            summary = "5.1.2.31 模型信息保存接口",
217
+            description = "5.1.2.31 模型信息保存接口",
218
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
219
+                    description = "模型信息对象",
220
+                    required = true,
221
+                    content = @Content(
222
+                            mediaType = "application/json",
223
+                            schema = @Schema(implementation = ModelInfo.class)
224
+                    )
225
+            )
226
+    )
227
+    @PostMapping("/" + VERSION_V1 + "/saveModel")
228
+    public MessageBean<ModelInfo> saveModel(@RequestBody ModelInfo modelInfo) {
229
+        resourceService.saveModel(modelInfo);
230
+        return MessageBean.ok(null, "个人文件夹保存接口");
231
+    }
232
+
233
+}

+ 337 - 0
src/main/java/com/lqkj/link/module/zone/controller/ZoneInfoController.java

@@ -0,0 +1,337 @@
1
+package com.lqkj.link.module.zone.controller;
2
+
3
+import com.alibaba.fastjson2.JSONObject;
4
+import com.lqkj.link.message.MessageBean;
5
+import com.lqkj.link.message.MessageListBean;
6
+import com.lqkj.link.module.base.service.BaseService;
7
+import com.lqkj.link.module.jwt.service.JwtService;
8
+import com.lqkj.link.module.zone.domain.ZoneInfo;
9
+import com.lqkj.link.module.zone.service.ZoneInfoService;
10
+import com.lqkj.link.util.FileUtils;
11
+import io.swagger.v3.oas.annotations.Operation;
12
+import io.swagger.v3.oas.annotations.Parameter;
13
+import io.swagger.v3.oas.annotations.media.Content;
14
+import io.swagger.v3.oas.annotations.media.Schema;
15
+import io.swagger.v3.oas.annotations.tags.Tag;
16
+import jakarta.servlet.http.HttpServletRequest;
17
+import org.apache.commons.lang3.StringUtils;
18
+import org.springframework.data.domain.Page;
19
+import org.springframework.web.bind.annotation.*;
20
+import org.springframework.web.multipart.MultipartFile;
21
+
22
+import java.util.List;
23
+import java.util.Map;
24
+import java.util.UUID;
25
+
26
+import static com.lqkj.link.APIVersion.VERSION_V1;
27
+
28
+@RestController
29
+@RequestMapping("/zone")
30
+@Tag(name = "作品/模板管理", description = "作品/模板管理")
31
+public class ZoneInfoController {
32
+
33
+    private final ZoneInfoService zoneInfoService;
34
+    private final JwtService jwtService;
35
+    private final BaseService baseService;
36
+
37
+    public ZoneInfoController(ZoneInfoService zoneInfoService, JwtService jwtService, BaseService baseService) {
38
+        this.zoneInfoService = zoneInfoService;
39
+        this.jwtService = jwtService;
40
+        this.baseService = baseService;
41
+    }
42
+
43
+    @Operation(
44
+            summary = "5.1.3.1 模板分页接口",
45
+            description = "5.1.3.1 模板分页接口",
46
+            parameters = {
47
+                    @Parameter(name = "name", description = "搜索关键词"),
48
+                    @Parameter(name = "page", description = "页码"),
49
+                    @Parameter(name = "pageSize", description = "每页数据条数")
50
+            }
51
+    )
52
+    @PostMapping({"/template/pageQuery", "/" + VERSION_V1 + "/templateList"})
53
+    public MessageBean<Page<ZoneInfo>> pageQueryTemplate(@RequestParam(required = false, defaultValue = "") String name,
54
+                                                         @RequestParam(required = false, defaultValue = "0") Integer page,
55
+                                                         @RequestParam(required = false, defaultValue = "10") Integer pageSize){
56
+        return MessageBean.ok(zoneInfoService.pageQueryTemplate(name, page, pageSize), "分页查询模板");
57
+    }
58
+
59
+    @Operation(
60
+            summary = "5.1.3.2 模板保存接口",
61
+            description = "5.1.3.2 模板保存接口",
62
+            requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
63
+                    description = "请求对象",
64
+                    required = true,
65
+                    content = @Content(
66
+                            mediaType = "application/json",
67
+                            schema = @Schema(implementation = ZoneInfo.class)
68
+                    )
69
+            )
70
+    )
71
+    @PostMapping("/template/save")
72
+    public MessageBean<ZoneInfo> saveTemplate(@RequestBody ZoneInfo zoneInfo) {
73
+        Map<String, Object> result = zoneInfoService.saveTemplate(zoneInfo);
74
+        if (result.getOrDefault("msg", null) != null) return MessageBean.error((String) result.get("msg"));
75
+        return MessageBean.ok((ZoneInfo) result.get("zone"), "模板保存接口");
76
+    }
77
+
78
+    @Operation(
79
+            summary = "5.1.3.3 模板删除接口",
80
+            description = "5.1.3.3 模板删除接口",
81
+            parameters = {
82
+                    @Parameter(name = "zoneIds", description = "模板ID", required = true)
83
+            }
84
+    )
85
+    @PostMapping("/template/delete")
86
+    public MessageBean deleteTemplate(@RequestParam List<Integer> zoneIds) {
87
+        zoneInfoService.deleteTemplate(zoneIds);
88
+        return MessageBean.ok(null, "模板删除接口");
89
+    }
90
+
91
+    @Operation(
92
+            summary = "5.1.3.4 上传模板zip文件",
93
+            description = "5.1.3.4 上传模板zip文件",
94
+            parameters = {
95
+                    @Parameter(name = "file", description = "模板zip文件", required = true, schema = @Schema(implementation = MultipartFile.class))
96
+            }
97
+    )
98
+    @PostMapping("/template/uploadTemplateZip")
99
+    public MessageBean<String> uploadTemplateZip(@RequestParam MultipartFile file) {
100
+        String fileName = file.getOriginalFilename();
101
+        String suffix = fileName == null ? "" : fileName.substring(fileName.lastIndexOf(".") + 1);
102
+        if (!suffix.equals("zip"))
103
+            return MessageBean.error("上传文件类型必须是zip压缩文件");
104
+        String newFileName = UUID.randomUUID() + ".zip";
105
+        String filePath = "./upload/template/";
106
+        FileUtils.saveFile(file, filePath, newFileName);
107
+        return MessageBean.ok(filePath.substring(1) + newFileName, "上传模板zip文件");
108
+    }
109
+
110
+    @Operation(
111
+            summary = "5.1.3.31 模板管理上传图片",
112
+            description = "5.1.3.31 模板管理上传图片",
113
+            parameters = {
114
+                    @Parameter(name = "file", description = "图标文件", required = true)
115
+            }
116
+    )
117
+    @PostMapping("/template/uploadImg")
118
+    public MessageBean<String> uploadImg(@RequestParam MultipartFile file) {
119
+        return baseService.uploadImg(file, "template/thumbnail/");
120
+    }
121
+
122
+    @Operation(
123
+            summary = "5.1.2.2 我的作品自动补全接口",
124
+            description = "5.1.2.2 我的作品自动补全接口",
125
+            parameters = {
126
+                    @Parameter(name = "keyword", description = "搜索关键词")
127
+            }
128
+    )
129
+    @PostMapping("/" + VERSION_V1 + "/autoCompleteMyWork")
130
+    public MessageListBean<String> autoCompleteMyWork(HttpServletRequest request,
131
+                                                      @RequestParam String keyword) {
132
+        String authHeader = request.getHeader("Authorization");
133
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
134
+        if (StringUtils.isBlank(keyword)) return MessageListBean.error("关键词为空!");
135
+        return MessageListBean.ok(zoneInfoService.autoCompleteMyWork(userCode, keyword), "我的作品自动补全");
136
+    }
137
+
138
+    @Operation(
139
+            summary = "5.1.2.24 资源中心自动补全接口",
140
+            description = "5.1.2.24 资源中心自动补全接口",
141
+            parameters = {
142
+                    @Parameter(name = "keyword", description = "搜索关键词"),
143
+                    @Parameter(name = "searchType", description = "搜索类型,0全部,1官方,2个人")
144
+            }
145
+    )
146
+    @PostMapping("/" + VERSION_V1 + "/autoCompleteResource")
147
+    public MessageListBean<String> autoCompleteResource(@RequestParam String keyword,
148
+                                                        @RequestParam(required = false, defaultValue = "0") Integer searchType) {
149
+        if (StringUtils.isBlank(keyword)) return MessageListBean.error("关键词为空!");
150
+        return MessageListBean.ok(zoneInfoService.autoCompleteResource(keyword, searchType), "资源中心自动补全");
151
+    }
152
+
153
+    @Operation(
154
+            summary = "5.1.2.25 审核中心自动补全接口",
155
+            description = "5.1.2.25 审核中心自动补全接口",
156
+            parameters = {
157
+                    @Parameter(name = "keyword", description = "搜索关键词"),
158
+                    @Parameter(name = "searchType", description = "搜索类型,0全部,1未审核,2已审核")
159
+            }
160
+    )
161
+    @PostMapping("/" + VERSION_V1 + "/autoCompleteAudit")
162
+    public MessageListBean<String> autoCompleteAudit(@RequestParam String keyword,
163
+                                                        @RequestParam(required = false, defaultValue = "0") Integer searchType) {
164
+        if (StringUtils.isBlank(keyword)) return MessageListBean.error("关键词为空!");
165
+        return MessageListBean.ok(zoneInfoService.autoCompleteAudit(keyword, searchType), "审核中心自动补全");
166
+    }
167
+
168
+
169
+    @Operation(
170
+            summary = "5.1.2.3 我的作品接口",
171
+            description = "5.1.2.3 我的作品接口",
172
+            parameters = {
173
+                    @Parameter(name = "name", description = "作品名称"),
174
+                    @Parameter(name = "page", description = "页码"),
175
+                    @Parameter(name = "pageSize", description = "每页数据条数")
176
+            }
177
+    )
178
+    @PostMapping("" + VERSION_V1 + "/myWork")
179
+    public MessageBean<Page<ZoneInfo>> myWork(@RequestParam(required = false, defaultValue = "") String name,
180
+                                        @RequestParam(required = false, defaultValue = "0") Integer page,
181
+                                        @RequestParam(required = false, defaultValue = "10") Integer pageSize,
182
+                                        HttpServletRequest request) {
183
+        String authHeader = request.getHeader("Authorization");
184
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
185
+        return MessageBean.ok(zoneInfoService.myWork(userCode, name, page, pageSize), "我的作品");
186
+    }
187
+
188
+    @Operation(
189
+            summary = "5.1.2.4 资源中心接口",
190
+            description = "5.1.2.4 资源中心接口",
191
+            parameters = {
192
+                    @Parameter(name = "name", description = "作品名称"),
193
+                    @Parameter(name = "searchType", description = "搜索类型,0全部,1官方,2个人"),
194
+                    @Parameter(name = "page", description = "页码"),
195
+                    @Parameter(name = "pageSize", description = "每页数据条数")
196
+            }
197
+    )
198
+    @PostMapping("/" + VERSION_V1 + "/resourceCenter")
199
+    public MessageBean<Page<Map<String, Object>>> resourceCenter(@RequestParam(required = false, defaultValue = "") String name,
200
+                                                                 @RequestParam(required = false, defaultValue = "0") Integer searchType,
201
+                                                                 @RequestParam(required = false, defaultValue = "0") Integer page,
202
+                                                                 @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
203
+        return MessageBean.ok(zoneInfoService.resourceCenter(name, searchType, page, pageSize), "资源中心");
204
+    }
205
+
206
+    @Operation(
207
+            summary = "5.1.2.16 查看接口",
208
+            description = "5.1.2.16 查看接口",
209
+            parameters = {
210
+                    @Parameter(name = "zoneId", description = "作品ID", required = true)
211
+            }
212
+    )
213
+    @PostMapping("/" + VERSION_V1 + "/view")
214
+    public MessageBean<String> view(@RequestParam Integer zoneId,
215
+                                     HttpServletRequest request) {
216
+        String authHeader = request.getHeader("Authorization");
217
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
218
+        zoneInfoService.view(zoneId, userCode);
219
+        return MessageBean.ok(null, "查看");
220
+    }
221
+
222
+    @Operation(
223
+            summary = "5.1.2.5 分享接口",
224
+            description = "5.1.2.5 分享接口",
225
+            parameters = {
226
+                    @Parameter(name = "zoneId", description = "作品ID", required = true)
227
+            }
228
+    )
229
+    @PostMapping("/" + VERSION_V1 + "/share")
230
+    public MessageBean<String> share(@RequestParam Integer zoneId,
231
+                                     HttpServletRequest request) {
232
+        String authHeader = request.getHeader("Authorization");
233
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
234
+        return MessageBean.ok(zoneInfoService.share(zoneId, userCode), "分享");
235
+    }
236
+
237
+    @Operation(
238
+            summary = "5.1.2.6 重命名接口",
239
+            description = "5.1.2.6 重命名接口",
240
+            parameters = {
241
+                    @Parameter(name = "zoneId", description = "作品ID", required = true),
242
+                    @Parameter(name = "newName", description = "新名称", required = true)
243
+            }
244
+    )
245
+    @PostMapping("/" + VERSION_V1 + "/rename")
246
+    public MessageBean<String> rename(@RequestParam Integer zoneId,
247
+                                     @RequestParam String newName,
248
+                                     HttpServletRequest request) {
249
+        if (StringUtils.isBlank(newName)) return MessageBean.error("作品名称不能为空!");
250
+        String authHeader = request.getHeader("Authorization");
251
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
252
+        String msg = zoneInfoService.rename(zoneId, newName, userCode);
253
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
254
+        return MessageBean.ok(null, "重命名");
255
+    }
256
+
257
+    @Operation(
258
+            summary = "5.1.2.7 删除接口",
259
+            description = "5.1.2.7 删除接口",
260
+            parameters = {
261
+                    @Parameter(name = "zoneId", description = "作品ID", required = true)
262
+            }
263
+    )
264
+    @PostMapping("/" + VERSION_V1 + "/delete")
265
+    public MessageBean<String> delete(@RequestParam Integer zoneId,
266
+                                      HttpServletRequest request) {
267
+        String authHeader = request.getHeader("Authorization");
268
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
269
+        String msg = zoneInfoService.deleteWork(zoneId, userCode);
270
+        if (StringUtils.isNotBlank(msg)) return MessageBean.error(msg);
271
+        return MessageBean.ok(null, "删除");
272
+    }
273
+
274
+    @Operation(
275
+            summary = "5.1.2.9 审核中心接口",
276
+            description = "5.1.2.9 审核中心接口",
277
+            parameters = {
278
+                    @Parameter(name = "name", description = "作品名称"),
279
+                    @Parameter(name = "searchType", description = "搜索类型,0全部,1未审核,2已审核"),
280
+                    @Parameter(name = "page", description = "页码"),
281
+                    @Parameter(name = "pageSize", description = "每页数据条数")
282
+            }
283
+    )
284
+    @PostMapping("/" + VERSION_V1 + "/auditCenter")
285
+    public MessageBean<Page<Map<String, Object>>> auditCenter(@RequestParam(required = false, defaultValue = "") String name,
286
+                                                                 @RequestParam(required = false, defaultValue = "0") Integer searchType,
287
+                                                                 @RequestParam(required = false, defaultValue = "0") Integer page,
288
+                                                                 @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
289
+        return MessageBean.ok(zoneInfoService.auditCenter(name, searchType, page, pageSize), "审核中心");
290
+    }
291
+
292
+    @Operation(
293
+            summary = "5.1.2.11 创建作品",
294
+            description = "5.1.2.11 创建作品",
295
+            parameters = {
296
+                    @Parameter(name = "name", description = "作品名称", required = true),
297
+                    @Parameter(name = "templateId", description = "模板作品ID")
298
+            }
299
+    )
300
+    @PostMapping("/" + VERSION_V1 + "/create")
301
+    public MessageBean<ZoneInfo> create(@RequestParam String name,
302
+                                        @RequestParam(required = false) Integer templateId,
303
+                                        HttpServletRequest request) {
304
+        String authHeader = request.getHeader("Authorization");
305
+        String userCode = jwtService.decryptUsernameWithHeader(authHeader);
306
+        Map<String, Object> result = zoneInfoService.create(name, templateId, userCode);
307
+        if (result.getOrDefault("msg", null) != null) return MessageBean.error((String) result.get("msg"));
308
+        return MessageBean.ok((ZoneInfo) result.get("zone"), "创建作品");
309
+    }
310
+
311
+    @Operation(
312
+            summary = "5.1.2.35 保存缩略图接口",
313
+            description = "5.1.2.35 保存缩略图接口",
314
+            parameters = {
315
+                    @Parameter(name = "zoneId", description = "作品ID", required = true),
316
+                    @Parameter(name = "thumbnailPath", description = "缩略图路径", required = true)
317
+            }
318
+    )
319
+    @PostMapping("/" + VERSION_V1 + "/saveThumbnail")
320
+    public MessageBean<String> saveThumbnail(@RequestParam Integer zoneId,
321
+                                      @RequestParam String thumbnailPath) {
322
+        zoneInfoService.saveThumbnail(zoneId, thumbnailPath);
323
+        return MessageBean.ok(null, "保存缩略图");
324
+    }
325
+
326
+    @Operation(
327
+            summary = "5.1.2.37 获取变换接口",
328
+            description = "5.1.2.37 获取变换接口",
329
+            parameters = {
330
+                    @Parameter(name = "zoneId", description = "作品ID", required = true)
331
+            }
332
+    )
333
+    @PostMapping("/" + VERSION_V1 + "/loadTrans")
334
+    public MessageBean<JSONObject> loadTrans(@RequestParam Integer zoneId) {
335
+        return MessageBean.ok(zoneInfoService.readTrans(zoneId), "获取变换接口");
336
+    }
337
+}

+ 67 - 0
src/main/java/com/lqkj/link/module/zone/domain/GeomInfo.java

@@ -0,0 +1,67 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import com.alibaba.fastjson2.JSONArray;
4
+import com.alibaba.fastjson2.JSONObject;
5
+import com.fasterxml.jackson.annotation.JsonIgnore;
6
+import io.hypersistence.utils.hibernate.type.json.JsonType;
7
+import jakarta.persistence.*;
8
+import lombok.AllArgsConstructor;
9
+import lombok.Getter;
10
+import lombok.NoArgsConstructor;
11
+import lombok.Setter;
12
+import org.hibernate.annotations.Type;
13
+import org.locationtech.jts.geom.Point;
14
+
15
+@Entity
16
+@Table(name = "geom_info")
17
+@Getter
18
+@Setter
19
+@NoArgsConstructor
20
+@AllArgsConstructor
21
+public class GeomInfo {
22
+    @Id
23
+    @Column(name = "geom_id")
24
+    private String geomId;
25
+    @Column(name = "zone_id")
26
+    private Integer zoneId;
27
+    @Column(name = "model_id")
28
+    private Integer modelId;
29
+    @Column(name = "layer_id")
30
+    private String layerId;
31
+    @Column(name = "geom_name")
32
+    private String geomName;
33
+    @Column(name = "building_id")
34
+    private Integer buildingId;
35
+    @Column(name = "floor")
36
+    private Integer floor;
37
+    @Column(name = "room_id")
38
+    private Integer roomId;
39
+    @Column(name = "geom", columnDefinition = "Geometry")
40
+    @JsonIgnore
41
+    private Point geom;
42
+    @Type(JsonType.class)
43
+    @Column(name = "properties", columnDefinition = "jsonb")
44
+    private JSONArray properties;
45
+    @Column(name = "locking")
46
+    private Boolean locking;
47
+    @Transient
48
+    private JSONObject location;
49
+    @Transient
50
+    private String Name;
51
+    @Type(JsonType.class)
52
+    @Column(name = "trans", columnDefinition = "jsonb")
53
+    @JsonIgnore
54
+    private JSONObject trans;
55
+    @Transient
56
+    private String modelPath;
57
+
58
+    public JSONObject getLocation() {
59
+        if (location == null) return trans;
60
+        return location;
61
+    }
62
+
63
+    public String getName() {
64
+        return geomId;
65
+    }
66
+
67
+}

+ 30 - 0
src/main/java/com/lqkj/link/module/zone/domain/LayerInfo.java

@@ -0,0 +1,30 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import jakarta.persistence.*;
4
+import lombok.AllArgsConstructor;
5
+import lombok.Getter;
6
+import lombok.NoArgsConstructor;
7
+import lombok.Setter;
8
+
9
+@Entity
10
+@Table(name = "layer_info")
11
+@Getter
12
+@Setter
13
+@NoArgsConstructor
14
+@AllArgsConstructor
15
+public class LayerInfo {
16
+    @Id
17
+    @Column(name = "layer_id")
18
+    private String layerId;
19
+    @Column(name = "zone_id")
20
+    private Integer zoneId;
21
+    @Column(name = "layer_name")
22
+    private String layerName;
23
+    @Transient
24
+    private String Name;
25
+    @Column(name = "locking")
26
+    private Boolean locking;
27
+    public String getName() {
28
+        return layerId;
29
+    }
30
+}

+ 50 - 0
src/main/java/com/lqkj/link/module/zone/domain/ModelCategory.java

@@ -0,0 +1,50 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+import jakarta.persistence.*;
5
+import lombok.AllArgsConstructor;
6
+import lombok.Getter;
7
+import lombok.NoArgsConstructor;
8
+import lombok.Setter;
9
+
10
+import java.util.List;
11
+
12
+@Entity
13
+@Table(name = "model_category")
14
+@Getter
15
+@Setter
16
+@NoArgsConstructor
17
+@AllArgsConstructor
18
+public class ModelCategory {
19
+    @Id
20
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
21
+    @Column(name = "category_id")
22
+    @Schema(description = "资源分类ID")
23
+    private Integer categoryId;
24
+    @Column(name = "user_id")
25
+    @Schema(description = "所属用户ID")
26
+    private Integer userId;
27
+    @Column(name = "category_name")
28
+    @Schema(description = "分类/文件夹名称")
29
+    private String categoryName;
30
+    @Column(name = "icon")
31
+    @Schema(description = "分类图标")
32
+    private String icon;
33
+    @Column(name = "order_id")
34
+    @Schema(description = "排序")
35
+    private Integer orderId;
36
+    @Transient
37
+    @Schema(description = "模型列表")
38
+    private List<ModelInfo> modelInfoList;
39
+    @Transient
40
+    @Schema(description = "模型数量")
41
+    private Integer modelCount;
42
+    @Column(name = "compress_file_path")
43
+    @Schema(description = "模型压缩文件路径")
44
+    private String compressFilePath;
45
+    @Transient
46
+    @Schema(description = "是否有上传模型压缩文件")
47
+    private Boolean uploadCompress;
48
+    @Column(name = "compress_file_name")
49
+    private String compressFileName;
50
+}

+ 51 - 0
src/main/java/com/lqkj/link/module/zone/domain/ModelInfo.java

@@ -0,0 +1,51 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import io.swagger.v3.oas.annotations.media.Schema;
4
+import jakarta.persistence.*;
5
+import lombok.AllArgsConstructor;
6
+import lombok.Getter;
7
+import lombok.NoArgsConstructor;
8
+import lombok.Setter;
9
+
10
+@Entity
11
+@Table(name = "model_info")
12
+@Getter
13
+@Setter
14
+@NoArgsConstructor
15
+@AllArgsConstructor
16
+public class ModelInfo {
17
+    @Id
18
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
19
+    @Column(name = "model_id")
20
+    @Schema(description = "模型信息ID")
21
+    private Integer modelId;
22
+    @Column(name = "category_id")
23
+    @Schema(description = "分类/文件夹ID")
24
+    private Integer categoryId;
25
+    @Column(name = "model_name")
26
+    @Schema(description = "模型名称")
27
+    private String modelName;
28
+    @Column(name = "json_path")
29
+    @Schema(description = "空间信息json文件地址")
30
+    String jsonPath;
31
+    @Column(name = "texture_path")
32
+    @Schema(description = "贴图文件地址")
33
+    private String texturePath;
34
+    @Column(name = "order_id")
35
+    @Schema(description = "排序")
36
+    private Integer orderId;
37
+    @Column(name = "original_path")
38
+    @Schema(description = "原始文件地址")
39
+    private String originalPath;
40
+    @Column(name = "model_icon")
41
+    @Schema(description = "模型图标")
42
+    private String modelIcon;
43
+    @Transient
44
+    private String Name;
45
+    @Column(name = "template_id")
46
+    private Integer templateId;
47
+
48
+    public String getName() {
49
+        return modelId.toString();
50
+    }
51
+}

+ 18 - 0
src/main/java/com/lqkj/link/module/zone/domain/OneZoneGeomInfos.java

@@ -0,0 +1,18 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import com.alibaba.fastjson2.JSONObject;
4
+import lombok.Getter;
5
+import lombok.Setter;
6
+
7
+import java.util.List;
8
+
9
+@Getter
10
+@Setter
11
+public class OneZoneGeomInfos {
12
+    private Integer zoneId;
13
+    private List<GeomInfo> modifyGeomList;
14
+    private List<String> deleteGeomList;
15
+    private List<LayerInfo> modifyLayerList;
16
+    private List<String> deleteLayerList;
17
+    private JSONObject trans;
18
+}

+ 14 - 0
src/main/java/com/lqkj/link/module/zone/domain/TemplateInfo.java

@@ -0,0 +1,14 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import com.alibaba.fastjson2.JSONObject;
4
+import lombok.Getter;
5
+import lombok.Setter;
6
+
7
+import java.util.List;
8
+
9
+@Getter
10
+@Setter
11
+public class TemplateInfo {
12
+    private String modelPath;
13
+    private List<JSONObject> location;
14
+}

+ 62 - 0
src/main/java/com/lqkj/link/module/zone/domain/ZoneInfo.java

@@ -0,0 +1,62 @@
1
+package com.lqkj.link.module.zone.domain;
2
+
3
+import com.alibaba.fastjson2.JSONObject;
4
+import com.fasterxml.jackson.annotation.JsonFormat;
5
+import io.hypersistence.utils.hibernate.type.json.JsonType;
6
+import io.swagger.v3.oas.annotations.media.Schema;
7
+import jakarta.persistence.*;
8
+import lombok.AllArgsConstructor;
9
+import lombok.Getter;
10
+import lombok.NoArgsConstructor;
11
+import lombok.Setter;
12
+import org.hibernate.annotations.Type;
13
+
14
+import java.util.Date;
15
+
16
+@Entity
17
+@Table(name = "zone_info")
18
+@Getter
19
+@Setter
20
+@NoArgsConstructor
21
+@AllArgsConstructor
22
+public class ZoneInfo {
23
+    @Id
24
+    @Column(name = "zone_id")
25
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
26
+    @Schema(description = "区域/作品ID")
27
+    private Integer zoneId;
28
+    @Column(name = "user_id")
29
+    @Schema(description = "作者用户ID")
30
+    private Integer userId;
31
+    @Column(name = "zone_name")
32
+    @Schema(description = "区域/作品名称")
33
+    private String zoneName;
34
+    @Type(JsonType.class)
35
+    @Column(name = "init_location", columnDefinition = "jsonb")
36
+    @Schema(description = "场景初始坐标")
37
+    private JSONObject initLocation;
38
+    @Column(name = "thumbnail")
39
+    @Schema(description = "封面图")
40
+    private String thumbnail;
41
+    @Column(name = "auth_status")
42
+    @Schema(description = "审核状态,0未申请,1待审,2通过,3拒绝")
43
+    private Integer authStatus;
44
+    @Column(name = "update_time")
45
+    @JsonFormat(pattern = "YYYY-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
46
+    @Schema(description = "更新时间")
47
+    private Date updateTime;
48
+    @Column(name = "share_count")
49
+    @Schema(description = "分享次数")
50
+    private Integer shareCount;
51
+    @Column(name = "view_count")
52
+    @Schema(description = "查看次数")
53
+    private Integer viewCount;
54
+    @Column(name = "template_file_name")
55
+    @Schema(description = "模板文件名称")
56
+    private String templateFileName;
57
+    @Column(name = "template_file_path")
58
+    @Schema(description = "模板文件路径")
59
+    private String templateFilePath;
60
+    @Column(name = "template_use")
61
+    private Integer templateUse;
62
+}

+ 73 - 0
src/main/java/com/lqkj/link/module/zone/repository/GeomInfoRepository.java

@@ -0,0 +1,73 @@
1
+package com.lqkj.link.module.zone.repository;
2
+
3
+import com.lqkj.link.module.zone.domain.GeomInfo;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.data.jpa.repository.Modifying;
6
+import org.springframework.data.jpa.repository.Query;
7
+import org.springframework.data.repository.query.Param;
8
+import org.springframework.stereotype.Repository;
9
+
10
+import java.util.List;
11
+import java.util.Map;
12
+
13
+@Repository
14
+public interface GeomInfoRepository extends JpaRepository<GeomInfo, String> {
15
+
16
+    List<GeomInfo> findAllByZoneId(Integer zoneId);
17
+
18
+    @Modifying
19
+    @Query(nativeQuery = true,
20
+        value = "with t1 as(insert into geom_info(geom_id, zone_id, model_id, layer_id, geom_name, building_id, floor, room_id, geom, properties, locking) " +
21
+                "select nextval('geom_info_geom_id_seq'), :zoneId, model_id, layer_id, geom_name, building_id, floor, room_id, geom, properties, locking " +
22
+                "from geom_info where zone_id = :templateId order by geom_id returning *)" +
23
+                "select min(t1.geom_id) - min(gi.geom_id) from t1, geom_info gi where gi.geom_id = :templateId"
24
+    )
25
+    Integer createWithTemplateReturnIncrement(@Param("templateId") Integer templateId,
26
+                                              @Param("zoneId") Integer zoneId);
27
+
28
+    @Modifying
29
+    @Query(nativeQuery = true,
30
+            value = "insert into geom_info(geom_id, zone_id, model_id, layer_id, geom_name, building_id, floor, room_id, geom, properties, locking) " +
31
+                    "select nextval('geom_info_geom_id_seq'), :zoneId, model_id, layer_id, geom_name, building_id, floor, room_id, geom, properties, locking " +
32
+                    "from geom_info where zone_id = :templateId returning *"
33
+    )
34
+    List<GeomInfo> createWithTemplate(@Param("templateId") Integer templateId,
35
+                                              @Param("zoneId") Integer zoneId);
36
+
37
+    @Modifying
38
+    @Query(nativeQuery = true,
39
+        value = "with t1 as(update geom_info set building_id = building_id + :increment where zone_id = :zoneId and building_id is not null)" +
40
+                "update geom_info set room_id = room_id + :increment where zone_id = :zoneId and room_id is not null"
41
+    )
42
+    void updateBuildingIdAndRoomId(@Param("zoneId") Integer zoneId,
43
+                                   @Param("increment") Integer increment);
44
+
45
+    @Query(nativeQuery = true,
46
+        value = "select * from geom_info where zone_id = :zoneId and layer_id is not null"
47
+    )
48
+    List<GeomInfo> queryHasLayer(@Param("zoneId") Integer zoneId);
49
+
50
+    @Modifying
51
+    @Query(nativeQuery = true,
52
+        value = "update geom_info set layer_id = layer_id + :increment where zone_id = :zoneId and layer_id is not null"
53
+    )
54
+    void updateLayerId(@Param("zoneId") Integer zoneId,
55
+                       @Param("increment") Integer increment);
56
+
57
+    @Query(nativeQuery = true,
58
+        value = "select geom_id, geom_name, layer_id, locking from geom_info where zone_id = :zoneId order by layer_id, geom_id"
59
+    )
60
+    List<Map<String, Object>> readLayer(@Param("zoneId") Integer zoneId);
61
+
62
+    @Query(nativeQuery = true,
63
+        value = "select count(*) > 0 from geom_info where zone_id = :zoneId"
64
+    )
65
+    Boolean hasGeom(@Param("zoneId") Integer zoneId);
66
+
67
+    @Modifying
68
+    @Query(nativeQuery = true,
69
+        value = "delete from geom_info where zone_id = :zoneId"
70
+    )
71
+    void deleteAllByZoneId(Integer zoneId);
72
+
73
+}

+ 50 - 0
src/main/java/com/lqkj/link/module/zone/repository/LayerInfoRepository.java

@@ -0,0 +1,50 @@
1
+package com.lqkj.link.module.zone.repository;
2
+
3
+import com.lqkj.link.module.zone.domain.LayerInfo;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.data.jpa.repository.Modifying;
6
+import org.springframework.data.jpa.repository.Query;
7
+import org.springframework.data.repository.query.Param;
8
+import org.springframework.stereotype.Repository;
9
+
10
+import java.util.List;
11
+import java.util.Map;
12
+
13
+@Repository
14
+public interface LayerInfoRepository extends JpaRepository<LayerInfo, String> {
15
+
16
+    @Modifying
17
+    @Query(nativeQuery = true,
18
+        value = "with t1 as(insert into layer_info(layer_id, zone_id, layer_name) " +
19
+                    "select nextval('layer_info_layer_id_seq'), :zoneId, layer_name " +
20
+                    "from layer_info where zone_id = :templateId  order by layer_id returning *)" +
21
+                "select min(t1.layer_id) - min(li.layer_id) from t1, layer_info li where li.zone_id = :templateId"
22
+    )
23
+    Integer createWithTemplateReturnIncrement(@Param("templateId") Integer templateId,
24
+                                              @Param("zoneId") Integer zoneId);
25
+
26
+    @Modifying
27
+    @Query(nativeQuery = true,
28
+            value = "insert into layer_info(layer_id, zone_id, layer_name) " +
29
+                    "select nextval('layer_info_layer_id_seq'), :zoneId, layer_name " +
30
+                    "from layer_info where zone_id = :templateId  order by layer_id returning *"
31
+    )
32
+    List<LayerInfo> createWithTemplate(@Param("templateId") Integer templateId,
33
+                                              @Param("zoneId") Integer zoneId);
34
+
35
+    List<LayerInfo> queryByZoneIdOrderByLayerId(Integer zoneId);
36
+
37
+    List<LayerInfo> queryAllByZoneId(Integer zoneId);
38
+
39
+    @Query(nativeQuery = true,
40
+        value = "with t1 as (select layer_id, bool_and(locking) as locking from geom_info where zone_id = :zoneId and layer_id is not null group by layer_id) " +
41
+                "select li.layer_id as \"layerId\", li.layer_name as \"layerName\", coalesce(t1.locking, false) as locking, concat(li.layer_id) as \"Name\" " +
42
+                "from layer_info li left join t1 on li.layer_id = t1.layer_id"
43
+    )
44
+    List<Map<String, Object>> queryAllByZoneIdV2(Integer zoneId);
45
+
46
+    @Query(nativeQuery = true,
47
+        value = "select count(*) > 0 from layer_info where zone_id = :zoneId"
48
+    )
49
+    Boolean hasLayer(@Param("zoneId") Integer zoneId);
50
+}

+ 60 - 0
src/main/java/com/lqkj/link/module/zone/repository/ModelCategoryRepository.java

@@ -0,0 +1,60 @@
1
+package com.lqkj.link.module.zone.repository;
2
+
3
+import com.lqkj.link.module.zone.domain.ModelCategory;
4
+import org.springframework.data.domain.Page;
5
+import org.springframework.data.domain.Pageable;
6
+import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Query;
8
+import org.springframework.data.repository.query.Param;
9
+import org.springframework.stereotype.Repository;
10
+
11
+import java.util.List;
12
+import java.util.Map;
13
+
14
+@Repository
15
+public interface ModelCategoryRepository extends JpaRepository<ModelCategory, Integer> {
16
+
17
+    @Query(nativeQuery = true,
18
+        value = "select * from model_category where " +
19
+                "user_id is null " +
20
+                "and (:categoryName = '' or category_name like concat('%', :categoryName, '%')) " +
21
+                "order by order_id"
22
+    )
23
+    Page<ModelCategory> pageQuery(@Param("categoryName") String categoryName,
24
+                                  Pageable pageable);
25
+
26
+    @Query(nativeQuery = true,
27
+            value = "select category_id as \"categoryId\", icon, category_name as \"categoryName\", mc.user_id is null as official," +
28
+                    "category_id as \"Name\" " +
29
+                    "from model_category mc left join user_info ui on mc.user_id = ui.user_id " +
30
+                    "where mc.user_id is null or ui.user_code = :userCode " +
31
+                    "order by order_id, category_id"
32
+    )
33
+    List<Map<String, Object>> queryWithUserCode(@Param("userCode") String userCode);
34
+
35
+    @Query(nativeQuery = true,
36
+        value = "select count(*) > 0 from model_category where category_name = :categoryName"
37
+    )
38
+    Boolean hasSameName(@Param("categoryName") String categoryName);
39
+
40
+    @Query(nativeQuery = true,
41
+            value = "select count(*) > 0 from model_category where category_name = :categoryName and category_id != :categoryId"
42
+    )
43
+    Boolean hasSameNameWithoutOne(@Param("categoryName") String categoryName,
44
+                                  @Param("categoryId") Integer categoryId);
45
+
46
+    @Query(nativeQuery = true,
47
+            value = "select count(*) > 0 from model_category where category_name = :categoryName and user_id = :userId"
48
+    )
49
+    Boolean hasSameNameByUser(@Param("categoryName") String categoryName,
50
+                              @Param("userId") Integer userId);
51
+
52
+    @Query(nativeQuery = true,
53
+            value = "select count(*) > 0 from model_category " +
54
+                    "where category_name = :categoryName and category_id != :categoryId and user_id = :userId"
55
+    )
56
+    Boolean hasSameNameByUserWithoutOne(@Param("categoryName") String categoryName,
57
+                                        @Param("categoryId") Integer categoryId,
58
+                                        @Param("userId") Integer userId);
59
+
60
+}

+ 43 - 0
src/main/java/com/lqkj/link/module/zone/repository/ModelInfoRepository.java

@@ -0,0 +1,43 @@
1
+package com.lqkj.link.module.zone.repository;
2
+
3
+import com.lqkj.link.module.zone.domain.ModelInfo;
4
+import org.springframework.data.jpa.repository.JpaRepository;
5
+import org.springframework.data.jpa.repository.Modifying;
6
+import org.springframework.data.jpa.repository.Query;
7
+import org.springframework.data.repository.query.Param;
8
+import org.springframework.stereotype.Repository;
9
+
10
+import java.util.List;
11
+
12
+@Repository
13
+public interface ModelInfoRepository extends JpaRepository<ModelInfo, Integer> {
14
+
15
+    @Query(nativeQuery = true,
16
+        value = "select count(*) from model_info where category_id = :categoryId"
17
+    )
18
+    Integer countWithCategory(@Param("categoryId") Integer categoryId);
19
+
20
+    @Query(nativeQuery = true,
21
+        value = "select mi.* from model_info mi " +
22
+                "left join model_category mc on mi.category_id = mc.category_id " +
23
+                "left join user_info ui on mc.user_id = ui.user_id " +
24
+                "where mc.user_id is null or ui.user_code = :userCode order by mi.order_id"
25
+    )
26
+    List<ModelInfo> listWitUserCode(@Param("userCode") String userCode);
27
+
28
+    @Query("select t from ModelInfo t where t.categoryId = :categoryId")
29
+    List<ModelInfo> listWithCategory(@Param("categoryId") Integer categoryId);
30
+
31
+    @Modifying
32
+    @Query(nativeQuery = true,
33
+        value = "delete from model_info where category_id = :categoryId"
34
+    )
35
+    void deleteWithCategory(@Param("categoryId") Integer categoryId);
36
+
37
+    @Modifying
38
+    @Query(nativeQuery = true,
39
+        value = "delete from model_info where template_id in :templateIds"
40
+    )
41
+    void deleteAllByTemplateIds(@Param("templateIds") List<Integer> templateIds);
42
+
43
+}

+ 189 - 0
src/main/java/com/lqkj/link/module/zone/repository/ZoneInfoRepository.java

@@ -0,0 +1,189 @@
1
+package com.lqkj.link.module.zone.repository;
2
+
3
+import com.lqkj.link.module.zone.domain.ZoneInfo;
4
+import org.springframework.data.domain.Page;
5
+import org.springframework.data.domain.Pageable;
6
+import org.springframework.data.jpa.repository.JpaRepository;
7
+import org.springframework.data.jpa.repository.Modifying;
8
+import org.springframework.data.jpa.repository.Query;
9
+import org.springframework.data.repository.query.Param;
10
+import org.springframework.stereotype.Repository;
11
+
12
+import java.util.List;
13
+import java.util.Map;
14
+
15
+@Repository
16
+public interface ZoneInfoRepository extends JpaRepository<ZoneInfo, Integer> {
17
+
18
+    @Query(nativeQuery = true,
19
+        value = "select * from zone_info " +
20
+                "where user_id is null " +
21
+                    "and (:zoneName = '' or zone_name like concat('%', :zoneName, '%')) " +
22
+                "order by update_time desc"
23
+    )
24
+    Page<ZoneInfo> pageQueryTemplate(@Param("zoneName") String zoneName,
25
+                             Pageable pageable);
26
+
27
+    @Query(nativeQuery = true,
28
+        value = "select distinct(zone_name) as \"name\" from zone_info zi, user_info ui " +
29
+                "where zi.user_id = ui.user_id and ui.user_code = :userCode and zone_name like concat('%', :keyword, '%') " +
30
+                "order by zone_name"
31
+    )
32
+    List<Map<String, Object>> autoCompleteMyWork(@Param("userCode") String userCode,
33
+                                                 @Param("keyword") String keyword);
34
+
35
+    @Query(nativeQuery = true,
36
+        value = "select distinct (zone_name) as \"name\" from zone_info " +
37
+                "where zone_name like concat('%', :keyword, '%') " +
38
+                    "and (user_id is null or auth_status = 2) " +
39
+                    "and (:searchType = 0 or (:searchType = 1 and user_id is null) or (:searchType = 2 and user_id is not null)) " +
40
+                "order by zone_name"
41
+    )
42
+    List<Map<String, Object>> autoCompleteResource(@Param("keyword") String keyword,
43
+                                                   @Param("searchType") Integer searchType);
44
+
45
+    @Query(nativeQuery = true,
46
+            value = "select distinct (zone_name) as \"name\" from zone_info zi, audit_record ar " +
47
+                    "where ar.zone_id = zi.zone_id and ar.auth_status != 4 and ar.auth_status != 5 " +
48
+                    "and zone_name like concat('%', :keyword, '%') " +
49
+                    "and (:searchType = 0 or (:searchType = 1 and ar.auth_status = 1 ) or (:searchType = 2 and ar.auth_status != 1)) " +
50
+                    "order by zone_name"
51
+    )
52
+    List<Map<String, Object>> autoCompleteAudit(@Param("keyword") String keyword,
53
+                                                   @Param("searchType") Integer searchType);
54
+
55
+    @Query(nativeQuery = true,
56
+        value = "select zi.* from zone_info zi, user_info ui " +
57
+                "where zi.user_id = ui.user_id and ui.user_code = :userCode " +
58
+                    "and zi.zone_name like concat('%', :name, '%') " +
59
+                "order by zi.update_time desc"
60
+    )
61
+    Page<ZoneInfo> pageQueryMyWork(@Param("userCode") String userCode,
62
+                                   @Param("name") String name,
63
+                                   Pageable pageable);
64
+
65
+    @Query(nativeQuery = true,
66
+        value = "select zi.zone_id as \"zoneId\", zi.zone_name as \"zoneName\"," +
67
+                "zi.thumbnail, ui.head_img as \"headImg\", ui.display_name as \"displayName\"," +
68
+                "zi.share_count as \"shareCount\", zi.view_count as \"viewCount\", ui.user_id as \"authorId\" " +
69
+                "from zone_info zi left join user_info ui " +
70
+                "on zi.user_id = ui.user_id " +
71
+                "where zone_name like concat('%', :name, '%') " +
72
+                "and (zi.user_id is null or zi.auth_status = 2) " +
73
+                "and (:searchType = 0 or (:searchType = 1 and zi.user_id is null) or (:searchType = 2 and zi.user_id is not null)) " +
74
+                "order by zi.update_time desc "
75
+    )
76
+    Page<Map<String, Object>> pageQueryResourceCenter(@Param("name") String name,
77
+                                           @Param("searchType") Integer searchType,
78
+                                           Pageable pageable);
79
+
80
+    @Modifying
81
+    @Query(nativeQuery = true,
82
+        value = "with t1 as (update zone_info set share_count = coalesce(share_count, 0) + 1 where zone_id = :zoneId)" +
83
+                "insert into share_info(record_id, zone_id, user_id, share_code, share_time, can_use) " +
84
+                "select nextval('share_info_record_id_seq'), :zoneId, user_id, :shareCode, now(), 7 " +
85
+                "from user_info where user_code = :userCode"
86
+    )
87
+    void share(@Param("zoneId") Integer zoneId,
88
+               @Param("userCode") String userCode,
89
+               @Param("shareCode") String shareCode);
90
+
91
+    @Modifying
92
+    @Query(nativeQuery = true,
93
+            value = "with t1 as (update zone_info set view_count = coalesce(view_count, 0) + 1 where zone_id = :zoneId)" +
94
+                    "insert into view_record(record_id, zone_id, user_id, create_time) " +
95
+                    "select nextval('view_record_record_id_seq'), :zoneId, user_id, now() " +
96
+                    "from user_info where user_code = :userCode"
97
+    )
98
+    void view(@Param("zoneId") Integer zoneId,
99
+               @Param("userCode") String userCode);
100
+
101
+    @Query(nativeQuery = true,
102
+        value = "select count(*) > 0 from zone_info zi, user_info ui " +
103
+                "where zi.zone_id != :zoneId and zi.zone_name = :zoneName " +
104
+                    "and zi.user_id = ui.user_id and ui.user_code = :userCode"
105
+    )
106
+    Boolean hasSameNameWithUser(@Param("zoneName") String zoneName,
107
+                                @Param("userCode") String userCode,
108
+                                @Param("zoneId") Integer zoneId);
109
+
110
+    Boolean existsByZoneNameAndUserId(String zoneName, Integer userId);
111
+
112
+    @Modifying
113
+    @Query(nativeQuery = true,
114
+        value = "update zone_info set zone_name = :zoneName, update_time = now() where zone_id = :zoneId"
115
+    )
116
+    void rename(@Param("zoneName") String zoneName,
117
+                @Param("zoneId") Integer zoneId);
118
+
119
+    @Query(nativeQuery = true,
120
+        value = "select ui.user_code = :userCode from zone_info zi, user_info ui " +
121
+                "where zi.zone_id = :zoneId and zi.user_id = ui.user_id "
122
+    )
123
+    Boolean isAuthor(@Param("zoneId") Integer zoneId,
124
+                     @Param("userCode") String userCode);
125
+
126
+    @Query(nativeQuery = true,
127
+        value = "select auth_status != 1 from zone_info where zone_id = :zoneId"
128
+    )
129
+    Boolean canBeDeleteWithAuthStatus(@Param("zoneId") Integer zoneId);
130
+
131
+    @Query(nativeQuery = true,
132
+            value = "select zi.zone_id as \"zoneId\", zi.zone_name as \"zoneName\", zi.thumbnail, " +
133
+                        "ui.display_name as \"displayName\", ui.head_img as \"headImg\", " +
134
+                        "to_char(ar.apply_time, 'YYYY-MM-dd hh24:mi:ss') as \"applyTime\", " +
135
+                        "ar.auth_status as \"authStatus\", ar.record_id as \"recorId\", " +
136
+                        "aui.display_name as \"auditor\", ui.user_id as \"authorId\"," +
137
+                        "to_char(ar.auth_time, 'YYYY-MM-dd hh24:mi:ss') as \"authTime\" " +
138
+                    "from zone_info zi " +
139
+                    "inner join audit_record ar on ar.zone_id = zi.zone_id " +
140
+                    "inner join user_info ui on zi.user_id = ui.user_id " +
141
+                    "left join user_info aui on ar.user_id = aui.user_id " +
142
+                    "where ar.auth_status != 4 and ar.auth_status != 5 and delete_status is false " +
143
+                        "and zone_name like concat('%', :name, '%') " +
144
+                        "and (:searchType = 0 or (:searchType = 1 and ar.auth_status = 1 ) or (:searchType = 2 and ar.auth_status in (2, 3))) " +
145
+                    "order by ar.apply_time desc"
146
+    )
147
+    Page<Map<String, Object>> auditCenter(@Param("name") String name,
148
+                                          @Param("searchType") Integer searchType,
149
+                                          Pageable pageable);
150
+
151
+    @Modifying
152
+    @Query(nativeQuery = true,
153
+        value = "update zone_info set auth_status = :authStatus " +
154
+                "where zone_id = (select zone_id from audit_record where record_id = :recordId)"
155
+    )
156
+    void updateAuthStatusWithAuditRecord(@Param("recordId") Integer recordId,
157
+                                         @Param("authStatus") Integer authStatus);
158
+
159
+    @Modifying
160
+    @Query(nativeQuery = true,
161
+        value = "update zone_info set auth_status = :authStatus, update_time = now() where zone_id = :zoneId"
162
+    )
163
+    void updateAuthStatus(@Param("zoneId") Integer zoneId,
164
+                          @Param("authStatus") Integer authStatus);
165
+
166
+    @Modifying
167
+    @Query(nativeQuery = true,
168
+        value = "update zone_info set template_use = coalesce(template_use, 0) + 1 where zone_id = :zoneId"
169
+    )
170
+    void addTemplateUse(@Param("zoneId") Integer zoneId);
171
+
172
+    @Modifying
173
+    @Query(nativeQuery = true,
174
+        value = "update zone_info set update_time = now() where zone_id = :zoneId"
175
+    )
176
+    void mergeUpdateTime(@Param("zoneId") Integer zoneId);
177
+
178
+    @Query(nativeQuery = true,
179
+        value = "select count(*) > 0 from zone_info where user_id is null and zone_name = :zoneName"
180
+    )
181
+    Boolean hasSameTemplateName(@Param("zoneName") String zoneName);
182
+
183
+    @Query(nativeQuery = true,
184
+            value = "select count(*) > 0 from zone_info " +
185
+                    "where user_id is null and zone_name = :zoneName and zone_id != :zoneId"
186
+    )
187
+    Boolean hasSameTemplateNameWithoutOne(@Param("zoneName") String zoneName,
188
+                                          @Param("zoneId") Integer zoneId);
189
+}

+ 80 - 0
src/main/java/com/lqkj/link/module/zone/service/GeomInfoService.java

@@ -0,0 +1,80 @@
1
+package com.lqkj.link.module.zone.service;
2
+
3
+import com.alibaba.fastjson2.JSONObject;
4
+import com.lqkj.link.module.zone.domain.GeomInfo;
5
+import com.lqkj.link.module.zone.domain.LayerInfo;
6
+import com.lqkj.link.module.zone.domain.OneZoneGeomInfos;
7
+import com.lqkj.link.module.zone.domain.ZoneInfo;
8
+import com.lqkj.link.module.zone.repository.GeomInfoRepository;
9
+import com.lqkj.link.module.zone.repository.LayerInfoRepository;
10
+import com.lqkj.link.module.zone.repository.ZoneInfoRepository;
11
+import org.apache.commons.lang3.StringUtils;
12
+import org.locationtech.jts.geom.Coordinate;
13
+import org.locationtech.jts.geom.GeometryFactory;
14
+import org.springframework.stereotype.Service;
15
+import org.springframework.transaction.annotation.Transactional;
16
+
17
+import java.util.Date;
18
+import java.util.List;
19
+
20
+@Service
21
+public class GeomInfoService {
22
+    private final GeomInfoRepository geomInfoRepository;
23
+    private final ZoneInfoRepository zoneInfoRepository;
24
+    private final LayerInfoRepository layerInfoRepository;
25
+
26
+    public GeomInfoService(GeomInfoRepository geomInfoRepository, ZoneInfoRepository zoneInfoRepository, LayerInfoRepository layerInfoRepository) {
27
+        this.geomInfoRepository = geomInfoRepository;
28
+        this.zoneInfoRepository = zoneInfoRepository;
29
+        this.layerInfoRepository = layerInfoRepository;
30
+    }
31
+
32
+    public List<GeomInfo> findAllByZoneId(Integer zoneId) {
33
+        return geomInfoRepository.findAllByZoneId(zoneId);
34
+    }
35
+
36
+    @Transactional
37
+    public void saveGeomByZone(OneZoneGeomInfos infos) {
38
+        GeometryFactory geometryFactory = new GeometryFactory();
39
+        // 保存元素
40
+        if (infos.getModifyGeomList() != null && infos.getModifyGeomList().size() > 0) {
41
+            for (GeomInfo geomInfo : infos.getModifyGeomList()) {
42
+                geomInfo.setTrans(geomInfo.getLocation());
43
+                JSONObject pointObject = geomInfo.getLocation().getJSONObject("translation");
44
+                geomInfo.setGeom(geometryFactory.createPoint(new Coordinate(
45
+                        Double.parseDouble(pointObject.get("x").toString()),
46
+                        Double.parseDouble(pointObject.get("y").toString()),
47
+                        Double.parseDouble(pointObject.get("z").toString()))));
48
+                if (StringUtils.isBlank(geomInfo.getLayerId())) {
49
+                    geomInfo.setLayerId(null);
50
+                }
51
+            }
52
+            geomInfoRepository.saveAll(infos.getModifyGeomList());
53
+        }
54
+
55
+        // 删除元素
56
+        if (infos.getDeleteGeomList() != null && infos.getDeleteGeomList().size() > 0)
57
+            geomInfoRepository.deleteAllByIdInBatch(infos.getDeleteGeomList());
58
+
59
+        // 修改作品的更新时间
60
+        ZoneInfo zoneInfo = zoneInfoRepository.findById(infos.getZoneId()).get();
61
+        zoneInfo.setUpdateTime(new Date());
62
+        zoneInfo.setInitLocation(infos.getTrans());
63
+        zoneInfoRepository.save(zoneInfo);
64
+    }
65
+
66
+    @Transactional
67
+    public void saveLayerByZone(OneZoneGeomInfos infos) {
68
+        // 保存图层
69
+        if (infos.getModifyLayerList() != null && infos.getModifyLayerList().size() > 0) {
70
+            for (LayerInfo layerInfo : infos.getModifyLayerList()) {
71
+                layerInfo.setZoneId(infos.getZoneId());
72
+            }
73
+            layerInfoRepository.saveAll(infos.getModifyLayerList());
74
+        }
75
+
76
+        // 删除图层
77
+        if (infos.getDeleteLayerList() != null && infos.getDeleteLayerList().size() > 0)
78
+            layerInfoRepository.deleteAllByIdInBatch(infos.getDeleteLayerList());
79
+    }
80
+}

+ 20 - 0
src/main/java/com/lqkj/link/module/zone/service/LayerInfoService.java

@@ -0,0 +1,20 @@
1
+package com.lqkj.link.module.zone.service;
2
+
3
+import com.lqkj.link.module.zone.domain.LayerInfo;
4
+import com.lqkj.link.module.zone.repository.LayerInfoRepository;
5
+import org.springframework.stereotype.Service;
6
+
7
+import java.util.List;
8
+
9
+@Service
10
+public class LayerInfoService {
11
+    private final LayerInfoRepository layerInfoRepository;
12
+
13
+    public LayerInfoService(LayerInfoRepository layerInfoRepository) {
14
+        this.layerInfoRepository = layerInfoRepository;
15
+    }
16
+
17
+    public List<LayerInfo> queryByZoneId(Integer zoneId) {
18
+        return layerInfoRepository.queryAllByZoneId(zoneId);
19
+    }
20
+}

+ 173 - 0
src/main/java/com/lqkj/link/module/zone/service/ResourceService.java

@@ -0,0 +1,173 @@
1
+package com.lqkj.link.module.zone.service;
2
+
3
+import com.lqkj.link.module.authority.repository.UserInfoRepository;
4
+import com.lqkj.link.module.config.domain.ConfigInfo;
5
+import com.lqkj.link.module.config.repository.ConfigInfoRepository;
6
+import com.lqkj.link.module.zone.domain.ModelCategory;
7
+import com.lqkj.link.module.zone.domain.ModelInfo;
8
+import com.lqkj.link.module.zone.repository.ModelCategoryRepository;
9
+import com.lqkj.link.module.zone.repository.ModelInfoRepository;
10
+import com.lqkj.link.util.Unzipper;
11
+import org.springframework.transaction.annotation.Transactional;
12
+import org.apache.commons.compress.archivers.ArchiveException;
13
+import org.springframework.data.domain.Page;
14
+import org.springframework.data.domain.PageRequest;
15
+import org.springframework.data.domain.Pageable;
16
+import org.springframework.stereotype.Service;
17
+
18
+import java.io.File;
19
+import java.io.IOException;
20
+import java.util.ArrayList;
21
+import java.util.List;
22
+import java.util.Map;
23
+import java.util.UUID;
24
+import java.util.stream.Collectors;
25
+
26
+@Service
27
+public class ResourceService {
28
+    private final ModelCategoryRepository categoryRepository;
29
+    private final ModelInfoRepository infoRepository;
30
+    private final UserInfoRepository userInfoRepository;
31
+
32
+    public ResourceService(ModelCategoryRepository categoryRepository, ModelInfoRepository infoRepository, UserInfoRepository userInfoRepository) {
33
+        this.categoryRepository = categoryRepository;
34
+        this.infoRepository = infoRepository;
35
+        this.userInfoRepository = userInfoRepository;
36
+    }
37
+
38
+    public Page<ModelCategory> pageQuery(String categoryName, Integer page, Integer pageSize) {
39
+        Pageable pageable = PageRequest.of(page, pageSize);
40
+        Page<ModelCategory> categoryPage = categoryRepository.pageQuery(categoryName, pageable);
41
+        for (ModelCategory category : categoryPage.getContent()) {
42
+            category.setModelCount(infoRepository.countWithCategory(category.getCategoryId()));
43
+        }
44
+        return categoryPage;
45
+    }
46
+
47
+    public ModelCategory detail(Integer categoryId) {
48
+        //        modelCategory.setModelInfoList(infoRepository.listWithCategory(categoryId));
49
+        return categoryRepository.findById(categoryId).get();
50
+    }
51
+
52
+    @Transactional
53
+    public String save(ModelCategory category) throws IOException, ArchiveException {
54
+        if ((category.getCategoryId() != null && categoryRepository.hasSameNameWithoutOne(category.getCategoryName(), category.getCategoryId()))
55
+            || (category.getCategoryId() == null && categoryRepository.hasSameName(category.getCategoryName()))) {
56
+            return "资源名称不能重复!";
57
+        }
58
+        Boolean uploadCompress = category.getUploadCompress();
59
+        category = categoryRepository.save(category);
60
+        String filePath = category.getCompressFilePath();
61
+        if (uploadCompress) {
62
+            infoRepository.deleteWithCategory(category.getCategoryId());
63
+//            Unzipper.unzip("." + filePath, "./upload/resource/" + category.getCategoryId() + "/", false);
64
+            Unzipper.unZipFiles(new File("." + filePath), "./upload/resource/" + category.getCategoryId() + "/");
65
+
66
+            Map<String, ModelInfo> modelInfoMap = infoRepository
67
+                    .listWithCategory(category.getCategoryId())
68
+                    .stream()
69
+                    .collect(Collectors.toMap(ModelInfo::getModelName, ModelInfo -> ModelInfo));
70
+            String modelFolderPath = "./upload/resource/" + category.getCategoryId() + "/model";
71
+            File modelFolder = new File(modelFolderPath);
72
+            if (modelFolder.isDirectory()) {
73
+                List<ModelInfo> list = new ArrayList<>();
74
+                File[] models = modelFolder.listFiles();
75
+                assert models != null;
76
+                for (File model : models) {
77
+                    if (model.isFile()) {
78
+                        String modelFileName = model.getName();
79
+                        String modelPath = "/upload/resource/" + category.getCategoryId() + "/model/";
80
+                        if (modelFileName.matches(".*[\u4e00-\u9fa5]+.*")) {
81
+                            // 如果包含中文,重命名
82
+                            String newFileName = UUID.randomUUID() + ".fbx";
83
+                            modelPath += newFileName;
84
+                            boolean rename = model.renameTo(new File("." + modelPath));
85
+                            System.out.println(rename);
86
+                            // 材质文件也需要重命名
87
+                            File oldMaterialFile = new File("." + "/upload/resource/" + category.getCategoryId() + "/model/" + modelFileName.replace(".fbx", ".json"));
88
+                            if (oldMaterialFile.exists()) {
89
+                                File newMaterialFile = new File("." + "/upload/resource/" + category.getCategoryId() + "/model/" + newFileName.replace(".fbx", ".json"));
90
+                                rename = oldMaterialFile.renameTo(newMaterialFile);
91
+                                System.out.println(rename);
92
+                            }
93
+
94
+                            // 模型图标也许要重命名
95
+                            File oldIconFile = new File("." + "/upload/resource/" + category.getCategoryId() + "/icon/" + modelFileName.replace(".fbx", ".png"));
96
+                            if (oldIconFile.exists()) {
97
+                                File newIconFile = new File("." + "/upload/resource/" + category.getCategoryId() + "/icon/" + newFileName.replace(".fbx", ".png"));
98
+                                rename = oldIconFile.renameTo(newIconFile);
99
+                                System.out.println(rename);
100
+                            }
101
+                        } else {
102
+                            modelPath += modelFileName;
103
+                        }
104
+                        if (!modelInfoMap.containsKey(modelFileName.substring(0, modelFileName.lastIndexOf(".")))) {
105
+                            list.add(new ModelInfo(null, category.getCategoryId(), modelFileName.substring(0, modelFileName.lastIndexOf(".")),
106
+                                    null, null, null, modelPath,
107
+                                    modelPath.replace("model", "icon").replace("fbx", "png"), null, null));
108
+                        } else {
109
+                            ModelInfo modelInfo = modelInfoMap.get(modelFileName.substring(0, modelFileName.lastIndexOf(".")));
110
+                            modelInfo.setOriginalPath(modelPath);
111
+                            modelInfo.setModelIcon(modelPath.replace("model", "icon").replace("fbx", "png"));
112
+                            modelInfo.setJsonPath(null);
113
+                            modelInfo.setTexturePath(null);
114
+                            list.add(modelInfo);
115
+                            modelInfoMap.remove(modelFileName.substring(0, modelFileName.lastIndexOf(".")));
116
+                        }
117
+                    }
118
+                }
119
+                infoRepository.saveAll(list);
120
+
121
+
122
+                List<Integer> deleteList = modelInfoMap
123
+                        .values()
124
+                        .stream()
125
+                        .map(ModelInfo::getModelId)
126
+                        .toList();
127
+
128
+                infoRepository.deleteAllByIdInBatch(deleteList);
129
+            }
130
+        }
131
+        // 更新用户资源刷新状态
132
+        userInfoRepository.updateRefreshStatus();
133
+        return null;
134
+    }
135
+
136
+    public void deleteModel(Integer modelId) {
137
+        infoRepository.deleteById(modelId);
138
+    }
139
+
140
+    @Transactional
141
+    public void deleteCategory(List<Integer> categoryId) {
142
+        categoryRepository.deleteAllByIdInBatch(categoryId);
143
+        // 更新用户资源刷新状态
144
+        userInfoRepository.updateRefreshStatus();
145
+    }
146
+
147
+    public List<Map<String, Object>> resourceCategory(String userCode) {
148
+        return categoryRepository.queryWithUserCode(userCode);
149
+    }
150
+
151
+    public List<ModelInfo> models(String userCode) {
152
+        return infoRepository.listWitUserCode(userCode);
153
+    }
154
+
155
+    public String savePersonal(ModelCategory modelCategory, String userCode) {
156
+        if (modelCategory.getCategoryId() == 0) {
157
+            modelCategory.setCategoryId(null);
158
+        }
159
+        Integer userId = userInfoRepository.findByUserCode(userCode).getUserId();
160
+        if ((modelCategory.getCategoryId() != null && categoryRepository.hasSameNameByUserWithoutOne(modelCategory.getCategoryName(), modelCategory.getCategoryId(), userId))
161
+                || (modelCategory.getCategoryId() == null && categoryRepository.hasSameNameByUser(modelCategory.getCategoryName(), userId))) {
162
+            return "不能与已有文件夹重名!";
163
+        }
164
+        modelCategory.setUserId(userId);
165
+        categoryRepository.save(modelCategory);
166
+        return null;
167
+    }
168
+
169
+    public void saveModel(ModelInfo modelInfo) {
170
+        infoRepository.save(modelInfo);
171
+    }
172
+
173
+}

+ 324 - 0
src/main/java/com/lqkj/link/module/zone/service/ZoneInfoService.java

@@ -0,0 +1,324 @@
1
+package com.lqkj.link.module.zone.service;
2
+
3
+import com.alibaba.fastjson2.JSON;
4
+import com.alibaba.fastjson2.JSONObject;
5
+import com.lqkj.link.module.authority.domain.UserInfo;
6
+import com.lqkj.link.module.authority.repository.UserInfoRepository;
7
+import com.lqkj.link.module.zone.domain.GeomInfo;
8
+import com.lqkj.link.module.zone.domain.ModelInfo;
9
+import com.lqkj.link.module.zone.domain.TemplateInfo;
10
+import com.lqkj.link.module.zone.domain.ZoneInfo;
11
+import com.lqkj.link.module.zone.repository.GeomInfoRepository;
12
+import com.lqkj.link.module.zone.repository.ModelInfoRepository;
13
+import com.lqkj.link.module.zone.repository.ZoneInfoRepository;
14
+import com.lqkj.link.util.Unzipper;
15
+import org.apache.commons.lang3.StringUtils;
16
+import org.locationtech.jts.geom.Coordinate;
17
+import org.locationtech.jts.geom.GeometryFactory;
18
+import org.springframework.data.domain.Page;
19
+import org.springframework.data.domain.PageRequest;
20
+import org.springframework.data.domain.Pageable;
21
+import org.springframework.stereotype.Service;
22
+import org.springframework.transaction.annotation.Transactional;
23
+
24
+import java.io.File;
25
+import java.nio.file.Files;
26
+import java.nio.file.Paths;
27
+import java.util.*;
28
+import java.util.stream.Collectors;
29
+
30
+@Service
31
+public class ZoneInfoService {
32
+    private final ZoneInfoRepository zoneInfoRepository;
33
+    private final UserInfoRepository userInfoRepository;
34
+    private final GeomInfoRepository geomInfoRepository;
35
+    private final ModelInfoRepository modelInfoRepository;
36
+
37
+    public ZoneInfoService(ZoneInfoRepository zoneInfoRepository, UserInfoRepository userInfoRepository,
38
+                           GeomInfoRepository geomInfoRepository, ModelInfoRepository modelInfoRepository) {
39
+        this.zoneInfoRepository = zoneInfoRepository;
40
+        this.userInfoRepository = userInfoRepository;
41
+        this.geomInfoRepository = geomInfoRepository;
42
+        this.modelInfoRepository = modelInfoRepository;
43
+    }
44
+
45
+    public Page<ZoneInfo> pageQueryTemplate(String zoneName, Integer page, Integer pageSize) {
46
+        Pageable pageable = PageRequest.of(page, pageSize);
47
+        return zoneInfoRepository.pageQueryTemplate(zoneName, pageable);
48
+    }
49
+
50
+    @Transactional
51
+    public Map<String, Object> saveTemplate(ZoneInfo zoneInfo) {
52
+        Map<String, Object> result = new HashMap<>();
53
+        if ((zoneInfo.getZoneId() != null && zoneInfoRepository.hasSameTemplateNameWithoutOne(zoneInfo.getZoneName(), zoneInfo.getZoneId()))
54
+                || (zoneInfo.getZoneId() == null && zoneInfoRepository.hasSameTemplateName(zoneInfo.getZoneName()))) {
55
+            result.put("msg", "模板名称不能重复!");
56
+            return result;
57
+        }
58
+        zoneInfo.setUpdateTime(new Date());
59
+        if (zoneInfo.getZoneId() == null) {
60
+            zoneInfo.setShareCount(0);
61
+            zoneInfo.setViewCount(0);
62
+            zoneInfo.setTemplateUse(0);
63
+        }
64
+        ZoneInfo zoneInfo1 = zoneInfoRepository.save(zoneInfo);
65
+        try {
66
+            if (StringUtils.isNotBlank(zoneInfo.getTemplateFilePath())) {
67
+                // 清除元素与模型
68
+                geomInfoRepository.deleteAllByZoneId(zoneInfo1.getZoneId());
69
+                modelInfoRepository.deleteAllByTemplateIds(Collections.singletonList(zoneInfo1.getZoneId()));
70
+
71
+                // 解压压缩文件
72
+                // 文件目录格式:
73
+                // --geom.json
74
+                // --models
75
+                // ----model1.fbx 模型1文件
76
+                // ----model2.fbx 模型2文件
77
+                // ----model1.json 模型1材质
78
+                // ----model2.json 模型2材质
79
+                //
80
+                // geom.json文件总json格式:
81
+                // [
82
+                //      {
83
+                //          "modelPath": "model1.fbx",
84
+                //          "location":[
85
+                //              {
86
+                //                  "rotation":
87
+                //                  {
88
+                //                      "x": 0,
89
+                //                      "y": 0,
90
+                //                      "z": 0,
91
+                //                      "w": 0
92
+                //                  },
93
+                //                  "translation":
94
+                //                  {
95
+                //                      "x": 0,
96
+                //                      "y": 0,
97
+                //                      "z": 0
98
+                //                  },
99
+                //                  "scale3D":
100
+                //                  {
101
+                //                      "x": 0,
102
+                //                      "y": 0,
103
+                //                      "z": 0
104
+                //                  }
105
+                //              }
106
+                //          ]
107
+                //      }
108
+                // ]
109
+                Unzipper.unZipFiles(new File("." + zoneInfo.getTemplateFilePath()), "./upload/template/" + zoneInfo1.getZoneId() + "/");
110
+                String geomJsonString = Files.readString(Paths.get("./upload/template/" + zoneInfo1.getZoneId() + "/geom.json"));
111
+                List<TemplateInfo> templateInfoList = JSON.parseArray(geomJsonString, TemplateInfo.class);
112
+
113
+                String modelFolderPath = "./upload/template/" + zoneInfo1.getZoneId() + "/models";
114
+                File modelFolder = new File(modelFolderPath);
115
+                List<ModelInfo> list = new ArrayList<>();
116
+                File[] models = modelFolder.listFiles();
117
+                assert models != null;
118
+                for (File model : models) {
119
+                    if (model.isFile()) {
120
+                        String modelFileName = model.getName();
121
+                        if (modelFileName.endsWith(".fbx")) {
122
+                            String modelPath = "/upload/template/" + zoneInfo1.getZoneId() + "/models/";
123
+                            if (modelFileName.matches(".*[\u4e00-\u9fa5]+.*")) {
124
+                                // 如果包含中文,重命名
125
+                                String newFileName =UUID.randomUUID() + ".fbx";
126
+                                modelPath += newFileName;
127
+                                boolean rename = model.renameTo(new File("." + modelPath));
128
+                                System.out.println(rename);
129
+                                // 材质文件也需要重命名
130
+                                File oldMaterialFile = new File("." + "/upload/template/" + zoneInfo1.getZoneId() + "/models/" + modelFileName.replace(".fbx", ".json"));
131
+                                if (oldMaterialFile.exists()) {
132
+                                    File newMaterialFile = new File("." + "/upload/template/" + zoneInfo1.getZoneId() + "/models/" + newFileName.replace(".fbx", ".json"));
133
+                                    rename = oldMaterialFile.renameTo(newMaterialFile);
134
+                                    System.out.println(rename);
135
+                                }
136
+                            } else {
137
+                                modelPath += modelFileName;
138
+                            }
139
+                            list.add(new ModelInfo(null, null, modelFileName.substring(0, modelFileName.lastIndexOf(".")).toLowerCase(),
140
+                                    null, null, null, modelPath,
141
+                                    null, null, zoneInfo1.getZoneId()));
142
+                        }
143
+                    }
144
+                }
145
+                List<ModelInfo> modelInfoList = modelInfoRepository.saveAll(list);
146
+                Map<String, ModelInfo> modelPathIdMap = modelInfoList
147
+                        .stream()
148
+                        .collect(Collectors.toMap(ModelInfo::getModelName, ModelInfo -> ModelInfo));
149
+
150
+                List<GeomInfo> geomInfoList = new ArrayList<>();
151
+                GeometryFactory geometryFactory = new GeometryFactory();
152
+                int j = 1;
153
+                for (TemplateInfo templateInfo : templateInfoList) {
154
+
155
+                    String modelName = templateInfo.getModelPath().substring(0, templateInfo.getModelPath().lastIndexOf(".")).toLowerCase();
156
+                    ModelInfo modelInfo = modelPathIdMap.get(modelName);
157
+                    for (int i = 0; i < templateInfo.getLocation().size(); i++) {
158
+                        JSONObject trans = templateInfo.getLocation().get(i);
159
+                        GeomInfo geomInfo = new GeomInfo();
160
+
161
+                        geomInfo.setGeomId(zoneInfo1.getZoneId() + "_" + j);
162
+                        geomInfo.setModelId(modelInfo.getModelId());
163
+                        geomInfo.setGeomName(modelInfo.getModelName());
164
+                        geomInfo.setZoneId(zoneInfo1.getZoneId());
165
+                        geomInfo.setLocking(false);
166
+
167
+                        geomInfo.setTrans(trans);
168
+                        JSONObject pointObject = trans.getJSONObject("translation");
169
+                        geomInfo.setGeom(geometryFactory.createPoint(new Coordinate(
170
+                                Double.parseDouble(pointObject.get("x").toString()),
171
+                                Double.parseDouble(pointObject.get("y").toString()),
172
+                                Double.parseDouble(pointObject.get("z").toString()))));
173
+                        j++;
174
+                        geomInfoList.add(geomInfo);
175
+                    }
176
+
177
+                }
178
+                geomInfoRepository.saveAll(geomInfoList);
179
+
180
+            }
181
+        } catch (Exception e) {
182
+            modelInfoRepository.deleteAllByTemplateIds(Collections.singletonList(zoneInfo1.getZoneId()));
183
+            zoneInfoRepository.delete(zoneInfo1);
184
+            result.put("msg", "模板压缩文件解压失败!");
185
+            return result;
186
+        }
187
+        result.put("zone", zoneInfo1);
188
+        return result;
189
+    }
190
+
191
+    @Transactional
192
+    public void deleteTemplate(List<Integer> zoneIds) {
193
+        zoneInfoRepository.deleteAllByIdInBatch(zoneIds);
194
+        modelInfoRepository.deleteAllByTemplateIds(zoneIds);
195
+    }
196
+
197
+    public List<String> autoCompleteMyWork(String userCode, String keyword) {
198
+        return zoneInfoRepository
199
+                .autoCompleteMyWork(userCode, keyword)
200
+                .stream()
201
+                .map(v -> (String) v.get("name"))
202
+                .toList();
203
+    }
204
+
205
+    public List<String> autoCompleteResource(String keyword, Integer searchType) {
206
+        return zoneInfoRepository
207
+                .autoCompleteResource(keyword, searchType)
208
+                .stream()
209
+                .map(v -> (String) v.get("name"))
210
+                .toList();
211
+    }
212
+
213
+    public List<String> autoCompleteAudit(String keyword, Integer searchType) {
214
+        return zoneInfoRepository
215
+                .autoCompleteAudit(keyword, searchType)
216
+                .stream()
217
+                .map(v -> (String) v.get("name"))
218
+                .toList();
219
+    }
220
+
221
+    public Page<ZoneInfo> myWork(String userCode, String name, Integer page, Integer pageSize) {
222
+        Pageable pageable = PageRequest.of(page, pageSize);
223
+        return zoneInfoRepository.pageQueryMyWork(userCode, name, pageable);
224
+    }
225
+
226
+    public Page<Map<String, Object>> resourceCenter(String name, Integer searchType, Integer page, Integer pageSize) {
227
+        Pageable pageable = PageRequest.of(page, pageSize);
228
+        return zoneInfoRepository.pageQueryResourceCenter(name, searchType, pageable);
229
+    }
230
+
231
+    public Page<Map<String, Object>> auditCenter(String name, Integer searchType, Integer page, Integer pageSize) {
232
+        Pageable pageable = PageRequest.of(page, pageSize);
233
+        return zoneInfoRepository.auditCenter(name, searchType, pageable);
234
+    }
235
+
236
+    @Transactional
237
+    public String share(Integer zoneId, String userCode) {
238
+        String shareCode = UUID.randomUUID().toString();
239
+        zoneInfoRepository.share(zoneId, userCode, shareCode);
240
+        return shareCode;
241
+    }
242
+
243
+    @Transactional
244
+    public void view(Integer zoneId, String userCode) {
245
+        zoneInfoRepository.view(zoneId, userCode);
246
+    }
247
+
248
+    @Transactional
249
+    public String rename(Integer zoneId, String newName, String userCode) {
250
+        if (zoneInfoRepository.hasSameNameWithUser(newName, userCode, zoneId)) {
251
+            return "不能与已有作品重名!";
252
+        }
253
+        zoneInfoRepository.rename(newName, zoneId);
254
+        return null;
255
+    }
256
+
257
+    public String deleteWork(Integer zoneId, String userCode) {
258
+        if (!zoneInfoRepository.isAuthor(zoneId, userCode)) {
259
+            return "您不是该作品的作者!";
260
+        }
261
+        if (!zoneInfoRepository.canBeDeleteWithAuthStatus(zoneId)) {
262
+            return "不能删除正在审核或已发布的作品!";
263
+        }
264
+        zoneInfoRepository.deleteById(zoneId);
265
+        return null;
266
+    }
267
+
268
+    @Transactional
269
+    public Map<String, Object> create(String name, Integer templateId, String userCode) {
270
+        Map<String, Object> result = new HashMap<>();
271
+        UserInfo userInfo = userInfoRepository.findByUserCode(userCode);
272
+        if (zoneInfoRepository.existsByZoneNameAndUserId(name, userInfo.getUserId())) {
273
+            result.put("msg", "不能与已有作品重名!");
274
+            return result;
275
+        }
276
+        ZoneInfo zoneInfo = new ZoneInfo(null, userInfo.getUserId(), name, null,
277
+                null, 0, new Date(), 0, 0,
278
+                null, null, 0);
279
+        ZoneInfo newInfo = zoneInfoRepository.save(zoneInfo);
280
+
281
+        if (templateId != null) {
282
+            GeometryFactory geometryFactory = new GeometryFactory();
283
+            ZoneInfo template = zoneInfoRepository.findById(templateId).get();
284
+            newInfo.setThumbnail(template.getThumbnail());
285
+            zoneInfoRepository.save(newInfo);
286
+            if (geomInfoRepository.hasGeom(templateId)) {
287
+                List<GeomInfo> geomInfoList = geomInfoRepository.findAllByZoneId(templateId);
288
+                List<GeomInfo> list = new ArrayList<>();
289
+                for (GeomInfo geomInfo : geomInfoList) {
290
+                    String geomId = geomInfo.getGeomId();
291
+                    String newId = newInfo.getZoneId() + "_" + geomId.split("_")[1];
292
+                    GeomInfo newGeom = JSON.parseObject(JSON.toJSONString(geomInfo), GeomInfo.class);
293
+                    newGeom.setGeomId(newId);
294
+                    newGeom.setZoneId(newInfo.getZoneId());
295
+                    newGeom.setTrans(geomInfo.getLocation());
296
+                    JSONObject pointObject = geomInfo.getLocation().getJSONObject("translation");
297
+                    newGeom.setGeom(geometryFactory.createPoint(new Coordinate(
298
+                            Double.parseDouble(pointObject.get("x").toString()),
299
+                            Double.parseDouble(pointObject.get("y").toString()),
300
+                            Double.parseDouble(pointObject.get("z").toString()))));
301
+                    newGeom.setLocking(false);
302
+                    list.add(newGeom);
303
+                }
304
+                geomInfoRepository.saveAll(list);
305
+            }
306
+        }
307
+        result.put("zone", newInfo);
308
+
309
+        // 模板使用次数+1
310
+        zoneInfoRepository.addTemplateUse(templateId);
311
+        return result;
312
+    }
313
+
314
+    public void saveThumbnail(Integer zoneId, String thumbnailPath) {
315
+        ZoneInfo zoneInfo = zoneInfoRepository.findById(zoneId).get();
316
+        zoneInfo.setThumbnail(thumbnailPath);
317
+        zoneInfoRepository.save(zoneInfo);
318
+    }
319
+
320
+    public JSONObject readTrans(Integer zoneId) {
321
+        return zoneInfoRepository.findById(zoneId).get().getInitLocation();
322
+    }
323
+
324
+}

+ 91 - 0
src/main/java/com/lqkj/link/util/AESUtils.java

@@ -0,0 +1,91 @@
1
+package com.lqkj.link.util;
2
+
3
+import com.alibaba.fastjson2.JSON;
4
+import com.alibaba.fastjson2.JSONArray;
5
+import com.alibaba.fastjson2.JSONObject;
6
+import com.lqkj.link.module.authority.domain.UserInfo;
7
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
8
+
9
+import javax.crypto.Cipher;
10
+import javax.crypto.spec.SecretKeySpec;
11
+import java.nio.charset.StandardCharsets;
12
+import java.security.Security;
13
+import java.util.Base64;
14
+import java.util.Date;
15
+import java.util.Random;
16
+
17
+
18
+public class AESUtils {
19
+    private static final String ALGORITHM = "AES";
20
+    private static final String TRANSFORMATION = "AES/ECB/PKCS7Padding";
21
+
22
+    static {
23
+        Security.addProvider(new BouncyCastleProvider());
24
+    }
25
+
26
+
27
+    public static String encrypt(String plainText, String key) throws Exception {
28
+        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
29
+        StringBuilder keyBuilder = new StringBuilder(key);
30
+        while (keyBuilder.length() < 16) {
31
+            keyBuilder.append("\0");
32
+        }
33
+        byte[] keyBytes = keyBuilder.toString().getBytes(StandardCharsets.UTF_8);
34
+        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, ALGORITHM));
35
+        byte[] doFinal = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
36
+        return Base64.getEncoder().encodeToString(doFinal);
37
+    }
38
+
39
+    public static String decrypt(String cipherText, String key) throws Exception {
40
+        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
41
+        StringBuilder keyBuilder = new StringBuilder(key);
42
+        while (keyBuilder.length() < 16) {
43
+            keyBuilder.append("\0");
44
+        }
45
+        byte[] keyBytes = keyBuilder.toString().getBytes(StandardCharsets.UTF_8);
46
+        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, ALGORITHM));
47
+        byte[] doFinal = cipher.doFinal(Base64.getDecoder().decode(cipherText));
48
+        return new String(doFinal);
49
+    }
50
+
51
+    public static String generateRandomKey(int length) {
52
+        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
53
+        Random random = new Random();
54
+        StringBuilder sb = new StringBuilder(length);
55
+        for (int i = 0; i < length; i++) {
56
+            int index = random.nextInt(characters.length());
57
+            sb.append(characters.charAt(index));
58
+        }
59
+        return sb.toString();
60
+    }
61
+
62
+    public static UserInfo encryptUser(UserInfo userInfo, String key) throws Exception {
63
+        Date updateTime = userInfo.getUpdateTime();
64
+        Date lockTime = userInfo.getLockTime();
65
+        JSONObject object = JSON.parseObject(JSON.toJSONString(userInfo));
66
+        object.remove("updateTime");
67
+        object.remove("lockTime");
68
+        JSONArray jsonArray = object.getJSONArray("roleInfoList");
69
+        if (jsonArray != null && jsonArray.size() > 0) {
70
+            for (int i = 0; i < jsonArray.size(); i++) {
71
+                JSONObject object1 = jsonArray.getJSONObject(i);
72
+                object1.remove("updateTime");
73
+            }
74
+        }
75
+        UserInfo encryptUser = JSON.parseObject(JSON.toJSONString(object), UserInfo.class);
76
+        encryptUser.setUserCode(encrypt(encryptUser.getUserCode(), key));
77
+        encryptUser.setAuthorizationCode(encrypt(encryptUser.getAuthorizationCode(), key));
78
+        encryptUser.setUpdateTime(updateTime);
79
+        encryptUser.setLockTime(lockTime);
80
+        return encryptUser;
81
+    }
82
+    public static void main(String[] args) throws Exception {
83
+//        String plainText = "123456";
84
+        String key = "abc";
85
+//        String cipherText = AESUtils.encrypt(plainText, key);
86
+        String cipherText = "5GzvPLBVRxQC6k37cknLMg==";
87
+        System.out.println(cipherText);
88
+        String plainText = AESUtils.decrypt(cipherText, key);
89
+        System.out.println(plainText);
90
+    }
91
+}

+ 182 - 0
src/main/java/com/lqkj/link/util/FileUtils.java

@@ -0,0 +1,182 @@
1
+package com.lqkj.link.util;
2
+
3
+import org.springframework.web.multipart.MultipartFile;
4
+
5
+import java.io.*;
6
+import java.net.URL;
7
+import java.net.URLConnection;
8
+import java.util.ArrayList;
9
+import java.util.Base64;
10
+import java.util.List;
11
+
12
+/**
13
+ * @ClassName FileUtils
14
+ * @Description: TODO
15
+ * @Author wells
16
+ * @Date 2019/11/29 9:22
17
+ * @Version V1.0
18
+ **/
19
+public class FileUtils {
20
+
21
+    public static void dirCopy(File src, String destPath) throws Exception {
22
+        if (!new File(destPath).exists()) {
23
+            new File(destPath).mkdirs();
24
+        }
25
+        for (File s : src.listFiles()) {
26
+            if (s.isFile()) {
27
+                fileCopy(s.getPath(), destPath + File.separator + s.getName());
28
+            } else {
29
+                dirCopy(s, destPath + File.separator + s.getName());
30
+            }
31
+        }
32
+    }
33
+
34
+    public static void fileCopy(String srcPath, String destPath) throws IOException {
35
+        File src = new File(srcPath);
36
+        File dest = new File(destPath);
37
+        try (InputStream is = new BufferedInputStream(new FileInputStream(src));
38
+             OutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
39
+            byte[] flush = new byte[1024];
40
+            int len = -1;
41
+            while ((len = is.read(flush)) != -1) {
42
+                out.write(flush, 0, len);
43
+            }
44
+            out.flush();
45
+        } catch (FileNotFoundException e) {
46
+            e.printStackTrace();
47
+        } catch (IOException e) {
48
+            e.printStackTrace();
49
+        }
50
+    }
51
+
52
+    public static void fileCopyIn(InputStream srcIn, String destPath, String fileName) {
53
+        if (!new File(destPath).exists()) {
54
+            new File(destPath).mkdirs();
55
+        }
56
+        File dest = new File(destPath + fileName);
57
+        try (
58
+                OutputStream out = new BufferedOutputStream(new FileOutputStream(dest))) {
59
+            byte[] flush = new byte[1024];
60
+            int len = -1;
61
+            while ((len = srcIn.read(flush)) != -1) {
62
+                out.write(flush, 0, len);
63
+            }
64
+            out.flush();
65
+        } catch (FileNotFoundException e) {
66
+            e.printStackTrace();
67
+        } catch (IOException e) {
68
+            e.printStackTrace();
69
+        }
70
+    }
71
+
72
+    /**
73
+     * 将base64字符解码保存文件
74
+     *
75
+     * @param base64Code
76
+     * @param targetPath
77
+     * @throws Exception
78
+     */
79
+
80
+    public static void decoderBase64File(String base64Code, String targetPath)
81
+            throws Exception {
82
+        File file = new File(targetPath.substring(0, targetPath.lastIndexOf("/")));
83
+        if (!file.exists()) {
84
+            file.mkdirs();
85
+        }
86
+        byte[] buffer = Base64.getDecoder().decode(base64Code);
87
+        FileOutputStream out = new FileOutputStream(targetPath);
88
+        out.write(buffer);
89
+        out.close();
90
+    }
91
+
92
+    /**
93
+     * 判断是否为图片格式
94
+     *
95
+     * @param fileExtension
96
+     * @return
97
+     */
98
+    public static Boolean isImgFile(String fileExtension) {
99
+        if (fileExtension.toLowerCase().contains("jpg") || fileExtension.toLowerCase().contains("jpeg") || fileExtension.toLowerCase().contains("png")
100
+                || fileExtension.contains("gif")) {
101
+            return true;
102
+        }
103
+        return false;
104
+    }
105
+
106
+    public static void downloadFile(String url, String targetPath) throws Exception {
107
+        File file = new File(targetPath.substring(0, targetPath.lastIndexOf("/")));
108
+        if (!file.exists()) {
109
+            file.mkdirs();
110
+        }
111
+
112
+        URL downloadUrl = new URL(url);
113
+        // 下载网络文件
114
+        int bytesum = 0;
115
+        int byteread = 0;
116
+        try {
117
+            URLConnection conn = downloadUrl.openConnection();
118
+            InputStream inStream = conn.getInputStream();
119
+            FileOutputStream fs = new FileOutputStream(targetPath);
120
+
121
+            byte[] buffer = new byte[1024];
122
+            while ((byteread = inStream.read(buffer)) != -1) {
123
+                bytesum += byteread;
124
+                System.out.println(bytesum);
125
+                fs.write(buffer, 0, byteread);
126
+            }
127
+        } catch (FileNotFoundException e) {
128
+            e.printStackTrace();
129
+        } catch (IOException e) {
130
+            e.printStackTrace();
131
+        }
132
+    }
133
+
134
+    /**
135
+     * 保存上传的文件到本地
136
+     *
137
+     * @param file 被删除文件的文件名
138
+     * @param path 保存路径
139
+     * @return 保存后的文件
140
+     */
141
+    public static File saveFile(MultipartFile file, String path, String name) {
142
+        try (InputStream inputStream = file.getInputStream()) {
143
+            File writeFile = new File(path + name);
144
+            org.apache.commons.io.FileUtils.copyInputStreamToFile(inputStream, writeFile);
145
+            return writeFile;
146
+        } catch (Exception e) {
147
+            return null;
148
+        }
149
+    }
150
+
151
+    public static List<File> searchFiles(File folder, final String keyword) {
152
+        List<File> result = new ArrayList<File>();
153
+        if (folder.isFile())
154
+            result.add(folder);
155
+
156
+        File[] subFolders = folder.listFiles(new FileFilter() {
157
+            @Override
158
+            public boolean accept(File file) {
159
+                if (file.isDirectory()) {
160
+                    return true;
161
+                }
162
+                if (file.getName().toLowerCase().contains(keyword)) {
163
+                    return true;
164
+                }
165
+                return false;
166
+            }
167
+        });
168
+
169
+        if (subFolders != null) {
170
+            for (File file : subFolders) {
171
+                if (file.isFile()) {
172
+                    // 如果是文件则将文件添加到结果列表中
173
+                    result.add(file);
174
+                } else {
175
+                    // 如果是文件夹,则递归调用本方法,然后把所有的文件加到结果列表中
176
+                    result.addAll(searchFiles(file, keyword));
177
+                }
178
+            }
179
+        }
180
+        return result;
181
+    }
182
+}

+ 26 - 0
src/main/java/com/lqkj/link/util/GeometryDeserializer.java

@@ -0,0 +1,26 @@
1
+package com.lqkj.link.util;
2
+
3
+import com.fasterxml.jackson.core.JsonParser;
4
+import com.fasterxml.jackson.databind.DeserializationContext;
5
+import com.fasterxml.jackson.databind.JsonDeserializer;
6
+import com.fasterxml.jackson.databind.JsonNode;
7
+import org.locationtech.jts.geom.Geometry;
8
+import org.locationtech.jts.io.WKTReader;
9
+
10
+import java.io.IOException;
11
+
12
+public class GeometryDeserializer extends JsonDeserializer<Geometry> {
13
+
14
+    private final WKTReader wktReader = new WKTReader();
15
+
16
+    @Override
17
+    public Geometry deserialize(JsonParser p, DeserializationContext context) throws IOException {
18
+        JsonNode node = p.getCodec().readTree(p);
19
+        String wkt = node.textValue();
20
+        try {
21
+            return wktReader.read(wkt);
22
+        } catch (Exception e) {
23
+            throw new IOException("Invalid geometry", e);
24
+        }
25
+    }
26
+}

+ 26 - 0
src/main/java/com/lqkj/link/util/GeometrySerializer.java

@@ -0,0 +1,26 @@
1
+package com.lqkj.link.util;
2
+
3
+import com.fasterxml.jackson.core.JsonGenerator;
4
+import com.fasterxml.jackson.databind.SerializerProvider;
5
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
6
+import org.apache.calcite.runtime.SpatialTypeUtils;
7
+import org.locationtech.jts.geom.Geometry;
8
+
9
+import java.io.IOException;
10
+
11
+public class GeometrySerializer extends StdSerializer<Geometry> {
12
+
13
+    public GeometrySerializer() {
14
+        this(null);
15
+    }
16
+
17
+    public GeometrySerializer(Class<Geometry> t) {
18
+        super(t);
19
+    }
20
+
21
+    @Override
22
+    public void serialize(Geometry geometry, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
23
+        jsonGenerator.writeString(SpatialTypeUtils.asGeoJson(geometry));
24
+    }
25
+
26
+}

+ 58 - 0
src/main/java/com/lqkj/link/util/JwtUtil.java

@@ -0,0 +1,58 @@
1
+//package com.lqkj.link.util;
2
+//
3
+//import io.jsonwebtoken.Claims;
4
+//import io.jsonwebtoken.Jws;
5
+//import io.jsonwebtoken.Jwts;
6
+//import io.jsonwebtoken.security.Keys;
7
+//import io.jsonwebtoken.security.SecureDigestAlgorithm;
8
+//
9
+//import javax.crypto.SecretKey;
10
+//import java.util.Date;
11
+//import java.util.Map;
12
+//
13
+//public class JwtUtil {
14
+//    /**
15
+//     * 生成jwt
16
+//     * 使用Hs256算法,私钥使用固定密钥
17
+//     * @param secretKey  jwt密钥
18
+//     * @param ttlMillis  jwt过期时间,单位毫秒
19
+//     * @param claims     设置的信息
20
+//     * @return
21
+//     */
22
+//    public static String createJWT(String secretKey, long ttlMillis, Map<String, Object> claims){
23
+//        //指定加密算法
24
+//        SecureDigestAlgorithm<SecretKey, SecretKey> algorithm = Jwts.SIG.HS256;
25
+//        //生成JWT的时间
26
+//        long expMillis = System.currentTimeMillis()+ttlMillis;
27
+//        Date exp = new Date(expMillis);
28
+//        //密钥实例
29
+//        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes());
30
+//
31
+//        String compact = Jwts.builder()
32
+//                .signWith(key, algorithm) //设置签名使用的签名算法和签名使用的秘钥
33
+//                //如果有私有声明,一点要先设置这个自己创建的私有的声明,这个是给builder的claims赋值,一旦卸载标准的声明赋值之后,就是覆盖了那些标准的声明的
34
+//                .expiration(exp)
35
+//                .claims(claims) //设置自定义负载信息
36
+//                .compact();//设置过期时间
37
+//        return compact;
38
+//    }
39
+//
40
+//
41
+//    /**
42
+//     * 解析jwt
43
+//     * @param token
44
+//     * @param secretKey
45
+//     * @return
46
+//     */
47
+//    public static Jws<Claims> parseJWT(String token, String secretKey){
48
+//        //密钥实例
49
+//        SecretKey key = Keys.hmacShaKeyFor(secretKey.getBytes());
50
+//
51
+//        Jws<Claims> claimsJws = Jwts.parser()
52
+//                .verifyWith(key)  //设置签名的密钥
53
+//                .build()
54
+//                .parseSignedClaims(token); //设置要解析的jwt
55
+//
56
+//        return claimsJws;
57
+//    }
58
+//}

+ 127 - 0
src/main/java/com/lqkj/link/util/RSAUtils.java

@@ -0,0 +1,127 @@
1
+package com.lqkj.link.util;
2
+
3
+import javax.crypto.Cipher;
4
+import java.nio.charset.StandardCharsets;
5
+import java.security.*;
6
+import java.security.spec.InvalidKeySpecException;
7
+import java.security.spec.X509EncodedKeySpec;
8
+import java.util.Base64;
9
+
10
+/**
11
+ * @ClassName RSAUtils
12
+ * @Description TODO
13
+ * @Author wells
14
+ * @Date 2021/3/2 11:37 上午
15
+ * @Version 1.0
16
+ **/
17
+public class RSAUtils {
18
+    //KeyPair is a simple holder for a key pair.
19
+    private static final KeyPair keyPair = initKey();
20
+
21
+    /**
22
+     * 初始化方法,产生key pair,提供provider和random
23
+     *
24
+     * @return KeyPair instance
25
+     */
26
+    private static KeyPair initKey() {
27
+        try {
28
+            //添加provider
29
+            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
30
+            Security.addProvider(provider);
31
+            //产生用于安全加密的随机数
32
+            SecureRandom random = new SecureRandom();
33
+            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
34
+            generator.initialize(1024, random);
35
+            return generator.generateKeyPair();
36
+        } catch (Exception e) {
37
+            throw new RuntimeException(e);
38
+        }
39
+    }
40
+
41
+    /**
42
+     * 产生public key
43
+     *
44
+     * @return public key字符串
45
+     */
46
+    public static String generateBase64PublicKey() {
47
+        PublicKey publicKey = keyPair.getPublic();
48
+        //encodeBase64(): Encodes binary data using the base64
49
+        //algorithm but does not chunk the output.
50
+        //getEncoded():返回key的原始编码形式
51
+        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
52
+    }
53
+
54
+    /**
55
+     * 解密数据
56
+     *
57
+     * @param string 需要解密的字符串
58
+     * @return 破解之后的字符串
59
+     */
60
+    public static String decryptBase64(String string) {
61
+        //decodeBase64():将Base64数据解码为"八位字节”数据
62
+        return new String(decrypt(Base64.getDecoder().decode(string.getBytes())));
63
+    }
64
+    public static String encryptBase64(String str) {
65
+        return Base64.getEncoder().encodeToString(encrypt(str.getBytes(StandardCharsets.UTF_8)));
66
+    }
67
+
68
+    public static String encryptBase64(String str, String publicKey) {
69
+        return Base64.getEncoder().encodeToString(encrypt(str.getBytes(StandardCharsets.UTF_8), publicKey));
70
+    }
71
+
72
+    private static byte[] encrypt(byte[] byteArray){
73
+        try {
74
+            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
75
+            Security.addProvider(provider);
76
+            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
77
+            PublicKey publicKey = keyPair.getPublic();
78
+            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
79
+            return cipher.doFinal(byteArray);
80
+        } catch (Exception e) {
81
+            throw new RuntimeException(e);
82
+        }
83
+    }
84
+
85
+    private static byte[] decrypt(byte[] byteArray) {
86
+        try {
87
+            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
88
+            Security.addProvider(provider);
89
+            //Cipher: 提供加密和解密功能的实例
90
+            //transformation: "algorithm/mode/padding"
91
+            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
92
+            PrivateKey privateKey = keyPair.getPrivate();
93
+            //初始化
94
+            cipher.init(Cipher.DECRYPT_MODE, privateKey);
95
+            //doFinal(): 加密或者解密数据
96
+            return cipher.doFinal(byteArray);
97
+        } catch (Exception e) {
98
+            throw new RuntimeException(e);
99
+        }
100
+    }
101
+
102
+    private static byte[] encrypt(byte[] byteArray, String publicKey){
103
+        try {
104
+            Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
105
+            Security.addProvider(provider);
106
+            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
107
+            cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(publicKey));
108
+            return cipher.doFinal(byteArray);
109
+        } catch (Exception e) {
110
+            throw new RuntimeException(e);
111
+        }
112
+    }
113
+
114
+    private static PublicKey getPublicKey(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
115
+        byte[] keyBytes = Base64.getDecoder().decode(key);
116
+        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
117
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
118
+        return keyFactory.generatePublic(keySpec);
119
+    }
120
+
121
+    public static void main(String[] args) {
122
+        String s = RSAUtils.encryptBase64("9wytyRIgskPdprmHvb13kJJpUv78=");
123
+        System.out.println(s);
124
+        String a = RSAUtils.decryptBase64(s);
125
+        System.out.println(a);
126
+    }
127
+}

+ 232 - 0
src/main/java/com/lqkj/link/util/Unzipper.java

@@ -0,0 +1,232 @@
1
+/*
2
+ *  Licensed to GraphHopper GmbH under one or more contributor
3
+ *  license agreements. See the NOTICE file distributed with this work for
4
+ *  additional information regarding copyright ownership.
5
+ *
6
+ *  GraphHopper GmbH licenses this file to you under the Apache License,
7
+ *  Version 2.0 (the "License"); you may not use this file except in
8
+ *  compliance with the License. You may obtain a copy of the License at
9
+ *
10
+ *       http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ *  Unless required by applicable law or agreed to in writing, software
13
+ *  distributed under the License is distributed on an "AS IS" BASIS,
14
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ *  See the License for the specific language governing permissions and
16
+ *  limitations under the License.
17
+ */
18
+package com.lqkj.link.util;
19
+
20
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
21
+import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
22
+import org.apache.commons.io.IOUtils;
23
+import org.slf4j.Logger;
24
+import org.slf4j.LoggerFactory;
25
+
26
+import java.io.*;
27
+import java.nio.charset.Charset;
28
+import java.util.ArrayList;
29
+import java.util.Enumeration;
30
+import java.util.zip.ZipEntry;
31
+import java.util.zip.ZipFile;
32
+import java.util.zip.ZipInputStream;
33
+
34
+/**
35
+ * @author Peter Karich
36
+ */
37
+public class Unzipper {
38
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
39
+
40
+    private static ZipArchiveInputStream getZipFile(File zipFile) throws Exception {
41
+        return new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
42
+    }
43
+
44
+    public void unzip(String from, boolean remove) throws IOException {
45
+        String to = pruneFileEnd(from);
46
+        unzip(from, to, remove);
47
+    }
48
+
49
+    public static boolean unzip(String fromStr, String toStr, boolean remove) throws IOException {
50
+        File from = new File(fromStr);
51
+        if (!from.exists() || fromStr.equals(toStr)) return false;
52
+
53
+        unzip(new FileInputStream(from), new File(toStr), null);
54
+
55
+        if (remove) removeDir(from);
56
+        return true;
57
+    }
58
+
59
+    interface ProgressListener {
60
+        void update(long val);
61
+    }
62
+
63
+    /**
64
+     * @param progressListener updates not in percentage but the number of bytes already read.
65
+     */
66
+    private static void unzip(InputStream fromIs, File toFolder, ProgressListener progressListener) throws IOException {
67
+        if (!toFolder.exists()) toFolder.mkdirs();
68
+
69
+        long sumBytes = 0;
70
+        ZipInputStream zis = new ZipInputStream(fromIs);
71
+        try {
72
+            ZipEntry ze = zis.getNextEntry();
73
+            byte[] buffer = new byte[8 * 1024];
74
+            while (ze != null) {
75
+                if (ze.isDirectory()) {
76
+                    new File(toFolder, ze.getName()).mkdir();
77
+                } else {
78
+                    double factor = 1;
79
+                    if (ze.getCompressedSize() > 0 && ze.getSize() > 0)
80
+                        factor = (double) ze.getCompressedSize() / ze.getSize();
81
+
82
+                    File newFile = new File(toFolder, ze.getName());
83
+                    FileOutputStream fos = new FileOutputStream(newFile);
84
+                    try {
85
+                        int len;
86
+                        while ((len = zis.read(buffer)) > 0) {
87
+                            fos.write(buffer, 0, len);
88
+                            sumBytes += len * factor;
89
+                            if (progressListener != null) progressListener.update(sumBytes);
90
+                        }
91
+                    } finally {
92
+                        fos.close();
93
+                    }
94
+                }
95
+
96
+                ze = zis.getNextEntry();
97
+            }
98
+            zis.closeEntry();
99
+        } finally {
100
+            zis.close();
101
+        }
102
+    }
103
+
104
+    /**
105
+     * 使用Apache commons-compress的解压,可以解决 zip 包中文件名有中文时跨平台的乱码问题
106
+     *
107
+     * @param zipFile 待解压文件
108
+     * @param descDir 解压路径
109
+     * @deprecated
110
+     */
111
+    public void unzip(File zipFile, String descDir) {
112
+        try (ZipArchiveInputStream inputStream = getZipFile(zipFile)) {
113
+            File pathFile = new File(descDir);
114
+            if (!pathFile.exists()) {
115
+                pathFile.mkdirs();
116
+            }
117
+            ZipArchiveEntry entry;
118
+            while ((entry = inputStream.getNextZipEntry()) != null) {
119
+                if (entry.isDirectory()) {
120
+                    File directory = new File(descDir, entry.getName());
121
+                    directory.mkdirs();
122
+                } else {
123
+                    OutputStream os = null;
124
+                    try {
125
+                        os = new BufferedOutputStream(new FileOutputStream(new File(descDir, entry.getName())));
126
+                        //输出文件路径信息
127
+                        logger.info("解压文件的当前路径为:{}", descDir + "/" + entry.getName());
128
+                        IOUtils.copy(inputStream, os);
129
+                    } finally {
130
+                        IOUtils.closeQuietly(os);
131
+                    }
132
+                }
133
+            }
134
+            logger.info("******************解压完毕********************");
135
+        } catch (Exception e) {
136
+            logger.error("[unzip] 解压zip文件出错", e);
137
+        }
138
+    }
139
+
140
+    /**
141
+     * 解压文件到指定目录
142
+     */
143
+    @SuppressWarnings({"rawtypes", "resource"})
144
+    public static void unZipFiles(File zipFile, String descDir) throws IOException {
145
+        System.out.println("文件:" + zipFile.getName() + ", 解压路径:" + descDir + ", 解压开始.");
146
+
147
+        long start = System.currentTimeMillis();
148
+        try {
149
+            System.err.println(zipFile.getName());
150
+            if (!zipFile.exists()) {
151
+                throw new IOException("需解压文件不存在.");
152
+            }
153
+            File pathFile = new File(descDir);
154
+            if (pathFile.exists()) {
155
+                removeDir(pathFile);
156
+            }
157
+            pathFile.mkdirs();
158
+            ZipFile zip = new ZipFile(zipFile, Charset.forName("GBK"));
159
+            for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
160
+                ZipEntry entry = (ZipEntry) entries.nextElement();
161
+                String zipEntryName = entry.getName();
162
+                System.err.println(zipEntryName);
163
+                InputStream in = zip.getInputStream(entry);
164
+                String outPath = (descDir + File.separator + zipEntryName).replaceAll("\\*", "/");
165
+                System.err.println(outPath);
166
+                // 判断路径是否存在,不存在则创建文件路径
167
+                File file = new File(outPath.substring(0, outPath.lastIndexOf('/')));
168
+                if (!file.exists()) {
169
+                    file.mkdirs();
170
+                }
171
+                // 判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
172
+                if (new File(outPath).isDirectory()) {
173
+                    continue;
174
+                }
175
+                // 输出文件路径信息
176
+                OutputStream out = new FileOutputStream(outPath);
177
+                byte[] buf1 = new byte[1024];
178
+                int len;
179
+                while ((len = in.read(buf1)) > 0) {
180
+                    out.write(buf1, 0, len);
181
+                }
182
+                in.close();
183
+                out.close();
184
+            }
185
+            zip.close();
186
+            System.out.println("文件:" + zipFile.getName() + ", 解压路径:" + descDir + ",解压完成. 耗时:" + (System.currentTimeMillis() - start) + "ms.");
187
+        } catch (Exception e) {
188
+            System.out.println("文件:" + zipFile.getName() + ", 解压路径:" + descDir + ",解压异常. 耗时:" + (System.currentTimeMillis() - start) + "ms.");
189
+            throw new IOException(e);
190
+        }
191
+    }
192
+
193
+    public ArrayList<File> getFiles(String path) {
194
+        //目标集合fileList
195
+        ArrayList<File> fileList = new ArrayList<>();
196
+        File file = new File(path);
197
+        if (file.isDirectory()) {
198
+            File[] files = file.listFiles();
199
+            if (files == null) return new ArrayList<>();
200
+            for (File fileIndex : files) {
201
+                //如果这个文件是目录,则进行递归搜索
202
+                if (fileIndex.isDirectory()) {
203
+                    fileList.addAll(getFiles(fileIndex.getPath()));
204
+                } else {
205
+                    //如果文件是普通文件,则将文件句柄放入集合中
206
+                    fileList.add(fileIndex);
207
+                }
208
+            }
209
+        }
210
+        return fileList;
211
+    }
212
+
213
+    public static String pruneFileEnd(String file) {
214
+        int index = file.lastIndexOf(".");
215
+        if (index < 0)
216
+            return file;
217
+        return file.substring(0, index);
218
+    }
219
+    public static boolean removeDir(File file) {
220
+        if (!file.exists()) {
221
+            return true;
222
+        }
223
+
224
+        if (file.isDirectory()) {
225
+            for (File f : file.listFiles()) {
226
+                removeDir(f);
227
+            }
228
+        }
229
+
230
+        return file.delete();
231
+    }
232
+}

+ 98 - 0
src/main/resources/application-install.yml

@@ -0,0 +1,98 @@
1
+server:
2
+  address: 192.168.4.219
3
+  servlet:
4
+    context-path: /link-server
5
+  port: 9099
6
+  error:
7
+    include-exception: true
8
+  compression:
9
+    enabled: false
10
+  tomcat:
11
+    max-connections: 1000
12
+    max-swallow-size: 1000MB
13
+    max-http-form-post-size: 1000MB
14
+spring:
15
+  application:
16
+    name: LINK-SERVER
17
+  servlet:
18
+    multipart:
19
+      max-file-size: 1000MB
20
+      max-request-size: 1000MB
21
+      file-size-threshold: 10MB
22
+  jdbc:
23
+    template:
24
+      query-timeout: 20s
25
+  jpa:
26
+    hibernate:
27
+      ddl-auto: none
28
+    generate-ddl: false
29
+    show-sql: false
30
+    open-in-view: true
31
+    properties:
32
+      hibernate:
33
+        event:
34
+          merge:
35
+            entity_copy_observer: allow
36
+        jdbc:
37
+          batch_size: 1000
38
+          fetch_size: 1000
39
+        temp:
40
+          use_jdbc_metadata_defaults: false
41
+        dialect: org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect
42
+        jpa:
43
+          properties:
44
+            hibernate:
45
+              jdbc:
46
+                batch_size: 1000
47
+              order_inserts: true
48
+    database-platform: org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect
49
+  datasource:
50
+    hikari:
51
+      driver-class-name: org.postgresql.Driver
52
+      username: postgres
53
+      password: lqkj!@#456
54
+      auto-commit: true
55
+      pool-name: link
56
+      minimum-idle: 4
57
+      maximum-pool-size: 200
58
+      idle-timeout: 60000
59
+      max-lifetime: 1800000
60
+      connection-timeout: 30000
61
+      read-only: false
62
+    url: jdbc:postgresql://192.168.4.241:5432/dev_link
63
+  flyway:
64
+    baseline-on-migrate: true
65
+    enabled: true
66
+    validate-on-migrate: false
67
+  web:
68
+    resources:
69
+      cache:
70
+        cachecontrol:
71
+          cache-public: true
72
+          max-age: 0s
73
+      chain:
74
+        cache: true
75
+        enabled: true
76
+  session:
77
+    jdbc:
78
+      initialize-schema: never
79
+  main:
80
+    allow-bean-definition-overriding: true
81
+logging:
82
+  register-shutdown-hook: true
83
+  level:
84
+    org.springframework.boot: info
85
+    org.ehcache.impl.internal.store.heap.OnHeapStore: error
86
+    org.apache.coyote.http11.Http11InputBuffer: debug
87
+    org.hibernate.SQL: debug
88
+    io.swagger.models.parameters.AbstractSerializableParameter: error
89
+  file:
90
+    name: ./log/link.log
91
+    path: classpath:log4j2.xml
92
+springdoc:
93
+  api-docs:
94
+    enabled: false
95
+    path: /v3/api-docs
96
+  swagger-ui:
97
+    persist-authorization: true
98
+    path: /swagger-ui.html

+ 0 - 0
src/main/resources/db/migration/V1__INIT.sql


+ 728 - 0
src/main/resources/db/migration/V2__1.0.0.sql

@@ -0,0 +1,728 @@
1
+/*==============================================================*/
2
+/* DBMS name:      PostgreSQL 9.x                               */
3
+/* Created on:     2024/4/18 20:54:02                           */
4
+/*==============================================================*/
5
+
6
+
7
+
8
+/*==============================================================*/
9
+/* Table: audit_record                                          */
10
+/*==============================================================*/
11
+create table audit_record (
12
+    record_id            SERIAL               not null,
13
+    zone_id              INT4                 null,
14
+    user_id              INT4                 null,
15
+    auth_status          INT4                 null,
16
+    apply_time           TIMESTAMP            null,
17
+    auth_time            TIMESTAMP            null,
18
+    delete_status        BOOL                 null,
19
+    delete_time          TIMESTAMP            null,
20
+    constraint PK_AUDIT_RECORD primary key (record_id)
21
+);
22
+
23
+comment on table audit_record is
24
+'审核记录:audit_record';
25
+
26
+comment on column audit_record.record_id is
27
+'记录ID:record_id';
28
+
29
+comment on column audit_record.zone_id is
30
+'审核作品ID:zone_id';
31
+
32
+comment on column audit_record.user_id is
33
+'审核员用户ID:user_id';
34
+
35
+comment on column audit_record.auth_status is
36
+'审核状态:auth_status,1待审核,2通过,3拒绝,4删除,5撤销';
37
+
38
+comment on column audit_record.apply_time is
39
+'申请审核时间:apply_time';
40
+
41
+comment on column audit_record.auth_time is
42
+'审核时间:auth_time';
43
+
44
+comment on column audit_record.delete_status is
45
+'是否删除:delete_status';
46
+
47
+comment on column audit_record.delete_time is
48
+'删除时间:delete_time';
49
+
50
+/*==============================================================*/
51
+/* Table: notice_info                                           */
52
+/*==============================================================*/
53
+create table notice_info (
54
+    info_id              SERIAL               not null,
55
+    bulletin_id          INT4                 null,
56
+    content              TEXT                 null,
57
+    create_time          TIMESTAMP            null,
58
+    user_id              INT4                 null,
59
+    has_view             BOOL                 null,
60
+    view_time            TIMESTAMP            null,
61
+    type                 INT4                 null,
62
+    constraint PK_NOTICE_INFO primary key (info_id)
63
+);
64
+
65
+comment on table notice_info is
66
+'通知信息:notice_info';
67
+
68
+comment on column notice_info.info_id is
69
+'信息ID:info_id';
70
+
71
+comment on column notice_info.bulletin_id is
72
+'公告ID:bulletin_id';
73
+
74
+comment on column notice_info.content is
75
+'信息内容:content';
76
+
77
+comment on column notice_info.create_time is
78
+'信息时间:create_time';
79
+
80
+comment on column notice_info.user_id is
81
+'通知用户ID:user_id';
82
+
83
+comment on column notice_info.has_view is
84
+'是否已查看:has_view';
85
+
86
+comment on column notice_info.view_time is
87
+'查看时间:view_time';
88
+
89
+comment on column notice_info.type is
90
+'类型:type,1更新日志,2系统公告, 3审核通知';
91
+
92
+/*==============================================================*/
93
+/* Table: authority_info                                        */
94
+/*==============================================================*/
95
+create table authority_info (
96
+    authority_id         INT4                 not null,
97
+    parent_id            INT4                 null,
98
+    authority_name       VARCHAR(255)         null,
99
+    en_name              VARCHAR(255)         null,
100
+    route                VARCHAR(255)         null,
101
+    component            VARCHAR(255)         null,
102
+    redirect             VARCHAR(255)         null,
103
+    icon                 VARCHAR(255)         null,
104
+    order_id             INT4                 null,
105
+    constraint PK_AUTHORITY_INFO primary key (authority_id)
106
+);
107
+
108
+comment on table authority_info is
109
+'权限信息:authority_info';
110
+
111
+comment on column authority_info.authority_id is
112
+'权限ID:authority_id';
113
+
114
+comment on column authority_info.parent_id is
115
+'父权限ID:parent_id';
116
+
117
+comment on column authority_info.authority_name is
118
+'权限名称:authority_name';
119
+
120
+comment on column authority_info.en_name is
121
+'英文名:en_name';
122
+
123
+comment on column authority_info.route is
124
+'路由地址:route';
125
+
126
+comment on column authority_info.component is
127
+'组件:component';
128
+
129
+comment on column authority_info.redirect is
130
+'重定向地址:redirect';
131
+
132
+comment on column authority_info.icon is
133
+'图标:icon';
134
+
135
+comment on column authority_info.order_id is
136
+'排序:order_id';
137
+
138
+insert into authority_info values
139
+    (1, null, '模板管理', 'Template', '/Template', '#', '/Template/TemplateManage', null, 1),
140
+    (2, 1, '模板管理', 'TemplateManage', 'TemplateManage', 'views/Template/TemplateManage', null, 'ant-design:dashboard-filled', 2),
141
+    (3, null, '资源管理', 'Resource', '/Resource', '#', '/Resource/ResourceManage', null, 3),
142
+    (4, 3, '资源管理', 'ResourceManage', 'ResourceManage', 'views/Resource/ResourceManage', null, 'carbon:skill-level-advanced', 4),
143
+    (5, null, '审核管理', 'Audit', '/Audit', '#', '/Audit/AuditManage', null, 5),
144
+    (6, 5, '审核管理', 'AuditManage', 'AuditManage', 'views/Audit/AuditManage', null, 'ri:function-fill', 6),
145
+    (7, null, '权限管理', 'Authority', '/Authority', '#', '/Authority/AuditManage', 'eos-icons:role-binding', 7),
146
+    (8, 7, '用户管理', 'User', 'User', 'views/Authority/User', null, null, 8),
147
+    (9, 7, '角色管理', 'Role', 'Role', 'views/Authority/Role', null, null, 9),
148
+    (10, null, '系统设置', 'System', '/System', '#', '/System/SystemSetting', null, 10),
149
+    (11, 10, '系统设置', 'SystemSetting', 'SystemSetting', 'views/System/SystemSetting', null, 'ic:outline-webhook', 11);
150
+
151
+/*==============================================================*/
152
+/* Table: bulletin_info                                         */
153
+/*==============================================================*/
154
+create table bulletin_info (
155
+    info_id              SERIAL               not null,
156
+    content              TEXT                 null,
157
+    create_time          TIMESTAMP            null,
158
+    info_type            INTEGER              null,
159
+    constraint PK_BULLETIN_INFO primary key (info_id)
160
+);
161
+
162
+comment on table bulletin_info is
163
+'公告信息表:bulletin_info';
164
+
165
+comment on column bulletin_info.info_id is
166
+'信息编号:info_id';
167
+
168
+comment on column bulletin_info.content is
169
+'信息内容:content';
170
+
171
+comment on column bulletin_info.create_time is
172
+'发布时间:create_time';
173
+
174
+comment on column bulletin_info.info_type is
175
+'公告类型:info_type,1更新日志,2系统公告';
176
+
177
+/*==============================================================*/
178
+/* Table: config_info                                           */
179
+/*==============================================================*/
180
+create table config_info (
181
+    config_key           VARCHAR(64)          not null,
182
+    config_value         TEXT                 null,
183
+    content_type         VARCHAR(50)          null,
184
+    constraint PK_CONFIG_INFO primary key (config_key)
185
+);
186
+
187
+comment on table config_info is
188
+'产品配置:config_info';
189
+
190
+comment on column config_info.config_key is
191
+'配置信息key:config_key';
192
+
193
+comment on column config_info.config_value is
194
+'配置信息值:config_value';
195
+
196
+comment on column config_info.content_type is
197
+'信息类型:content_type';
198
+
199
+insert into config_info values
200
+('banner', '[]', 'application/json'),
201
+('direction', '', 'String'),
202
+('login_bg', '', 'image/png');
203
+
204
+/*==============================================================*/
205
+/* Table: geom_info                                             */
206
+/*==============================================================*/
207
+create table geom_info (
208
+    geom_id              VARCHAR(64)               not null,
209
+    zone_id              INT4                 null,
210
+    model_id             INT4                 null,
211
+    layer_id             VARCHAR(64)                 null,
212
+    geom_name            VARCHAR(255)         null,
213
+    building_id          INT4                 null,
214
+    floor                INT4                 null,
215
+    room_id              INT4                 null,
216
+    geom                 geometry             null,
217
+    properties           jsonb                null,
218
+    locking              BOOL                 null,
219
+    trans                jsonb                null,
220
+    constraint PK_GEOM_INFO primary key (geom_id)
221
+);
222
+
223
+comment on table geom_info is
224
+'空间信息:geom_info';
225
+
226
+comment on column geom_info.geom_id is
227
+'元素ID:geom_id';
228
+
229
+comment on column geom_info.zone_id is
230
+'区域ID:zone_id';
231
+
232
+comment on column geom_info.model_id is
233
+'模型ID:model_id';
234
+
235
+comment on column geom_info.layer_id is
236
+'图层ID:layer_id';
237
+
238
+comment on column geom_info.geom_name is
239
+'元素名称:geom_name';
240
+
241
+comment on column geom_info.building_id is
242
+'大楼ID:building_id';
243
+
244
+comment on column geom_info.floor is
245
+'楼层:floor';
246
+
247
+comment on column geom_info.room_id is
248
+'房间ID:room_id';
249
+
250
+comment on column geom_info.geom is
251
+'空间信息:geom';
252
+
253
+comment on column geom_info.properties is
254
+'属性信息:properties';
255
+
256
+comment on column geom_info.locking is
257
+'锁定:locking';
258
+
259
+comment on column geom_info.trans is
260
+'变换:trans';
261
+
262
+/*==============================================================*/
263
+/* Table: layer_info                                            */
264
+/*==============================================================*/
265
+create table layer_info (
266
+    layer_id             VARCHAR(64)               not null,
267
+    zone_id              INT4                 null,
268
+    layer_name           VARCHAR(255)         null,
269
+    locking              BOOL                 null,
270
+    constraint PK_LAYER_INFO primary key (layer_id)
271
+);
272
+
273
+comment on table layer_info is
274
+'图层信息:layer_info';
275
+
276
+comment on column layer_info.layer_id is
277
+'图层ID:layer_id';
278
+
279
+comment on column layer_info.zone_id is
280
+'区域ID:zone_id';
281
+
282
+comment on column layer_info.layer_name is
283
+'图层名称:layer_name';
284
+
285
+comment on column layer_info.locking is
286
+'是否锁定:locking';
287
+
288
+/*==============================================================*/
289
+/* Table: model_category                                        */
290
+/*==============================================================*/
291
+create table model_category (
292
+    category_id          SERIAL               not null,
293
+    user_id              INT4                 null,
294
+    icon                 VARCHAR(1024)         null,
295
+    category_name        VARCHAR(255)         null,
296
+    order_id             INT4                 null,
297
+    compress_file_path   VARCHAR(1024)        null,
298
+    compress_file_name   VARCHAR(1024)        null,
299
+    constraint PK_MODEL_CATEGORY primary key (category_id)
300
+);
301
+
302
+comment on table model_category is
303
+'模型分类:model_category';
304
+
305
+comment on column model_category.category_id is
306
+'分类ID:category_id';
307
+
308
+comment on column model_category.user_id is
309
+'用户ID:user_id';
310
+
311
+comment on column model_category.icon is
312
+'图标:icon';
313
+
314
+comment on column model_category.category_name is
315
+'分类名称:category_name';
316
+
317
+comment on column model_category.order_id is
318
+'排序:order_id';
319
+
320
+comment on column model_category.compress_file_path is
321
+'模型压缩文件路径:compress_file_path';
322
+
323
+comment on column model_category.compress_file_name is
324
+'模型压缩文件名称:compress_file_name';
325
+
326
+/*==============================================================*/
327
+/* Table: model_info                                            */
328
+/*==============================================================*/
329
+create table model_info (
330
+    model_id             SERIAL               not null,
331
+    category_id          INT4                 null,
332
+    model_name           VARCHAR(255)         null,
333
+    json_path            VARCHAR(255)         null,
334
+    texture_path         VARCHAR(255)         null,
335
+    order_id             INT4                 null,
336
+    original_path        VARCHAR(255)         null,
337
+    model_icon           VARCHAR(255)         null,
338
+    template_id          int4                 null,
339
+    constraint PK_MODEL_INFO primary key (model_id)
340
+);
341
+
342
+comment on table model_info is
343
+'模型信息:model_info';
344
+
345
+comment on column model_info.model_id is
346
+'模型ID:model_id';
347
+
348
+comment on column model_info.category_id is
349
+'分类ID:category_id';
350
+
351
+comment on column model_info.model_name is
352
+'模型名称:model_name';
353
+
354
+comment on column model_info.json_path is
355
+'空间信息文件地址:json_path';
356
+
357
+comment on column model_info.texture_path is
358
+'贴图文件地址:texture_path';
359
+
360
+comment on column model_info.order_id is
361
+'排序:order_id';
362
+
363
+comment on column model_info.original_path is
364
+'原始模型文件地址:original_path';
365
+
366
+comment on column model_info.model_icon is
367
+'模型图标文件地址:model_icon';
368
+
369
+comment on column model_info.template_id is
370
+'模板ID:template_id';
371
+
372
+/*==============================================================*/
373
+/* Table: role_authority                                        */
374
+/*==============================================================*/
375
+create table role_authority (
376
+    role_id              INT4                 not null,
377
+    authority_id         INT4                 not null,
378
+    constraint PK_ROLE_AUTHORITY primary key (role_id, authority_id)
379
+);
380
+
381
+comment on table role_authority is
382
+'角色权限信息:role_authority';
383
+
384
+comment on column role_authority.role_id is
385
+'角色ID:role_id';
386
+
387
+comment on column role_authority.authority_id is
388
+'权限ID:authority_id';
389
+
390
+insert into role_authority select 1,  generate_series (1, 11);
391
+
392
+/*==============================================================*/
393
+/* Table: role_info                                             */
394
+/*==============================================================*/
395
+create table role_info (
396
+    role_id              SERIAL               not null,
397
+    role_name            VARCHAR(255)         null,
398
+    en_name              VARCHAR(255)         null,
399
+    update_time          TIMESTAMP            null,
400
+    constraint PK_ROLE_INFO primary key (role_id)
401
+);
402
+
403
+comment on table role_info is
404
+'角色信息:role_info';
405
+
406
+comment on column role_info.role_id is
407
+'角色ID:role_id';
408
+
409
+comment on column role_info.role_name is
410
+'角色名称:role_name';
411
+
412
+comment on column role_info.en_name is
413
+'英文名称:en_name';
414
+
415
+comment on column role_info.update_time is
416
+'更新时间:update_time';
417
+
418
+insert into role_info values
419
+    (1, '超级管理员', 'superAdmin', now());
420
+
421
+select nextval('role_info_role_id_seq');
422
+
423
+/*==============================================================*/
424
+/* Table: share_info                                            */
425
+/*==============================================================*/
426
+create table share_info (
427
+    record_id            SERIAL               not null,
428
+    zone_id              INT4                 null,
429
+    user_id              INT4                 null,
430
+    share_code           VARCHAR(64)          null,
431
+    share_time           TIMESTAMP            null,
432
+    can_use              INT4                 null,
433
+    constraint PK_SHARE_INFO primary key (record_id)
434
+);
435
+
436
+comment on table share_info is
437
+'分享记录:share_info';
438
+
439
+comment on column share_info.record_id is
440
+'记录ID:record_id';
441
+
442
+comment on column share_info.zone_id is
443
+'区域ID:zone_id';
444
+
445
+comment on column share_info.user_id is
446
+'用户ID:user_id';
447
+
448
+comment on column share_info.share_code is
449
+'随机序号:share_code';
450
+
451
+comment on column share_info.share_time is
452
+'分享时间:share_time';
453
+
454
+comment on column share_info.can_use is
455
+'有效期(天):can_use';
456
+
457
+/*==============================================================*/
458
+/* Table: user_info                                             */
459
+/*==============================================================*/
460
+create table user_info (
461
+    user_id              SERIAL               not null,
462
+    user_code            VARCHAR(255)         null,
463
+    display_name         VARCHAR(255)         null,
464
+    password             VARCHAR(255)         null,
465
+    authorization_code   VARCHAR(64)          null,
466
+    head_img             VARCHAR(1024)        null,
467
+    file_save_path       VARCHAR(1024)        null,
468
+    has_auth             BOOL                 null,
469
+    login_error_count    INT4                 null,
470
+    locking              BOOL                 null,
471
+    lock_time            TIMESTAMP            null,
472
+    update_time          TIMESTAMP            null,
473
+    has_manage           BOOLEAN              null,
474
+    refresh_resource     BOOLEAN              not null default false,
475
+    constraint PK_USER_INFO primary key (user_id)
476
+);
477
+
478
+comment on table user_info is
479
+'用户信息:user_info';
480
+
481
+comment on column user_info.user_id is
482
+'用户ID:user_id';
483
+
484
+comment on column user_info.user_code is
485
+'登录账号:user_code';
486
+
487
+comment on column user_info.display_name is
488
+'显示名称:display_name';
489
+
490
+comment on column user_info.password is
491
+'登录密码:password';
492
+
493
+comment on column user_info.authorization_code is
494
+'授权码:authorization_code';
495
+
496
+comment on column user_info.head_img is
497
+'头像:head_img';
498
+
499
+comment on column user_info.file_save_path is
500
+'文件保存路径:file_save_path';
501
+
502
+comment on column user_info.has_auth is
503
+'是否有审核权限:has_auth';
504
+
505
+comment on column user_info.login_error_count is
506
+'登录错误次数:login_error_count';
507
+
508
+comment on column user_info.locking is
509
+'是否锁定:locking';
510
+
511
+comment on column user_info.lock_time is
512
+'锁定时间:lock_time';
513
+
514
+comment on column user_info.update_time is
515
+'更新时间:update_time';
516
+
517
+comment on column user_info.has_manage is
518
+'能否进入管理后台:has_manage';
519
+
520
+comment on column user_info.refresh_resource is
521
+'是否需要刷新资源:refresh_resource';
522
+
523
+/*==============================================================*/
524
+/* Table: user_role                                             */
525
+/*==============================================================*/
526
+create table user_role (
527
+    role_id              INT4                 not null,
528
+    user_id              INT4                 not null,
529
+    constraint PK_USER_ROLE primary key (role_id, user_id)
530
+);
531
+
532
+comment on table user_role is
533
+'用户角色:user_role';
534
+
535
+comment on column user_role.role_id is
536
+'角色ID:role_id';
537
+
538
+comment on column user_role.user_id is
539
+'用户ID:user_id';
540
+
541
+/*==============================================================*/
542
+/* Table: view_record                                           */
543
+/*==============================================================*/
544
+create table view_record (
545
+    record_id            SERIAL               not null,
546
+    user_id              INT4                 null,
547
+    zone_id              INT4                 null,
548
+    create_time          TIMESTAMP            null,
549
+    constraint PK_VIEW_RECORD primary key (record_id)
550
+);
551
+
552
+comment on table view_record is
553
+'作品查看记录:view_record';
554
+
555
+comment on column view_record.record_id is
556
+'记录ID:record_id';
557
+
558
+comment on column view_record.user_id is
559
+'用户ID:user_id';
560
+
561
+comment on column view_record.zone_id is
562
+'区域ID:zone_id';
563
+
564
+comment on column view_record.create_time is
565
+'记录时间:create_time';
566
+
567
+/*==============================================================*/
568
+/* Table: zone_info                                             */
569
+/*==============================================================*/
570
+create table zone_info (
571
+    zone_id              SERIAL               not null,
572
+    user_id              INT4                 null,
573
+    zone_name            VARCHAR(255)         null,
574
+    init_location        jsonb                null,
575
+    thumbnail            VARCHAR(1024)        null,
576
+    auth_status          INT4                 null,
577
+    update_time          TIMESTAMP            null,
578
+    share_count          INT4                 null default 0,
579
+    view_count           INT4                 null default 0,
580
+    order_id             INT4                 null,
581
+    template_file_name   VARCHAR(1024)        null,
582
+    template_file_path   VARCHAR(1024)        null,
583
+    template_use         int4                 null,
584
+    constraint PK_ZONE_INFO primary key (zone_id)
585
+);
586
+
587
+comment on table zone_info is
588
+'区域信息:zone_info';
589
+
590
+comment on column zone_info.zone_id is
591
+'区域ID:zone_id';
592
+
593
+comment on column zone_info.user_id is
594
+'用户ID:user_id';
595
+
596
+comment on column zone_info.zone_name is
597
+'区域名称:zone_name';
598
+
599
+comment on column zone_info.init_location is
600
+'初始坐标:init_location';
601
+
602
+comment on column zone_info.thumbnail is
603
+'缩略图:thumbnail';
604
+
605
+comment on column zone_info.auth_status is
606
+'审核状态:auth_status,0未申请,1待审核,2通过,3拒绝';
607
+
608
+comment on column zone_info.update_time is
609
+'更新时间:update_time';
610
+
611
+comment on column zone_info.share_count is
612
+'分享次数:share_count';
613
+
614
+comment on column zone_info.view_count is
615
+'查看次数:view_count';
616
+
617
+comment on column zone_info.order_id is
618
+'排序:order_id';
619
+
620
+comment on column zone_info.template_file_name is
621
+'模板压缩文件名称:template_file_name';
622
+
623
+comment on column zone_info.template_file_path is
624
+'模板压缩文件路径:template_file_path';
625
+
626
+comment on column zone_info.template_use is
627
+'模板使用次数:template_use';
628
+
629
+alter table audit_record
630
+    add constraint FK_AUDIT_RECORD_REF_USER foreign key (user_id)
631
+        references user_info (user_id)
632
+        on delete cascade on update cascade;
633
+
634
+alter table audit_record
635
+    add constraint FK_AUDIT_RECORD_REF_ZONE foreign key (zone_id)
636
+        references zone_info (zone_id)
637
+        on delete cascade on update cascade;
638
+
639
+alter table notice_info
640
+    add constraint FK_NOTICE_REF_BULLETIN foreign key (bulletin_id)
641
+        references bulletin_info (info_id)
642
+        on delete cascade on update cascade;
643
+
644
+alter table notice_info
645
+    add constraint FK_NOTICE_REF_USER foreign key (user_id)
646
+        references user_info (user_id)
647
+        on delete cascade on update cascade;
648
+
649
+alter table authority_info
650
+    add constraint FK_AUTHORITY_REF_SELF foreign key (parent_id)
651
+        references authority_info (authority_id)
652
+        on delete cascade on update cascade;
653
+
654
+alter table geom_info
655
+    add constraint FK_GEOM_REF_LAYER foreign key (layer_id)
656
+        references layer_info (layer_id)
657
+        on delete set null on update cascade;
658
+
659
+alter table geom_info
660
+    add constraint FK_GEOM_REF_MODEL foreign key (model_id)
661
+        references model_info (model_id)
662
+        on delete cascade on update cascade;
663
+
664
+alter table geom_info
665
+    add constraint FK_GEOM_REF_ZONE foreign key (zone_id)
666
+        references zone_info (zone_id)
667
+        on delete cascade on update cascade;
668
+
669
+alter table layer_info
670
+    add constraint FK_LAYER_REF_ZONE foreign key (zone_id)
671
+        references zone_info (zone_id)
672
+        on delete cascade on update cascade;
673
+
674
+alter table model_category
675
+    add constraint FK_MODEL_CATEGORY_REF_USER foreign key (user_id)
676
+        references user_info (user_id)
677
+        on delete cascade on update cascade;
678
+
679
+alter table model_info
680
+    add constraint FK_MODEL_REF_MODEL_CATEGORY foreign key (category_id)
681
+        references model_category (category_id)
682
+        on delete cascade on update cascade;
683
+
684
+alter table role_authority
685
+    add constraint FK_ROLE_AUTH_REF_AUTH foreign key (authority_id)
686
+        references authority_info (authority_id)
687
+        on delete cascade on update cascade;
688
+
689
+alter table role_authority
690
+    add constraint FK_ROLE_AUTH_REF_ROLE foreign key (role_id)
691
+        references role_info (role_id)
692
+        on delete cascade on update cascade;
693
+
694
+alter table share_info
695
+    add constraint FK_SHARE_REF_USER foreign key (user_id)
696
+        references user_info (user_id)
697
+        on delete cascade on update cascade;
698
+
699
+alter table share_info
700
+    add constraint FK_SHARE_REF_ZONE foreign key (zone_id)
701
+        references zone_info (zone_id)
702
+        on delete cascade on update cascade;
703
+
704
+alter table user_role
705
+    add constraint FK_USER_ROLE_REF_ROLE foreign key (role_id)
706
+        references role_info (role_id)
707
+        on delete cascade on update cascade;
708
+
709
+alter table user_role
710
+    add constraint FK_USER_ROLE_REF_USER foreign key (user_id)
711
+        references user_info (user_id)
712
+        on delete cascade on update cascade;
713
+
714
+alter table view_record
715
+    add constraint FK_VIEW_RECORD_REF_USER foreign key (user_id)
716
+        references user_info (user_id)
717
+        on delete cascade on update cascade;
718
+
719
+alter table view_record
720
+    add constraint FK_VIEW_RECORD_REF_ZONE foreign key (zone_id)
721
+        references zone_info (zone_id)
722
+        on delete cascade on update cascade;
723
+
724
+alter table zone_info
725
+    add constraint FK_ZONE_REF_USER foreign key (user_id)
726
+        references user_info (user_id)
727
+        on delete cascade on update cascade;
728
+

+ 43 - 0
src/main/resources/log4j2.xml

@@ -0,0 +1,43 @@
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!-- 设置log4j2的自身log级别为warn -->
3
+<!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
4
+<Configuration status="OFF">
5
+    <Properties>
6
+        <Property name="LOG_PATH">./log</Property>
7
+        <Property name="LOG_FILE">./log/cmccr2.log</Property>
8
+        <Property name="PID">????</Property>
9
+        <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
10
+        <Property name="LOG_LEVEL_PATTERN">%5p</Property>
11
+        <Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
12
+        <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATEFORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD}</Property>
13
+        <Property name="FILE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} ${sys:PID} --- [%t] %-40.40c{1.} : %m%n${LOG_EXCEPTION_CONVERSION_WORD}</Property>
14
+    </Properties>
15
+    <Appenders>
16
+        <Console name="Console" target="SYSTEM_OUT" follow="true" immediateFlush="false">
17
+            <PatternLayout pattern="${CONSOLE_LOG_PATTERN}" />
18
+        </Console>
19
+        <RollingFile name="File" fileName="${LOG_FILE}" filePattern="${LOG_PATH}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz" immediateFlush="false">
20
+            <PatternLayout>
21
+                <Pattern>${FILE_LOG_PATTERN}</Pattern>
22
+            </PatternLayout>
23
+            <Policies>
24
+                <SizeBasedTriggeringPolicy size="10 MB" />
25
+            </Policies>
26
+        </RollingFile>
27
+    </Appenders>
28
+
29
+    <Loggers>
30
+        <Logger name="org.apache.catalina.startup.DigesterFactory" level="error" />
31
+        <Logger name="org.apache.catalina.util.LifecycleBase" level="error" />
32
+        <Logger name="org.apache.coyote.http11.Http11NioProtocol" level="warn" />
33
+        <logger name="org.apache.sshd.common.util.SecurityUtils" level="warn"/>
34
+        <Logger name="org.apache.tomcat.util.net.NioSelectorPool" level="warn" />
35
+        <Logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="error" />
36
+        <Logger name="org.hibernate.validator.internal.util.Version" level="warn" />
37
+        <logger name="org.springframework.boot.actuate.endpoint.jmx" level="warn"/>
38
+        <AsyncRoot level="info" additivity="false">
39
+            <AppenderRef ref="Console"/>
40
+            <AppenderRef ref="File"/>
41
+        </AsyncRoot>
42
+    </Loggers>
43
+</Configuration>

+ 13 - 0
src/test/java/com/lqkj/link/LinkServerApplicationTests.java

@@ -0,0 +1,13 @@
1
+package com.lqkj.link;
2
+
3
+import org.junit.jupiter.api.Test;
4
+import org.springframework.boot.test.context.SpringBootTest;
5
+
6
+@SpringBootTest
7
+class LinkServerApplicationTests {
8
+
9
+    @Test
10
+    void contextLoads() {
11
+    }
12
+
13
+}