Compare commits
No commits in common. "main" and "v2" have entirely different histories.
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/gradlew text eol=lf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.jar binary
|
30
.github/workflows/ci.yaml
vendored
Normal file
30
.github/workflows/ci.yaml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
name: ci
|
||||||
|
on: [pull_request, push, workflow_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
java: [17]
|
||||||
|
os: [ubuntu-22.04]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- name: checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: setup jdk ${{ matrix.java }}
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: ${{ matrix.java }}
|
||||||
|
distribution: 'microsoft'
|
||||||
|
- name: make gradle wrapper executable
|
||||||
|
if: ${{ runner.os != 'Windows' }}
|
||||||
|
run: chmod +x ./gradlew
|
||||||
|
- name: setup proxy
|
||||||
|
run: echo "systemProp.http.proxyHost=192.168.5.6\\nsystemProp.http.proxyPort=7890\\nsystemProp.https.proxyHost=192.168.5.6\\nsystemProp.https.proxyPort=7890" >> gradle.properties
|
||||||
|
- name: build
|
||||||
|
run: _JAVA_OPTIONS="-Dhttp.proxyHost=192.168.5.6 -Dhttp.proxyPort=7890 -Dhttps.proxyHost=192.168.5.6 -Dhttps.proxyPort=7890" ./gradlew clean bootJar --no-daemon
|
||||||
|
- name: capture build artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Artifacts
|
||||||
|
path: build/libs/
|
176
.gitignore
vendored
176
.gitignore
vendored
@ -1,144 +1,42 @@
|
|||||||
# ---> Java
|
HELP.md
|
||||||
# Compiled class file
|
|
||||||
*.class
|
|
||||||
|
|
||||||
# Log file
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# BlueJ files
|
|
||||||
*.ctxt
|
|
||||||
|
|
||||||
# Mobile Tools for Java (J2ME)
|
|
||||||
.mtj.tmp/
|
|
||||||
|
|
||||||
# Package Files #
|
|
||||||
*.jar
|
|
||||||
*.war
|
|
||||||
*.nar
|
|
||||||
*.ear
|
|
||||||
*.zip
|
|
||||||
*.tar.gz
|
|
||||||
*.rar
|
|
||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
|
||||||
hs_err_pid*
|
|
||||||
replay_pid*
|
|
||||||
|
|
||||||
# ---> JetBrains
|
|
||||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
|
||||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
|
||||||
|
|
||||||
# User-specific stuff
|
|
||||||
.idea/**/workspace.xml
|
|
||||||
.idea/**/tasks.xml
|
|
||||||
.idea/**/usage.statistics.xml
|
|
||||||
.idea/**/dictionaries
|
|
||||||
.idea/**/shelf
|
|
||||||
|
|
||||||
# AWS User-specific
|
|
||||||
.idea/**/aws.xml
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
.idea/**/contentModel.xml
|
|
||||||
|
|
||||||
# Sensitive or high-churn files
|
|
||||||
.idea/**/dataSources/
|
|
||||||
.idea/**/dataSources.ids
|
|
||||||
.idea/**/dataSources.local.xml
|
|
||||||
.idea/**/sqlDataSources.xml
|
|
||||||
.idea/**/dynamic.xml
|
|
||||||
.idea/**/uiDesigner.xml
|
|
||||||
.idea/**/dbnavigator.xml
|
|
||||||
|
|
||||||
# Gradle
|
|
||||||
.idea/**/gradle.xml
|
|
||||||
.idea/**/libraries
|
|
||||||
|
|
||||||
# Gradle and Maven with auto-import
|
|
||||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
|
||||||
# since they will be recreated, and may cause churn. Uncomment if using
|
|
||||||
# auto-import.
|
|
||||||
# .idea/artifacts
|
|
||||||
# .idea/compiler.xml
|
|
||||||
# .idea/jarRepositories.xml
|
|
||||||
# .idea/modules.xml
|
|
||||||
# .idea/*.iml
|
|
||||||
# .idea/modules
|
|
||||||
# *.iml
|
|
||||||
# *.ipr
|
|
||||||
|
|
||||||
# CMake
|
|
||||||
cmake-build-*/
|
|
||||||
|
|
||||||
# Mongo Explorer plugin
|
|
||||||
.idea/**/mongoSettings.xml
|
|
||||||
|
|
||||||
# File-based project format
|
|
||||||
*.iws
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
out/
|
|
||||||
|
|
||||||
# mpeltonen/sbt-idea plugin
|
|
||||||
.idea_modules/
|
|
||||||
|
|
||||||
# JIRA plugin
|
|
||||||
atlassian-ide-plugin.xml
|
|
||||||
|
|
||||||
# Cursive Clojure plugin
|
|
||||||
.idea/replstate.xml
|
|
||||||
|
|
||||||
# SonarLint plugin
|
|
||||||
.idea/sonarlint/
|
|
||||||
|
|
||||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
|
||||||
com_crashlytics_export_strings.xml
|
|
||||||
crashlytics.properties
|
|
||||||
crashlytics-build.properties
|
|
||||||
fabric.properties
|
|
||||||
|
|
||||||
# Editor-based Rest Client
|
|
||||||
.idea/httpRequests
|
|
||||||
|
|
||||||
# Android studio 3.1+ serialized cache file
|
|
||||||
.idea/caches/build_file_checksums.ser
|
|
||||||
|
|
||||||
# ---> VisualStudioCode
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
!.vscode/*.code-snippets
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Built Visual Studio Code Extensions
|
|
||||||
*.vsix
|
|
||||||
|
|
||||||
# ---> Gradle
|
|
||||||
.gradle
|
.gradle
|
||||||
**/build/
|
build/
|
||||||
!src/**/build/
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
# Ignore Gradle GUI config
|
### STS ###
|
||||||
gradle-app.setting
|
.apt_generated
|
||||||
|
|
||||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
|
||||||
!gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Avoid ignore Gradle wrappper properties
|
|
||||||
!gradle-wrapper.properties
|
|
||||||
|
|
||||||
# Cache of project
|
|
||||||
.gradletasknamecache
|
|
||||||
|
|
||||||
# Eclipse Gradle plugin generated files
|
|
||||||
# Eclipse Core
|
|
||||||
.project
|
|
||||||
# JDT-specific (Eclipse Java Development Tools)
|
|
||||||
.classpath
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
# Running
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
out/
|
||||||
|
!**/src/main/**/out/
|
||||||
|
!**/src/test/**/out/
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
run/
|
run/
|
||||||
|
|
||||||
|
|
||||||
|
build*
|
||||||
|
run*
|
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
BIN
.idea/.cache/.Apifox_Helper/.toolWindow.db
generated
Binary file not shown.
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@ -1,8 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
1
.idea/.name
generated
1
.idea/.name
generated
@ -1 +0,0 @@
|
|||||||
clubs
|
|
15
.idea/ApifoxUploaderProjectSetting.xml
generated
15
.idea/ApifoxUploaderProjectSetting.xml
generated
@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ApifoxUploaderProjectSetting">
|
|
||||||
<option name="apiAccessToken" value="APS-QWelq6AktQqByilNWeWZgKoPT7a4ml1d" />
|
|
||||||
<option name="apiProjectIds">
|
|
||||||
<array>
|
|
||||||
<option value="<byte-array>rO0ABXNyADZjb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmFwaS5hY2NvdW50LlByb2plY3RBbmRNb2R1bGUAAAAAAAAAAQIAFVoABmVuYWJsZUwACG1vZHVsZUlkdAASTGphdmEvbGFuZy9TdHJpbmc7TAAGb3RoZXIxcQB+AAFMAAdvdGhlcjEwcQB+AAFMAAdvdGhlcjExcQB+AAFMAAdvdGhlcjEycQB+AAFMAAZvdGhlcjJxAH4AAUwABm90aGVyM3EAfgABTAAGb3RoZXI0cQB+AAFMAAZvdGhlcjVxAH4AAUwABm90aGVyNnEAfgABTAAGb3RoZXI3cQB+AAFMAAZvdGhlcjhxAH4AAUwABm90aGVyOXEAfgABTAAKcGF0aEJlZm9yZXEAfgABTAANcHJvamVjdEZvbGRlcnEAfgABTAAPcHJvamVjdEZvbGRlcklkcQB+AAFMAAlwcm9qZWN0SWRxAH4AAUwAC3Byb2plY3ROYW1lcQB+AAFMAAxzY2hlbWFGb2xkZXJxAH4AAUwACHNjaGVtYUlkcQB+AAF4cAB0AAZoaWRkZW5wcHBwcHBwcHBwcHB0AApwYXRoQmVmb3JldAANcHJvamVjdEZvbGRlcnQAD3Byb2plY3RGb2xkZXJJZHQAC3Byb2plY3ROYW1ldAAIaGlkZGVuSWR0AABxAH4ACQ==</byte-array>" />
|
|
||||||
<option value="<byte-array>rO0ABXNyADZjb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmFwaS5hY2NvdW50LlByb2plY3RBbmRNb2R1bGUAAAAAAAAAAQIAFVoABmVuYWJsZUwACG1vZHVsZUlkdAASTGphdmEvbGFuZy9TdHJpbmc7TAAGb3RoZXIxcQB+AAFMAAdvdGhlcjEwcQB+AAFMAAdvdGhlcjExcQB+AAFMAAdvdGhlcjEycQB+AAFMAAZvdGhlcjJxAH4AAUwABm90aGVyM3EAfgABTAAGb3RoZXI0cQB+AAFMAAZvdGhlcjVxAH4AAUwABm90aGVyNnEAfgABTAAGb3RoZXI3cQB+AAFMAAZvdGhlcjhxAH4AAUwABm90aGVyOXEAfgABTAAKcGF0aEJlZm9yZXEAfgABTAANcHJvamVjdEZvbGRlcnEAfgABTAAPcHJvamVjdEZvbGRlcklkcQB+AAFMAAlwcm9qZWN0SWRxAH4AAUwAC3Byb2plY3ROYW1lcQB+AAFMAAxzY2hlbWFGb2xkZXJxAH4AAUwACHNjaGVtYUlkcQB+AAF4cAF0AAVjbHVic3BwcHBwcHBwcHBwcHQAAHQACeagueebruW9lXQAATB0AAc1NjAxNzQwdAAQSVRaWC1DbHViLVNlcnZlcnEAfgAFcQB+AAY=</byte-array>" />
|
|
||||||
<option value="<byte-array>rO0ABXNyADZjb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmFwaS5hY2NvdW50LlByb2plY3RBbmRNb2R1bGUAAAAAAAAAAQIAFVoABmVuYWJsZUwACG1vZHVsZUlkdAASTGphdmEvbGFuZy9TdHJpbmc7TAAGb3RoZXIxcQB+AAFMAAdvdGhlcjEwcQB+AAFMAAdvdGhlcjExcQB+AAFMAAdvdGhlcjEycQB+AAFMAAZvdGhlcjJxAH4AAUwABm90aGVyM3EAfgABTAAGb3RoZXI0cQB+AAFMAAZvdGhlcjVxAH4AAUwABm90aGVyNnEAfgABTAAGb3RoZXI3cQB+AAFMAAZvdGhlcjhxAH4AAUwABm90aGVyOXEAfgABTAAKcGF0aEJlZm9yZXEAfgABTAANcHJvamVjdEZvbGRlcnEAfgABTAAPcHJvamVjdEZvbGRlcklkcQB+AAFMAAlwcm9qZWN0SWRxAH4AAUwAC3Byb2plY3ROYW1lcQB+AAFMAAxzY2hlbWFGb2xkZXJxAH4AAUwACHNjaGVtYUlkcQB+AAF4cAF0AApjbHVicy5tYWlucHBwcHBwcHBwcHBwdAAAdAAJ5qC555uu5b2VdAABMHQABzU2MDE3NDB0ABBJVFpYLUNsdWItU2VydmVycQB+AAVxAH4ABg==</byte-array>" />
|
|
||||||
</array>
|
|
||||||
</option>
|
|
||||||
<option name="treeNodes" value="<byte-array>rO0ABXNyABdqYXZhLnV0aWwuTGlua2VkSGFzaE1hcDTATlwQbMD7AgABWgALYWNjZXNzT3JkZXJ4cgARamF2YS51dGlsLkhhc2hNYXAFB9rBwxZg0QMAAkYACmxvYWRGYWN0b3JJAAl0aHJlc2hvbGR4cD9AAAAAAAAMdwgAAAAQAAAAAnQABzI5ODc1MzJzcgAuY29tLml0YW5nY2VudC5pZGVhLnBsdWdpbi5hcGkuYWNjb3VudC5UcmVlTm9kZQAAAAAAAAABAgALTAAHYWxsUGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACGNoaWxkcmVudAAPTGphdmEvdXRpbC9NYXA7TAAIZnVsbFBhdGhxAH4ABUwAA2tleXEAfgAFTAAEbmFtZXEAfgAFTAAIcGFyZW50SWRxAH4ABUwACXByb2plY3RJZHEAfgAFTAALcHJvamVjdE5hbWVxAH4ABUwABnRlYW1JZHEAfgAFTAAIdGVhbU5hbWVxAH4ABUwABHR5cGV0ADBMY29tL2l0YW5nY2VudC9pZGVhL3BsdWdpbi9hcGkvYWNjb3VudC9Ob2RlVHlwZTt4cHQADOS4quS6uuWboumYn3NxAH4AAD9AAAAAAAAMdwgAAAAQAAAAAXQABzUzMTk5NzVzcQB+AAR0ABnkuKrkurrlm6LpmJ8v5Liq5Lq66aG555uuc3EAfgAAP0AAAAAAAAB3CAAAABAAAAAAeABwcQB+AAt0ABbkuKrkurrpobnnm64gKDUzMTk5NzUpdAAHMjk4NzUzMnQABzUzMTk5NzV0AAzkuKrkurrpobnnm650AAcyOTg3NTMycH5yAC5jb20uaXRhbmdjZW50LmlkZWEucGx1Z2luLmFwaS5hY2NvdW50Lk5vZGVUeXBlAAAAAAAAAAASAAB4cgAOamF2YS5sYW5nLkVudW0AAAAAAAAAABIAAHhwdAAHUFJPSkVDVHgAcHEAfgADdAAM5Liq5Lq65Zui6ZifcHBwdAAHMjk4NzUzMnQADOS4quS6uuWboumYn35xAH4AFHQABFRFQU10AAcyOTg3NTM1c3EAfgAEdAAbTWFrZU1pbmVjcmFmdEdyZWF0QWdhaW5UZWFtc3EAfgAAP0AAAAAAAAx3CAAAABAAAAACdAAHNTMxOTk3OHNxAH4ABHQALE1ha2VNaW5lY3JhZnRHcmVhdEFnYWluVGVhbS9GaWxlTWFuYWdlci1WZXIyc3EAfgAAP0AAAAAAAAx3CAAAABAAAAACdAALNC42NzcyMzU4RTdzcQB+AAR0AEVNYWtlTWluZWNyYWZ0R3JlYXRBZ2FpblRlYW0vRmlsZU1hbmFnZXItVmVyMi/mlofku7bmk43kvZznm7jlhbPmjqXlj6NzcQB+AAA/QAAAAAAAAHcIAAAAEAAAAAB4AHQAGOaWh+S7tuaTjeS9nOebuOWFs+aOpeWPo3EAfgAldAAY5paH5Lu25pON5L2c55u45YWz5o6l5Y+jdAAHNTMxOTk3OHQACTUzMTk5NzguMHQAEEZpbGVNYW5hZ2VyLVZlcjJwcH5xAH4AFHQABkZPTERFUnQACzQuNjc3MjM4OEU3c3EAfgAEdAA/TWFrZU1pbmVjcmFmdEdyZWF0QWdhaW5UZWFtL0ZpbGVNYW5hZ2VyLVZlcjIv55So5oi355u45YWz5o6l5Y+jc3EAfgAAP0AAAAAAAAB3CAAAABAAAAAAeAB0ABLnlKjmiLfnm7jlhbPmjqXlj6NxAH4AMHQAEueUqOaIt+ebuOWFs+aOpeWPo3QABzUzMTk5Nzh0AAk1MzE5OTc4LjB0ABBGaWxlTWFuYWdlci1WZXIycHBxAH4ALngAcHEAfgAhdAAaRmlsZU1hbmFnZXItVmVyMiAoNTMxOTk3OCl0AAcyOTg3NTM1dAAHNTMxOTk3OHQAEEZpbGVNYW5hZ2VyLVZlcjJ0AAcyOTg3NTM1cHEAfgAWdAAHNTYwMTc0MHNxAH4ABHQALE1ha2VNaW5lY3JhZnRHcmVhdEFnYWluVGVhbS9JVFpYLUNsdWItU2VydmVyc3EAfgAAP0AAAAAAAAB3CAAAABAAAAAAeABwcQB+AD50ABpJVFpYLUNsdWItU2VydmVyICg1NjAxNzQwKXQABzI5ODc1MzV0AAc1NjAxNzQwdAAQSVRaWC1DbHViLVNlcnZlcnQABzI5ODc1MzVwcQB+ABZ4AHBxAH4AHXQAG01ha2VNaW5lY3JhZnRHcmVhdEFnYWluVGVhbXBwcHQABzI5ODc1MzV0ABtNYWtlTWluZWNyYWZ0R3JlYXRBZ2FpblRlYW1xAH4AG3gA</byte-array>" />
|
|
||||||
<option name="treeNodesJTree" value="<byte-array>rO0ABXNyACFqYXZheC5zd2luZy50cmVlLkRlZmF1bHRUcmVlTW9kZWynvpEmGsXl2QMAA1oAEmFza3NBbGxvd3NDaGlsZHJlbkwADGxpc3RlbmVyTGlzdHQAJUxqYXZheC9zd2luZy9ldmVudC9FdmVudExpc3RlbmVyTGlzdDtMAARyb290dAAbTGphdmF4L3N3aW5nL3RyZWUvVHJlZU5vZGU7eHAAc3IAI2phdmF4LnN3aW5nLmV2ZW50LkV2ZW50TGlzdGVuZXJMaXN0kUjMLXPfDt4DAAB4cHB4c3IAJ2phdmF4LnN3aW5nLnRyZWUuRGVmYXVsdE11dGFibGVUcmVlTm9kZcRYv/zyqHHgAwADWgAOYWxsb3dzQ2hpbGRyZW5MAAhjaGlsZHJlbnQAEkxqYXZhL3V0aWwvVmVjdG9yO0wABnBhcmVudHQAIkxqYXZheC9zd2luZy90cmVlL011dGFibGVUcmVlTm9kZTt4cAFzcgAQamF2YS51dGlsLlZlY3RvctmXfVuAO68BAwADSQARY2FwYWNpdHlJbmNyZW1lbnRJAAxlbGVtZW50Q291bnRbAAtlbGVtZW50RGF0YXQAE1tMamF2YS9sYW5nL09iamVjdDt4cAAAAAAAAAACdXIAE1tMamF2YS5sYW5nLk9iamVjdDuQzlifEHMpbAIAAHhwAAAACnNxAH4ABgFzcQB+AAoAAAAAAAAAAXVxAH4ADQAAAApzcQB+AAYBcHEAfgAPdXEAfgANAAAAAnQACnVzZXJPYmplY3RzcgAuY29tLml0YW5nY2VudC5pZGVhLnBsdWdpbi5hcGkuYWNjb3VudC5UcmVlTm9kZQAAAAAAAAABAgALTAAHYWxsUGF0aHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACGNoaWxkcmVudAAPTGphdmEvdXRpbC9NYXA7TAAIZnVsbFBhdGhxAH4AFkwAA2tleXEAfgAWTAAEbmFtZXEAfgAWTAAIcGFyZW50SWRxAH4AFkwACXByb2plY3RJZHEAfgAWTAALcHJvamVjdE5hbWVxAH4AFkwABnRlYW1JZHEAfgAWTAAIdGVhbU5hbWVxAH4AFkwABHR5cGV0ADBMY29tL2l0YW5nY2VudC9pZGVhL3BsdWdpbi9hcGkvYWNjb3VudC9Ob2RlVHlwZTt4cHQAGeS4quS6uuWboumYny/kuKrkurrpobnnm65zcgAXamF2YS51dGlsLkxpbmtlZEhhc2hNYXA0wE5cEGzA+wIAAVoAC2FjY2Vzc09yZGVyeHIAEWphdmEudXRpbC5IYXNoTWFwBQfawcMWYNEDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAAAHcIAAAAEAAAAAB4AHB0AAc1MzE5OTc1dAAW5Liq5Lq66aG555uuICg1MzE5OTc1KXQABzI5ODc1MzJ0AAc1MzE5OTc1dAAM5Liq5Lq66aG555uudAAHMjk4NzUzMnB+cgAuY29tLml0YW5nY2VudC5pZGVhLnBsdWdpbi5hcGkuYWNjb3VudC5Ob2RlVHlwZQAAAAAAAAAAEgAAeHIADmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQAB1BST0pFQ1R4cHBwcHBwcHBweHEAfgAJdXEAfgANAAAAAnEAfgAUc3EAfgAVdAAM5Liq5Lq65Zui6Zifc3EAfgAbP0AAAAAAAAB3CAAAABAAAAAAeABwdAAHMjk4NzUzMnQADOS4quS6uuWboumYn3BwcHQABzI5ODc1MzJ0AAzkuKrkurrlm6LpmJ9+cQB+ACR0AARURUFNeHNxAH4ABgFzcQB+AAoAAAAAAAAAAnVxAH4ADQAAAApzcQB+AAYBc3EAfgAKAAAAAAAAAAJ1cQB+AA0AAAAKc3EAfgAGAXBxAH4ANXVxAH4ADQAAAAJxAH4AFHNxAH4AFXQARU1ha2VNaW5lY3JhZnRHcmVhdEFnYWluVGVhbS9GaWxlTWFuYWdlci1WZXIyL+aWh+S7tuaTjeS9nOebuOWFs+aOpeWPo3NxAH4AGz9AAAAAAAAAdwgAAAAQAAAAAHgAdAAY5paH5Lu25pON5L2c55u45YWz5o6l5Y+jdAALNC42NzcyMzU4RTd0ABjmlofku7bmk43kvZznm7jlhbPmjqXlj6N0AAc1MzE5OTc4dAAJNTMxOTk3OC4wdAAQRmlsZU1hbmFnZXItVmVyMnBwfnEAfgAkdAAGRk9MREVSeHNxAH4ABgFwcQB+ADV1cQB+AA0AAAACcQB+ABRzcQB+ABV0AD9NYWtlTWluZWNyYWZ0R3JlYXRBZ2FpblRlYW0vRmlsZU1hbmFnZXItVmVyMi/nlKjmiLfnm7jlhbPmjqXlj6NzcQB+ABs/QAAAAAAAAHcIAAAAEAAAAAB4AHQAEueUqOaIt+ebuOWFs+aOpeWPo3QACzQuNjc3MjM4OEU3dAAS55So5oi355u45YWz5o6l5Y+jdAAHNTMxOTk3OHQACTUzMTk5NzguMHQAEEZpbGVNYW5hZ2VyLVZlcjJwcHEAfgBDeHBwcHBwcHBweHEAfgAydXEAfgANAAAAAnEAfgAUc3EAfgAVdAAsTWFrZU1pbmVjcmFmdEdyZWF0QWdhaW5UZWFtL0ZpbGVNYW5hZ2VyLVZlcjJzcQB+ABs/QAAAAAAAAHcIAAAAEAAAAAB4AHB0AAc1MzE5OTc4dAAaRmlsZU1hbmFnZXItVmVyMiAoNTMxOTk3OCl0AAcyOTg3NTM1dAAHNTMxOTk3OHQAEEZpbGVNYW5hZ2VyLVZlcjJ0AAcyOTg3NTM1cHEAfgAmeHNxAH4ABgFwcQB+ADJ1cQB+AA0AAAACcQB+ABRzcQB+ABV0ACxNYWtlTWluZWNyYWZ0R3JlYXRBZ2FpblRlYW0vSVRaWC1DbHViLVNlcnZlcnNxAH4AGz9AAAAAAAAAdwgAAAAQAAAAAHgAcHQABzU2MDE3NDB0ABpJVFpYLUNsdWItU2VydmVyICg1NjAxNzQwKXQABzI5ODc1MzV0AAc1NjAxNzQwdAAQSVRaWC1DbHViLVNlcnZlcnQABzI5ODc1MzVwcQB+ACZ4cHBwcHBwcHB4cQB+AAl1cQB+AA0AAAACcQB+ABRzcQB+ABV0ABtNYWtlTWluZWNyYWZ0R3JlYXRBZ2FpblRlYW1zcQB+ABs/QAAAAAAAAHcIAAAAEAAAAAB4AHB0AAcyOTg3NTM1dAAbTWFrZU1pbmVjcmFmdEdyZWF0QWdhaW5UZWFtcHBwdAAHMjk4NzUzNXQAG01ha2VNaW5lY3JhZnRHcmVhdEFnYWluVGVhbXEAfgAweHBwcHBwcHBweHB1cQB+AA0AAAACcQB+ABRzcQB+ABV0AARSb290cHB0AAEwcQB+AG9wcHBwcHEAfgAweHNxAH4ACgAAAAAAAAACdXEAfgANAAAACnQABHJvb3RxAH4ACXBwcHBwcHBweHg=</byte-array>" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
9
.idea/ITZX-Clubs-Home-Server.iml
generated
9
.idea/ITZX-Clubs-Home-Server.iml
generated
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
15
.idea/compiler.xml
generated
15
.idea/compiler.xml
generated
@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<annotationProcessing>
|
|
||||||
<profile name="Gradle Imported" enabled="true">
|
|
||||||
<outputRelativeToContentRoot value="true" />
|
|
||||||
<processorPath useClasspath="false">
|
|
||||||
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.30/f195ee86e6c896ea47a1d39defbe20eb59cd149d/lombok-1.18.30.jar" />
|
|
||||||
</processorPath>
|
|
||||||
<module name="clubs.main" />
|
|
||||||
</profile>
|
|
||||||
</annotationProcessing>
|
|
||||||
<bytecodeTargetLevel target="17" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
33
.idea/dataSources.xml
generated
33
.idea/dataSources.xml
generated
@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="itzx@172.16.127.100" uuid="6d73dcf2-41f4-4403-89d0-be443cbd1b39">
|
|
||||||
<driver-ref>mysql.8</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<imported>true</imported>
|
|
||||||
<remarks>$PROJECT_DIR$/src/main/resources/application.properties</remarks>
|
|
||||||
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:mysql://172.16.127.100:3306/itzx</jdbc-url>
|
|
||||||
<jdbc-additional-properties>
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
|
||||||
</jdbc-additional-properties>
|
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
|
||||||
</data-source>
|
|
||||||
<data-source source="LOCAL" name="0@172.16.127.100" uuid="41d00101-c8a0-446a-a28b-8027776414f2">
|
|
||||||
<driver-ref>redis</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>jdbc.RedisDriver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:redis://172.16.127.100:6379/0</jdbc-url>
|
|
||||||
<jdbc-additional-properties>
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.resource.type" value="Deployment" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
|
||||||
</jdbc-additional-properties>
|
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
15
.idea/inspectionProfiles/Project_Default.xml
generated
15
.idea/inspectionProfiles/Project_Default.xml
generated
@ -1,15 +0,0 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<profile version="1.0">
|
|
||||||
<option name="myName" value="Project Default" />
|
|
||||||
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,java.lang.foreign.Arena,ofAuto,java.lang.foreign.Arena,global,java.util.concurrent.ConcurrentHashMap,remove" />
|
|
||||||
</inspection_tool>
|
|
||||||
<inspection_tool class="IncorrectHttpHeaderInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
|
||||||
<option name="customHeaders">
|
|
||||||
<set>
|
|
||||||
<option value="Set-Authorization" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</inspection_tool>
|
|
||||||
</profile>
|
|
||||||
</component>
|
|
40
.idea/jarRepositories.xml
generated
40
.idea/jarRepositories.xml
generated
@ -1,40 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RemoteRepositoriesConfiguration">
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="central" />
|
|
||||||
<option name="name" value="Maven Central repository" />
|
|
||||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="jboss.community" />
|
|
||||||
<option name="name" value="JBoss Community repository" />
|
|
||||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="MavenRepo" />
|
|
||||||
<option name="name" value="MavenRepo" />
|
|
||||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="maven" />
|
|
||||||
<option name="name" value="maven" />
|
|
||||||
<option name="url" value="https://maven.aliyun.com/repository/gradle-plugin" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="maven4" />
|
|
||||||
<option name="name" value="maven4" />
|
|
||||||
<option name="url" value="https://mirrors.cloud.tencent.com/repository/maven/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="maven2" />
|
|
||||||
<option name="name" value="maven2" />
|
|
||||||
<option name="url" value="https://maven.aliyun.com/repository/public/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="maven3" />
|
|
||||||
<option name="name" value="maven3" />
|
|
||||||
<option name="url" value="https://repo.huaweicloud.com/repository/maven/" />
|
|
||||||
</remote-repository>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
22
.idea/misc.xml
generated
22
.idea/misc.xml
generated
@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ASMSmaliIdeaPluginConfiguration">
|
|
||||||
<asm skipDebug="true" skipFrames="true" skipCode="false" expandFrames="false" />
|
|
||||||
<groovy codeStyle="LEGACY" />
|
|
||||||
</component>
|
|
||||||
<component name="EntryPointsManager">
|
|
||||||
<list size="4">
|
|
||||||
<item index="0" class="java.lang.String" itemvalue="jakarta.websocket.OnClose" />
|
|
||||||
<item index="1" class="java.lang.String" itemvalue="jakarta.websocket.OnMessage" />
|
|
||||||
<item index="2" class="java.lang.String" itemvalue="jakarta.websocket.OnOpen" />
|
|
||||||
<item index="3" class="java.lang.String" itemvalue="jakarta.websocket.server.ServerEndpoint" />
|
|
||||||
</list>
|
|
||||||
</component>
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
9
.idea/modules.xml
generated
9
.idea/modules.xml
generated
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/clubs.iml" filepath="$PROJECT_DIR$/.idea/modules/clubs.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/clubs.main.iml" filepath="$PROJECT_DIR$/.idea/modules/clubs.main.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
10
.idea/modules/clubs.iml
generated
10
.idea/modules/clubs.iml
generated
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module version="4">
|
|
||||||
<component name="AdditionalModuleElements">
|
|
||||||
<content url="file://$MODULE_DIR$/../.." dumb="true">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/../dataSources" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/../dictionaries" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/../../run" />
|
|
||||||
</content>
|
|
||||||
</component>
|
|
||||||
</module>
|
|
8
.idea/modules/clubs.main.iml
generated
8
.idea/modules/clubs.main.iml
generated
@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module version="4">
|
|
||||||
<component name="AdditionalModuleElements">
|
|
||||||
<content url="file://$MODULE_DIR$/../../build/generated/sources/annotationProcessor/java/main">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../build/generated/sources/annotationProcessor/java/main" isTestSource="false" generated="true" />
|
|
||||||
</content>
|
|
||||||
</component>
|
|
||||||
</module>
|
|
6
.idea/vcs.xml
generated
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
87
HELP.md
87
HELP.md
@ -1,87 +0,0 @@
|
|||||||
# Getting Started
|
|
||||||
|
|
||||||
### Reference Documentation
|
|
||||||
|
|
||||||
For further reference, please consider the following sections:
|
|
||||||
|
|
||||||
* [Official Gradle documentation](https://docs.gradle.org)
|
|
||||||
* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.2.4/gradle-plugin/reference/html/)
|
|
||||||
* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.2.4/gradle-plugin/reference/html/#build-image)
|
|
||||||
* [GraalVM Native Image Support](https://docs.spring.io/spring-boot/docs/3.2.4/reference/html/native-image.html#native-image)
|
|
||||||
* [Spring Boot Actuator](https://docs.spring.io/spring-boot/docs/3.2.4/reference/htmlsingle/index.html#actuator)
|
|
||||||
* [Spring Boot DevTools](https://docs.spring.io/spring-boot/docs/3.2.4/reference/htmlsingle/index.html#using.devtools)
|
|
||||||
* [MyBatis Framework](https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/)
|
|
||||||
* [Spring REST Docs](https://docs.spring.io/spring-restdocs/docs/current/reference/htmlsingle/)
|
|
||||||
* [Spring Shell](https://spring.io/projects/spring-shell)
|
|
||||||
* [Spring Web](https://docs.spring.io/spring-boot/docs/3.2.4/reference/htmlsingle/index.html#web)
|
|
||||||
* [WebSocket](https://docs.spring.io/spring-boot/docs/3.2.4/reference/htmlsingle/index.html#messaging.websockets)
|
|
||||||
|
|
||||||
### Guides
|
|
||||||
|
|
||||||
The following guides illustrate how to use some features concretely:
|
|
||||||
|
|
||||||
* [Building a RESTful Web Service with Spring Boot Actuator](https://spring.io/guides/gs/actuator-service/)
|
|
||||||
* [MyBatis Quick Start](https://github.com/mybatis/spring-boot-starter/wiki/Quick-Start)
|
|
||||||
* [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/)
|
|
||||||
* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
|
|
||||||
* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
|
|
||||||
* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
|
|
||||||
* [Using WebSocket to build an interactive web application](https://spring.io/guides/gs/messaging-stomp-websocket/)
|
|
||||||
|
|
||||||
### Additional Links
|
|
||||||
|
|
||||||
These additional references should also help you:
|
|
||||||
|
|
||||||
* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)
|
|
||||||
* [Configure AOT settings in Build Plugin](https://docs.spring.io/spring-boot/docs/3.2.4/gradle-plugin/reference/htmlsingle/#aot)
|
|
||||||
|
|
||||||
## GraalVM Native Support
|
|
||||||
|
|
||||||
This project has been configured to let you generate either a lightweight container or a native executable.
|
|
||||||
It is also possible to run your tests in a native image.
|
|
||||||
|
|
||||||
### Lightweight Container with Cloud Native Buildpacks
|
|
||||||
|
|
||||||
If you're already familiar with Spring Boot container images support, this is the easiest way to get started.
|
|
||||||
Docker should be installed and configured on your machine prior to creating the image.
|
|
||||||
|
|
||||||
To create the image, run the following goal:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./gradlew bootBuildImage
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, you can run the app like any other container:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ docker run --rm -p 8080:8080 clubs:0.0.1-SNAPSHOT
|
|
||||||
```
|
|
||||||
|
|
||||||
### Executable with Native Build Tools
|
|
||||||
|
|
||||||
Use this option if you want to explore more options such as running your tests in a native image.
|
|
||||||
The GraalVM `native-image` compiler should be installed and configured on your machine.
|
|
||||||
|
|
||||||
NOTE: GraalVM 22.3+ is required.
|
|
||||||
|
|
||||||
To create the executable, run the following goal:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./gradlew nativeCompile
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, you can run the app as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ build/native/nativeCompile/clubs
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also run your existing tests suite in a native image.
|
|
||||||
This is an efficient way to validate the compatibility of your application.
|
|
||||||
|
|
||||||
To run your existing tests in a native image, run the following goal:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./gradlew nativeTest
|
|
||||||
```
|
|
||||||
|
|
9
LICENSE
9
LICENSE
@ -1,9 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2024 ITZX
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
31
README.md
31
README.md
@ -3,35 +3,6 @@
|
|||||||
A clubs home for Hangzhou Electron & Information Vocational School
|
A clubs home for Hangzhou Electron & Information Vocational School
|
||||||
building by springboot3.0 with mysql db
|
building by springboot3.0 with mysql db
|
||||||
---
|
---
|
||||||
<h1><center><font color="red"> ⚠⚠⚠⚠ <font color="yellow">🚮 D.E.P.R.E.C.A.T.E.D </font>⚠⚠⚠⚠ </font></center></h1>
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### 1.Create user table
|
### Add QQ(3357223099(wzp))/QQ (3315932219(Litrix)) and tell him you want to deployment this site
|
||||||
|
|
||||||
```mysql
|
|
||||||
create table user
|
|
||||||
(
|
|
||||||
id int comment '用户ID(自增)',
|
|
||||||
name varchar(20) not null comment '用户名',
|
|
||||||
password char(40) not null comment '密码(使用SHA1)',
|
|
||||||
auth int default 0 not null comment '用户对应权限组ID',
|
|
||||||
avatar char(40) null comment '用户头像sha1',
|
|
||||||
create_time datetime default now() not null comment '用户创建时间',
|
|
||||||
update_time datetime default now() not null on update now() comment '用户数据更新时间'
|
|
||||||
)
|
|
||||||
comment '用户表';
|
|
||||||
|
|
||||||
create unique index user_id_index
|
|
||||||
on user (id)
|
|
||||||
comment '用户表主键';
|
|
||||||
|
|
||||||
alter table user
|
|
||||||
add constraint user_pk
|
|
||||||
primary key (id) comment '用户表主键';
|
|
||||||
|
|
||||||
alter table user
|
|
||||||
modify id int auto_increment comment '用户ID(自增)';
|
|
||||||
```
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
id("org.springframework.boot") version "3.2.4"
|
id("org.springframework.boot") version "3.4.0"
|
||||||
id("io.spring.dependency-management") version "1.1.4"
|
id("io.spring.dependency-management") version "1.1.6"
|
||||||
id("org.asciidoctor.jvm.convert") version "3.3.2"
|
|
||||||
id("org.springdoc.openapi-gradle-plugin") version "1.8.0"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "org.mmga"
|
group = "org.blue"
|
||||||
version = "0.0.1-SNAPSHOT"
|
version = "0.0.1-SNAPSHOT"
|
||||||
|
|
||||||
java {
|
java {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(17)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
@ -20,59 +20,29 @@ configurations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven { url = uri("https://maven.aliyun.com/repository/public/") }
|
|
||||||
maven { url = uri("https://repo.huaweicloud.com/repository/maven/") }
|
|
||||||
maven { url = uri("https://mirrors.cloud.tencent.com/repository/maven/") }
|
|
||||||
maven { url = uri("https://maven.aliyun.com/repository/gradle-plugin") }
|
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
url = uri("https://wzpmc.cn:90/repository/maven-public/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extra["snippetsDir"] = file("build/generated-snippets")
|
|
||||||
extra["springShellVersion"] = "3.2.3"
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web") {
|
|
||||||
exclude("com.fasterxml.jackson.core", "jackson-core")
|
|
||||||
}
|
|
||||||
implementation("org.springframework.boot:spring-boot-starter-websocket")
|
implementation("org.springframework.boot:spring-boot-starter-websocket")
|
||||||
implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3")
|
implementation("org.mmga:make-minecraft-great-again-spring-boot-starter:0.0.5")
|
||||||
implementation("org.springframework.shell:spring-shell-starter")
|
implementation("com.mybatis-flex:mybatis-flex-spring-boot-starter:1.10.2")
|
||||||
implementation("org.springdoc:springdoc-openapi-starter-webmvc-api:2.5.0")
|
annotationProcessor("com.mybatis-flex:mybatis-flex-processor:1.10.2")
|
||||||
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0")
|
|
||||||
// https://mvnrepository.com/artifact/commons-codec/commons-codec
|
// https://mvnrepository.com/artifact/commons-codec/commons-codec
|
||||||
implementation("commons-codec:commons-codec:1.16.1")
|
implementation("commons-codec:commons-codec:1.16.1")
|
||||||
// https://mvnrepository.com/artifact/com.auth0/java-jwt
|
implementation("org.springframework.boot:spring-boot-starter-data-redis:3.4.0")
|
||||||
// https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2
|
|
||||||
implementation("com.alibaba.fastjson2:fastjson2:2.0.48")
|
|
||||||
// https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2-extension-spring6
|
|
||||||
implementation("com.alibaba.fastjson2:fastjson2-extension-spring6:2.0.48")
|
|
||||||
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis
|
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-redis:3.2.4")
|
|
||||||
implementation("com.auth0:java-jwt:4.4.0")
|
|
||||||
compileOnly("org.projectlombok:lombok")
|
compileOnly("org.projectlombok:lombok")
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
|
||||||
runtimeOnly("com.mysql:mysql-connector-j")
|
runtimeOnly("com.mysql:mysql-connector-j")
|
||||||
annotationProcessor("org.projectlombok:lombok")
|
annotationProcessor("org.projectlombok:lombok")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
testImplementation("org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.3")
|
testImplementation("org.mybatis.spring.boot:mybatis-spring-boot-starter-test:3.0.4")
|
||||||
}
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
|
||||||
dependencyManagement {
|
|
||||||
imports {
|
|
||||||
mavenBom("org.springframework.shell:spring-shell-dependencies:${property("springShellVersion")}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test> {
|
tasks.withType<Test> {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
|
||||||
outputs.dir(project.extra["snippetsDir"]!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.asciidoctor {
|
|
||||||
inputs.dir(project.extra["snippetsDir"]!!)
|
|
||||||
dependsOn(tasks.test)
|
|
||||||
}
|
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
7
gradlew
vendored
7
gradlew
vendored
@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@ -84,7 +86,8 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
@ -1 +1 @@
|
|||||||
rootProject.name = "clubs"
|
rootProject.name = "club"
|
||||||
|
24
src/main/java/org/blue/club/ClubApplication.java
Normal file
24
src/main/java/org/blue/club/ClubApplication.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package org.blue.club;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.audit.AuditManager;
|
||||||
|
import com.mybatisflex.core.audit.ConsoleMessageCollector;
|
||||||
|
import com.mybatisflex.core.audit.MessageCollector;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableWebSocket
|
||||||
|
@EnableScheduling
|
||||||
|
public class ClubApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
//开启审计功能
|
||||||
|
AuditManager.setAuditEnable(true);
|
||||||
|
MessageCollector collector = new ConsoleMessageCollector();
|
||||||
|
AuditManager.setMessageCollector(collector);
|
||||||
|
SpringApplication.run(ClubApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
src/main/java/org/blue/club/annotation/Auth.java
Normal file
22
src/main/java/org/blue/club/annotation/Auth.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package org.blue.club.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Target({ElementType.PARAMETER, ElementType.METHOD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface Auth {
|
||||||
|
PermissionDescription[] permissions() default {};
|
||||||
|
|
||||||
|
LogicType permissionType() default LogicType.ANY;
|
||||||
|
|
||||||
|
AuthDescription[] auths() default {};
|
||||||
|
|
||||||
|
LogicType authType() default LogicType.ANY;
|
||||||
|
|
||||||
|
enum LogicType {
|
||||||
|
ANY, ALL
|
||||||
|
}
|
||||||
|
}
|
14
src/main/java/org/blue/club/annotation/AuthDescription.java
Normal file
14
src/main/java/org/blue/club/annotation/AuthDescription.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package org.blue.club.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
public @interface AuthDescription {
|
||||||
|
DescriptionType type() default DescriptionType.NORMAL;
|
||||||
|
|
||||||
|
long value();
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package org.blue.club.annotation;
|
||||||
|
|
||||||
|
public enum DescriptionType {
|
||||||
|
NORMAL,
|
||||||
|
CLUB
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.blue.club.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.ANNOTATION_TYPE)
|
||||||
|
public @interface PermissionDescription {
|
||||||
|
DescriptionType type() default DescriptionType.NORMAL;
|
||||||
|
|
||||||
|
long value();
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.blue.club.configuration;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.blue.club.annotation.Auth;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AuthConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Class<? extends Annotation> authAnnotation() {
|
||||||
|
return Auth.class;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package org.blue.club.configuration;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.blue.club.annotation.Auth;
|
||||||
|
import org.blue.club.annotation.AuthDescription;
|
||||||
|
import org.blue.club.annotation.PermissionDescription;
|
||||||
|
import org.blue.club.dao.AuthDao;
|
||||||
|
import org.blue.club.dao.UserDao;
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
import org.blue.club.entities.vo.data.UserVo;
|
||||||
|
import org.mmga.spring.boot.starter.componet.AuthorizationHandler;
|
||||||
|
import org.mmga.spring.boot.starter.componet.JwtUtils;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||||
|
import org.mmga.spring.boot.starter.utils.VoUtils;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CustomAuthorizationHandler implements AuthorizationHandler<User> {
|
||||||
|
private final JwtUtils jwtUtils;
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final VoUtils voUtils;
|
||||||
|
private final AuthDao authDao;
|
||||||
|
private User guestUser;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<User> auth(String token, Annotation ann) {
|
||||||
|
if (ann instanceof Auth auth) {
|
||||||
|
User user = guestUser;
|
||||||
|
if (guestUser == null) {
|
||||||
|
user = new User();
|
||||||
|
user.setId(-1L);
|
||||||
|
user.setName("游客");
|
||||||
|
user.setAuth(authDao.selectOneWithRelationsById(1));
|
||||||
|
guestUser = user;
|
||||||
|
}
|
||||||
|
if (token != null) {
|
||||||
|
Optional<Long> i = jwtUtils.verifyToken(token);
|
||||||
|
if (i.isEmpty()) throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "token错误!"));
|
||||||
|
Long userId = i.get();
|
||||||
|
UserVo userVo = userDao.selectOneWithRelationsById(userId);
|
||||||
|
if (userVo == null)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "用户不存在!"));
|
||||||
|
user = voUtils.vo2DtoSafe(userVo, User.class);
|
||||||
|
}
|
||||||
|
AuthDescription[] auths = auth.auths();
|
||||||
|
Stream<AuthDescription> authStream = Arrays.stream(auths);
|
||||||
|
boolean isAuthAccept = auths.length == 0 || (auth.authType().equals(Auth.LogicType.ANY) ? authStream.anyMatch(user::hasAuth) : authStream.allMatch(user::hasAuth));
|
||||||
|
if (!isAuthAccept) throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "权限不足!"));
|
||||||
|
PermissionDescription[] permissions = auth.permissions();
|
||||||
|
Stream<PermissionDescription> permissionStream = Arrays.stream(permissions);
|
||||||
|
boolean isPermissionAccept = permissions.length == 0 || (auth.permissionType().equals(Auth.LogicType.ANY) ? permissionStream.anyMatch(user::hasPermission) : permissionStream.allMatch(user::hasPermission));
|
||||||
|
if (!isPermissionAccept)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "权限不足!"));
|
||||||
|
return Optional.of(user);
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.blue.club.configuration;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
|
import io.swagger.v3.oas.models.servers.Server;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class CustomDocsConfiguration {
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
public OpenAPI myApi(@Autowired OpenAPI api) {
|
||||||
|
api.addServersItem(new Server().url("https://wzpmc.cn:18080/").description("外网开放API"));
|
||||||
|
api.addServersItem(new Server().url("http://172.16.114.84:58082/").description("开发用API"));
|
||||||
|
api.addServersItem(new Server().url("http://127.0.0.1:58082/").description("调试用API"));
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package org.blue.club.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class DirConfiguration {
|
||||||
|
@Bean
|
||||||
|
public File tmpFolder() throws IOException {
|
||||||
|
return createDefaultFolder("tmp");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public File avatarFolder() throws IOException {
|
||||||
|
return createDefaultFolder("avatar");
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createDefaultFolder(String name) throws IOException {
|
||||||
|
File folderFile = new File(name);
|
||||||
|
if (folderFile.exists()) return folderFile;
|
||||||
|
if (!folderFile.mkdirs()) throw new IOException("无法创建文件夹" + name);
|
||||||
|
return folderFile;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.configuration;
|
package org.blue.club.configuration;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
33
src/main/java/org/blue/club/controller/AvatarController.java
Normal file
33
src/main/java/org/blue/club/controller/AvatarController.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package org.blue.club.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.blue.club.annotation.Auth;
|
||||||
|
import org.blue.club.services.AvatarServices;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/avatar")
|
||||||
|
@Tag(name = "头像相关接口")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AvatarController {
|
||||||
|
private final AvatarServices avatarServices;
|
||||||
|
|
||||||
|
@GetMapping("/{sha1}")
|
||||||
|
@Operation(description = "获取头像文件")
|
||||||
|
public void getAvatar(HttpServletResponse response, @Schema(description = "头像文件SHA1值") @PathVariable("sha1") String sha1) {
|
||||||
|
avatarServices.getAvatar(response, sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/upload")
|
||||||
|
@Operation(description = "上传头像")
|
||||||
|
@Auth
|
||||||
|
public Result<String> changeAvatar(MultipartFile file) {
|
||||||
|
return avatarServices.changeAvatar(file);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.controller;
|
package org.blue.club.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONException;
|
import com.alibaba.fastjson2.JSONException;
|
||||||
@ -13,13 +13,14 @@ import jakarta.websocket.server.ServerEndpoint;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.mmga.clubs.entities.chess.Room;
|
import org.blue.club.dao.UserDao;
|
||||||
import org.mmga.clubs.entities.chess.packet.*;
|
import org.blue.club.entities.dto.chess.Room;
|
||||||
import org.mmga.clubs.entities.chess.packet.request.*;
|
import org.blue.club.entities.dto.chess.packet.*;
|
||||||
import org.mmga.clubs.entities.user.User;
|
import org.blue.club.entities.dto.chess.packet.request.*;
|
||||||
import org.mmga.clubs.service.UserService;
|
import org.blue.club.entities.dto.user.User;
|
||||||
import org.mmga.clubs.utils.JwtUtils;
|
import org.blue.club.utils.WebSocketUtils;
|
||||||
import org.mmga.clubs.utils.WebSocketUtils;
|
import org.mmga.spring.boot.starter.componet.JwtUtils;
|
||||||
|
import org.mmga.spring.boot.starter.utils.VoUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -43,26 +44,79 @@ public class ChessController {
|
|||||||
private static final ConcurrentHashMap<UUID, Room> rooms = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<UUID, Room> rooms = new ConcurrentHashMap<>();
|
||||||
private static final ConcurrentHashMap<Session, Boolean> pingPong = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Session, Boolean> pingPong = new ConcurrentHashMap<>();
|
||||||
private static JwtUtils jwtUtils;
|
private static JwtUtils jwtUtils;
|
||||||
private static UserService userService;
|
private static VoUtils voUtils;
|
||||||
|
private static UserDao userDao;
|
||||||
|
private final Queue<String> messageQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
private boolean isLogin = false;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Room getRoomByPlayer(String id) {
|
||||||
|
for (Room value : rooms.values()) {
|
||||||
|
if (value.isIn(id)) return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void staticOnClose(Session session) {
|
||||||
|
String sessionId = session.getId();
|
||||||
|
Room roomByPlayer = getRoomByPlayer(sessionId);
|
||||||
|
if (roomByPlayer != null) {
|
||||||
|
roomByPlayer.leave(session);
|
||||||
|
roomByPlayer.broadcast(roomByPlayer.getRoomInfo(users));
|
||||||
|
}
|
||||||
|
log.info("session closed {}", sessionId);
|
||||||
|
sessions.remove(sessionId);
|
||||||
|
users.remove(sessionId);
|
||||||
|
pingPong.remove(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Scheduled(fixedDelay = 10000)
|
||||||
|
public static void connectionManager() {
|
||||||
|
for (Session value : sessions.values()) {
|
||||||
|
if (!pingPong.getOrDefault(value, true)) {
|
||||||
|
log.info("closed by connectionManager");
|
||||||
|
if (value.isOpen()) {
|
||||||
|
value.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "链接延迟过高"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
staticOnClose(value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pingPong.put(value, false);
|
||||||
|
log.info("send ping to session {}", value.getId());
|
||||||
|
value.getAsyncRemote().sendPing(Unpooled.buffer().writeLong(System.currentTimeMillis()).nioBuffer());
|
||||||
|
}
|
||||||
|
Instant instant = new Date().toInstant();
|
||||||
|
Instant before10Min = instant.plus(-10, ChronoUnit.MINUTES);
|
||||||
|
rooms.entrySet().stream()
|
||||||
|
.filter(e -> e.getValue().getState().equals(Room.RoomState.CREATED))
|
||||||
|
.filter(e -> e.getValue().getLastStateChange().toInstant().isBefore(before10Min))
|
||||||
|
.map(Map.Entry::getKey)
|
||||||
|
.forEach(rooms::remove);
|
||||||
|
rooms.values().forEach(Room::tryClean);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setVoUtils(VoUtils voUtils) {
|
||||||
|
ChessController.voUtils = voUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public void setUserDao(UserDao userDao) {
|
||||||
|
ChessController.userDao = userDao;
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void setJwtUtils(JwtUtils jwtUtils) {
|
public void setJwtUtils(JwtUtils jwtUtils) {
|
||||||
ChessController.jwtUtils = jwtUtils;
|
ChessController.jwtUtils = jwtUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public void setUserService(UserService userService) {
|
|
||||||
ChessController.userService = userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Queue<String> messageQueue = new ConcurrentLinkedQueue<>();
|
|
||||||
private boolean isLogin = false;
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@OnOpen
|
@OnOpen
|
||||||
public void onOpen(Session session, @PathParam("token") String token) {
|
public void onOpen(Session session, @PathParam("token") String token) {
|
||||||
isLogin = false;
|
isLogin = false;
|
||||||
Optional<Integer> i = jwtUtils.verifyTokenSafe(token);
|
Optional<Long> i = jwtUtils.verifyToken(token);
|
||||||
if (i.isEmpty()) {
|
if (i.isEmpty()) {
|
||||||
WebSocketUtils.sendPacket(new ErrorPacket("token验证失败!"), session);
|
WebSocketUtils.sendPacket(new ErrorPacket("token验证失败!"), session);
|
||||||
log.info("closed by token verifier");
|
log.info("closed by token verifier");
|
||||||
@ -71,10 +125,10 @@ public class ChessController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String sessionId = session.getId();
|
String sessionId = session.getId();
|
||||||
User user = userService.getUserById(i.get());
|
User user = voUtils.vo2DtoSafe(userDao.selectOneWithRelationsById(i.get()), User.class);
|
||||||
WebSocketUtils.sendPacket(new UserInfoPacket(user), session);
|
WebSocketUtils.sendPacket(new UserInfoPacket(user), session);
|
||||||
String existsUser = null;
|
String existsUser = null;
|
||||||
int id = user.getId();
|
long id = user.getId();
|
||||||
for (Map.Entry<String, User> entry : users.entrySet()) {
|
for (Map.Entry<String, User> entry : users.entrySet()) {
|
||||||
User value = entry.getValue();
|
User value = entry.getValue();
|
||||||
if (value.getId() == id) {
|
if (value.getId() == id) {
|
||||||
@ -102,7 +156,6 @@ public class ChessController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OnMessage
|
@OnMessage
|
||||||
public void onPong(PongMessage pongMessage, Session session) {
|
public void onPong(PongMessage pongMessage, Session session) {
|
||||||
ByteBuffer applicationData = pongMessage.getApplicationData();
|
ByteBuffer applicationData = pongMessage.getApplicationData();
|
||||||
@ -138,7 +191,7 @@ public class ChessController {
|
|||||||
public Object handleMessage(JSONObject object, String packetName, Session session) {
|
public Object handleMessage(JSONObject object, String packetName, Session session) {
|
||||||
if (packetName == null) return new ErrorPacket("错误的请求类型");
|
if (packetName == null) return new ErrorPacket("错误的请求类型");
|
||||||
try {
|
try {
|
||||||
Class<?> packetType = Class.forName("org.mmga.clubs.entities.chess.packet.request." + packetName + "Request");
|
Class<?> packetType = Class.forName("org.blue.club.entities.dto.chess.packet.request." + packetName + "Request");
|
||||||
JSONObject payloadJson = object.getJSONObject("payload");
|
JSONObject payloadJson = object.getJSONObject("payload");
|
||||||
if (payloadJson == null) {
|
if (payloadJson == null) {
|
||||||
Field[] declaredFields = packetType.getDeclaredFields();
|
Field[] declaredFields = packetType.getDeclaredFields();
|
||||||
@ -212,57 +265,8 @@ public class ChessController {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static Room getRoomByPlayer(String id) {
|
|
||||||
for (Room value : rooms.values()) {
|
|
||||||
if (value.isIn(id)) return value;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void staticOnClose(Session session) {
|
|
||||||
String sessionId = session.getId();
|
|
||||||
Room roomByPlayer = getRoomByPlayer(sessionId);
|
|
||||||
if (roomByPlayer != null) {
|
|
||||||
roomByPlayer.leave(session);
|
|
||||||
roomByPlayer.broadcast(roomByPlayer.getRoomInfo(users));
|
|
||||||
}
|
|
||||||
log.info("session closed {}", sessionId);
|
|
||||||
sessions.remove(sessionId);
|
|
||||||
users.remove(sessionId);
|
|
||||||
pingPong.remove(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClose
|
@OnClose
|
||||||
public void onClose(Session session) {
|
public void onClose(Session session) {
|
||||||
staticOnClose(session);
|
staticOnClose(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Scheduled(fixedDelay = 10000)
|
|
||||||
public static void connectionManager() {
|
|
||||||
for (Session value : sessions.values()) {
|
|
||||||
if (!pingPong.getOrDefault(value, true)) {
|
|
||||||
log.info("closed by connectionManager");
|
|
||||||
if (value.isOpen()) {
|
|
||||||
value.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "链接延迟过高"));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
staticOnClose(value);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
pingPong.put(value, false);
|
|
||||||
log.info("send ping to session {}", value.getId());
|
|
||||||
value.getAsyncRemote().sendPing(Unpooled.buffer().writeLong(System.currentTimeMillis()).nioBuffer());
|
|
||||||
}
|
|
||||||
Instant instant = new Date().toInstant();
|
|
||||||
Instant before10Min = instant.plus(-10, ChronoUnit.MINUTES);
|
|
||||||
rooms.entrySet().stream()
|
|
||||||
.filter(e -> e.getValue().getState().equals(Room.RoomState.CREATED))
|
|
||||||
.filter(e -> e.getValue().getLastStateChange().toInstant().isBefore(before10Min))
|
|
||||||
.map(Map.Entry::getKey)
|
|
||||||
.forEach(rooms::remove);
|
|
||||||
rooms.values().forEach(Room::tryClean);
|
|
||||||
}
|
|
||||||
}
|
}
|
86
src/main/java/org/blue/club/controller/ClubController.java
Normal file
86
src/main/java/org/blue/club/controller/ClubController.java
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package org.blue.club.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.blue.club.annotation.Auth;
|
||||||
|
import org.blue.club.annotation.DescriptionType;
|
||||||
|
import org.blue.club.annotation.PermissionDescription;
|
||||||
|
import org.blue.club.entities.dto.club.req.*;
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
import org.blue.club.entities.vo.data.ClubVo;
|
||||||
|
import org.blue.club.services.ClubServices;
|
||||||
|
import org.mmga.spring.boot.starter.entities.PagerData;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Tag(name = "社团相关接口")
|
||||||
|
@RequestMapping("/api/club")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ClubController {
|
||||||
|
private final ClubServices clubServices;
|
||||||
|
|
||||||
|
@GetMapping("/")
|
||||||
|
@Operation(description = "分页获取社团")
|
||||||
|
public Result<PagerData<ClubVo>> getClubs(@Schema(description = "分页数据第几页") @RequestParam Integer page, @Schema(description = "分页数据每页数据量") @RequestParam Integer num) {
|
||||||
|
return clubServices.getClubs(page, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(description = "创建社团")
|
||||||
|
@Auth(permissions = {@PermissionDescription(3)})
|
||||||
|
@PutMapping("/create")
|
||||||
|
public Result<ClubVo> createClub(@RequestBody CreateClubRequest request) {
|
||||||
|
return clubServices.createClub(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(description = "向社团添加用户")
|
||||||
|
@PutMapping("/user/add")
|
||||||
|
public Result<Boolean> clubAddUser(@Auth(permissions = {@PermissionDescription(3), @PermissionDescription(value = 2, type = DescriptionType.CLUB)}) User user, @RequestBody ClubAddUserRequest request) {
|
||||||
|
return clubServices.clubAddUser(user, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(description = "分页列出社团的所有用户")
|
||||||
|
@GetMapping("/user/list")
|
||||||
|
public Result<PagerData<User>> clubGetUsers(@Schema(description = "分页数据第几页") @RequestParam Integer page, @Schema(description = "分页数据每页数据量") @RequestParam Integer num, @Schema(description = "社团ID") @RequestParam Long clubId) {
|
||||||
|
return clubServices.clubGetUsers(page, num, clubId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(description = "从社团中删除用户")
|
||||||
|
@DeleteMapping("/user/remove")
|
||||||
|
public Result<Boolean> clubRemoveUser(@Auth(permissions = {@PermissionDescription(3), @PermissionDescription(value = 2, type = DescriptionType.CLUB)}) User user, @Schema(description = "社团ID") @RequestParam long clubId, @Schema(description = "需要删除的用户ID") @RequestParam long userId) {
|
||||||
|
return clubServices.clubRemoveUser(user, clubId, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(description = "修改社团用户权限")
|
||||||
|
@PutMapping("/user/auth")
|
||||||
|
public Result<Boolean> clubChangeUserAuth(@Auth(permissions = {@PermissionDescription(3), @PermissionDescription(value = 2, type = DescriptionType.CLUB)}) User user, @RequestBody ClubChangeUserAuthRequest request) {
|
||||||
|
return clubServices.clubChangeUserAuth(user, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/avatar")
|
||||||
|
@Operation(description = "修改社团头像")
|
||||||
|
public Result<Boolean> changeAvatar(@RequestParam("code") @Schema(description = "修改头像操作码,可以通过将图片文件上传至([POST] /api/avatar/upload)接口获取") String avatarOperationCode, @Schema(description = "被修改的社团ID") @RequestParam long clubId, @Auth(permissions = {@PermissionDescription(3), @PermissionDescription(value = 1, type = DescriptionType.CLUB)}) User user) {
|
||||||
|
return clubServices.changeAvatar(avatarOperationCode, clubId, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/name")
|
||||||
|
@Operation(description = "修改社团名称")
|
||||||
|
@Auth(permissions = {@PermissionDescription(3)})
|
||||||
|
public Result<Boolean> changeName(@RequestBody ChangeClubNameRequest request) {
|
||||||
|
return clubServices.changeName(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/commit")
|
||||||
|
@Operation(description = "修改社团名称")
|
||||||
|
public Result<Boolean> changeCommit(@RequestBody ChangeClubCommitRequest request, @Auth(permissions = {@PermissionDescription(3), @PermissionDescription(value = 1, type = DescriptionType.CLUB)}) User user) {
|
||||||
|
return clubServices.changeCommit(request, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
@Operation(description = "获取社团")
|
||||||
|
public Result<ClubVo> getClub(@Schema(description = "社团ID") @PathVariable("id") long id) {
|
||||||
|
return clubServices.getClub(id);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package org.blue.club.controller;
|
||||||
|
|
||||||
|
import org.blue.club.exceptions.ServerException;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
|
||||||
|
@ControllerAdvice
|
||||||
|
public class ServerExceptionHandler {
|
||||||
|
@ExceptionHandler({ServerException.class})
|
||||||
|
public ResponseEntity<Result<Void>> handleAuthorizationException(ServerException e) {
|
||||||
|
Result<Void> result = e.getResult();
|
||||||
|
return ResponseEntity.ok(result);
|
||||||
|
}
|
||||||
|
}
|
92
src/main/java/org/blue/club/controller/UserController.java
Normal file
92
src/main/java/org/blue/club/controller/UserController.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package org.blue.club.controller;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.blue.club.annotation.Auth;
|
||||||
|
import org.blue.club.annotation.PermissionDescription;
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
import org.blue.club.entities.dto.user.req.*;
|
||||||
|
import org.blue.club.entities.dto.user.resp.VerifyCodeResponse;
|
||||||
|
import org.blue.club.services.UserServices;
|
||||||
|
import org.mmga.spring.boot.starter.annotation.AuthMapping;
|
||||||
|
import org.mmga.spring.boot.starter.entities.PagerData;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/user")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "用户相关接口")
|
||||||
|
public class UserController {
|
||||||
|
private final UserServices userServices;
|
||||||
|
|
||||||
|
@PostMapping("/login")
|
||||||
|
@AuthMapping
|
||||||
|
@Operation(description = "用户登录", responses = {@ApiResponse(description = "返回是否登录成功", responseCode = "200")})
|
||||||
|
public Result<User> login(@RequestBody LoginRequest user) {
|
||||||
|
return userServices.login(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuthMapping
|
||||||
|
@PutMapping("/create")
|
||||||
|
@Operation(description = "创建用户", responses = {@ApiResponse(description = "返回创建后的用户")})
|
||||||
|
public Result<User> createUser(@RequestBody RegisterRequest user) {
|
||||||
|
return userServices.createUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/info")
|
||||||
|
@Operation(description = "获取用户信息")
|
||||||
|
public Result<User> getUserInfo(@Auth User user) {
|
||||||
|
return Result.success(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/all")
|
||||||
|
@Operation(description = "获取所有用户信息(分页)")
|
||||||
|
@Auth(permissions = {@PermissionDescription(3), @PermissionDescription(4)})
|
||||||
|
public Result<PagerData<User>> getAllUserInfo(@RequestParam("num") int num, @RequestParam("page") int page, @RequestParam(value = "onlyNoClub", defaultValue = "false") boolean onlyNoClub) {
|
||||||
|
return userServices.getAllUserInfo(num, page, onlyNoClub);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/rename")
|
||||||
|
@Operation(description = "修改用户名")
|
||||||
|
@Auth
|
||||||
|
public Result<Boolean> changeUsername(@RequestBody UserRenameRequest renameVo, @Auth User user) {
|
||||||
|
return userServices.changeUsername(renameVo, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/password")
|
||||||
|
@Operation(description = "修改密码")
|
||||||
|
public Result<Boolean> changePassword(@RequestBody UserChangePasswordRequest changePasswordVo, @Auth User user) {
|
||||||
|
return userServices.changePassword(changePasswordVo, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/auth")
|
||||||
|
@Operation(description = "修改用户权限组")
|
||||||
|
@Auth(permissions = {@PermissionDescription(3), @PermissionDescription(4)})
|
||||||
|
public Result<Boolean> changeAuth(@RequestBody UserChangeAuthRequest userChangeAuthVo) {
|
||||||
|
return userServices.changeAuth(userChangeAuthVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/avatar")
|
||||||
|
@Operation(description = "修改用户头像")
|
||||||
|
public Result<Boolean> changeAvatar(@RequestParam("code") @Schema(description = "修改头像操作码,可以通过将图片文件上传至([POST] /api/avatar/upload)接口获取") String avatarOperationCode, @Schema(description = "被修改的用户ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED) @RequestParam(defaultValue = "-1") long userId, @Auth User user) {
|
||||||
|
return userServices.changeAvatar(avatarOperationCode, userId, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/verify")
|
||||||
|
@Operation(description = "获取验证码")
|
||||||
|
public Result<VerifyCodeResponse> generatorVerifyCode() {
|
||||||
|
return userServices.getVerifyCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/info/{id}")
|
||||||
|
@Operation(description = "获取简略用户信息")
|
||||||
|
public Result<User> getSimpleInfo(@PathVariable("id") int userId) {
|
||||||
|
return userServices.getUserInfo(userId);
|
||||||
|
}
|
||||||
|
}
|
9
src/main/java/org/blue/club/dao/AuthDao.java
Normal file
9
src/main/java/org/blue/club/dao/AuthDao.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.blue.club.dao;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.blue.club.entities.vo.data.AuthVo;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface AuthDao extends BaseMapper<AuthVo> {
|
||||||
|
}
|
9
src/main/java/org/blue/club/dao/ClubDao.java
Normal file
9
src/main/java/org/blue/club/dao/ClubDao.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.blue.club.dao;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.blue.club.entities.vo.data.ClubVo;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ClubDao extends BaseMapper<ClubVo> {
|
||||||
|
}
|
9
src/main/java/org/blue/club/dao/ClubUserAuthDao.java
Normal file
9
src/main/java/org/blue/club/dao/ClubUserAuthDao.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.blue.club.dao;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.blue.club.entities.vo.data.ClubUserAuthVo;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface ClubUserAuthDao extends BaseMapper<ClubUserAuthVo> {
|
||||||
|
}
|
9
src/main/java/org/blue/club/dao/UserDao.java
Normal file
9
src/main/java/org/blue/club/dao/UserDao.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.blue.club.dao;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.blue.club.entities.vo.data.UserVo;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface UserDao extends BaseMapper<UserVo> {
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package org.blue.club.dao.redis;
|
||||||
|
|
||||||
|
import org.blue.club.entities.vo.data.AvatarTmpVo;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface AvatarOperationDao extends CrudRepository<AvatarTmpVo, String> {
|
||||||
|
}
|
9
src/main/java/org/blue/club/dao/redis/VerifyDao.java
Normal file
9
src/main/java/org/blue/club/dao/redis/VerifyDao.java
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package org.blue.club.dao.redis;
|
||||||
|
|
||||||
|
import org.blue.club.entities.vo.VerifyVo;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface VerifyDao extends CrudRepository<VerifyVo, String> {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.chess;
|
package org.blue.club.entities.dto.chess;
|
||||||
|
|
||||||
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
import com.alibaba.fastjson2.annotation.JSONField;
|
||||||
@ -7,12 +7,12 @@ import lombok.AccessLevel;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.mmga.clubs.entities.chess.packet.PlayerJoinRoomPacket;
|
import org.blue.club.entities.dto.chess.packet.PlayerJoinRoomPacket;
|
||||||
import org.mmga.clubs.entities.chess.packet.PlayerLeavePacket;
|
import org.blue.club.entities.dto.chess.packet.PlayerLeavePacket;
|
||||||
import org.mmga.clubs.entities.chess.packet.PlayerSideAllocationPacket;
|
import org.blue.club.entities.dto.chess.packet.PlayerSideAllocationPacket;
|
||||||
import org.mmga.clubs.entities.chess.packet.RoomInfoPacket;
|
import org.blue.club.entities.dto.chess.packet.RoomInfoPacket;
|
||||||
import org.mmga.clubs.entities.user.User;
|
import org.blue.club.entities.dto.user.User;
|
||||||
import org.mmga.clubs.utils.WebSocketUtils;
|
import org.blue.club.utils.WebSocketUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.chess.packet;
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
public record ErrorPacket(String reason) {
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
import org.blue.club.entities.dto.chess.Room;
|
||||||
|
|
||||||
|
public record HasPlayerWinPacket(Room.WinInfo winInfo) {
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
import org.blue.club.entities.dto.chess.Room;
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
|
||||||
|
public record PlayerJoinRoomPacket(User user, Room room) {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.chess.packet;
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
public record PlayerLeavePacket(String player) {
|
public record PlayerLeavePacket(String player) {
|
||||||
}
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
public record PlayerLosePacket() {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.chess.packet;
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
public record PlayerSideAllocationPacket(boolean isWhite) {
|
public record PlayerSideAllocationPacket(boolean isWhite) {
|
||||||
}
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
public record PlayerWinPacket() {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.chess.packet;
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
package org.mmga.clubs.entities.chess.packet;
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
import org.mmga.clubs.entities.chess.Room;
|
import org.blue.club.entities.dto.chess.Room;
|
||||||
import org.mmga.clubs.entities.user.User;
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
import org.blue.club.entities.dto.chess.Room;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public record RoomListPacket(Collection<Room> rooms) {
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet;
|
||||||
|
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
|
||||||
|
public record UserInfoPacket(User user) {
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet.request;
|
||||||
|
|
||||||
|
public record CreateRoomRequest() {
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet.request;
|
||||||
|
|
||||||
|
public record PlaceChessPieceRequest(int x, int y) {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.chess.packet.request;
|
package org.blue.club.entities.dto.chess.packet.request;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet.request;
|
||||||
|
|
||||||
|
public record ResetRoomRequest() {
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
package org.blue.club.entities.dto.chess.packet.request;
|
||||||
|
|
||||||
|
public record RoomListRequest() {
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.blue.club.entities.dto.club.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(name = "修改社团简介请求")
|
||||||
|
public record ChangeClubCommitRequest(@Schema(description = "社团ID") Long clubId,
|
||||||
|
@Schema(description = "新社团简介") String commit) {
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.blue.club.entities.dto.club.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(name = "修改社团名称请求")
|
||||||
|
public record ChangeClubNameRequest(@Schema(description = "社团ID") Long clubId,
|
||||||
|
@Schema(description = "新社团名称") String name) {
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.blue.club.entities.dto.club.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(name = "社团添加用户请求体")
|
||||||
|
public record ClubAddUserRequest(@Schema(description = "社团ID") long clubId, @Schema(description = "用户ID") long userId, @Schema(description = "用户在社团的权限组ID") long clubAuthId) {
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.blue.club.entities.dto.club.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(name = "修改社团用户权限组请求体")
|
||||||
|
public record ClubChangeUserAuthRequest(@Schema(description = "修改的用户ID") Long userId,@Schema(description = "社团ID") Long clubId,@Schema(description = "新的AuthID") Long newAuthId) {
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.blue.club.entities.dto.club.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(name = "创建社团请求体")
|
||||||
|
public record CreateClubRequest(@Schema(description = "社团名称") String name) {
|
||||||
|
}
|
51
src/main/java/org/blue/club/entities/dto/user/User.java
Normal file
51
src/main/java/org/blue/club/entities/dto/user/User.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package org.blue.club.entities.dto.user;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.RelationManyToOne;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.blue.club.annotation.AuthDescription;
|
||||||
|
import org.blue.club.annotation.DescriptionType;
|
||||||
|
import org.blue.club.annotation.PermissionDescription;
|
||||||
|
import org.blue.club.entities.vo.data.AuthVo;
|
||||||
|
import org.blue.club.entities.vo.data.ClubAuthVo;
|
||||||
|
import org.blue.club.entities.vo.data.ClubVo;
|
||||||
|
import org.mmga.spring.boot.starter.annotation.VoFieldMapper;
|
||||||
|
import org.mmga.spring.boot.starter.interfaces.IdHolder;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class User implements IdHolder {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
@Nullable
|
||||||
|
private String avatar;
|
||||||
|
@RelationManyToOne(selfField = "auth", targetField = "id")
|
||||||
|
@VoFieldMapper("auths")
|
||||||
|
private AuthVo auth;
|
||||||
|
@RelationManyToOne(joinTable = "club_user_auth", selfField = "id", joinSelfColumn = "user_id", targetField = "id", joinTargetColumn = "club_id")
|
||||||
|
private ClubVo club;
|
||||||
|
@RelationManyToOne(joinTable = "club_user_auth", selfField = "id", joinSelfColumn = "user_id", targetField = "id", joinTargetColumn = "auth_id")
|
||||||
|
private ClubAuthVo clubAuth;
|
||||||
|
|
||||||
|
public boolean hasPermission(long id) {
|
||||||
|
return this.hasPermission(DescriptionType.NORMAL, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(DescriptionType type, long id) {
|
||||||
|
return (type.equals(DescriptionType.CLUB) ? clubAuth : auth).hasPermission(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPermission(PermissionDescription description) {
|
||||||
|
return hasPermission(description.type(), description.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasSuperAdminPermission() {
|
||||||
|
return this.hasPermission(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAuth(AuthDescription description) {
|
||||||
|
long authId = description.value();
|
||||||
|
return (description.type().equals(DescriptionType.CLUB) ? clubAuth.getId() : auth.getId()) == authId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.blue.club.entities.dto.user.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
|
@Schema(name = "用户登录参数")
|
||||||
|
public record LoginRequest(@Schema(description = "用户名") String username,
|
||||||
|
@Schema(description = "用户密码(使用MD5摘要后的hex字符串)") String password,
|
||||||
|
@Schema(description = "验证码密钥") String key,
|
||||||
|
@Schema(description = "验证码") String code) {
|
||||||
|
public String sha1HexPassword() {
|
||||||
|
return DigestUtils.sha1Hex(this.password);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.blue.club.entities.dto.user.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
|
@Schema(name = "用户注册参数")
|
||||||
|
public record RegisterRequest(@Schema(description = "用户名") String username,
|
||||||
|
@Schema(description = "用户密码(使用MD5摘要后的hex字符串)") String password,
|
||||||
|
@Schema(description = "注册用户的权限组ID") Long auth,
|
||||||
|
@Schema(description = "验证码密钥") String key,
|
||||||
|
@Schema(description = "验证码") String code) {
|
||||||
|
public String sha1HexPassword() {
|
||||||
|
return DigestUtils.sha1Hex(this.password);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.blue.club.entities.dto.user.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(name = "用户修改权限组请求体")
|
||||||
|
public record UserChangeAuthRequest(@Schema(description = "被修改的用户ID") long id,
|
||||||
|
@Schema(description = "新的权限组ID") long authId) {
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package org.blue.club.entities.dto.user.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@Schema(name = "用户修改密码请求体")
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class UserChangePasswordRequest {
|
||||||
|
@Schema(description = "被修改的用户ID")
|
||||||
|
private final Long id;
|
||||||
|
@Schema(description = "修改后的密码MD5值")
|
||||||
|
private final String newPassword;
|
||||||
|
@Schema(description = "修改前的密码MD5值", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||||
|
private String oldPassword;
|
||||||
|
|
||||||
|
public UserChangePasswordRequest sha1HexPassword() {
|
||||||
|
String oldPassword = Objects.isNull(this.oldPassword) ? null : DigestUtils.sha1Hex(this.oldPassword);
|
||||||
|
String newPassword = Objects.isNull(this.newPassword) ? null : DigestUtils.sha1Hex(this.newPassword);
|
||||||
|
return new UserChangePasswordRequest(this.id, oldPassword, newPassword);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.blue.club.entities.dto.user.req;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Schema(name = "用户修改用户名请求体")
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserRenameRequest {
|
||||||
|
@Schema(description = "新用户名")
|
||||||
|
private final String newName;
|
||||||
|
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||||
|
private Long id;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.blue.club.entities.dto.user.resp;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
@Schema(description = "验证码返回值")
|
||||||
|
public record VerifyCodeResponse(@Schema(description = "验证码图像base64") String img,
|
||||||
|
@Schema(description = "验证码验证密钥") String key) {
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.verify;
|
package org.blue.club.entities.vo;
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.redis.core.RedisHash;
|
import org.springframework.data.redis.core.RedisHash;
|
@ -0,0 +1,6 @@
|
|||||||
|
package org.blue.club.entities.vo.abs;
|
||||||
|
|
||||||
|
public interface IPermission {
|
||||||
|
String getName();
|
||||||
|
long getId();
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.blue.club.entities.vo.abs;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface PermissionsHolder {
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
long getId();
|
||||||
|
|
||||||
|
List<? extends IPermission> getPermissions();
|
||||||
|
|
||||||
|
default boolean hasPermission(long permissionId) {
|
||||||
|
return this.getPermissions().stream().anyMatch(p -> p.getId() == permissionId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Table("auth_permission")
|
||||||
|
public class AuthPermissionVo extends BaseDataVo {
|
||||||
|
@Column("auth_id")
|
||||||
|
private Long authId;
|
||||||
|
@Column("permission_id")
|
||||||
|
private Long permissionId;
|
||||||
|
}
|
24
src/main/java/org/blue/club/entities/vo/data/AuthVo.java
Normal file
24
src/main/java/org/blue/club/entities/vo/data/AuthVo.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.RelationManyToMany;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.blue.club.entities.vo.abs.PermissionsHolder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("auth")
|
||||||
|
@Data
|
||||||
|
public class AuthVo extends BaseDataVo implements PermissionsHolder {
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
@RelationManyToMany(joinTable = "auth_permission",
|
||||||
|
selfField = "id", joinSelfColumn = "auth_id",
|
||||||
|
targetField = "id", joinTargetColumn = "permission_id"
|
||||||
|
)
|
||||||
|
private List<PermissionVo> permissions;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mmga.clubs.entities.user.change;
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
import org.springframework.data.annotation.Id;
|
import org.springframework.data.annotation.Id;
|
||||||
import org.springframework.data.redis.core.RedisHash;
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
@ -7,5 +7,5 @@ import org.springframework.data.redis.core.index.Indexed;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
@RedisHash("avatar")
|
@RedisHash("avatar")
|
||||||
public record UserAvatarOperationVo(@Id String operationCode, @Indexed String avatarSHA, @Indexed int userId, @Indexed Date createTime) {
|
public record AvatarTmpVo(@Id String operationCode, @Indexed String sha1, @Indexed Date createTime) {
|
||||||
}
|
}
|
12
src/main/java/org/blue/club/entities/vo/data/BaseDataVo.java
Normal file
12
src/main/java/org/blue/club/entities/vo/data/BaseDataVo.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class BaseDataVo {
|
||||||
|
@Column(value = "create_time", onUpdateValue = "now()", onInsertValue = "now()")
|
||||||
|
protected Date createTime;
|
||||||
|
@Column(value = "update_time", onUpdateValue = "now()", onInsertValue = "now()")
|
||||||
|
protected Date updateTime;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("club_auth_permission")
|
||||||
|
@Schema(name = "社团权限/权限组关联")
|
||||||
|
@Data
|
||||||
|
public class ClubAuthPermissionVo extends BaseDataVo {
|
||||||
|
@Schema(description = "权限组ID")
|
||||||
|
@Column("auth_id")
|
||||||
|
private long authId;
|
||||||
|
@Schema(description = "权限ID")
|
||||||
|
@Column("permission_id")
|
||||||
|
private long permissionId;
|
||||||
|
}
|
28
src/main/java/org/blue/club/entities/vo/data/ClubAuthVo.java
Normal file
28
src/main/java/org/blue/club/entities/vo/data/ClubAuthVo.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.RelationManyToMany;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.blue.club.entities.vo.abs.PermissionsHolder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("club_auth")
|
||||||
|
@Data
|
||||||
|
@Schema(name = "社团权限")
|
||||||
|
public class ClubAuthVo extends BaseDataVo implements PermissionsHolder {
|
||||||
|
@Schema(description = "社团权限ID")
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
@Schema(description = "社团权限名称")
|
||||||
|
private String name;
|
||||||
|
@RelationManyToMany(joinTable = "club_auth_permission",
|
||||||
|
selfField = "id", joinSelfColumn = "auth_id",
|
||||||
|
targetField = "id", joinTargetColumn = "permission_id"
|
||||||
|
)
|
||||||
|
private List<ClubPermissionVo> permissions;
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.blue.club.entities.vo.abs.IPermission;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("club_permission")
|
||||||
|
@Schema(name = "社团权限")
|
||||||
|
@Data
|
||||||
|
public class ClubPermissionVo extends BaseDataVo implements IPermission {
|
||||||
|
@Id
|
||||||
|
@Schema(name = "权限ID")
|
||||||
|
private long id;
|
||||||
|
@Schema(name = "权限名称")
|
||||||
|
private String name;
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("club_user_auth")
|
||||||
|
@Data
|
||||||
|
public class ClubUserAuthVo extends BaseDataVo {
|
||||||
|
@Column("user_id")
|
||||||
|
private Long userId;
|
||||||
|
@Column("club_id")
|
||||||
|
private Long clubId;
|
||||||
|
@Column("auth_id")
|
||||||
|
private Long authId;
|
||||||
|
}
|
17
src/main/java/org/blue/club/entities/vo/data/ClubVo.java
Normal file
17
src/main/java/org/blue/club/entities/vo/data/ClubVo.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Table("club")
|
||||||
|
public class ClubVo extends BaseDataVo {
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private String commit;
|
||||||
|
private String avatar;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.blue.club.entities.vo.abs.IPermission;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("permission")
|
||||||
|
@Data
|
||||||
|
public class PermissionVo extends BaseDataVo implements IPermission {
|
||||||
|
@Id
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
}
|
31
src/main/java/org/blue/club/entities/vo/data/UserVo.java
Normal file
31
src/main/java/org/blue/club/entities/vo/data/UserVo.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package org.blue.club.entities.vo.data;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.KeyType;
|
||||||
|
import com.mybatisflex.annotation.RelationManyToOne;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.mmga.spring.boot.starter.annotation.VoIgnore;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Table("user")
|
||||||
|
public class UserVo extends BaseDataVo {
|
||||||
|
@Id(keyType = KeyType.Auto)
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
@VoIgnore
|
||||||
|
private String password;
|
||||||
|
@VoIgnore
|
||||||
|
private Long auth;
|
||||||
|
@Nullable
|
||||||
|
private String avatar;
|
||||||
|
@RelationManyToOne(selfField = "auth", targetField = "id")
|
||||||
|
private AuthVo auths;
|
||||||
|
@RelationManyToOne(joinTable = "club_user_auth", selfField = "id", joinSelfColumn = "user_id", targetField = "id", joinTargetColumn = "club_id")
|
||||||
|
private ClubVo club;
|
||||||
|
@RelationManyToOne(joinTable = "club_user_auth", selfField = "id", joinSelfColumn = "user_id", targetField = "id", joinTargetColumn = "auth_id")
|
||||||
|
private ClubAuthVo clubAuth;
|
||||||
|
}
|
14
src/main/java/org/blue/club/exceptions/ServerException.java
Normal file
14
src/main/java/org/blue/club/exceptions/ServerException.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package org.blue.club.exceptions;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class ServerException extends RuntimeException {
|
||||||
|
private final Result<Void> result;
|
||||||
|
|
||||||
|
public ServerException(Result<Void> result) {
|
||||||
|
super(result.getMsg());
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package org.blue.club.schedule;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.blue.club.dao.redis.AvatarOperationDao;
|
||||||
|
import org.blue.club.dao.redis.VerifyDao;
|
||||||
|
import org.blue.club.entities.vo.VerifyVo;
|
||||||
|
import org.blue.club.entities.vo.data.AvatarTmpVo;
|
||||||
|
import org.blue.club.utils.iop.FileUtils;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RemoveExpireDataSchedule {
|
||||||
|
private final AvatarOperationDao avatarDao;
|
||||||
|
private final File tmpFolder;
|
||||||
|
private final VerifyDao verifyDao;
|
||||||
|
private final FileUtils fileUtils;
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 1000)
|
||||||
|
public void removeTempAvatar() {
|
||||||
|
Instant now = Instant.now();
|
||||||
|
for (AvatarTmpVo avatarTmpVo : avatarDao.findAll()) {
|
||||||
|
Date time = avatarTmpVo.createTime();
|
||||||
|
Instant instant = time.toInstant();
|
||||||
|
Instant expireTime = instant.plus(15, ChronoUnit.MINUTES);
|
||||||
|
if (expireTime.isAfter(now)) {
|
||||||
|
String s = avatarTmpVo.operationCode();
|
||||||
|
File deleteFile = new File(tmpFolder, s);
|
||||||
|
if (deleteFile.exists()) {
|
||||||
|
fileUtils.tryDeleteOrDeleteOnExit(deleteFile);
|
||||||
|
}
|
||||||
|
avatarDao.delete(avatarTmpVo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedDelay = 1000)
|
||||||
|
public void removeExpiredVerify() {
|
||||||
|
Instant now = Instant.now();
|
||||||
|
for (VerifyVo verifyVo : verifyDao.findAll()) {
|
||||||
|
Instant instant = verifyVo.createTime().toInstant();
|
||||||
|
Instant expireTime = instant.plus(15, ChronoUnit.MINUTES);
|
||||||
|
if (expireTime.isAfter(now)) {
|
||||||
|
verifyDao.delete(verifyVo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
src/main/java/org/blue/club/services/AvatarServices.java
Normal file
91
src/main/java/org/blue/club/services/AvatarServices.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package org.blue.club.services;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletOutputStream;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.apache.tomcat.util.buf.HexUtils;
|
||||||
|
import org.blue.club.dao.redis.AvatarOperationDao;
|
||||||
|
import org.blue.club.entities.vo.data.AvatarTmpVo;
|
||||||
|
import org.blue.club.exceptions.ServerException;
|
||||||
|
import org.blue.club.utils.iop.FileUtils;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.mmga.spring.boot.starter.utils.RandomUtils;
|
||||||
|
import org.springframework.http.ContentDisposition;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.security.DigestInputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AvatarServices {
|
||||||
|
private final RandomUtils randomUtils;
|
||||||
|
private final File tmpFolder;
|
||||||
|
private final File avatarFolder;
|
||||||
|
private final AvatarOperationDao avatarOperationDao;
|
||||||
|
private final FileUtils fileUtils;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public Result<String> changeAvatar(MultipartFile file) {
|
||||||
|
String s = randomUtils.generatorRandomFileName(32);
|
||||||
|
DigestInputStream digestInputStream = new DigestInputStream(file.getInputStream(), DigestUtils.getSha1Digest());
|
||||||
|
File tmpFile = new File(tmpFolder, s);
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
|
||||||
|
digestInputStream.transferTo(fos);
|
||||||
|
}
|
||||||
|
MessageDigest messageDigest = digestInputStream.getMessageDigest();
|
||||||
|
String sha1Hex = HexUtils.toHexString(messageDigest.digest());
|
||||||
|
avatarOperationDao.save(new AvatarTmpVo(s, sha1Hex, new Date()));
|
||||||
|
return Result.success("上传成功", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void getAvatar(HttpServletResponse response, String sha1) {
|
||||||
|
File targetFile = new File(avatarFolder, sha1);
|
||||||
|
if (!targetFile.getAbsolutePath().startsWith(avatarFolder.getAbsolutePath())) {
|
||||||
|
Result.failed(HttpStatus.NOT_FOUND, "文件不存在!").writeToResponse(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!targetFile.exists()) {
|
||||||
|
Result.failed(HttpStatus.NOT_FOUND, "文件不存在!").writeToResponse(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try (FileInputStream fileInputStream = new FileInputStream(targetFile)) {
|
||||||
|
response.setContentType("image/png");
|
||||||
|
response.setHeader("Content-Disposition", ContentDisposition.attachment().filename(sha1 + ".png").build().toString());
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
StreamUtils.copy(fileInputStream, outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<String> permanentSaveAvatar(String avatarOperationCode) {
|
||||||
|
Optional<AvatarTmpVo> byId = avatarOperationDao.findById(avatarOperationCode);
|
||||||
|
if (byId.isEmpty()) return Optional.empty();
|
||||||
|
AvatarTmpVo avatarTmpVo = byId.get();
|
||||||
|
File tmpFile = new File(tmpFolder, avatarOperationCode);
|
||||||
|
String sha1 = avatarTmpVo.sha1();
|
||||||
|
File targetFile = new File(avatarFolder, sha1);
|
||||||
|
changeAvatarFile(tmpFile, targetFile);
|
||||||
|
avatarOperationDao.deleteById(avatarOperationCode);
|
||||||
|
return Optional.of(sha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeAvatarFile(File tmpFile, File targetFile) {
|
||||||
|
if (targetFile.exists()) {
|
||||||
|
fileUtils.tryDeleteOrDeleteOnExit(tmpFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tmpFile.renameTo(targetFile))
|
||||||
|
throw new ServerException(Result.failed(HttpStatus.INTERNAL_SERVER_ERROR, "移动头像文件失败!请联系管理员处理"));
|
||||||
|
}
|
||||||
|
}
|
175
src/main/java/org/blue/club/services/ClubServices.java
Normal file
175
src/main/java/org/blue/club/services/ClubServices.java
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package org.blue.club.services;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.paginate.Page;
|
||||||
|
import com.mybatisflex.core.query.QueryCondition;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.blue.club.dao.ClubDao;
|
||||||
|
import org.blue.club.dao.ClubUserAuthDao;
|
||||||
|
import org.blue.club.dao.UserDao;
|
||||||
|
import org.blue.club.entities.dto.club.req.*;
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
import org.blue.club.entities.vo.data.ClubAuthVo;
|
||||||
|
import org.blue.club.entities.vo.data.ClubUserAuthVo;
|
||||||
|
import org.blue.club.entities.vo.data.ClubVo;
|
||||||
|
import org.blue.club.entities.vo.data.UserVo;
|
||||||
|
import org.blue.club.utils.NullableUtils;
|
||||||
|
import org.mmga.spring.boot.starter.entities.PagerData;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||||
|
import org.mmga.spring.boot.starter.utils.VoUtils;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.mybatisflex.core.query.QueryMethods.select;
|
||||||
|
import static org.blue.club.entities.vo.data.table.ClubUserAuthVoTableDef.CLUB_USER_AUTH_VO;
|
||||||
|
import static org.blue.club.entities.vo.data.table.ClubVoTableDef.CLUB_VO;
|
||||||
|
import static org.blue.club.entities.vo.data.table.UserVoTableDef.USER_VO;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class ClubServices {
|
||||||
|
private final ClubDao clubDao;
|
||||||
|
private final ClubUserAuthDao clubUserAuthDao;
|
||||||
|
private final AvatarServices avatarServices;
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final VoUtils voUtils;
|
||||||
|
|
||||||
|
public Result<PagerData<ClubVo>> getClubs(Integer page, Integer num) {
|
||||||
|
Page<ClubVo> data = clubDao.paginate(page, num, QueryCondition.createEmpty());
|
||||||
|
return Result.success(new PagerData<>(data.getTotalRow(), data.getRecords()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<ClubVo> createClub(CreateClubRequest request) {
|
||||||
|
if (clubDao.selectCountByCondition(CLUB_VO.NAME.eq(clubDao)) > 0)
|
||||||
|
return Result.failed(HttpStatus.CONFLICT, "社团名称已存在!");
|
||||||
|
ClubVo clubVo = new ClubVo();
|
||||||
|
clubVo.setName(request.name());
|
||||||
|
return Result.success(clubVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Result<Boolean> clubAddUser(User user, ClubAddUserRequest request) {
|
||||||
|
long requestClubId = request.clubId();
|
||||||
|
long userClubId = -1;
|
||||||
|
ClubVo userClub = user.getClub();
|
||||||
|
if (userClub != null) {
|
||||||
|
userClubId = userClub.getId();
|
||||||
|
}
|
||||||
|
boolean isUserSuperAdmin = user.hasSuperAdminPermission();
|
||||||
|
if (userClubId != requestClubId && !isUserSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
long userClubAuthId = -1;
|
||||||
|
ClubAuthVo clubAuth = user.getClubAuth();
|
||||||
|
if (clubAuth != null) {
|
||||||
|
userClubAuthId = clubAuth.getId();
|
||||||
|
}
|
||||||
|
long requestClubAuthId = request.clubAuthId();
|
||||||
|
if (requestClubAuthId >= userClubAuthId && !isUserSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
long requestUserId = request.userId();
|
||||||
|
if (clubUserAuthDao.selectCountByCondition(CLUB_USER_AUTH_VO.USER_ID.eq(requestUserId)) > 0)
|
||||||
|
return Result.failed(HttpStatus.CONFLICT, "此用户已在社团中");
|
||||||
|
ClubUserAuthVo clubUserAuthVo = new ClubUserAuthVo();
|
||||||
|
clubUserAuthVo.setClubId(requestClubId);
|
||||||
|
clubUserAuthVo.setUserId(requestUserId);
|
||||||
|
clubUserAuthVo.setAuthId(requestClubAuthId);
|
||||||
|
clubUserAuthDao.insert(clubUserAuthVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<PagerData<User>> clubGetUsers(Integer page, Integer num, Long clubId) {
|
||||||
|
if (clubDao.selectCountByCondition(CLUB_VO.ID.eq(clubId)) == 0)
|
||||||
|
return Result.failed(HttpStatus.NOT_FOUND, "社团不存在!");
|
||||||
|
Page<ClubUserAuthVo> paginate = clubUserAuthDao.paginate(page, num, select(CLUB_USER_AUTH_VO.ALL_COLUMNS).where(CLUB_USER_AUTH_VO.CLUB_ID.eq(clubId)).orderBy(CLUB_USER_AUTH_VO.AUTH_ID.asc(), CLUB_USER_AUTH_VO.USER_ID.asc()));
|
||||||
|
long totalRow = paginate.getTotalRow();
|
||||||
|
if (totalRow == 0) return Result.success(new PagerData<>(0, List.of()));
|
||||||
|
List<UserVo> userVos = userDao.selectListWithRelationsByQuery(select(USER_VO.ALL_COLUMNS).from(USER_VO).where(USER_VO.ID.in(paginate.getRecords().stream().map(ClubUserAuthVo::getUserId).toList())));
|
||||||
|
return Result.success(new PagerData<>(totalRow, userVos.stream().map(e -> voUtils.vo2DtoSafe(e, User.class)).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> clubRemoveUser(User user, long clubId, long userId) {
|
||||||
|
ClubUserAuthVo clubUserAuthVo = clubUserAuthDao.selectOneByCondition(CLUB_USER_AUTH_VO.USER_ID.eq(userId).and(CLUB_USER_AUTH_VO.CLUB_ID.eq(clubId)));
|
||||||
|
if (clubUserAuthVo == null) return Result.failed(HttpStatus.NOT_FOUND, "未知用户");
|
||||||
|
boolean isSuperAdmin = user.hasSuperAdminPermission();
|
||||||
|
ClubVo club = user.getClub();
|
||||||
|
long userClubId = NullableUtils.ifNonNullDoElse(club, ClubVo::getId, clubId);
|
||||||
|
if (userClubId != clubId && !isSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
Long authId = clubUserAuthVo.getAuthId();
|
||||||
|
ClubAuthVo clubAuth = user.getClubAuth();
|
||||||
|
Long clubAuthId = NullableUtils.ifNonNullDoElse(clubAuth, ClubAuthVo::getId, -1L);
|
||||||
|
if (clubAuthId <= authId && !isSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
clubUserAuthDao.deleteByCondition(CLUB_USER_AUTH_VO.USER_ID.eq(userId).and(CLUB_USER_AUTH_VO.CLUB_ID.eq(clubId)));
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> clubChangeUserAuth(User user, ClubChangeUserAuthRequest request) {
|
||||||
|
long targetUserId = request.userId();
|
||||||
|
long targetClubId = request.clubId();
|
||||||
|
ClubUserAuthVo clubUserAuthVo = clubUserAuthDao.selectOneByCondition(CLUB_USER_AUTH_VO.USER_ID.eq(targetUserId).and(CLUB_USER_AUTH_VO.CLUB_ID.eq(targetClubId)));
|
||||||
|
if (clubUserAuthVo == null) return Result.failed(HttpStatus.NOT_FOUND, "未知用户");
|
||||||
|
long originalClubAuthId = NullableUtils.ifNonNullDoElse(clubUserAuthVo, ClubUserAuthVo::getAuthId, -1L);
|
||||||
|
long targetClubAuthId = request.newAuthId();
|
||||||
|
long operatorClubAuthId = NullableUtils.ifNonNullDoElse(user.getClubAuth(), ClubAuthVo::getId, -1L);
|
||||||
|
long operatorClubId = NullableUtils.ifNonNullDoElse(user.getClub(), ClubVo::getId, -1L);
|
||||||
|
boolean isSuperAdmin = user.hasSuperAdminPermission();
|
||||||
|
// 不能修改和此用户社团不同的社团的用户
|
||||||
|
if (operatorClubId != targetClubId && !isSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
// 不能修改原始权限比操作者更高的用户
|
||||||
|
if (originalClubAuthId >= operatorClubAuthId && !isSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
// 当目标权限比操作者更高时不允许修改
|
||||||
|
if (targetClubAuthId >= operatorClubAuthId && !isSuperAdmin)
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
clubUserAuthVo.setAuthId(targetClubAuthId);
|
||||||
|
clubUserAuthDao.updateByCondition(clubUserAuthVo, CLUB_USER_AUTH_VO.USER_ID.eq(targetUserId).and(CLUB_USER_AUTH_VO.CLUB_ID.eq(targetClubId)));
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> changeAvatar(String avatarOperationCode, long clubId, User user) {
|
||||||
|
long operatorUserClubId = NullableUtils.ifNonNullDoElse(user.getClub(), ClubVo::getId, -1L);
|
||||||
|
if (clubId != operatorUserClubId && !user.hasSuperAdminPermission())
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
Optional<String> result = avatarServices.permanentSaveAvatar(avatarOperationCode);
|
||||||
|
if (result.isEmpty()) return Result.failed(HttpStatus.NOT_FOUND, "操作码错误或过期");
|
||||||
|
ClubVo clubVo = new ClubVo();
|
||||||
|
clubVo.setId(clubId);
|
||||||
|
clubVo.setAvatar(result.get());
|
||||||
|
clubDao.update(clubVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> changeName(ChangeClubNameRequest request) {
|
||||||
|
long clubId = request.clubId();
|
||||||
|
String newName = request.name();
|
||||||
|
ClubVo clubVo = new ClubVo();
|
||||||
|
clubVo.setId(clubId);
|
||||||
|
clubVo.setName(newName);
|
||||||
|
clubDao.update(clubVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> changeCommit(ChangeClubCommitRequest request, User user) {
|
||||||
|
long operatorUserClubId = NullableUtils.ifNonNullDoElse(user.getClub(), ClubVo::getId, -1L);
|
||||||
|
long clubId = request.clubId();
|
||||||
|
if (clubId != operatorUserClubId && !user.hasSuperAdminPermission())
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
ClubVo clubVo = new ClubVo();
|
||||||
|
clubVo.setId(clubId);
|
||||||
|
clubVo.setCommit(request.commit());
|
||||||
|
clubDao.update(clubVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<ClubVo> getClub(long id) {
|
||||||
|
return Result.success(clubDao.selectOneById(id));
|
||||||
|
}
|
||||||
|
}
|
168
src/main/java/org/blue/club/services/UserServices.java
Normal file
168
src/main/java/org/blue/club/services/UserServices.java
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package org.blue.club.services;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.paginate.Page;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.blue.club.dao.UserDao;
|
||||||
|
import org.blue.club.dao.redis.VerifyDao;
|
||||||
|
import org.blue.club.entities.dto.user.User;
|
||||||
|
import org.blue.club.entities.dto.user.req.*;
|
||||||
|
import org.blue.club.entities.dto.user.resp.VerifyCodeResponse;
|
||||||
|
import org.blue.club.entities.vo.VerifyVo;
|
||||||
|
import org.blue.club.entities.vo.data.UserVo;
|
||||||
|
import org.blue.club.utils.iop.VerifyCodeUtils;
|
||||||
|
import org.mmga.spring.boot.starter.entities.PagerData;
|
||||||
|
import org.mmga.spring.boot.starter.entities.Result;
|
||||||
|
import org.mmga.spring.boot.starter.exception.AuthorizationException;
|
||||||
|
import org.mmga.spring.boot.starter.properties.Env;
|
||||||
|
import org.mmga.spring.boot.starter.properties.MainProperties;
|
||||||
|
import org.mmga.spring.boot.starter.utils.VoUtils;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.mybatisflex.core.query.QueryMethods.select;
|
||||||
|
import static org.blue.club.entities.vo.data.table.ClubUserAuthVoTableDef.CLUB_USER_AUTH_VO;
|
||||||
|
import static org.blue.club.entities.vo.data.table.UserVoTableDef.USER_VO;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class UserServices {
|
||||||
|
private final UserDao userDao;
|
||||||
|
private final VerifyDao verifyDao;
|
||||||
|
private final VoUtils voUtils;
|
||||||
|
private final VerifyCodeUtils verifyCodeUtils;
|
||||||
|
private final MainProperties mainProperties;
|
||||||
|
private final AvatarServices avatarServices;
|
||||||
|
|
||||||
|
private boolean isWrongVerifyCode(String key, String code) {
|
||||||
|
if (mainProperties.getEnv().equals(Env.DEV)) return false;
|
||||||
|
Optional<VerifyVo> targetCode = verifyDao.findById(key);
|
||||||
|
if (targetCode.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
verifyDao.deleteById(key);
|
||||||
|
return !targetCode.get().answer().equals(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Result<User> login(LoginRequest loginRequest) {
|
||||||
|
if (this.isWrongVerifyCode(loginRequest.key(), loginRequest.code())) {
|
||||||
|
return Result.failed(HttpStatus.FORBIDDEN, "错误的验证码");
|
||||||
|
}
|
||||||
|
UserVo userVo = userDao.selectOneWithRelationsByCondition(USER_VO.NAME.eq(loginRequest.username()).and(USER_VO.PASSWORD.eq(loginRequest.sha1HexPassword())));
|
||||||
|
if (userVo == null) return Result.failed(HttpStatus.NOT_FOUND, "用户不存在!");
|
||||||
|
User user = voUtils.vo2DtoSafe(userVo, User.class);
|
||||||
|
return Result.success(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Result<User> createUser(RegisterRequest request) {
|
||||||
|
if (this.isWrongVerifyCode(request.key(), request.code())) {
|
||||||
|
return Result.failed(HttpStatus.FORBIDDEN, "错误的验证码");
|
||||||
|
}
|
||||||
|
if (userDao.selectCountByCondition(USER_VO.NAME.eq(request.username())) > 0) {
|
||||||
|
return Result.failed(HttpStatus.CONFLICT, "用户已存在");
|
||||||
|
}
|
||||||
|
UserVo userVo = new UserVo();
|
||||||
|
userVo.setName(request.username());
|
||||||
|
userVo.setPassword(request.sha1HexPassword());
|
||||||
|
userVo.setAuth(request.auth());
|
||||||
|
userDao.insert(userVo);
|
||||||
|
System.out.println(userVo);
|
||||||
|
UserVo insertedUserData = userDao.selectOneWithRelationsById(userVo.getId());
|
||||||
|
return Result.success(voUtils.vo2DtoSafe(insertedUserData, User.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<PagerData<User>> getAllUserInfo(int num, int page, boolean onlyNoClub) {
|
||||||
|
QueryWrapper from = select(USER_VO.ALL_COLUMNS).from(USER_VO);
|
||||||
|
if (onlyNoClub) {
|
||||||
|
from.leftJoin(CLUB_USER_AUTH_VO).on(CLUB_USER_AUTH_VO.USER_ID.eq(USER_VO.ID)).where(CLUB_USER_AUTH_VO.CLUB_ID.isNull());
|
||||||
|
}
|
||||||
|
Page<UserVo> userVoPage = userDao.paginateWithRelations(page, num, from);
|
||||||
|
long totalRow = userVoPage.getTotalRow();
|
||||||
|
List<UserVo> records = userVoPage.getRecords();
|
||||||
|
return Result.success(new PagerData<>(totalRow, records.stream().map(e -> voUtils.vo2DtoSafe(e, User.class)).toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> changeUsername(UserRenameRequest renameVo, User user) {
|
||||||
|
Long id = renameVo.getId();
|
||||||
|
Long operatorId = user.getId();
|
||||||
|
if (id == null) id = operatorId;
|
||||||
|
if (!operatorId.equals(id) && !user.hasPermission(4L))
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "权限不足!"));
|
||||||
|
String s = renameVo.getNewName();
|
||||||
|
if (userDao.selectCountByCondition(USER_VO.NAME.eq(s)) > 0)
|
||||||
|
return Result.failed(HttpStatus.CONFLICT, "用户名已存在!");
|
||||||
|
UserVo userVo = new UserVo();
|
||||||
|
userVo.setId(id);
|
||||||
|
userVo.setName(s);
|
||||||
|
userDao.update(userVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> changePassword(UserChangePasswordRequest changePasswordVo, User user) {
|
||||||
|
UserChangePasswordRequest shaHex = changePasswordVo.sha1HexPassword();
|
||||||
|
String newPassword = shaHex.getNewPassword();
|
||||||
|
String oldPassword = shaHex.getOldPassword();
|
||||||
|
Long id = changePasswordVo.getId();
|
||||||
|
UserVo newUserVo = new UserVo();
|
||||||
|
newUserVo.setId(id);
|
||||||
|
newUserVo.setPassword(newPassword);
|
||||||
|
if (user.hasPermission(4L)) {
|
||||||
|
userDao.update(newUserVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
Long operatorUserId = user.getId();
|
||||||
|
if (oldPassword == null || !id.equals(operatorUserId))
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.UNAUTHORIZED, "权限不足!"));
|
||||||
|
if (userDao.selectCountByCondition(USER_VO.ID.eq(operatorUserId)) <= 0)
|
||||||
|
return Result.failed(HttpStatus.NOT_FOUND, "旧密码不匹配");
|
||||||
|
userDao.update(newUserVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Boolean> changeAuth(UserChangeAuthRequest userChangeAuthVo) {
|
||||||
|
UserVo userVo = new UserVo();
|
||||||
|
userVo.setId(userChangeAuthVo.id());
|
||||||
|
userVo.setAuth(userChangeAuthVo.authId());
|
||||||
|
userDao.update(userVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Result<Boolean> changeAvatar(String avatarOperationCode, long userId, User user) {
|
||||||
|
long operatorUserId = user.getId();
|
||||||
|
if (userId == -1) {
|
||||||
|
userId = operatorUserId;
|
||||||
|
}
|
||||||
|
if (userId != operatorUserId && !user.hasSuperAdminPermission())
|
||||||
|
throw new AuthorizationException(Result.failed(HttpStatus.FORBIDDEN, "权限不足!"));
|
||||||
|
Optional<String> result = avatarServices.permanentSaveAvatar(avatarOperationCode);
|
||||||
|
if (result.isEmpty()) return Result.failed(HttpStatus.NOT_FOUND, "操作码错误或过期");
|
||||||
|
UserVo userVo = new UserVo();
|
||||||
|
userVo.setId(userId);
|
||||||
|
userVo.setAvatar(result.get());
|
||||||
|
userDao.update(userVo);
|
||||||
|
return Result.success(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Result<VerifyCodeResponse> getVerifyCode() {
|
||||||
|
VerifyCodeResponse verifyCodeResponse = verifyCodeUtils.generateVerifyCode();
|
||||||
|
return Result.success(verifyCodeResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Result<User> getUserInfo(int userId) {
|
||||||
|
UserVo userVo = userDao.selectOneWithRelationsById(userId);
|
||||||
|
if (userVo == null) return Result.failed("用户不存在!");
|
||||||
|
User user = voUtils.vo2DtoSafe(userVo, User.class);
|
||||||
|
return Result.success(user);
|
||||||
|
}
|
||||||
|
}
|
12
src/main/java/org/blue/club/utils/NullableUtils.java
Normal file
12
src/main/java/org/blue/club/utils/NullableUtils.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package org.blue.club.utils;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class NullableUtils {
|
||||||
|
public static <T, R> R ifNonNullDoElse(@Nullable T value, Function<? super T, ? extends R> handle, R defaultValue) {
|
||||||
|
if (value == null) return defaultValue;
|
||||||
|
return handle.apply(value);
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
package org.mmga.clubs.utils;
|
package org.blue.club.utils;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import jakarta.websocket.Session;
|
import jakarta.websocket.Session;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.mmga.clubs.entities.chess.packet.BaseWebSocketPacket;
|
import org.blue.club.entities.dto.chess.packet.BaseWebSocketPacket;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
16
src/main/java/org/blue/club/utils/iop/FileUtils.java
Normal file
16
src/main/java/org/blue/club/utils/iop/FileUtils.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package org.blue.club.utils.iop;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class FileUtils {
|
||||||
|
public void tryDeleteOrDeleteOnExit(File file) {
|
||||||
|
if (file.delete()) return;
|
||||||
|
log.warn("删除文件{}失败,尝试在退出时删除", file.getAbsolutePath());
|
||||||
|
file.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
64
src/main/java/org/blue/club/utils/iop/VerifyCodeUtils.java
Normal file
64
src/main/java/org/blue/club/utils/iop/VerifyCodeUtils.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package org.blue.club.utils.iop;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.apache.commons.codec.binary.Base64OutputStream;
|
||||||
|
import org.blue.club.dao.redis.VerifyDao;
|
||||||
|
import org.blue.club.entities.dto.user.resp.VerifyCodeResponse;
|
||||||
|
import org.blue.club.entities.vo.VerifyVo;
|
||||||
|
import org.mmga.spring.boot.starter.utils.RandomUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VerifyCodeUtils {
|
||||||
|
public static final int width = 120;
|
||||||
|
public static final int height = 40;
|
||||||
|
public static final int fontSize = 25;
|
||||||
|
public static final Font mainFont = new Font("宋体", Font.BOLD, fontSize);
|
||||||
|
|
||||||
|
private final RandomUtils randomUtils;
|
||||||
|
private final VerifyDao verifyDao;
|
||||||
|
|
||||||
|
private void setToRandomColor(Graphics g) {
|
||||||
|
Random random = new Random();
|
||||||
|
g.setColor(new Color(20 + random.nextInt(120), 20 + random.nextInt(120), 20 + random.nextInt(120)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public VerifyCodeResponse generateVerifyCode() {
|
||||||
|
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics g = image.createGraphics();
|
||||||
|
g.setFont(mainFont);
|
||||||
|
String text = randomUtils.generatorRandomFileName(4);
|
||||||
|
int x = 0;
|
||||||
|
for (char c : text.toCharArray()) {
|
||||||
|
Random random = new Random();
|
||||||
|
setToRandomColor(g);
|
||||||
|
g.drawString(c + "", 15 + x * 20, 20 + new Random().nextInt(10));
|
||||||
|
for (int j = 0; j < random.nextInt(3, 7); j++) {
|
||||||
|
setToRandomColor(g);
|
||||||
|
g.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
g.dispose();
|
||||||
|
String s = randomUtils.generatorRandomString(32);
|
||||||
|
|
||||||
|
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); Base64OutputStream base64OutputStream = new Base64OutputStream(byteArrayOutputStream)) {
|
||||||
|
ImageIO.write(image, "png", base64OutputStream);
|
||||||
|
base64OutputStream.flush();
|
||||||
|
String base64 = byteArrayOutputStream.toString(StandardCharsets.UTF_8);
|
||||||
|
verifyDao.save(new VerifyVo(s, text, new Date()));
|
||||||
|
return new VerifyCodeResponse(base64, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user