Compare commits
11 Commits
19c3640f4f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 99877eddcc | |||
| de8fc0256f | |||
| 48a24b99e1 | |||
| 54b7cedac6 | |||
| 75743c6ef6 | |||
| 86a4bc8b0a | |||
| eff39eb7f8 | |||
| 230ceea0fa | |||
| b099d42883 | |||
| aadf880052 | |||
| ad3cfef96f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,4 @@
|
|||||||
.*
|
.*
|
||||||
gradlew*
|
|
||||||
build
|
build
|
||||||
|
|
||||||
!.gitignore
|
!.gitignore
|
||||||
58
build.gradle
58
build.gradle
@@ -1,12 +1,17 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlin_version = '1.6.10'
|
jvm_version = '21'
|
||||||
spring_version = "2.7.0"
|
kotlin_version = '2.0.0'
|
||||||
|
spring_version = '3.3.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
|
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,19 +22,21 @@ buildscript {
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
group 'com.synebula'
|
group 'com.synebula'
|
||||||
version '1.5.0'
|
version '1.7.0'
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' }
|
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||||
|
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,27 +51,36 @@ subprojects {
|
|||||||
testApi group: 'junit', name: 'junit', version: '4.12'
|
testApi group: 'junit', name: 'junit', version: '4.12'
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = 1.8
|
/*** 指定 Java & Kotlin 语言编译目标JVM ***/
|
||||||
targetCompatibility = 1.8
|
sourceCompatibility = "$jvm_version"
|
||||||
|
targetCompatibility = "$jvm_version"
|
||||||
compileKotlin {
|
compileKotlin {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
compilerOptions {
|
||||||
|
jvmTarget = JvmTarget.valueOf("JVM_$jvm_version")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
compileTestKotlin {
|
compileTestKotlin {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
compilerOptions {
|
||||||
|
jvmTarget = JvmTarget.valueOf("JVM_$jvm_version")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
// repositories {
|
repositories {
|
||||||
// maven {
|
maven {
|
||||||
// allowInsecureProtocol = true
|
name = "Gitea"
|
||||||
// url = "$nexus_url"
|
url = uri("https://git.synebula.com/api/packages/alex/maven")
|
||||||
// credentials {
|
|
||||||
// username = "$nexus_usr"
|
credentials(HttpHeaderCredentials) {
|
||||||
// password = "$nexus_pwd"
|
name = "Authorization"
|
||||||
// }
|
value = "token 1b9a13c1c75832c2f82beba8c8db340364eff7b1"
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
authentication {
|
||||||
|
header(HttpHeaderAuthentication)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
publications {
|
publications {
|
||||||
mavenJava(MavenPublication) {
|
mavenJava(MavenPublication) {
|
||||||
|
|||||||
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
#Mon May 18 17:21:26 CST 2020
|
#Thu Jun 06 15:31:38 CST 2024
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
234
gradlew
vendored
Normal file
234
gradlew
vendored
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
90
gradlew.bat
vendored
Normal file
90
gradlew.bat
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %
|
||||||
|
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.synebula.gaea.app.autoconfig
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.ComponentScan
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(basePackages = ["com.synebula.gaea.app.bus", "com.synebula.gaea.app.component", "com.synebula.gaea.app.security"])
|
||||||
|
class AppAutoConfiguration
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.app.component.bus
|
package com.synebula.gaea.app.bus
|
||||||
|
|
||||||
import com.synebula.gaea.bus.Bus
|
import com.synebula.gaea.bus.Bus
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.app.component.bus
|
package com.synebula.gaea.app.bus
|
||||||
|
|
||||||
import com.synebula.gaea.bus.DomainSubscribe
|
import com.synebula.gaea.bus.DomainSubscribe
|
||||||
import com.synebula.gaea.bus.IBus
|
import com.synebula.gaea.bus.IBus
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.app.component.cache
|
package com.synebula.gaea.app.cache
|
||||||
|
|
||||||
import com.google.common.cache.Cache
|
import com.google.common.cache.Cache
|
||||||
import com.google.common.cache.CacheBuilder
|
import com.google.common.cache.CacheBuilder
|
||||||
@@ -24,7 +24,7 @@ open class Cache<K, V>(expire: Int) : ICache<K, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun add(key: K, value: V) {
|
override fun add(key: K, value: V) {
|
||||||
this.guavaCache.put(key, value)
|
this.guavaCache.put(key!!, value!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.synebula.gaea.app.component.poi
|
package com.synebula.gaea.app.component.poi
|
||||||
|
|
||||||
import com.synebula.gaea.app.struct.ExcelData
|
|
||||||
import com.synebula.gaea.data.date.DateTime
|
import com.synebula.gaea.data.date.DateTime
|
||||||
import com.synebula.gaea.exception.NoticeUserException
|
import com.synebula.gaea.exception.NoticeUserException
|
||||||
import org.apache.poi.hpsf.Decimal
|
import org.apache.poi.hpsf.Decimal
|
||||||
@@ -40,7 +39,7 @@ object Excel {
|
|||||||
val titleFont = wb.createFont()
|
val titleFont = wb.createFont()
|
||||||
titleFont.bold = true
|
titleFont.bold = true
|
||||||
titleStyle.setFont(titleFont)
|
titleStyle.setFont(titleFont)
|
||||||
setBorderStyle(titleStyle, BorderStyle.THIN)
|
setBorderStyle(titleStyle)
|
||||||
|
|
||||||
//声明列对象
|
//声明列对象
|
||||||
// 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
|
// 第三步,在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制
|
||||||
@@ -62,7 +61,7 @@ object Excel {
|
|||||||
val contentStyle = wb.createCellStyle()
|
val contentStyle = wb.createCellStyle()
|
||||||
contentStyle.alignment = HorizontalAlignment.LEFT// 创建一个修改居左格式
|
contentStyle.alignment = HorizontalAlignment.LEFT// 创建一个修改居左格式
|
||||||
contentStyle.verticalAlignment = VerticalAlignment.CENTER
|
contentStyle.verticalAlignment = VerticalAlignment.CENTER
|
||||||
setBorderStyle(contentStyle, BorderStyle.THIN)
|
setBorderStyle(contentStyle)
|
||||||
|
|
||||||
//创建内容
|
//创建内容
|
||||||
var col = 0
|
var col = 0
|
||||||
@@ -146,6 +145,7 @@ object Excel {
|
|||||||
this.getCellValue(cell, evaluator).toString().toIntOrNull()
|
this.getCellValue(cell, evaluator).toString().toIntOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Double::class.java.name -> {
|
Double::class.java.name -> {
|
||||||
if (cell.cellType == CellType.NUMERIC) {
|
if (cell.cellType == CellType.NUMERIC) {
|
||||||
cell.numericCellValue
|
cell.numericCellValue
|
||||||
@@ -153,6 +153,7 @@ object Excel {
|
|||||||
this.getCellValue(cell, evaluator).toString().toDoubleOrNull()
|
this.getCellValue(cell, evaluator).toString().toDoubleOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Float::class.java.name -> {
|
Float::class.java.name -> {
|
||||||
if (cell.cellType == CellType.NUMERIC) {
|
if (cell.cellType == CellType.NUMERIC) {
|
||||||
cell.numericCellValue.toFloat()
|
cell.numericCellValue.toFloat()
|
||||||
@@ -160,6 +161,7 @@ object Excel {
|
|||||||
this.getCellValue(cell, evaluator).toString().toFloatOrNull()
|
this.getCellValue(cell, evaluator).toString().toFloatOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Decimal::class.java.name -> {
|
Decimal::class.java.name -> {
|
||||||
if (cell.cellType == CellType.NUMERIC) {
|
if (cell.cellType == CellType.NUMERIC) {
|
||||||
cell.numericCellValue.toBigDecimal()
|
cell.numericCellValue.toBigDecimal()
|
||||||
@@ -167,6 +169,7 @@ object Excel {
|
|||||||
this.getCellValue(cell, evaluator).toString().toBigDecimalOrNull()
|
this.getCellValue(cell, evaluator).toString().toBigDecimalOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean::class.java.name -> {
|
Boolean::class.java.name -> {
|
||||||
if (cell.cellType == CellType.BOOLEAN) {
|
if (cell.cellType == CellType.BOOLEAN) {
|
||||||
cell.booleanCellValue
|
cell.booleanCellValue
|
||||||
@@ -174,11 +177,13 @@ object Excel {
|
|||||||
this.getCellValue(cell, evaluator).toString().toBoolean()
|
this.getCellValue(cell, evaluator).toString().toBoolean()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Date::class.java.name -> try {
|
Date::class.java.name -> try {
|
||||||
cell.dateCellValue
|
cell.dateCellValue
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
DateTime(cell.stringCellValue).date
|
DateTime(cell.stringCellValue).date
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> cell.stringCellValue
|
else -> cell.stringCellValue
|
||||||
}
|
}
|
||||||
rowData[columns[c].first] = value
|
rowData[columns[c].first] = value
|
||||||
@@ -278,7 +283,7 @@ object Excel {
|
|||||||
/**
|
/**
|
||||||
* 设置cell style的边框
|
* 设置cell style的边框
|
||||||
*/
|
*/
|
||||||
private fun setBorderStyle(style: HSSFCellStyle, borderStyle: BorderStyle) {
|
private fun setBorderStyle(style: HSSFCellStyle, borderStyle: BorderStyle = BorderStyle.THIN) {
|
||||||
style.borderTop = borderStyle
|
style.borderTop = borderStyle
|
||||||
style.borderRight = borderStyle
|
style.borderRight = borderStyle
|
||||||
style.borderBottom = borderStyle
|
style.borderBottom = borderStyle
|
||||||
@@ -297,6 +302,7 @@ object Excel {
|
|||||||
numericCellValue
|
numericCellValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CellType.STRING -> cell.richStringCellValue.string
|
CellType.STRING -> cell.richStringCellValue.string
|
||||||
CellType.BLANK -> ""
|
CellType.BLANK -> ""
|
||||||
CellType.FORMULA -> evaluator.evaluate(cell).toString()
|
CellType.FORMULA -> evaluator.evaluate(cell).toString()
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.synebula.gaea.app.component.poi
|
||||||
|
|
||||||
|
class ExcelData(
|
||||||
|
var title: String = "",
|
||||||
|
var columnNames: List<String> = listOf(),
|
||||||
|
var data: List<List<String>> = listOf()
|
||||||
|
)
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.synebula.gaea.app
|
package com.synebula.gaea.app.controller
|
||||||
|
|
||||||
import com.synebula.gaea.app.cmd.ICommandApp
|
import com.synebula.gaea.app.controller.cmd.ICommandApp
|
||||||
import com.synebula.gaea.app.query.IQueryApp
|
import com.synebula.gaea.app.controller.query.IQueryApp
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.domain.service.ICommand
|
import com.synebula.gaea.domain.service.ICommand
|
||||||
import com.synebula.gaea.domain.service.IService
|
import com.synebula.gaea.domain.service.IService
|
||||||
import com.synebula.gaea.log.ILogger
|
import com.synebula.gaea.log.ILogger
|
||||||
import com.synebula.gaea.query.IQuery
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,11 +17,12 @@ import org.springframework.beans.factory.annotation.Autowired
|
|||||||
* @param query 业务查询服务
|
* @param query 业务查询服务
|
||||||
* @param logger 日志组件
|
* @param logger 日志组件
|
||||||
*/
|
*/
|
||||||
open class Application<TCommand : ICommand, TView, ID>(
|
open class DomainApplication<TCommand : ICommand, TView, ID>(
|
||||||
override var name: String,
|
override var name: String,
|
||||||
override var service: IService<ID>,
|
override var service: IService<ID>,
|
||||||
override var query: IQuery<TView, ID>,
|
override var query: IQuery,
|
||||||
override var logger: ILogger,
|
override var clazz: Class<TView>,
|
||||||
|
override var logger: ILogger
|
||||||
) : ICommandApp<TCommand, ID>, IQueryApp<TView, ID> {
|
) : ICommandApp<TCommand, ID>, IQueryApp<TView, ID> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.synebula.gaea.app
|
package com.synebula.gaea.app.controller
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.synebula.gaea.app.security.session.UserSession
|
||||||
import com.synebula.gaea.data.message.HttpMessage
|
import com.synebula.gaea.data.message.HttpMessage
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
import com.synebula.gaea.data.message.Status
|
import com.synebula.gaea.data.message.Status
|
||||||
@@ -58,14 +58,12 @@ interface IApplication {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户信息
|
* 获取用户信息
|
||||||
* @param clazz 用户信息结构类
|
|
||||||
*/
|
*/
|
||||||
fun <T> userSession(clazz: Class<T>): T? {
|
fun userSession(): UserSession? {
|
||||||
try {
|
try {
|
||||||
val authentication = SecurityContextHolder.getContext().authentication.principal.toString()
|
val authentication = SecurityContextHolder.getContext().authentication.principal
|
||||||
try {
|
try {
|
||||||
val gson = Gson()
|
return authentication as UserSession
|
||||||
return gson.fromJson(authentication, clazz)
|
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
logger.error(this, ex, "[$name]解析用户信息异常!用户信息:$authentication: ${ex.message}")
|
logger.error(this, ex, "[$name]解析用户信息异常!用户信息:$authentication: ${ex.message}")
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package com.synebula.gaea.app
|
package com.synebula.gaea.app.controller
|
||||||
|
|
||||||
import com.synebula.gaea.app.cmd.ISimpleCommandApp
|
import com.synebula.gaea.app.controller.cmd.ISimpleCommandApp
|
||||||
import com.synebula.gaea.app.query.IQueryApp
|
import com.synebula.gaea.app.controller.query.IQueryApp
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
import com.synebula.gaea.domain.service.ISimpleService
|
|
||||||
import com.synebula.gaea.log.ILogger
|
import com.synebula.gaea.log.ILogger
|
||||||
import com.synebula.gaea.query.IQuery
|
import com.synebula.gaea.record.service.IService
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,14 +17,14 @@ import org.springframework.beans.factory.annotation.Autowired
|
|||||||
* @param query 业务查询服务
|
* @param query 业务查询服务
|
||||||
* @param logger 日志组件
|
* @param logger 日志组件
|
||||||
*/
|
*/
|
||||||
open class SimpleApplication<TRoot : IAggregateRoot<ID>, ID>(
|
open class RecordApplication<TRoot : IAggregateRoot<ID>, ID>(
|
||||||
override var name: String,
|
override var name: String,
|
||||||
override var service: ISimpleService<TRoot, ID>,
|
override var service: IService<TRoot, ID>,
|
||||||
override var query: IQuery<TRoot, ID>,
|
override var query: IQuery,
|
||||||
|
override var clazz: Class<TRoot>,
|
||||||
override var logger: ILogger,
|
override var logger: ILogger,
|
||||||
) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> {
|
) : ISimpleCommandApp<TRoot, ID>, IQueryApp<TRoot, ID> {
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
override lateinit var httpMessageFactory: HttpMessageFactory
|
override lateinit var httpMessageFactory: HttpMessageFactory
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.app.cmd
|
package com.synebula.gaea.app.controller.cmd
|
||||||
|
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
import com.synebula.gaea.domain.service.ICommand
|
import com.synebula.gaea.domain.service.ICommand
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.synebula.gaea.app.cmd
|
package com.synebula.gaea.app.controller.cmd
|
||||||
|
|
||||||
import com.synebula.gaea.app.IApplication
|
import com.synebula.gaea.app.controller.IApplication
|
||||||
import com.synebula.gaea.data.message.HttpMessage
|
import com.synebula.gaea.data.message.HttpMessage
|
||||||
import com.synebula.gaea.data.message.Status
|
import com.synebula.gaea.data.message.Status
|
||||||
import com.synebula.gaea.domain.service.ICommand
|
import com.synebula.gaea.domain.service.ICommand
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.synebula.gaea.app.cmd
|
package com.synebula.gaea.app.controller.cmd
|
||||||
|
|
||||||
import com.synebula.gaea.app.IApplication
|
import com.synebula.gaea.app.controller.IApplication
|
||||||
import com.synebula.gaea.data.message.HttpMessage
|
import com.synebula.gaea.data.message.HttpMessage
|
||||||
import com.synebula.gaea.data.message.Status
|
import com.synebula.gaea.data.message.Status
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
import com.synebula.gaea.domain.service.ISimpleService
|
import com.synebula.gaea.record.service.IService
|
||||||
import com.synebula.gaea.spring.aop.annotation.Method
|
import com.synebula.gaea.spring.aop.annotation.Method
|
||||||
import org.springframework.web.bind.annotation.*
|
import org.springframework.web.bind.annotation.*
|
||||||
|
|
||||||
@@ -16,12 +16,13 @@ import org.springframework.web.bind.annotation.*
|
|||||||
* @since 2020-05-15
|
* @since 2020-05-15
|
||||||
*/
|
*/
|
||||||
interface ISimpleCommandApp<TRoot : IAggregateRoot<ID>, ID> : IApplication {
|
interface ISimpleCommandApp<TRoot : IAggregateRoot<ID>, ID> : IApplication {
|
||||||
var service: ISimpleService<TRoot, ID>
|
var service: IService<TRoot, ID>
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
@Method("添加")
|
@Method("添加")
|
||||||
fun add(@RequestBody entity: TRoot): HttpMessage {
|
fun add(@RequestBody entity: TRoot): HttpMessage {
|
||||||
return this.httpMessageFactory.create(service.add(entity))
|
val id = service.add(entity)
|
||||||
|
return this.httpMessageFactory.create(id!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{id:.+}")
|
@PutMapping("/{id:.+}")
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.synebula.gaea.app.cmd
|
package com.synebula.gaea.app.controller.cmd
|
||||||
|
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
import com.synebula.gaea.domain.service.ISimpleService
|
import com.synebula.gaea.record.service.IService
|
||||||
import com.synebula.gaea.log.ILogger
|
import com.synebula.gaea.log.ILogger
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired
|
|||||||
*/
|
*/
|
||||||
open class SimpleCommandApp<TRoot : IAggregateRoot<ID>, ID>(
|
open class SimpleCommandApp<TRoot : IAggregateRoot<ID>, ID>(
|
||||||
override var name: String,
|
override var name: String,
|
||||||
override var service: ISimpleService<TRoot, ID>,
|
override var service: IService<TRoot, ID>,
|
||||||
override var logger: ILogger,
|
override var logger: ILogger,
|
||||||
) : ISimpleCommandApp<TRoot, ID> {
|
) : ISimpleCommandApp<TRoot, ID> {
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.synebula.gaea.app.query
|
package com.synebula.gaea.app.controller.query
|
||||||
|
|
||||||
import com.synebula.gaea.app.IApplication
|
import com.synebula.gaea.app.controller.IApplication
|
||||||
import com.synebula.gaea.data.message.HttpMessage
|
import com.synebula.gaea.data.message.HttpMessage
|
||||||
import com.synebula.gaea.query.IQuery
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.query.Params
|
import com.synebula.gaea.db.query.Params
|
||||||
import com.synebula.gaea.spring.aop.annotation.Method
|
import com.synebula.gaea.spring.aop.annotation.Method
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.PathVariable
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
@@ -13,12 +13,14 @@ interface IQueryApp<TView, ID> : IApplication {
|
|||||||
/**
|
/**
|
||||||
* 查询服务
|
* 查询服务
|
||||||
*/
|
*/
|
||||||
var query: IQuery<TView, ID>
|
var query: IQuery
|
||||||
|
|
||||||
|
var clazz: Class<TView>
|
||||||
|
|
||||||
@Method("获取数据")
|
@Method("获取数据")
|
||||||
@GetMapping("/{id:.+}")
|
@GetMapping("/{id:.+}")
|
||||||
fun get(@PathVariable id: ID): HttpMessage {
|
fun get(@PathVariable id: ID): HttpMessage {
|
||||||
val data = this.query.get(id)
|
val data = this.query.get(id, clazz)
|
||||||
val msg = this.httpMessageFactory.create()
|
val msg = this.httpMessageFactory.create()
|
||||||
msg.data = data
|
msg.data = data
|
||||||
return msg
|
return msg
|
||||||
@@ -27,7 +29,7 @@ interface IQueryApp<TView, ID> : IApplication {
|
|||||||
@Method("获取列表数据")
|
@Method("获取列表数据")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
fun list(@RequestParam params: LinkedHashMap<String, String>): HttpMessage {
|
fun list(@RequestParam params: LinkedHashMap<String, String>): HttpMessage {
|
||||||
val data = this.query.list(params)
|
val data = this.query.list(params, clazz)
|
||||||
return this.httpMessageFactory.create(data)
|
return this.httpMessageFactory.create(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@ interface IQueryApp<TView, ID> : IApplication {
|
|||||||
@RequestParam parameters: LinkedHashMap<String, String>
|
@RequestParam parameters: LinkedHashMap<String, String>
|
||||||
): HttpMessage {
|
): HttpMessage {
|
||||||
val params = Params(page, size, parameters)
|
val params = Params(page, size, parameters)
|
||||||
val data = this.query.paging(params)
|
val data = this.query.paging(params, clazz)
|
||||||
return this.httpMessageFactory.create(data)
|
return this.httpMessageFactory.create(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.synebula.gaea.app.query
|
package com.synebula.gaea.app.controller.query
|
||||||
|
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.log.ILogger
|
import com.synebula.gaea.log.ILogger
|
||||||
import com.synebula.gaea.query.IQuery
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,7 +14,8 @@ import org.springframework.beans.factory.annotation.Autowired
|
|||||||
*/
|
*/
|
||||||
open class QueryApp<TView, ID>(
|
open class QueryApp<TView, ID>(
|
||||||
override var name: String,
|
override var name: String,
|
||||||
override var query: IQuery<TView, ID>,
|
override var query: IQuery,
|
||||||
|
override var clazz: Class<TView>,
|
||||||
override var logger: ILogger,
|
override var logger: ILogger,
|
||||||
) : IQueryApp<TView, ID> {
|
) : IQueryApp<TView, ID> {
|
||||||
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.synebula.gaea.app.component.security
|
package com.synebula.gaea.app.security
|
||||||
|
|
||||||
import com.auth0.jwt.JWT
|
import com.auth0.jwt.JWT
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
import com.auth0.jwt.algorithms.Algorithm
|
||||||
|
import com.auth0.jwt.exceptions.TokenExpiredException
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.synebula.gaea.app.struct.exception.TokenCloseExpireException
|
|
||||||
import com.synebula.gaea.log.ILogger
|
import com.synebula.gaea.log.ILogger
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
@@ -71,6 +71,25 @@ class TokenManager {
|
|||||||
.sign(algorithm)
|
.sign(algorithm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验token是否正确
|
||||||
|
*
|
||||||
|
* @param token 密钥
|
||||||
|
* @param func 自定义验证方法
|
||||||
|
*/
|
||||||
|
fun verifyTime(token: String, func: (total: Long, remain: Long) -> Unit) {
|
||||||
|
try {
|
||||||
|
val now = Date()
|
||||||
|
val jwt = JWT.decode(token)
|
||||||
|
val total = jwt.expiresAt.time - jwt.issuedAt.time //总时间
|
||||||
|
val remain = jwt.expiresAt.time - now.time //剩余的时间
|
||||||
|
func(total, remain)
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
this.logger.error(this, ex, "解析token出错")
|
||||||
|
throw ex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验token是否正确
|
* 校验token是否正确
|
||||||
*
|
*
|
||||||
@@ -78,21 +97,16 @@ class TokenManager {
|
|||||||
* @return 是否正确
|
* @return 是否正确
|
||||||
*/
|
*/
|
||||||
fun <T> verify(token: String, clazz: Class<T>): T? {
|
fun <T> verify(token: String, clazz: Class<T>): T? {
|
||||||
try {
|
return try {
|
||||||
val now = Date()
|
|
||||||
val algorithm = Algorithm.HMAC256(secret)
|
val algorithm = Algorithm.HMAC256(secret)
|
||||||
val jwt = JWT.decode(token)
|
|
||||||
val remain = jwt.expiresAt.time - now.time //剩余的时间
|
|
||||||
val total = jwt.expiresAt.time - jwt.issuedAt.time //总时间
|
|
||||||
if (remain > 0 && 1.0 * remain / total <= 0.3) //存活时间少于总时间的1/3重新下发
|
|
||||||
throw TokenCloseExpireException("", JWT.decode(token).getClaim("user").asString())
|
|
||||||
|
|
||||||
val result = JWT.require(algorithm).build().verify(token)
|
val result = JWT.require(algorithm).build().verify(token)
|
||||||
val json = result.getClaim(this.payload).asString()
|
val json = result.getClaim(this.payload).asString()
|
||||||
return gson.fromJson(json, clazz)
|
gson.fromJson(json, clazz)
|
||||||
|
} catch (ex: TokenExpiredException) {
|
||||||
|
null
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
this.logger.debug(this, ex, "解析token出错")
|
this.logger.error(this, ex, "解析token出错")
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,20 +117,15 @@ class TokenManager {
|
|||||||
* @return 是否正确
|
* @return 是否正确
|
||||||
*/
|
*/
|
||||||
fun verify(token: String): String {
|
fun verify(token: String): String {
|
||||||
try {
|
return try {
|
||||||
val now = Date()
|
|
||||||
val algorithm = Algorithm.HMAC256(secret)
|
val algorithm = Algorithm.HMAC256(secret)
|
||||||
val jwt = JWT.decode(token)
|
|
||||||
val remain = jwt.expiresAt.time - now.time //剩余的时间
|
|
||||||
val total = jwt.expiresAt.time - jwt.issuedAt.time //总时间
|
|
||||||
if (remain > 0 && 1.0 * remain / total <= 0.3) //存活时间少于总时间的1/3重新下发
|
|
||||||
throw TokenCloseExpireException("", JWT.decode(token).getClaim("user").asString())
|
|
||||||
|
|
||||||
val result = JWT.require(algorithm).build().verify(token)
|
val result = JWT.require(algorithm).build().verify(token)
|
||||||
return result.getClaim(payload).asString()
|
result.getClaim(this.payload).asString()
|
||||||
|
} catch (ex: TokenExpiredException) {
|
||||||
|
""
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
this.logger.debug(this, ex, "解析token出错")
|
this.logger.error(this, ex, "解析token出错")
|
||||||
throw ex
|
throw ex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.synebula.gaea.app.component.security
|
package com.synebula.gaea.app.security
|
||||||
|
|
||||||
import com.synebula.gaea.app.component.security.session.UserSessionManager
|
import com.synebula.gaea.app.security.session.UserSessionManager
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
import com.synebula.gaea.data.message.Status
|
import com.synebula.gaea.data.message.Status
|
||||||
|
import jakarta.servlet.FilterChain
|
||||||
|
import jakarta.servlet.ServletException
|
||||||
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||||
import org.springframework.security.core.context.SecurityContextHolder
|
import org.springframework.security.core.context.SecurityContextHolder
|
||||||
import org.springframework.web.filter.OncePerRequestFilter
|
import org.springframework.web.filter.OncePerRequestFilter
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import javax.servlet.FilterChain
|
|
||||||
import javax.servlet.ServletException
|
|
||||||
import javax.servlet.http.HttpServletRequest
|
|
||||||
import javax.servlet.http.HttpServletResponse
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +40,9 @@ class WebAuthorization(
|
|||||||
val identity = if (this.storage == "cookie") {
|
val identity = if (this.storage == "cookie") {
|
||||||
request.cookies.find { it.name == tokenKey }?.value ?: ""
|
request.cookies.find { it.name == tokenKey }?.value ?: ""
|
||||||
} else {
|
} else {
|
||||||
request.getHeader(tokenKey) ?: ""
|
var token = request.getHeader(tokenKey) ?: ""
|
||||||
|
if (token.isEmpty()) token = request.getParameter(tokenKey) ?: ""
|
||||||
|
token
|
||||||
}
|
}
|
||||||
val user = this.userSessionManager.userSession(identity)
|
val user = this.userSessionManager.userSession(identity)
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
@@ -62,4 +64,5 @@ class WebAuthorization(
|
|||||||
response.flushBuffer()
|
response.flushBuffer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
package com.synebula.gaea.app.component.security
|
package com.synebula.gaea.app.security
|
||||||
|
|
||||||
import com.synebula.gaea.app.component.security.session.UserSessionManager
|
import com.synebula.gaea.app.security.session.UserSessionManager
|
||||||
import com.synebula.gaea.data.message.HttpMessageFactory
|
import com.synebula.gaea.data.message.HttpMessageFactory
|
||||||
import com.synebula.gaea.data.message.Status
|
import com.synebula.gaea.data.message.Status
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.security.config.Customizer
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer
|
||||||
@@ -36,24 +37,27 @@ class WebSecurity {
|
|||||||
@Bean
|
@Bean
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain {
|
fun filterChain(httpSecurity: HttpSecurity): SecurityFilterChain {
|
||||||
httpSecurity.cors().and().csrf().disable() // 跨域伪造请求限制无效
|
httpSecurity.cors(Customizer.withDefaults())
|
||||||
|
.csrf { it.disable() } // 跨域伪造请求限制无效
|
||||||
// 设置Session的创建策略为:Spring Security永不创建HttpSession 不使用HttpSession来获取SecurityContext
|
// 设置Session的创建策略为:Spring Security永不创建HttpSession 不使用HttpSession来获取SecurityContext
|
||||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
|
.sessionManagement { it.sessionCreationPolicy(SessionCreationPolicy.STATELESS) }
|
||||||
// 除了登录接口其他资源都必须登录访问
|
// 除了登录接口其他资源都必须登录访问
|
||||||
.and().authorizeRequests().antMatchers(this.signInPath).permitAll().anyRequest().authenticated()
|
.authorizeHttpRequests { it.requestMatchers(this.signInPath).permitAll().anyRequest().authenticated() }
|
||||||
// 添加鉴权拦截器
|
// 添加鉴权拦截器
|
||||||
.and().addFilterBefore(
|
.addFilterBefore(
|
||||||
WebAuthorization(httpMessageFactory, userSessionManager),
|
WebAuthorization(httpMessageFactory, userSessionManager),
|
||||||
UsernamePasswordAuthenticationFilter::class.java
|
UsernamePasswordAuthenticationFilter::class.java
|
||||||
).exceptionHandling().authenticationEntryPoint { _, response, _ ->
|
).exceptionHandling {
|
||||||
response.status = Status.Success
|
it.authenticationEntryPoint { _, response, _ ->
|
||||||
response.characterEncoding = "utf-8"
|
response.status = Status.Success
|
||||||
response.contentType = "text/javascript;charset=utf-8"
|
response.characterEncoding = "utf-8"
|
||||||
response.writer.print(
|
response.contentType = "text/javascript;charset=utf-8"
|
||||||
this.httpMessageFactory.create(
|
response.writer.print(
|
||||||
Status.Unauthorized, "用户未登录,请重新登录后尝试!"
|
this.httpMessageFactory.create(
|
||||||
|
Status.Unauthorized, "用户未登录,请重新登录后尝试!"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return httpSecurity.build()
|
return httpSecurity.build()
|
||||||
@@ -62,7 +66,7 @@ class WebSecurity {
|
|||||||
@Bean
|
@Bean
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun ignoringCustomizer(): WebSecurityCustomizer {
|
fun ignoringCustomizer(): WebSecurityCustomizer {
|
||||||
return WebSecurityCustomizer { web -> web.ignoring().antMatchers(this.signInPath) }
|
return WebSecurityCustomizer { web -> web.ignoring().requestMatchers(this.signInPath) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.synebula.gaea.app.security.session
|
||||||
|
|
||||||
|
import com.synebula.gaea.data.permission.AuthorityType
|
||||||
|
import com.synebula.gaea.data.permission.PermissionType
|
||||||
|
|
||||||
|
open class User {
|
||||||
|
/**
|
||||||
|
* 权限类型, 根据类型来动态应用[permissions]中的权限信息. 通常配置在角色中
|
||||||
|
*/
|
||||||
|
var permissionType = PermissionType.Minimum
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户的权限信息. 通常通过角色配置
|
||||||
|
*/
|
||||||
|
var permissions = mapOf<String, AuthorityType>()
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.app.component.security.session
|
package com.synebula.gaea.app.security.session
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登陆用户会话信息
|
* 登陆用户会话信息
|
||||||
@@ -27,7 +27,7 @@ class UserSession(var uid: String, var user: Any) {
|
|||||||
* 获取指定类型的用户信息
|
* 获取指定类型的用户信息
|
||||||
*/
|
*/
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
fun <T> user(): T {
|
fun <T : User> user(): T {
|
||||||
return user as T
|
return user as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.synebula.gaea.app.component.security.session
|
package com.synebula.gaea.app.security.session
|
||||||
|
|
||||||
import com.synebula.gaea.app.component.cache.Cache
|
import com.synebula.gaea.app.cache.Cache
|
||||||
import com.synebula.gaea.ext.toMd5
|
import com.synebula.gaea.ext.toMd5
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package com.synebula.gaea.app.struct
|
|
||||||
|
|
||||||
class ExcelData(var title: String = "",
|
|
||||||
var columnNames: List<String> = listOf(),
|
|
||||||
var data: List<List<String>> = listOf())
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package com.synebula.gaea.app.struct.exception
|
|
||||||
|
|
||||||
import com.auth0.jwt.exceptions.TokenExpiredException
|
|
||||||
|
|
||||||
class TokenCloseExpireException(msg: String, var payload: String) : TokenExpiredException(msg)
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
com.synebula.gaea.app.autoconfig.AppAutoConfiguration
|
||||||
@@ -5,7 +5,7 @@ ext {
|
|||||||
dependencies {
|
dependencies {
|
||||||
api project(":src:gaea")
|
api project(":src:gaea")
|
||||||
|
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa:$spring_version")
|
api("org.springframework.boot:spring-boot-starter-data-jpa:$spring_version")
|
||||||
implementation("org.javassist:javassist:$jassist_version")
|
implementation("org.javassist:javassist:$jassist_version")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
package com.synebula.gaea.jpa
|
package com.synebula.gaea.jpa
|
||||||
|
|
||||||
import com.synebula.gaea.query.IQuery
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.query.Page
|
import com.synebula.gaea.db.query.Page
|
||||||
import com.synebula.gaea.query.Params
|
import com.synebula.gaea.db.query.Params
|
||||||
|
import com.synebula.gaea.jpa.proxy.method.resolver.PageMethodResolver
|
||||||
|
import jakarta.persistence.EntityManager
|
||||||
|
import org.springframework.data.domain.Pageable
|
||||||
|
import org.springframework.data.jpa.domain.Specification
|
||||||
import org.springframework.data.jpa.repository.support.SimpleJpaRepository
|
import org.springframework.data.jpa.repository.support.SimpleJpaRepository
|
||||||
import javax.persistence.EntityManager
|
|
||||||
|
|
||||||
class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: EntityManager) : IQuery<TView, ID> {
|
@Suppress("UNCHECKED_CAST")
|
||||||
protected var repo: SimpleJpaRepository<TView, ID>
|
class JpaQuery(protected var entityManager: EntityManager) : IQuery {
|
||||||
|
protected var repos = mutableMapOf<Class<*>, SimpleJpaRepository<*, *>>()
|
||||||
|
|
||||||
init {
|
|
||||||
repo = SimpleJpaRepository<TView, ID>(clazz, entityManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
override operator fun get(id: ID): TView? {
|
override operator fun <TView, ID> get(id: ID, clazz: Class<TView>): TView? {
|
||||||
val view = this.repo.findById(id)
|
val repo = this.getJpaRepository(clazz)
|
||||||
|
val view = repo.findById(id!!)
|
||||||
return if (view.isPresent) view.get() else null
|
return if (view.isPresent) view.get() else null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,9 +27,10 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
|
|||||||
* @param params 查询条件。
|
* @param params 查询条件。
|
||||||
* @return 视图列表
|
* @return 视图列表
|
||||||
*/
|
*/
|
||||||
override fun list(params: Map<String, String>?): List<TView> {
|
override fun <TView> list(params: Map<String, String>?, clazz: Class<TView>): List<TView> {
|
||||||
// method proxy in JpaRepositoryProxy [SimpleJpaRepository]
|
val repo = this.getJpaRepository(clazz)
|
||||||
return emptyList()
|
val spec = params?.toSpecification(clazz) as Specification<TView>
|
||||||
|
return repo.findAll(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,9 +39,10 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
|
|||||||
* @param params 查询条件。
|
* @param params 查询条件。
|
||||||
* @return 数量
|
* @return 数量
|
||||||
*/
|
*/
|
||||||
override fun count(params: Map<String, String>?): Int {
|
override fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Long {
|
||||||
// method proxy in JpaRepositoryProxy [SimpleJpaRepository]
|
val repo = this.getJpaRepository(clazz)
|
||||||
return -1
|
val spec = params?.toSpecification(clazz) as Specification<TView>
|
||||||
|
return repo.count(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,9 +51,11 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
|
|||||||
* @param params 分页条件
|
* @param params 分页条件
|
||||||
* @return 分页数据
|
* @return 分页数据
|
||||||
*/
|
*/
|
||||||
override fun paging(params: Params): Page<TView> {
|
override fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView> {
|
||||||
// method proxy in JpaRepositoryProxy [SimpleJpaRepository]
|
val repo = this.getJpaRepository(clazz)
|
||||||
return Page()
|
val p = PageMethodResolver("findAll", clazz).mappingArguments(arrayOf(params))
|
||||||
|
val page = repo.findAll(p[0] as Specification<TView>, p[1] as Pageable)
|
||||||
|
return Page(page.number + 1, page.size, page.totalElements, page.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,9 +65,18 @@ class JpaQuery<TView, ID>(override var clazz: Class<TView>, entityManager: Entit
|
|||||||
*
|
*
|
||||||
* @return 视图列表
|
* @return 视图列表
|
||||||
*/
|
*/
|
||||||
override fun range(field: String, params: List<Any>): List<TView> {
|
override fun <TView> range(field: String, params: List<Any>, clazz: Class<TView>): List<TView> {
|
||||||
// method proxy in JpaRepositoryProxy [SimpleJpaRepository]
|
// method proxy in JpaRepositoryProxy [SimpleJpaRepository]
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <TView> getJpaRepository(clazz: Class<TView>): SimpleJpaRepository<TView, in Any> {
|
||||||
|
if (this.repos.isNotEmpty() && this.repos.containsKey(clazz)) {
|
||||||
|
return this.repos[clazz] as SimpleJpaRepository<TView, Any>
|
||||||
|
} else {
|
||||||
|
val r = SimpleJpaRepository<TView, Any>(clazz, entityManager)
|
||||||
|
this.repos[clazz] = r
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,13 @@ package com.synebula.gaea.jpa
|
|||||||
|
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
import com.synebula.gaea.domain.repository.IRepository
|
import com.synebula.gaea.domain.repository.IRepository
|
||||||
|
import jakarta.persistence.EntityManager
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
import org.springframework.data.jpa.repository.support.SimpleJpaRepository
|
import org.springframework.data.jpa.repository.support.SimpleJpaRepository
|
||||||
import javax.persistence.EntityManager
|
|
||||||
|
|
||||||
|
|
||||||
class JpaRepository<TAggregateRoot : IAggregateRoot<ID>, ID>(
|
open class JpaRepository<TAggregateRoot : IAggregateRoot<ID>, ID>(
|
||||||
override var clazz: Class<TAggregateRoot>,
|
final override var clazz: Class<TAggregateRoot>,
|
||||||
entityManager: EntityManager
|
entityManager: EntityManager
|
||||||
) : IRepository<TAggregateRoot, ID> {
|
) : IRepository<TAggregateRoot, ID> {
|
||||||
protected var repo: JpaRepository<TAggregateRoot, ID>? = null
|
protected var repo: JpaRepository<TAggregateRoot, ID>? = null
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.synebula.gaea.jpa
|
||||||
|
|
||||||
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
|
import com.synebula.gaea.domain.repository.IRepository
|
||||||
|
import com.synebula.gaea.domain.repository.IRepositoryFactory
|
||||||
|
import jakarta.persistence.EntityManager
|
||||||
|
|
||||||
|
class JpaRepositoryFactory(private var entityManager: EntityManager) : IRepositoryFactory {
|
||||||
|
override fun createRawRepository(clazz: Class<*>): IRepository<*, *> {
|
||||||
|
val constructor = JpaRepository::class.java.getConstructor(Class::class.java, EntityManager::class.java)
|
||||||
|
return constructor.newInstance(clazz, this.entityManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : IAggregateRoot<I>, I> createRepository(clazz: Class<T>): IRepository<T, I> {
|
||||||
|
return JpaRepository(clazz, this.entityManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
package com.synebula.gaea.jpa
|
package com.synebula.gaea.jpa
|
||||||
|
|
||||||
import com.synebula.gaea.data.date.DateTime
|
import com.synebula.gaea.data.date.DateTime
|
||||||
import com.synebula.gaea.query.Operator
|
import com.synebula.gaea.db.query.Operator
|
||||||
import com.synebula.gaea.query.Where
|
import com.synebula.gaea.db.query.Where
|
||||||
|
import jakarta.persistence.criteria.*
|
||||||
import org.springframework.data.jpa.domain.Specification
|
import org.springframework.data.jpa.domain.Specification
|
||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.persistence.criteria.CriteriaBuilder
|
|
||||||
import javax.persistence.criteria.CriteriaQuery
|
|
||||||
import javax.persistence.criteria.Predicate
|
|
||||||
import javax.persistence.criteria.Root
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,79 +66,209 @@ fun String.tryToDigital(field: Field): Double {
|
|||||||
* @param clazz 类
|
* @param clazz 类
|
||||||
* @return Specification
|
* @return Specification
|
||||||
*/
|
*/
|
||||||
fun Map<String, String>?.toSpecification(clazz: Class<*>): Specification<*> {
|
fun Map<String, String>.toSpecification(clazz: Class<*>): Specification<*> {
|
||||||
val rangeStartSuffix = "[0]" //范围查询开始后缀
|
val rangeStartSuffix = "[0]" //范围查询开始后缀
|
||||||
val rangeEndSuffix = "[1]" //范围查询结束后缀
|
val rangeEndSuffix = "[1]" //范围查询结束后缀
|
||||||
return Specification<Any?> { root: Root<Any?>, _: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
|
return Specification<Any?> { root: Root<Any?>, _: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
|
||||||
val predicates: MutableList<Predicate> = ArrayList()
|
val predicates = mutableListOf<Predicate>()
|
||||||
for (argumentName in this!!.keys) {
|
for (argumentName in this.keys) {
|
||||||
if (this[argumentName] == null) continue
|
|
||||||
var fieldName = argumentName
|
|
||||||
var operator: Operator
|
|
||||||
|
|
||||||
// 判断是否为range类型(范围内查询)
|
|
||||||
var start = true
|
|
||||||
if (fieldName.endsWith(rangeStartSuffix) || fieldName.endsWith(rangeEndSuffix)) {
|
|
||||||
fieldName = fieldName.substring(fieldName.length - 3)
|
|
||||||
if (fieldName.endsWith(rangeEndSuffix)) start = false
|
|
||||||
}
|
|
||||||
val field = clazz.getDeclaredField(fieldName)
|
|
||||||
val where: Where = field.getDeclaredAnnotation(Where::class.java)
|
|
||||||
operator = where.operator
|
|
||||||
|
|
||||||
// 如果是范围内容, 判断是数值类型还是时间类型
|
|
||||||
if (operator === Operator.Range) {
|
|
||||||
if (clazz.getDeclaredField(fieldName).type != Date::class.java) {
|
|
||||||
operator = if (start) Operator.Gte else Operator.Lte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var predicate: Predicate
|
|
||||||
var digitalValue: Double
|
|
||||||
try {
|
try {
|
||||||
|
var fieldName = argumentName
|
||||||
|
val fieldValue = this[argumentName]!!
|
||||||
|
var operator: Operator = Operator.Default
|
||||||
|
|
||||||
|
// 判断是否为range类型(范围内查询)
|
||||||
|
var start = true
|
||||||
|
if (fieldName.endsWith(rangeStartSuffix) || fieldName.endsWith(rangeEndSuffix)) {
|
||||||
|
fieldName = fieldName.substring(fieldName.length - 3)
|
||||||
|
if (fieldName.endsWith(rangeEndSuffix)) start = false
|
||||||
|
}
|
||||||
|
val fieldTree = fieldName.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
//查找是否是嵌入字段, 找到最深的类型
|
||||||
|
var field: Field
|
||||||
|
if (fieldTree.isNotEmpty()) {
|
||||||
|
var hostClass = clazz //需要查找字段所在的class
|
||||||
|
var i = 0
|
||||||
|
do {
|
||||||
|
field = hostClass.getDeclaredField(fieldTree[i])
|
||||||
|
hostClass = field.type
|
||||||
|
i++
|
||||||
|
} while (i < fieldTree.size)
|
||||||
|
} else {
|
||||||
|
field = clazz.getDeclaredField(fieldName)
|
||||||
|
}
|
||||||
|
val where = field.getDeclaredAnnotation(Where::class.java)
|
||||||
|
if (where != null) operator = where.operator
|
||||||
|
|
||||||
|
// 如果是范围内容, 判断是数值类型还是时间类型
|
||||||
|
if (operator === Operator.Range) {
|
||||||
|
if (field.type != Date::class.java) {
|
||||||
|
operator = if (start) Operator.Gte else Operator.Lte
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var predicate: Predicate
|
||||||
|
var digitalValue: Double
|
||||||
when (operator) {
|
when (operator) {
|
||||||
Operator.Ne -> predicate =
|
Operator.Ne -> predicate = criteriaBuilder.notEqual(
|
||||||
criteriaBuilder.notEqual(root.get<Any>(fieldName), this[fieldName]!!.toFieldType(field))
|
getFieldPath<Any>(root, fieldName),
|
||||||
|
typeConvert(field, fieldValue)
|
||||||
|
)
|
||||||
|
|
||||||
Operator.Lt -> {
|
Operator.Lt -> try {
|
||||||
digitalValue = this[fieldName]!!.tryToDigital(field)
|
digitalValue = parseDigital(field, fieldValue)
|
||||||
predicate = criteriaBuilder.lessThan(root.get(fieldName), digitalValue)
|
predicate = criteriaBuilder.lessThan(getFieldPath(root, fieldName), digitalValue)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(
|
||||||
|
String.format(
|
||||||
|
"class [%s] field [%s] can not use annotation Where(Operator.lt)",
|
||||||
|
field.declaringClass.name,
|
||||||
|
field.name
|
||||||
|
), e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator.Gt -> {
|
Operator.Gt -> try {
|
||||||
digitalValue = this[fieldName]!!.tryToDigital(field)
|
digitalValue = parseDigital(field, fieldValue)
|
||||||
predicate = criteriaBuilder.greaterThan(root.get(fieldName), digitalValue)
|
predicate = criteriaBuilder.greaterThan(
|
||||||
|
getFieldPath(
|
||||||
|
root,
|
||||||
|
fieldName
|
||||||
|
), digitalValue
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(
|
||||||
|
String.format(
|
||||||
|
"class [%s] field [%s] can not use annotation Where(Operator.gt)",
|
||||||
|
field.declaringClass.name,
|
||||||
|
field.name
|
||||||
|
), e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator.Lte -> {
|
Operator.Lte -> try {
|
||||||
digitalValue = this[fieldName]!!.tryToDigital(field)
|
digitalValue = parseDigital(field, fieldValue)
|
||||||
predicate = criteriaBuilder.lessThanOrEqualTo(root.get(fieldName), digitalValue)
|
predicate = criteriaBuilder.lessThanOrEqualTo(
|
||||||
|
getFieldPath(
|
||||||
|
root,
|
||||||
|
fieldName
|
||||||
|
), digitalValue
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(
|
||||||
|
String.format(
|
||||||
|
"class [%s] field [%s] can not use annotation Where(Operator.lte)",
|
||||||
|
field.declaringClass.name,
|
||||||
|
field.name
|
||||||
|
), e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator.Gte -> {
|
Operator.Gte -> try {
|
||||||
digitalValue = this[fieldName]!!.tryToDigital(field)
|
digitalValue = parseDigital(field, fieldValue)
|
||||||
predicate = criteriaBuilder.greaterThanOrEqualTo(root.get(fieldName), digitalValue)
|
predicate = criteriaBuilder.greaterThanOrEqualTo(
|
||||||
|
getFieldPath(
|
||||||
|
root,
|
||||||
|
fieldName
|
||||||
|
), digitalValue
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(
|
||||||
|
String.format(
|
||||||
|
"class [%s] field [%s] can not use annotation Where(Operator.gte)",
|
||||||
|
field.declaringClass.name,
|
||||||
|
field.name
|
||||||
|
), e
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Operator.Like -> predicate = criteriaBuilder.like(root.get(fieldName), "%${this[fieldName]}%")
|
Operator.Like -> predicate = criteriaBuilder.like(
|
||||||
Operator.Range -> {
|
getFieldPath(root, fieldName),
|
||||||
predicate = if (start) {
|
String.format("%%%s%%", fieldValue)
|
||||||
criteriaBuilder.greaterThanOrEqualTo(root.get(fieldName), this[argumentName]!!)
|
)
|
||||||
} else {
|
|
||||||
criteriaBuilder.lessThanOrEqualTo(root.get(fieldName), this[argumentName]!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> predicate =
|
Operator.Range -> predicate = if (start) criteriaBuilder.greaterThanOrEqualTo(
|
||||||
criteriaBuilder.equal(root.get<Any>(fieldName), this[fieldName]!!.toFieldType(field))
|
getFieldPath(root, fieldName), this[argumentName]!!
|
||||||
|
) else criteriaBuilder.lessThanOrEqualTo(
|
||||||
|
getFieldPath(root, fieldName), this[argumentName]!!
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> predicate = criteriaBuilder.equal(
|
||||||
|
getFieldPath<Any>(root, fieldName),
|
||||||
|
typeConvert(field, fieldValue)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
predicates.add(predicate)
|
predicates.add(predicate)
|
||||||
} catch (e: NoSuchFieldException) {
|
} catch (e: NoSuchFieldException) {
|
||||||
throw Error(
|
throw RuntimeException(e)
|
||||||
"class [${field.declaringClass.name}] field [${field.name}] can't annotation [@Where(${operator.declaringClass.simpleName}.${operator.name})]",
|
|
||||||
e
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
criteriaBuilder.and(*predicates.toTypedArray())
|
criteriaBuilder.and(*predicates.toTypedArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字段在
|
||||||
|
*/
|
||||||
|
fun <Y> getFieldPath(root: Root<Any?>, field: String): Path<Y>? {
|
||||||
|
val fieldTree = field.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
var path: Path<Y>
|
||||||
|
if (fieldTree.isNotEmpty()) {
|
||||||
|
path = root.get(fieldTree[0])
|
||||||
|
for (i in 1 until fieldTree.size) {
|
||||||
|
path = path.get(fieldTree[i])
|
||||||
|
}
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return root.get(field)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型转换
|
||||||
|
*
|
||||||
|
* @param field 字段对象
|
||||||
|
* @param value 值
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
fun typeConvert(field: Field, value: String): Any {
|
||||||
|
var result: Any = value
|
||||||
|
val fieldType = field.type
|
||||||
|
if (fieldType != value.javaClass) {
|
||||||
|
if (Int::class.java == fieldType || Int::class.javaPrimitiveType == fieldType) {
|
||||||
|
result = value.toInt()
|
||||||
|
}
|
||||||
|
if (Double::class.java == fieldType || Double::class.javaPrimitiveType == fieldType) {
|
||||||
|
result = value.toDouble()
|
||||||
|
}
|
||||||
|
if (Float::class.java == fieldType || Float::class.javaPrimitiveType == fieldType) {
|
||||||
|
result = value.toFloat()
|
||||||
|
}
|
||||||
|
if (Date::class.java == fieldType) {
|
||||||
|
result = DateTime(value, "yyyy-MM-dd HH:mm:ss").date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化数值类型
|
||||||
|
*
|
||||||
|
* @param field 字段对象
|
||||||
|
* @param value 值
|
||||||
|
* @return double
|
||||||
|
*/
|
||||||
|
fun parseDigital(field: Field, value: String): Double {
|
||||||
|
val result: Double
|
||||||
|
val fieldType = field.type
|
||||||
|
result =
|
||||||
|
if (Int::class.java == fieldType || Int::class.javaPrimitiveType == fieldType || Double::class.java == fieldType || Double::class.javaPrimitiveType == fieldType || Float::class.java == fieldType || Float::class.javaPrimitiveType == fieldType) {
|
||||||
|
value.toDouble()
|
||||||
|
} else throw java.lang.RuntimeException(
|
||||||
|
String.format(
|
||||||
|
"class [%s] field [%s] is not digital",
|
||||||
|
field.declaringClass.name,
|
||||||
|
field.name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ import org.springframework.beans.factory.FactoryBean
|
|||||||
import org.springframework.cglib.proxy.Enhancer
|
import org.springframework.cglib.proxy.Enhancer
|
||||||
import org.springframework.data.repository.Repository
|
import org.springframework.data.repository.Repository
|
||||||
|
|
||||||
class JpaRepositoryFactory(
|
class JpaDbContextFactory(
|
||||||
private val beanFactory: BeanFactory,
|
private val beanFactory: BeanFactory,
|
||||||
private val interfaceType: Class<*>,
|
private val interfaceType: Class<*>,
|
||||||
private val implBeanNames: List<String>
|
private val implBeanNames: List<String>
|
||||||
) : FactoryBean<Any> {
|
) : FactoryBean<Any> {
|
||||||
override fun getObject(): Any {
|
override fun getObject(): Any {
|
||||||
val handler: JpaRepositoryProxy<*, *, *> = JpaRepositoryProxy<Repository<Any, Any>, Any, Any>(
|
val handler: JpaDbContextProxy<*, *, *> = JpaDbContextProxy<Repository<Any, Any>, Any, Any>(
|
||||||
beanFactory,
|
beanFactory,
|
||||||
interfaceType, implBeanNames
|
interfaceType, implBeanNames
|
||||||
)
|
)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.synebula.gaea.jpa.proxy
|
package com.synebula.gaea.jpa.proxy
|
||||||
|
|
||||||
import com.synebula.gaea.jpa.proxy.method.JpaMethodProxy
|
import com.synebula.gaea.jpa.proxy.method.JpaMethodProxy
|
||||||
|
import jakarta.persistence.EntityManager
|
||||||
import javassist.*
|
import javassist.*
|
||||||
import javassist.bytecode.AnnotationsAttribute
|
import javassist.bytecode.AnnotationsAttribute
|
||||||
import javassist.bytecode.MethodInfo
|
import javassist.bytecode.MethodInfo
|
||||||
@@ -24,9 +25,8 @@ import org.springframework.data.repository.Repository
|
|||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.lang.reflect.ParameterizedType
|
import java.lang.reflect.ParameterizedType
|
||||||
import java.lang.reflect.Type
|
import java.lang.reflect.Type
|
||||||
import javax.persistence.EntityManager
|
|
||||||
|
|
||||||
class JpaRepositoryProxy<T : Repository<S, ID>?, S, ID>(
|
class JpaDbContextProxy<T : Repository<S, ID>?, S, ID>(
|
||||||
beanFactory: BeanFactory,
|
beanFactory: BeanFactory,
|
||||||
interfaceType: Class<*>,
|
interfaceType: Class<*>,
|
||||||
implementBeanNames: List<String>?
|
implementBeanNames: List<String>?
|
||||||
@@ -8,5 +8,5 @@ import kotlin.reflect.KClass
|
|||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
@Inherited
|
@Inherited
|
||||||
@Import(JpaRepositoryRegister::class)
|
@Import(JpaDbContextRegister::class)
|
||||||
annotation class JpaRepositoryProxyScan(val basePackages: Array<String> = [], val scanInterfaces: Array<KClass<*>> = [])
|
annotation class JpaDbContextProxyScan(val basePackages: Array<String> = [], val scanInterfaces: Array<KClass<*>> = [])
|
||||||
@@ -24,17 +24,20 @@ import org.springframework.util.ClassUtils
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.stream.Collectors
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
class JpaRepositoryRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware,
|
class JpaDbContextRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware,
|
||||||
EnvironmentAware,
|
EnvironmentAware,
|
||||||
BeanFactoryAware {
|
BeanFactoryAware {
|
||||||
|
|
||||||
private lateinit var environment: Environment
|
private lateinit var environment: Environment
|
||||||
private lateinit var resourceLoader: ResourceLoader
|
private lateinit var resourceLoader: ResourceLoader
|
||||||
private var classLoader: ClassLoader? = null
|
private var classLoader: ClassLoader? = null
|
||||||
private var beanFactory: BeanFactory? = null
|
private var beanFactory: BeanFactory? = null
|
||||||
|
|
||||||
|
|
||||||
override fun registerBeanDefinitions(metadata: AnnotationMetadata, registry: BeanDefinitionRegistry) {
|
override fun registerBeanDefinitions(metadata: AnnotationMetadata, registry: BeanDefinitionRegistry) {
|
||||||
val attributes = AnnotationAttributes(
|
val attributes = AnnotationAttributes(
|
||||||
metadata.getAnnotationAttributes(
|
metadata.getAnnotationAttributes(
|
||||||
JpaRepositoryProxyScan::class.java.name
|
JpaDbContextProxyScan::class.java.name
|
||||||
) ?: mapOf()
|
) ?: mapOf()
|
||||||
)
|
)
|
||||||
val basePackages = attributes.getStringArray("basePackages")
|
val basePackages = attributes.getStringArray("basePackages")
|
||||||
@@ -55,7 +58,7 @@ class JpaRepositoryRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware
|
|||||||
val implClazzDefinitions = scan(basePackages, arrayOf(beanClazzTypeFilter))
|
val implClazzDefinitions = scan(basePackages, arrayOf(beanClazzTypeFilter))
|
||||||
for (definition in implClazzDefinitions) {
|
for (definition in implClazzDefinitions) {
|
||||||
definition.isAutowireCandidate = false
|
definition.isAutowireCandidate = false
|
||||||
registry.registerBeanDefinition(Objects.requireNonNull(definition.beanClassName), definition)
|
registry.registerBeanDefinition(Objects.requireNonNull(definition.beanClassName!!), definition)
|
||||||
}
|
}
|
||||||
// 构建bean定义
|
// 构建bean定义
|
||||||
// 1 bean参数
|
// 1 bean参数
|
||||||
@@ -66,7 +69,7 @@ class JpaRepositoryRegister : ImportBeanDefinitionRegistrar, ResourceLoaderAware
|
|||||||
builder.addConstructorArgValue(beanClazz)
|
builder.addConstructorArgValue(beanClazz)
|
||||||
builder.addConstructorArgValue(implBeanNames)
|
builder.addConstructorArgValue(implBeanNames)
|
||||||
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
||||||
definition.beanClass = JpaRepositoryFactory::class.java
|
definition.beanClass = JpaDbContextFactory::class.java
|
||||||
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
||||||
registry.registerBeanDefinition(beanClazz.name, definition)
|
registry.registerBeanDefinition(beanClazz.name, definition)
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ import com.synebula.gaea.jpa.proxy.method.resolver.AbstractMethodResolver
|
|||||||
import com.synebula.gaea.jpa.proxy.method.resolver.DefaultMethodResolver
|
import com.synebula.gaea.jpa.proxy.method.resolver.DefaultMethodResolver
|
||||||
import com.synebula.gaea.jpa.proxy.method.resolver.FindMethodResolver
|
import com.synebula.gaea.jpa.proxy.method.resolver.FindMethodResolver
|
||||||
import com.synebula.gaea.jpa.proxy.method.resolver.PageMethodResolver
|
import com.synebula.gaea.jpa.proxy.method.resolver.PageMethodResolver
|
||||||
import com.synebula.gaea.query.Params
|
import com.synebula.gaea.db.query.Params
|
||||||
import org.springframework.data.domain.Pageable
|
import org.springframework.data.domain.Pageable
|
||||||
import org.springframework.data.jpa.domain.Specification
|
import org.springframework.data.jpa.domain.Specification
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ class FindMethodResolver(targetMethodName: String, clazz: Class<*>) : AbstractMe
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun mappingArguments(args: Array<Any>): Array<Any> {
|
override fun mappingArguments(args: Array<Any>): Array<Any> {
|
||||||
val params = args[0] as Map<String, String>?
|
val params = args[0] as Map<String, String>?
|
||||||
val specification = params.toSpecification(entityClazz)
|
val specification = params?.toSpecification(entityClazz)
|
||||||
return arrayOf(specification)
|
return if (specification != null) arrayOf(specification) else arrayOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mappingResult(result: Any): Any {
|
override fun mappingResult(result: Any): Any {
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
package com.synebula.gaea.jpa.proxy.method.resolver
|
package com.synebula.gaea.jpa.proxy.method.resolver
|
||||||
|
|
||||||
import com.synebula.gaea.jpa.toSpecification
|
import com.synebula.gaea.jpa.toSpecification
|
||||||
import com.synebula.gaea.query.Order
|
import com.synebula.gaea.db.query.Order
|
||||||
import com.synebula.gaea.query.Params
|
import com.synebula.gaea.db.query.Params
|
||||||
|
import jakarta.persistence.EmbeddedId
|
||||||
|
import jakarta.persistence.Id
|
||||||
import org.springframework.data.domain.Page
|
import org.springframework.data.domain.Page
|
||||||
import org.springframework.data.domain.PageRequest
|
import org.springframework.data.domain.PageRequest
|
||||||
import org.springframework.data.domain.Pageable
|
import org.springframework.data.domain.Pageable
|
||||||
import org.springframework.data.domain.Sort
|
import org.springframework.data.domain.Sort
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.persistence.EmbeddedId
|
import com.synebula.gaea.db.query.Page as QueryPage
|
||||||
import javax.persistence.Id
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页方法参数映射
|
* 分页方法参数映射
|
||||||
@@ -29,8 +30,7 @@ class PageMethodResolver(targetMethodName: String, clazz: Class<*>) : AbstractMe
|
|||||||
val fields = entityClazz.declaredFields
|
val fields = entityClazz.declaredFields
|
||||||
for (field in fields) {
|
for (field in fields) {
|
||||||
val isId = Arrays.stream(field.declaredAnnotations).anyMatch { annotation: Annotation ->
|
val isId = Arrays.stream(field.declaredAnnotations).anyMatch { annotation: Annotation ->
|
||||||
(annotation.annotationClass.java == Id::class.java
|
(annotation.annotationClass.java == Id::class.java || annotation.annotationClass.java == EmbeddedId::class.java)
|
||||||
|| annotation.annotationClass.java == EmbeddedId::class.java)
|
|
||||||
}
|
}
|
||||||
if (isId) {
|
if (isId) {
|
||||||
sort = Sort.by(Sort.Direction.ASC, field.name)
|
sort = Sort.by(Sort.Direction.ASC, field.name)
|
||||||
@@ -50,7 +50,7 @@ class PageMethodResolver(targetMethodName: String, clazz: Class<*>) : AbstractMe
|
|||||||
override fun mappingResult(result: Any): Any {
|
override fun mappingResult(result: Any): Any {
|
||||||
val page = result as Page<*>
|
val page = result as Page<*>
|
||||||
|
|
||||||
// Page 页面从0开始
|
// Page 页面从0开始 [com.synebula.gaea.query.Page as QueryPage]
|
||||||
return com.synebula.gaea.query.Page(page.number + 1, page.size, page.totalElements.toInt(), page.content)
|
return QueryPage(page.number + 1, page.size, page.totalElements, page.content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package com.synebula.gaea.mongodb
|
package com.synebula.gaea.mongodb
|
||||||
|
|
||||||
import com.synebula.gaea.data.date.DateTime
|
import com.synebula.gaea.data.date.DateTime
|
||||||
import com.synebula.gaea.query.Operator
|
import com.synebula.gaea.db.query.Operator
|
||||||
import com.synebula.gaea.query.Order
|
import com.synebula.gaea.db.query.Order
|
||||||
import com.synebula.gaea.query.Where
|
import com.synebula.gaea.db.query.Where
|
||||||
import org.springframework.data.domain.Sort
|
import org.springframework.data.domain.Sort
|
||||||
import org.springframework.data.mongodb.core.query.Criteria
|
import org.springframework.data.mongodb.core.query.Criteria
|
||||||
import org.springframework.data.mongodb.core.query.Query
|
import org.springframework.data.mongodb.core.query.Query
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ import com.synebula.gaea.spring.autoconfig.Factory
|
|||||||
import com.synebula.gaea.spring.autoconfig.Proxy
|
import com.synebula.gaea.spring.autoconfig.Proxy
|
||||||
import org.springframework.beans.factory.BeanFactory
|
import org.springframework.beans.factory.BeanFactory
|
||||||
|
|
||||||
class MongodbRepositoryFactory(
|
class MongoDbContextFactory(
|
||||||
supertype: Class<*>,
|
supertype: Class<*>,
|
||||||
var beanFactory: BeanFactory,
|
var beanFactory: BeanFactory,
|
||||||
) : Factory(supertype) {
|
) : Factory(supertype) {
|
||||||
override fun createProxy(): Proxy {
|
override fun createProxy(): Proxy {
|
||||||
return MongodbRepositoryProxy(supertype, this.beanFactory)
|
return MongoDbContextProxy(supertype, this.beanFactory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.synebula.gaea.mongodb.autoconfig
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.context.IDbContext
|
||||||
|
import com.synebula.gaea.domain.repository.IRepository
|
||||||
|
import com.synebula.gaea.mongodb.db.MongodbQuery
|
||||||
|
import com.synebula.gaea.mongodb.repository.MongodbRepository
|
||||||
|
import com.synebula.gaea.db.query.IQuery
|
||||||
|
import com.synebula.gaea.reflect.getGenericInterface
|
||||||
|
import com.synebula.gaea.spring.autoconfig.Proxy
|
||||||
|
import org.springframework.beans.factory.BeanFactory
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
|
class MongoDbContextProxy(
|
||||||
|
private var supertype: Class<*>, private var beanFactory: BeanFactory
|
||||||
|
) : Proxy() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实际的执行类
|
||||||
|
*/
|
||||||
|
private var context: Any?
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (this.supertype.interfaces.any { it == IDbContext::class.java }) {
|
||||||
|
this.context = beanFactory.getBean(IDbContext::class.java)
|
||||||
|
if (context == null) {
|
||||||
|
val constructor = IDbContext::class.java.getConstructor(Class::class.java, MongoTemplate::class.java)
|
||||||
|
this.context = constructor.newInstance(this.beanFactory.getBean(MongoTemplate::class.java))
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 判断接口类型
|
||||||
|
val clazz: Class<*> // 代理服务类型
|
||||||
|
val interfaceClazz: Class<*> // 代理服务接口
|
||||||
|
|
||||||
|
if (this.supertype.interfaces.any { it == IQuery::class.java }) {
|
||||||
|
clazz = MongodbQuery::class.java
|
||||||
|
interfaceClazz = IQuery::class.java
|
||||||
|
} else {
|
||||||
|
clazz = MongodbRepository::class.java
|
||||||
|
interfaceClazz = IRepository::class.java
|
||||||
|
}
|
||||||
|
val constructor = clazz.getConstructor(Class::class.java, MongoTemplate::class.java)
|
||||||
|
this.context = constructor.newInstance(
|
||||||
|
this.supertype.getGenericInterface(interfaceClazz)!!.actualTypeArguments[0],
|
||||||
|
this.beanFactory.getBean(MongoTemplate::class.java)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行代理方法
|
||||||
|
*
|
||||||
|
* @param proxy 代理对象
|
||||||
|
* @param method 需要执行的方法
|
||||||
|
* @param args 参数列表
|
||||||
|
* @return 方法执行结果
|
||||||
|
*/
|
||||||
|
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
|
||||||
|
try {
|
||||||
|
val proxyMethod: Method = this.context!!.javaClass.getMethod(method.name, *method.parameterTypes)
|
||||||
|
return proxyMethod.invoke(this.context, *args)
|
||||||
|
} catch (ex: NoSuchMethodException) {
|
||||||
|
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${this.context!!.javaClass}], you must implements interface [${this.supertype.name}] ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package com.synebula.gaea.mongodb.autoconfig
|
package com.synebula.gaea.mongodb.autoconfig
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.context.IDbContext
|
||||||
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.domain.repository.IRepository
|
import com.synebula.gaea.domain.repository.IRepository
|
||||||
import com.synebula.gaea.query.IQuery
|
|
||||||
import com.synebula.gaea.spring.autoconfig.Register
|
import com.synebula.gaea.spring.autoconfig.Register
|
||||||
import org.springframework.beans.factory.config.BeanDefinition
|
import org.springframework.beans.factory.config.BeanDefinition
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||||
@@ -9,20 +10,20 @@ import org.springframework.beans.factory.support.GenericBeanDefinition
|
|||||||
import org.springframework.core.annotation.AnnotationAttributes
|
import org.springframework.core.annotation.AnnotationAttributes
|
||||||
import org.springframework.core.type.AnnotationMetadata
|
import org.springframework.core.type.AnnotationMetadata
|
||||||
|
|
||||||
class MongodbRepositoryRegister : Register() {
|
class MongoDbContextRegister : Register() {
|
||||||
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
|
override fun scan(metadata: AnnotationMetadata): Map<String, BeanDefinition> {
|
||||||
val result = mutableMapOf<String, BeanDefinition>()
|
val result = mutableMapOf<String, BeanDefinition>()
|
||||||
|
|
||||||
// 获取注解参数信息:basePackages
|
// 获取注解参数信息:basePackages
|
||||||
val attributes = AnnotationAttributes(
|
val attributes = AnnotationAttributes(
|
||||||
metadata.getAnnotationAttributes(
|
metadata.getAnnotationAttributes(
|
||||||
MongodbRepositoryScan::class.java.name
|
MongoDbRepositoryScan::class.java.name
|
||||||
) ?: mapOf()
|
) ?: mapOf()
|
||||||
)
|
)
|
||||||
val basePackages = attributes.getStringArray("basePackages")
|
val basePackages = attributes.getStringArray("basePackages")
|
||||||
val beanDefinitions = this.doScan(
|
val beanDefinitions = this.doScan(
|
||||||
basePackages,
|
basePackages,
|
||||||
arrayOf(this.interfaceFilter(arrayOf(IRepository::class.java, IQuery::class.java)))
|
arrayOf(this.interfaceFilter(arrayOf(IDbContext::class.java, IQuery::class.java, IRepository::class.java)))
|
||||||
)
|
)
|
||||||
beanDefinitions.forEach { beanDefinition ->
|
beanDefinitions.forEach { beanDefinition ->
|
||||||
// 获取实际的bean类型
|
// 获取实际的bean类型
|
||||||
@@ -44,7 +45,7 @@ class MongodbRepositoryRegister : Register() {
|
|||||||
builder.addConstructorArgValue(beanClazz)
|
builder.addConstructorArgValue(beanClazz)
|
||||||
builder.addConstructorArgValue(this._beanFactory)
|
builder.addConstructorArgValue(this._beanFactory)
|
||||||
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
||||||
definition.beanClass = MongodbRepositoryFactory::class.java
|
definition.beanClass = MongoDbContextFactory::class.java
|
||||||
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
||||||
result[beanClazz.name] = definition
|
result[beanClazz.name] = definition
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ class MongodbRepositoryRegister : Register() {
|
|||||||
builder.addConstructorArgValue(this._beanFactory)
|
builder.addConstructorArgValue(this._beanFactory)
|
||||||
builder.addConstructorArgValue(emptyArray<String>())
|
builder.addConstructorArgValue(emptyArray<String>())
|
||||||
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
val definition = builder.rawBeanDefinition as GenericBeanDefinition
|
||||||
definition.beanClass = MongodbRepositoryFactory::class.java
|
definition.beanClass = MongoDbContextFactory::class.java
|
||||||
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
definition.autowireMode = GenericBeanDefinition.AUTOWIRE_BY_TYPE
|
||||||
result[IRepository::class.java.name] = definition
|
result[IRepository::class.java.name] = definition
|
||||||
}
|
}
|
||||||
@@ -8,5 +8,5 @@ import java.lang.annotation.Inherited
|
|||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
@Inherited
|
@Inherited
|
||||||
@Import(MongodbRepositoryRegister::class)
|
@Import(MongoDbContextRegister::class)
|
||||||
annotation class MongodbRepositoryScan(val basePackages: Array<String> = [])
|
annotation class MongoDbRepositoryScan(val basePackages: Array<String> = [])
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.synebula.gaea.mongodb.autoconfig
|
|
||||||
|
|
||||||
import com.synebula.gaea.domain.repository.IRepository
|
|
||||||
import com.synebula.gaea.mongodb.query.MongodbQuery
|
|
||||||
import com.synebula.gaea.mongodb.repository.MongodbRepository
|
|
||||||
import com.synebula.gaea.query.IQuery
|
|
||||||
import com.synebula.gaea.reflect.getGenericInterface
|
|
||||||
import com.synebula.gaea.spring.autoconfig.Proxy
|
|
||||||
import org.springframework.beans.factory.BeanFactory
|
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate
|
|
||||||
import java.lang.reflect.Method
|
|
||||||
|
|
||||||
class MongodbRepositoryProxy(
|
|
||||||
private var supertype: Class<*>, private var beanFactory: BeanFactory
|
|
||||||
) : Proxy() {
|
|
||||||
|
|
||||||
private var mongodbRepo: Any
|
|
||||||
|
|
||||||
init {
|
|
||||||
// 判断接口类型
|
|
||||||
val clazz: Class<*> // 代理服务类型
|
|
||||||
val interfaceClazz: Class<*> // 代理服务接口
|
|
||||||
if (this.supertype.interfaces.any { it == IRepository::class.java }) {
|
|
||||||
clazz = MongodbRepository::class.java
|
|
||||||
interfaceClazz = IRepository::class.java
|
|
||||||
} else {
|
|
||||||
clazz = MongodbQuery::class.java
|
|
||||||
interfaceClazz = IQuery::class.java
|
|
||||||
}
|
|
||||||
|
|
||||||
val constructor = clazz.getConstructor(Class::class.java, MongoTemplate::class.java)
|
|
||||||
this.mongodbRepo = constructor.newInstance(
|
|
||||||
this.supertype.getGenericInterface(interfaceClazz)!!.actualTypeArguments[0],
|
|
||||||
this.beanFactory.getBean(MongoTemplate::class.java)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行代理方法
|
|
||||||
*
|
|
||||||
* @param proxy 代理对象
|
|
||||||
* @param method 需要执行的方法
|
|
||||||
* @param args 参数列表
|
|
||||||
* @return 方法执行结果
|
|
||||||
*/
|
|
||||||
override fun exec(proxy: Any, method: Method, args: Array<Any>): Any? {
|
|
||||||
try {
|
|
||||||
val proxyMethod: Method = this.mongodbRepo.javaClass.getMethod(method.name, *method.parameterTypes)
|
|
||||||
return proxyMethod.invoke(this.mongodbRepo, *args)
|
|
||||||
} catch (ex: NoSuchMethodException) {
|
|
||||||
throw NoSuchMethodException("method [${method.toGenericString()}] not implements in class [${this.mongodbRepo.javaClass}], you must implements interface [${this.supertype.name}] ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.synebula.gaea.mongodb.db
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.IEntity
|
||||||
|
import com.synebula.gaea.db.context.IDbContext
|
||||||
|
import com.synebula.gaea.mongodb.where
|
||||||
|
import com.synebula.gaea.mongodb.whereId
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate
|
||||||
|
import org.springframework.data.mongodb.core.query.Query
|
||||||
|
|
||||||
|
class MongodbContext(
|
||||||
|
protected var template: MongoTemplate
|
||||||
|
) : IDbContext {
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> add(entity: TEntity, clazz: Class<TEntity>) {
|
||||||
|
this.template.save(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> add(entities: List<TEntity>, clazz: Class<TEntity>) {
|
||||||
|
this.template.insert(entities, clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> remove(id: ID, clazz: Class<TEntity>) {
|
||||||
|
this.template.remove(whereId(id), clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> get(id: ID, clazz: Class<TEntity>): TEntity? {
|
||||||
|
return this.template.findOne(whereId(id), clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> update(entity: TEntity, clazz: Class<TEntity>) {
|
||||||
|
this.template.save(entity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> update(entities: List<TEntity>, clazz: Class<TEntity>) {
|
||||||
|
this.template.save(entities)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <TEntity : IEntity<ID>, ID> count(params: Map<String, String>?, clazz: Class<TEntity>): Int {
|
||||||
|
val query = Query()
|
||||||
|
return this.template.count(query.where(params, clazz), clazz).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isCommitted=true
|
||||||
|
|
||||||
|
override fun commit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun rollback() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.mongodb.query
|
package com.synebula.gaea.mongodb.db
|
||||||
|
|
||||||
|
|
||||||
import com.synebula.gaea.ext.firstCharLowerCase
|
import com.synebula.gaea.ext.firstCharLowerCase
|
||||||
@@ -6,10 +6,10 @@ import com.synebula.gaea.mongodb.order
|
|||||||
import com.synebula.gaea.mongodb.select
|
import com.synebula.gaea.mongodb.select
|
||||||
import com.synebula.gaea.mongodb.where
|
import com.synebula.gaea.mongodb.where
|
||||||
import com.synebula.gaea.mongodb.whereId
|
import com.synebula.gaea.mongodb.whereId
|
||||||
import com.synebula.gaea.query.IUniversalQuery
|
import com.synebula.gaea.db.query.IQuery
|
||||||
import com.synebula.gaea.query.Page
|
import com.synebula.gaea.db.query.Page
|
||||||
import com.synebula.gaea.query.Params
|
import com.synebula.gaea.db.query.Params
|
||||||
import com.synebula.gaea.query.Table
|
import com.synebula.gaea.db.query.Table
|
||||||
import com.synebula.gaea.reflect.fieldNames
|
import com.synebula.gaea.reflect.fieldNames
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate
|
import org.springframework.data.mongodb.core.MongoTemplate
|
||||||
import org.springframework.data.mongodb.core.query.Criteria
|
import org.springframework.data.mongodb.core.query.Criteria
|
||||||
@@ -19,7 +19,7 @@ import org.springframework.data.mongodb.core.query.Query
|
|||||||
* 实现IQuery的Mongodb查询类
|
* 实现IQuery的Mongodb查询类
|
||||||
* @param template MongodbRepo对象
|
* @param template MongodbRepo对象
|
||||||
*/
|
*/
|
||||||
open class MongodbUniversalQuery(var template: MongoTemplate) : IUniversalQuery {
|
open class MongodbQuery(var template: MongoTemplate) : IQuery {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用View解析是collection时是否校验存在,默认不校验
|
* 使用View解析是collection时是否校验存在,默认不校验
|
||||||
@@ -38,9 +38,9 @@ open class MongodbUniversalQuery(var template: MongoTemplate) : IUniversalQuery
|
|||||||
return this.find(query, clazz)
|
return this.find(query, clazz)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Int {
|
override fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Long {
|
||||||
val query = Query()
|
val query = Query()
|
||||||
return this.template.count(query.where(params, clazz), this.collection(clazz)).toInt()
|
return this.template.count(query.where(params, clazz), this.collection(clazz))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView> {
|
override fun <TView> paging(params: Params, clazz: Class<TView>): Page<TView> {
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
package com.synebula.gaea.mongodb.query
|
|
||||||
|
|
||||||
import com.synebula.gaea.ext.firstCharLowerCase
|
|
||||||
import com.synebula.gaea.mongodb.order
|
|
||||||
import com.synebula.gaea.mongodb.select
|
|
||||||
import com.synebula.gaea.mongodb.where
|
|
||||||
import com.synebula.gaea.mongodb.whereId
|
|
||||||
import com.synebula.gaea.query.IQuery
|
|
||||||
import com.synebula.gaea.query.Page
|
|
||||||
import com.synebula.gaea.query.Params
|
|
||||||
import com.synebula.gaea.query.Table
|
|
||||||
import com.synebula.gaea.reflect.fieldNames
|
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate
|
|
||||||
import org.springframework.data.mongodb.core.query.Criteria
|
|
||||||
import org.springframework.data.mongodb.core.query.Query
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实现IQuery的Mongodb查询类
|
|
||||||
* @param template MongodbRepo对象
|
|
||||||
*/
|
|
||||||
|
|
||||||
open class MongodbQuery<TView, ID>(override var clazz: Class<TView>, var template: MongoTemplate) :
|
|
||||||
IQuery<TView, ID> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用View解析是collection时是否校验存在,默认不校验
|
|
||||||
*/
|
|
||||||
var validViewCollection = false
|
|
||||||
|
|
||||||
override fun get(id: ID): TView? {
|
|
||||||
return this.template.findOne(whereId(id), clazz, this.collection(clazz))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun list(params: Map<String, String>?): List<TView> {
|
|
||||||
val fields = this.fields(clazz)
|
|
||||||
val query = Query()
|
|
||||||
query.where(params, clazz)
|
|
||||||
query.select(fields)
|
|
||||||
return this.find(query, clazz)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun count(params: Map<String, String>?): Int {
|
|
||||||
val query = Query()
|
|
||||||
return this.template.count(query.where(params, clazz), this.collection(clazz)).toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun paging(params: Params): Page<TView> {
|
|
||||||
val query = Query()
|
|
||||||
val fields = this.fields(clazz)
|
|
||||||
val result = Page<TView>(params.page, params.size)
|
|
||||||
result.total = this.count(params.parameters)
|
|
||||||
//如果总数和索引相同,说明该页没有数据,直接跳到上一页
|
|
||||||
if (result.total == result.index) {
|
|
||||||
params.page -= 1
|
|
||||||
result.page -= 1
|
|
||||||
}
|
|
||||||
query.select(fields)
|
|
||||||
query.where(params.parameters, clazz)
|
|
||||||
query.with(order(params.orders))
|
|
||||||
query.skip(params.index).limit(params.size)
|
|
||||||
result.data = this.find(query, clazz)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun range(field: String, params: List<Any>): List<TView> {
|
|
||||||
return this.find(Query.query(Criteria.where(field).`in`(params)), clazz)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun find(query: Query, clazz: Class<TView>): List<TView> {
|
|
||||||
return this.template.find(query, clazz, this.collection(clazz))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <TView> fields(clazz: Class<TView>): Array<String> {
|
|
||||||
return clazz.fieldNames().toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取collection
|
|
||||||
*/
|
|
||||||
fun <TView> collection(clazz: Class<TView>): String {
|
|
||||||
val table = clazz.getDeclaredAnnotation(Table::class.java)
|
|
||||||
return if (table != null) table.name
|
|
||||||
else {
|
|
||||||
val name = clazz.simpleName.removeSuffix("View").firstCharLowerCase()
|
|
||||||
if (!validViewCollection || this.template.collectionExists(name)) name
|
|
||||||
else throw RuntimeException("找不到名为[${clazz.name}]的集合")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
package com.synebula.gaea.mongodb.query
|
|
||||||
|
|
||||||
import com.synebula.gaea.query.IQuery
|
|
||||||
import com.synebula.gaea.query.IQueryFactory
|
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate
|
|
||||||
|
|
||||||
class MongodbQueryFactory(var template: MongoTemplate) : IQueryFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建IQuery接口类型
|
|
||||||
*/
|
|
||||||
override fun createRawQuery(clazz: Class<*>): IQuery<*, *> {
|
|
||||||
val constructor = MongodbQuery::class.java.getConstructor(Class::class.java, MongoTemplate::class.java)
|
|
||||||
return constructor.newInstance(clazz, this.template)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建IQuery接口类型
|
|
||||||
*/
|
|
||||||
override fun <T, I> createQuery(clazz: Class<T>): IQuery<T, I> {
|
|
||||||
return MongodbQuery(clazz, template)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package com.synebula.gaea.mongodb.repository
|
|
||||||
|
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
|
||||||
import com.synebula.gaea.domain.repository.IUniversalRepository
|
|
||||||
import com.synebula.gaea.mongodb.where
|
|
||||||
import com.synebula.gaea.mongodb.whereId
|
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate
|
|
||||||
import org.springframework.data.mongodb.core.query.Query
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实现ITypedRepository的Mongodb仓储类
|
|
||||||
* @param repo MongodbRepo对象
|
|
||||||
*/
|
|
||||||
open class MongodbUniversalRepository(private var repo: MongoTemplate) : IUniversalRepository {
|
|
||||||
|
|
||||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>) {
|
|
||||||
this.repo.remove(whereId(id), clazz)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(
|
|
||||||
id: ID,
|
|
||||||
clazz: Class<TAggregateRoot>,
|
|
||||||
): TAggregateRoot? {
|
|
||||||
return this.repo.findOne(whereId(id), clazz)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
|
|
||||||
root: TAggregateRoot,
|
|
||||||
clazz: Class<TAggregateRoot>,
|
|
||||||
) {
|
|
||||||
this.repo.save(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新多个个对象。
|
|
||||||
*
|
|
||||||
* @param roots 需要更新的对象。
|
|
||||||
*/
|
|
||||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(
|
|
||||||
roots: List<TAggregateRoot>,
|
|
||||||
clazz: Class<TAggregateRoot>
|
|
||||||
) {
|
|
||||||
this.repo.save(roots)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(root: TAggregateRoot, clazz: Class<TAggregateRoot>) {
|
|
||||||
this.repo.save(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(
|
|
||||||
roots: List<TAggregateRoot>,
|
|
||||||
clazz: Class<TAggregateRoot>,
|
|
||||||
) {
|
|
||||||
this.repo.insert(roots, clazz)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <TAggregateRoot> count(params: Map<String, String>?, clazz: Class<TAggregateRoot>): Int {
|
|
||||||
val query = Query()
|
|
||||||
return this.repo.count(query.where(params, clazz), clazz).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,12 +13,3 @@ dependencies {
|
|||||||
|
|
||||||
api("org.springframework.boot:spring-boot-starter-aop:$spring_version")
|
api("org.springframework.boot:spring-boot-starter-aop:$spring_version")
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
publish(MavenPublication) {
|
|
||||||
from components.java
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.synebula.gaea.data.serialization.json.IJsonSerializer
|
|||||||
|
|
||||||
class HttpMessage(private var serializer: IJsonSerializer) : DataMessage<Any>() {
|
class HttpMessage(private var serializer: IJsonSerializer) : DataMessage<Any>() {
|
||||||
|
|
||||||
|
|
||||||
constructor(data: Any, serializer: IJsonSerializer) : this(serializer) {
|
constructor(data: Any, serializer: IJsonSerializer) : this(serializer) {
|
||||||
this.data = data
|
this.data = data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.synebula.gaea.data.permission
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 元素授权类型
|
||||||
|
*/
|
||||||
|
enum class AuthorityType {
|
||||||
|
Default,
|
||||||
|
Deny,
|
||||||
|
Allow
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.synebula.gaea.data.permission
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色权限类型
|
||||||
|
*/
|
||||||
|
enum class PermissionType {
|
||||||
|
/**
|
||||||
|
* 拥有所有权限
|
||||||
|
*/
|
||||||
|
All,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拥有最大权限
|
||||||
|
* 不配置无权则有权限
|
||||||
|
*/
|
||||||
|
Maximum,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最小权限
|
||||||
|
* 不配置有权则无权限
|
||||||
|
*/
|
||||||
|
Minimum,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 没有任何权限
|
||||||
|
*/
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.domain.model
|
package com.synebula.gaea.db
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 继承本接口,说明对象为实体类型。
|
* 继承本接口,说明对象为实体类型。
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.synebula.gaea.db.context
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.IEntity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 继承自IUnitOfWork,表示实现了工作单元模式的上下文接口。
|
||||||
|
*
|
||||||
|
* @author alex
|
||||||
|
*/
|
||||||
|
interface IDbContext : IUnitOfWork {
|
||||||
|
/**
|
||||||
|
* 插入单个对象。
|
||||||
|
*
|
||||||
|
* @param entity 需要插入的对象。
|
||||||
|
* @return 返回原对象,如果对象ID为自增,则补充自增ID。
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> add(entity: TEntity, clazz: Class<TEntity>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插入多个个对象。
|
||||||
|
*
|
||||||
|
* @param entities 需要插入的对象。
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> add(entities: List<TEntity>, clazz: Class<TEntity>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新对象。
|
||||||
|
*
|
||||||
|
* @param entity 需要更新的对象。
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> update(entity: TEntity, clazz: Class<TEntity>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新多个个对象。
|
||||||
|
*
|
||||||
|
* @param entities 需要更新的对象。
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> update(entities: List<TEntity>, clazz: Class<TEntity>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过id删除该条数据
|
||||||
|
*
|
||||||
|
* @param id id
|
||||||
|
* @param clazz 操作数据的类型
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> remove(id: ID, clazz: Class<TEntity>)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据ID获取对象。
|
||||||
|
*
|
||||||
|
* @param id id
|
||||||
|
* @param clazz 操作数据的类型
|
||||||
|
* @return 聚合根
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> get(id: ID, clazz: Class<TEntity>): TEntity?
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查询符合条件记录的数量
|
||||||
|
*
|
||||||
|
* @param params 查询条件。
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
fun <TEntity : IEntity<ID>, ID> count(params: Map<String, String>?, clazz: Class<TEntity>): Int
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.domain.repository.context
|
package com.synebula.gaea.db.context
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表示所有继承于该接口的类型都是Unit Of Work的一种实现。
|
* 表示所有继承于该接口的类型都是Unit Of Work的一种实现。
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询基接口, 其中方法都指定了查询的视图类型。
|
* 查询基接口, 其中方法都指定了查询的视图类型。
|
||||||
*
|
*
|
||||||
* @author alex
|
* @author alex
|
||||||
*/
|
*/
|
||||||
interface IUniversalQuery {
|
interface IQuery {
|
||||||
/**
|
/**
|
||||||
* 根据Key获取对象。
|
* 根据Key获取对象。
|
||||||
*
|
*
|
||||||
@@ -28,7 +28,7 @@ interface IUniversalQuery {
|
|||||||
* @param params 查询条件。
|
* @param params 查询条件。
|
||||||
* @return 数量
|
* @return 数量
|
||||||
*/
|
*/
|
||||||
fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Int
|
fun <TView> count(params: Map<String, String>?, clazz: Class<TView>): Long
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据实体类条件查询所有符合条件记录(分页查询)
|
* 根据实体类条件查询所有符合条件记录(分页查询)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
enum class Operator {
|
enum class Operator {
|
||||||
/**
|
/**
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class OrderType
|
* class OrderType
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页数据。
|
* 分页数据。
|
||||||
@@ -13,13 +13,13 @@ data class Page<T>(var page: Int = 0, var size: Int = 0) {
|
|||||||
/**
|
/**
|
||||||
* 总数据量。
|
* 总数据量。
|
||||||
*/
|
*/
|
||||||
var total: Int = 0
|
var total: Long = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据索引,从0开始。表示数据在总量的第几条。(index = (page - 1) * size )
|
* 数据索引,从0开始。表示数据在总量的第几条。(index = (page - 1) * size )
|
||||||
*/
|
*/
|
||||||
val index: Int
|
val index: Long
|
||||||
get() = (page - 1) * size
|
get() = (page - 1) * size.toLong()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 结果数据。
|
* 结果数据。
|
||||||
@@ -36,7 +36,7 @@ data class Page<T>(var page: Int = 0, var size: Int = 0) {
|
|||||||
* @param data 结果数据。
|
* @param data 结果数据。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
constructor(page: Int, size: Int, total: Int, data: List<T>) : this(page, size) {
|
constructor(page: Int, size: Int, total: Long, data: List<T>) : this(page, size) {
|
||||||
this.page = page
|
this.page = page
|
||||||
this.size = size
|
this.size = size
|
||||||
this.total = total
|
this.total = total
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class 分页参数信息
|
* class 分页参数信息
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
annotation class Table(val name: String = "")
|
annotation class Table(val name: String = "")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.query
|
package com.synebula.gaea.db.query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字段注解,规定字段的查询方式
|
* 字段注解,规定字段的查询方式
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.synebula.gaea.domain.event
|
package com.synebula.gaea.domain.event
|
||||||
|
|
||||||
import com.synebula.gaea.data.message.IEvent
|
import com.synebula.gaea.data.message.IEvent
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.db.IEntity
|
||||||
|
|
||||||
class AfterRemoveEvent<T : IAggregateRoot<I>, I>(var id: I? = null) : IEvent
|
class AfterRemoveEvent<T : IEntity<I>, I>(var id: I? = null) : IEvent
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.synebula.gaea.domain.event
|
package com.synebula.gaea.domain.event
|
||||||
|
|
||||||
import com.synebula.gaea.data.message.IEvent
|
import com.synebula.gaea.data.message.IEvent
|
||||||
|
import com.synebula.gaea.db.IEntity
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
|
|
||||||
class BeforeRemoveEvent<T : IAggregateRoot<I>, I>(var id: I? = null) : IEvent
|
class BeforeRemoveEvent<T : IEntity<I>, I>(var id: I? = null) : IEvent
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package com.synebula.gaea.domain.model
|
package com.synebula.gaea.domain.model
|
||||||
|
|
||||||
abstract class AggregateRoot<ID> : Entity<ID>(), IAggregateRoot<ID> {
|
abstract class AggregateRoot<ID> : Entity<ID>(), IAggregateRoot<ID> {
|
||||||
override var alive: Boolean = true
|
override var avalible: Boolean = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
package com.synebula.gaea.domain.model
|
package com.synebula.gaea.domain.model
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.IEntity
|
||||||
|
|
||||||
abstract class Entity<ID> : IEntity<ID>
|
abstract class Entity<ID> : IEntity<ID>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.synebula.gaea.domain.model
|
package com.synebula.gaea.domain.model
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.IEntity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 继承本接口,说明对象为聚合根。
|
* 继承本接口,说明对象为聚合根。
|
||||||
*
|
*
|
||||||
@@ -10,5 +12,5 @@ interface IAggregateRoot<ID> : IEntity<ID> {
|
|||||||
/**
|
/**
|
||||||
* 实体对象是否有效。
|
* 实体对象是否有效。
|
||||||
*/
|
*/
|
||||||
var alive: Boolean
|
var avalible: Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package com.synebula.gaea.domain.model
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 继承本接口,说明对象为值类型。
|
|
||||||
* @author alex
|
|
||||||
*/
|
|
||||||
interface IValue
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package com.synebula.gaea.domain.repository
|
|
||||||
|
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 定义了提供增删改的仓储接口。
|
|
||||||
* 本接口泛型放置到方法上,并需要显式提供聚合根的class对象
|
|
||||||
*/
|
|
||||||
interface IUniversalRepository {
|
|
||||||
/**
|
|
||||||
* 插入单个对象。
|
|
||||||
*
|
|
||||||
* @param root 需要插入的对象。
|
|
||||||
* @return 返回原对象,如果对象ID为自增,则补充自增ID。
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(root: TAggregateRoot, clazz: Class<TAggregateRoot>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 插入多个个对象。
|
|
||||||
*
|
|
||||||
* @param roots 需要插入的对象。
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> add(roots: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新对象。
|
|
||||||
*
|
|
||||||
* @param root 需要更新的对象。
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(root: TAggregateRoot, clazz: Class<TAggregateRoot>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新多个个对象。
|
|
||||||
*
|
|
||||||
* @param roots 需要更新的对象。
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> update(roots: List<TAggregateRoot>, clazz: Class<TAggregateRoot>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过id删除该条数据
|
|
||||||
*
|
|
||||||
* @param id id
|
|
||||||
* @param clazz 操作数据的类型
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> remove(id: ID, clazz: Class<TAggregateRoot>)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据ID获取对象。
|
|
||||||
*
|
|
||||||
* @param id id
|
|
||||||
* @param clazz 操作数据的类型
|
|
||||||
* @return 聚合根
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot : IAggregateRoot<ID>, ID> get(id: ID, clazz: Class<TAggregateRoot>): TAggregateRoot?
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据条件查询符合条件记录的数量
|
|
||||||
*
|
|
||||||
* @param params 查询条件。
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
fun <TAggregateRoot> count(params: Map<String, String>?, clazz: Class<TAggregateRoot>): Int
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.synebula.gaea.domain.repository.context
|
|
||||||
|
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 继承自IUnitOfWork,表示实现了工作单元模式的上下文接口。
|
|
||||||
*
|
|
||||||
* @author alex
|
|
||||||
*/
|
|
||||||
interface IContext : IUnitOfWork {
|
|
||||||
/**
|
|
||||||
* 将指定的聚合根标注为“新建”状态。
|
|
||||||
* @param obj 聚合根
|
|
||||||
*/
|
|
||||||
fun <T : IAggregateRoot<ID>, ID> add(obj: T)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将指定的聚合根标注为“更改”状态。
|
|
||||||
*
|
|
||||||
* @param obj 聚合根
|
|
||||||
*/
|
|
||||||
fun <T : IAggregateRoot<ID>, ID> update(obj: T)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将指定的聚合根标注为“删除”状态。
|
|
||||||
*
|
|
||||||
* @param obj 聚合根
|
|
||||||
*/
|
|
||||||
fun <T : IAggregateRoot<ID>, ID> remove(obj: T)
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ import com.synebula.gaea.domain.event.AfterRemoveEvent
|
|||||||
import com.synebula.gaea.domain.event.BeforeRemoveEvent
|
import com.synebula.gaea.domain.event.BeforeRemoveEvent
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.domain.model.IAggregateRoot
|
||||||
import com.synebula.gaea.domain.repository.IRepository
|
import com.synebula.gaea.domain.repository.IRepository
|
||||||
import javax.annotation.Resource
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,7 +25,7 @@ open class Service<TRoot : IAggregateRoot<ID>, ID>(
|
|||||||
protected open var repository: IRepository<TRoot, ID>,
|
protected open var repository: IRepository<TRoot, ID>,
|
||||||
protected open var mapper: IObjectMapper,
|
protected open var mapper: IObjectMapper,
|
||||||
) : IService<ID> {
|
) : IService<ID> {
|
||||||
@Resource
|
|
||||||
protected open var bus: IBus<Any>? = null
|
protected open var bus: IBus<Any>? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
package com.synebula.gaea.domain.service
|
|
||||||
|
|
||||||
import com.synebula.gaea.bus.IBus
|
|
||||||
import com.synebula.gaea.data.message.DataMessage
|
|
||||||
import com.synebula.gaea.domain.event.AfterRemoveEvent
|
|
||||||
import com.synebula.gaea.domain.event.BeforeRemoveEvent
|
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
|
||||||
import com.synebula.gaea.domain.repository.IRepository
|
|
||||||
import com.synebula.gaea.log.ILogger
|
|
||||||
import javax.annotation.Resource
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 依赖了IRepository仓储借口的服务实现类 GenericsService
|
|
||||||
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
|
|
||||||
*
|
|
||||||
* @param repository 仓储对象
|
|
||||||
* @param clazz 聚合根类对象
|
|
||||||
* @param logger 日志组件
|
|
||||||
* @author alex
|
|
||||||
* @version 0.1
|
|
||||||
* @since 2020-05-17
|
|
||||||
*/
|
|
||||||
open class SimpleService<TRoot : IAggregateRoot<ID>, ID>(
|
|
||||||
protected open var clazz: Class<TRoot>,
|
|
||||||
protected open var repository: IRepository<TRoot, ID>,
|
|
||||||
override var logger: ILogger,
|
|
||||||
) : ISimpleService<TRoot, ID> {
|
|
||||||
@Resource
|
|
||||||
protected open var bus: IBus<Any>? = null
|
|
||||||
|
|
||||||
override fun add(root: TRoot): DataMessage<ID> {
|
|
||||||
val msg = DataMessage<ID>()
|
|
||||||
this.repository.add(root)
|
|
||||||
msg.data = root.id
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun update(id: ID, root: TRoot) {
|
|
||||||
root.id = id
|
|
||||||
this.repository.update(root)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun remove(id: ID) {
|
|
||||||
val beforeRemoveEvent = BeforeRemoveEvent<TRoot, ID>(id)
|
|
||||||
this.bus?.publish(beforeRemoveEvent.topic(this.clazz), beforeRemoveEvent)
|
|
||||||
this.repository.remove(id)
|
|
||||||
val afterRemoveEvent = AfterRemoveEvent<TRoot, ID>(id)
|
|
||||||
this.bus?.publish(afterRemoveEvent.topic(this.clazz), afterRemoveEvent)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 增加对象
|
|
||||||
*
|
|
||||||
* @param roots 增加对象命令列表
|
|
||||||
*/
|
|
||||||
override fun add(roots: List<TRoot>) {
|
|
||||||
this.repository.add(roots)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量更新对象
|
|
||||||
*
|
|
||||||
* @param roots 更新对象命令列表
|
|
||||||
*/
|
|
||||||
override fun update(roots: List<TRoot>) {
|
|
||||||
this.repository.update(roots)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
package com.synebula.gaea.query
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询基接口, 其中方法都指定了查询的视图类型。
|
|
||||||
*
|
|
||||||
* @author alex
|
|
||||||
*/
|
|
||||||
interface IQuery<TView, ID> {
|
|
||||||
/**
|
|
||||||
* 仓储的视图类
|
|
||||||
*/
|
|
||||||
var clazz: Class<TView>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据Key获取对象。
|
|
||||||
*
|
|
||||||
* @param id 对象Key。
|
|
||||||
* @return 视图结果
|
|
||||||
*/
|
|
||||||
fun get(id: ID): TView?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据实体类条件查询所有符合条件记录
|
|
||||||
*`
|
|
||||||
* @param params 查询条件。
|
|
||||||
* @return 视图列表
|
|
||||||
*/
|
|
||||||
fun list(params: Map<String, String>?): List<TView>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据条件查询符合条件记录的数量
|
|
||||||
*
|
|
||||||
* @param params 查询条件。
|
|
||||||
* @return 数量
|
|
||||||
*/
|
|
||||||
fun count(params: Map<String, String>?): Int
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据实体类条件查询所有符合条件记录(分页查询)
|
|
||||||
*
|
|
||||||
* @param params 分页条件
|
|
||||||
* @return 分页数据
|
|
||||||
*/
|
|
||||||
fun paging(params: Params): Page<TView>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询条件范围内数据。
|
|
||||||
* @param field 查询字段
|
|
||||||
* @param params 查询条件
|
|
||||||
*
|
|
||||||
* @return 视图列表
|
|
||||||
*/
|
|
||||||
fun range(field: String, params: List<Any>): List<TView>
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.synebula.gaea.query
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Query 工厂接口。 定义了Query的创建方法。
|
|
||||||
*/
|
|
||||||
interface IQueryFactory {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建原始类型的IQuery接口类型
|
|
||||||
*/
|
|
||||||
fun createRawQuery(clazz: Class<*>): IQuery<*, *>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建指定类型的IQuery接口类型
|
|
||||||
*/
|
|
||||||
fun <T, I> createQuery(clazz: Class<T>): IQuery<T, I>
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.synebula.gaea.record.model
|
||||||
|
|
||||||
|
import com.synebula.gaea.db.IEntity
|
||||||
|
|
||||||
|
interface IRecord<ID> : IEntity<ID>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.synebula.gaea.domain.record
|
package com.synebula.gaea.record.model
|
||||||
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.synebula.gaea.domain.service
|
package com.synebula.gaea.record.service
|
||||||
|
|
||||||
import com.synebula.gaea.data.message.DataMessage
|
import com.synebula.gaea.data.message.DataMessage
|
||||||
import com.synebula.gaea.domain.model.IAggregateRoot
|
import com.synebula.gaea.db.IEntity
|
||||||
import com.synebula.gaea.log.ILogger
|
import com.synebula.gaea.log.ILogger
|
||||||
|
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@ import com.synebula.gaea.log.ILogger
|
|||||||
* @version 0.0.1
|
* @version 0.0.1
|
||||||
* @since 2016年9月18日 下午2:23:15
|
* @since 2016年9月18日 下午2:23:15
|
||||||
*/
|
*/
|
||||||
interface ISimpleService<TAggregateRoot : IAggregateRoot<ID>, ID> {
|
interface IService<Entity : IEntity<ID>, ID> {
|
||||||
/**
|
/**
|
||||||
* 日志组件。
|
* 日志组件。
|
||||||
*/
|
*/
|
||||||
@@ -20,31 +20,31 @@ interface ISimpleService<TAggregateRoot : IAggregateRoot<ID>, ID> {
|
|||||||
/**
|
/**
|
||||||
* 增加对象
|
* 增加对象
|
||||||
*
|
*
|
||||||
* @param root 增加对象命令
|
* @param entity 增加对象命令
|
||||||
*/
|
*/
|
||||||
fun add(root: TAggregateRoot): DataMessage<ID>
|
fun add(entity: Entity): ID?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加对象
|
* 增加对象
|
||||||
*
|
*
|
||||||
* @param roots 增加对象命令列表
|
* @param entities 增加对象命令列表
|
||||||
*/
|
*/
|
||||||
fun add(roots: List<TAggregateRoot>)
|
fun add(entities: List<Entity>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新对象
|
* 更新对象
|
||||||
*
|
*
|
||||||
* @param id 对象ID
|
* @param id 对象ID
|
||||||
* @param root 更新对象命令
|
* @param entity 更新对象命令
|
||||||
*/
|
*/
|
||||||
fun update(id: ID, root: TAggregateRoot)
|
fun update(id: ID, entity: Entity)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量更新对象
|
* 批量更新对象
|
||||||
*
|
*
|
||||||
* @param roots 更新对象命令列表
|
* @param entities 更新对象命令列表
|
||||||
*/
|
*/
|
||||||
fun update(roots: List<TAggregateRoot>)
|
fun update(entities: List<Entity>)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增加对象
|
* 增加对象
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package com.synebula.gaea.record.service
|
||||||
|
|
||||||
|
import com.synebula.gaea.bus.IBus
|
||||||
|
import com.synebula.gaea.data.message.DataMessage
|
||||||
|
import com.synebula.gaea.db.context.IDbContext
|
||||||
|
import com.synebula.gaea.domain.event.AfterRemoveEvent
|
||||||
|
import com.synebula.gaea.domain.event.BeforeRemoveEvent
|
||||||
|
import com.synebula.gaea.log.ILogger
|
||||||
|
import com.synebula.gaea.record.model.IRecord
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 依赖了IRepository仓储借口的服务实现类 GenericsService
|
||||||
|
* 该类依赖仓储接口 @see IGenericsRepository, 需要显式提供聚合根的class对象
|
||||||
|
*
|
||||||
|
* @param context 仓储对象
|
||||||
|
* @param clazz 聚合根类对象
|
||||||
|
* @param logger 日志组件
|
||||||
|
* @author alex
|
||||||
|
* @version 0.1
|
||||||
|
* @since 2020-05-17
|
||||||
|
*/
|
||||||
|
open class Service<TEntity : IRecord<ID>, ID>(
|
||||||
|
protected open var clazz: Class<TEntity>,
|
||||||
|
protected open var context: IDbContext,
|
||||||
|
protected open var bus: IBus<Any>? = null,
|
||||||
|
override var logger: ILogger
|
||||||
|
) : IService<TEntity, ID> {
|
||||||
|
|
||||||
|
override fun add(entity: TEntity): ID? {
|
||||||
|
this.context.add(entity, clazz)
|
||||||
|
return entity.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(id: ID, entity: TEntity) {
|
||||||
|
entity.id = id
|
||||||
|
this.context.update(entity, clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(id: ID) {
|
||||||
|
val beforeRemoveEvent = BeforeRemoveEvent<TEntity, ID>(id)
|
||||||
|
this.bus?.publish(beforeRemoveEvent.topic(this.clazz), beforeRemoveEvent)
|
||||||
|
this.context.remove(id, clazz)
|
||||||
|
val afterRemoveEvent = AfterRemoveEvent<TEntity, ID>(id)
|
||||||
|
this.bus?.publish(afterRemoveEvent.topic(this.clazz), afterRemoveEvent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增加对象
|
||||||
|
*
|
||||||
|
* @param entitys 增加对象命令列表
|
||||||
|
*/
|
||||||
|
override fun add(entitys: List<TEntity>) {
|
||||||
|
this.context.add(entitys, clazz)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量更新对象
|
||||||
|
*
|
||||||
|
* @param entitys 更新对象命令列表
|
||||||
|
*/
|
||||||
|
override fun update(entitys: List<TEntity>) {
|
||||||
|
this.context.update(entitys, clazz)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user