slambb пре 3 година
комит
e81559e5cc
100 измењених фајлова са 5280 додато и 0 уклоњено
  1. 3 0
      .gitattributes
  2. 33 0
      .gitignore
  3. 182 0
      mvnw.cmd
  4. 187 0
      pom.xml
  5. 261 0
      src/main/java/com/td/WaDa/BossApplication.java
  6. 21 0
      src/main/java/com/td/WaDa/annotation/Between.java
  7. 12 0
      src/main/java/com/td/WaDa/annotation/Decrypt.java
  8. 12 0
      src/main/java/com/td/WaDa/annotation/Encrypt.java
  9. 16 0
      src/main/java/com/td/WaDa/annotation/In.java
  10. 13 0
      src/main/java/com/td/WaDa/annotation/Like.java
  11. 170 0
      src/main/java/com/td/WaDa/aspect/SafetyAspect.java
  12. 77 0
      src/main/java/com/td/WaDa/common/controller/CommonController.java
  13. 16 0
      src/main/java/com/td/WaDa/common/pojo/ComConfig.java
  14. 27 0
      src/main/java/com/td/WaDa/common/pojo/CultivateKeys.java
  15. 22 0
      src/main/java/com/td/WaDa/common/pojo/IpVo.java
  16. 31 0
      src/main/java/com/td/WaDa/common/pojo/MonitorVo.java
  17. 39 0
      src/main/java/com/td/WaDa/common/pojo/PageCondition.java
  18. 62 0
      src/main/java/com/td/WaDa/common/pojo/PageInfo.java
  19. 42 0
      src/main/java/com/td/WaDa/common/pojo/ParameterRequestWrapper.java
  20. 74 0
      src/main/java/com/td/WaDa/common/pojo/Result.java
  21. 14 0
      src/main/java/com/td/WaDa/common/repository/ComConfigRepository.java
  22. 16 0
      src/main/java/com/td/WaDa/common/repository/CommonRepository.java
  23. 23 0
      src/main/java/com/td/WaDa/common/service/ComConfigService.java
  24. 89 0
      src/main/java/com/td/WaDa/common/service/ComConfigServiceImpl.java
  25. 27 0
      src/main/java/com/td/WaDa/common/service/CommonService.java
  26. 159 0
      src/main/java/com/td/WaDa/common/service/CommonServiceImpl.java
  27. 27 0
      src/main/java/com/td/WaDa/config/async/AsyncConfig.java
  28. 137 0
      src/main/java/com/td/WaDa/config/enums/ResultEnum.java
  29. 25 0
      src/main/java/com/td/WaDa/config/exception/AuthorizeException.java
  30. 175 0
      src/main/java/com/td/WaDa/config/logback/LoggingWSServer.java
  31. 104 0
      src/main/java/com/td/WaDa/config/monitor/MonitorWSServer.java
  32. 166 0
      src/main/java/com/td/WaDa/config/security/CaptchaFilterConfig.java
  33. 88 0
      src/main/java/com/td/WaDa/config/security/DynamicallyUrlInterceptor.java
  34. 55 0
      src/main/java/com/td/WaDa/config/security/ErrorPageConfig.java
  35. 70 0
      src/main/java/com/td/WaDa/config/security/LoginFailureHandlerConfig.java
  36. 154 0
      src/main/java/com/td/WaDa/config/security/LoginSuccessHandlerConfig.java
  37. 37 0
      src/main/java/com/td/WaDa/config/security/LogoutHandlerConfig.java
  38. 56 0
      src/main/java/com/td/WaDa/config/security/MyAccessDecisionManager.java
  39. 77 0
      src/main/java/com/td/WaDa/config/security/MyFilterInvocationSecurityMetadataSource.java
  40. 51 0
      src/main/java/com/td/WaDa/config/security/MyInvalidSessionStrategy.java
  41. 20 0
      src/main/java/com/td/WaDa/config/security/PasswordConfig.java
  42. 148 0
      src/main/java/com/td/WaDa/config/security/SecurityConfig.java
  43. 51 0
      src/main/java/com/td/WaDa/config/security/UserConfig.java
  44. 51 0
      src/main/java/com/td/WaDa/config/security/gameConfig.java
  45. 34 0
      src/main/java/com/td/WaDa/config/token/WebConfig.java
  46. 26 0
      src/main/java/com/td/WaDa/config/websocket/MyEndpointConfigure.java
  47. 32 0
      src/main/java/com/td/WaDa/config/websocket/WebSocketConfig.java
  48. 184 0
      src/main/java/com/td/WaDa/filter/gameFilter.java
  49. 15 0
      src/main/java/com/td/WaDa/game/comcntorder/controller/ComCntOrderController.java
  50. 33 0
      src/main/java/com/td/WaDa/game/comcntorder/pojo/ComCntOrder.java
  51. 40 0
      src/main/java/com/td/WaDa/game/comcntorder/repository/ComCntOrderRepository.java
  52. 25 0
      src/main/java/com/td/WaDa/game/comcntorder/service/ComCntOrderService.java
  53. 54 0
      src/main/java/com/td/WaDa/game/comcntorder/service/ComCntOrderServiceImpl.java
  54. 18 0
      src/main/java/com/td/WaDa/game/comcntorder/vo/ComCntOrderDateVo.java
  55. 23 0
      src/main/java/com/td/WaDa/game/comcntorder/vo/ComCntOrderPayTypeSumVo.java
  56. 28 0
      src/main/java/com/td/WaDa/game/comcntorder/vo/ComCntOrderVo.java
  57. 29 0
      src/main/java/com/td/WaDa/game/comcnttosnb/controller/ComCntToSnbController.java
  58. 52 0
      src/main/java/com/td/WaDa/game/comcnttosnb/pojo/ComCntToSnb.java
  59. 11 0
      src/main/java/com/td/WaDa/game/comcnttosnb/repository/ComCntToSnbRespository.java
  60. 37 0
      src/main/java/com/td/WaDa/game/comcnttosnb/service/ComCntToSnbService.java
  61. 185 0
      src/main/java/com/td/WaDa/game/comcnttosnb/service/ComCntToSnbServiceImpl.java
  62. 50 0
      src/main/java/com/td/WaDa/game/comcnttosnb/vo/ComCntToSnbVo.java
  63. 31 0
      src/main/java/com/td/WaDa/game/comconfigland/controller/ComConfigLandController.java
  64. 55 0
      src/main/java/com/td/WaDa/game/comconfigland/pojo/ComConfigLand.java
  65. 9 0
      src/main/java/com/td/WaDa/game/comconfigland/repository/ComConfigLandRepository.java
  66. 13 0
      src/main/java/com/td/WaDa/game/comconfigland/service/ComConfigLandService.java
  67. 33 0
      src/main/java/com/td/WaDa/game/comconfigland/service/ComConfigLandServiceImpl.java
  68. 54 0
      src/main/java/com/td/WaDa/game/comconfigland/vo/ComConfigLandVo.java
  69. 15 0
      src/main/java/com/td/WaDa/game/comexplainland/controller/ComExplainLandController.java
  70. 52 0
      src/main/java/com/td/WaDa/game/comexplainland/pojo/ComExplainLand.java
  71. 9 0
      src/main/java/com/td/WaDa/game/comexplainland/repository/ComExplainLandRepository.java
  72. 8 0
      src/main/java/com/td/WaDa/game/comexplainland/service/ComExplainLandService.java
  73. 21 0
      src/main/java/com/td/WaDa/game/comexplainland/service/ComExplainLandServiceImpl.java
  74. 48 0
      src/main/java/com/td/WaDa/game/comexplainland/vo/ComExplainLandVo.java
  75. 15 0
      src/main/java/com/td/WaDa/game/comfruit/controller/ComFruitController.java
  76. 30 0
      src/main/java/com/td/WaDa/game/comfruit/pojo/ComFruit.java
  77. 9 0
      src/main/java/com/td/WaDa/game/comfruit/repository/ComFruitRepository.java
  78. 13 0
      src/main/java/com/td/WaDa/game/comfruit/service/ComFruitService.java
  79. 40 0
      src/main/java/com/td/WaDa/game/comfruit/service/ComFruitServiceImpl.java
  80. 37 0
      src/main/java/com/td/WaDa/game/comfruit/vo/ComFruitAmountVo.java
  81. 25 0
      src/main/java/com/td/WaDa/game/comfruit/vo/ComFruitVo.java
  82. 35 0
      src/main/java/com/td/WaDa/game/commallfood/controller/ComMallFoodController.java
  83. 36 0
      src/main/java/com/td/WaDa/game/commallfood/pojo/ComMallFood.java
  84. 9 0
      src/main/java/com/td/WaDa/game/commallfood/repository/ComMallFoodRepository.java
  85. 8 0
      src/main/java/com/td/WaDa/game/commallfood/service/ComMallFoodService.java
  86. 21 0
      src/main/java/com/td/WaDa/game/commallfood/service/ComMallFoodServiceImpl.java
  87. 32 0
      src/main/java/com/td/WaDa/game/commallfood/vo/ComMallFoodSimpleVo.java
  88. 31 0
      src/main/java/com/td/WaDa/game/commallfood/vo/ComMallFoodVo.java
  89. 34 0
      src/main/java/com/td/WaDa/game/commallother/controller/ComMallOtherController.java
  90. 38 0
      src/main/java/com/td/WaDa/game/commallother/pojo/ComMallOther.java
  91. 13 0
      src/main/java/com/td/WaDa/game/commallother/repository/ComMallOtherRepository.java
  92. 11 0
      src/main/java/com/td/WaDa/game/commallother/service/ComMallOtherService.java
  93. 27 0
      src/main/java/com/td/WaDa/game/commallother/service/ComMallOtherServiceImpl.java
  94. 34 0
      src/main/java/com/td/WaDa/game/commallother/vo/ComMallOtherSimpleVo.java
  95. 33 0
      src/main/java/com/td/WaDa/game/commallother/vo/ComMallOtherVo.java
  96. 291 0
      src/main/java/com/td/WaDa/game/commallseed/controller/ComMallSeedController.java
  97. 50 0
      src/main/java/com/td/WaDa/game/commallseed/pojo/ComMallSeed.java
  98. 9 0
      src/main/java/com/td/WaDa/game/commallseed/repository/ComMallSeedRepository.java
  99. 14 0
      src/main/java/com/td/WaDa/game/commallseed/service/ComMallSeedService.java
  100. 41 0
      src/main/java/com/td/WaDa/game/commallseed/service/ComMallSeedServiceImpl.java

+ 3 - 0
.gitattributes

@@ -0,0 +1,3 @@
+*.js linguist-language=Java
+*.css linguist-language=Java
+*.html linguist-language=Java

+ 33 - 0
.gitignore

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

+ 182 - 0
mvnw.cmd

@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Found %WRAPPER_JAR%
+    )
+) else (
+    if not "%MVNW_REPOURL%" == "" (
+        SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %DOWNLOAD_URL%
+    )
+
+    powershell -Command "&{"^
+		"$webclient = new-object System.Net.WebClient;"^
+		"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+		"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+		"}"^
+		"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%

+ 187 - 0
pom.xml

@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.4.3</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.td</groupId>
+    <artifactId>WaDa</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>WaDa</name>
+    <description>Demo project for Spring Boot</description>
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.22</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.20</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.vaadin.external.google</groupId>
+                    <artifactId>android-json</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+		        <!--热部署工具dev-tools-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional>
+            <scope>runtime</scope>
+        </dependency>
+
+        <!-- security安全校验 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!--jwt-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
+
+        <!-- thymeleaf模板 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+
+        <!--添加springdata-jpa依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+        </dependency>
+
+        <!--添加MySQL驱动依赖 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.13</version>
+        </dependency>
+
+        <!-- CopyUtil需要用到 -->
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
+            <version>3.2.2</version>
+        </dependency>
+
+        <!-- springboot websocket -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+
+        <!-- Base64编码需要  -->
+        <dependency>
+            <groupId>org.apache.directory.studio</groupId>
+            <artifactId>org.apache.commons.codec</artifactId>
+            <version>1.8</version>
+        </dependency>
+
+        <!--提供更多的加密、填充方式-->
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk16</artifactId>
+            <version>1.46</version>
+        </dependency>
+
+        <!--aop 面向切面-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!--https://github.com/oshi/oshi。-->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-json</artifactId>
+            <version>3.6.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.60</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.9</version>
+        </dependency>
+
+        <!--redis 处理分布式锁等相关问题-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>SNTown</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+			<!-- 跳过启动测试 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <skipTests>true</skipTests>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 261 - 0
src/main/java/com/td/WaDa/BossApplication.java

@@ -0,0 +1,261 @@
+package com.td.WaDa;
+import com.td.WaDa.common.service.ComConfigService;
+import com.td.WaDa.game.comusers.service.ComUsersService;
+import com.td.WaDa.sys.sysmenu.vo.SysMenuVo;
+import com.td.WaDa.sys.syssetting.service.SysSettingService;
+import com.td.WaDa.sys.syssettinglimit.service.SysSettingLimitService;
+import com.td.WaDa.sys.syssettingtask.service.SysSettingTaskService;
+import com.td.WaDa.sys.sysshortcutmenu.service.SysShortcutMenuService;
+import com.td.WaDa.sys.sysshortcutmenu.vo.SysShortcutMenuVo;
+import com.td.WaDa.sys.sysuser.service.SysUserService;
+import com.td.WaDa.sys.sysuser.vo.SysUserVo;
+import com.td.WaDa.sys.sysusermenu.service.SysUserMenuService;
+import com.td.WaDa.util.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+
+@EnableAsync//开启异步调用
+@EnableCaching// 开启缓存,需要显示的指定
+@EnableScheduling
+@SpringBootApplication
+public class BossApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(BossApplication.class, args);
+    }
+
+    /**
+     * 解决不能注入session注册表问题
+     */
+    @Bean
+    SessionRegistry sessionRegistry() {
+        return new SessionRegistryImpl();
+    }
+}
+
+@Slf4j
+@Controller
+@RequestMapping("/")
+@Configuration
+class IndexController {
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @Autowired
+    private SysSettingService sysSettingService;
+
+    @Autowired
+    private SysSettingTaskService sysSettingTaskService;
+
+    @Autowired
+    private SysSettingLimitService sysSettingLimitService;
+
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    @Autowired
+    private SysUserMenuService sysUserMenuService;
+
+    @Autowired
+    private SysShortcutMenuService sysShortcutMenuService;
+
+    @Autowired
+    private ComUsersService comUsersService;
+
+    @Autowired
+    private ComConfigService comConfigService;
+
+    @Value("${server.servlet.context-path:}")
+    private String contextPath;
+
+
+    /**
+     * 端口
+     */
+    @Value("${server.port}")
+    private String port;
+
+    /**
+     * 启动成功
+     */
+    @Bean
+    public ApplicationRunner applicationRunner() {
+        return applicationArguments -> {
+            try {
+                /**
+                 * 当启动时候,向主redis设置一次数据。
+                 */
+                ////系统启动时获取数据库数据,设置到公用静态集合sysSettingMap
+                ////SysSettingVo sysSettingVo = sysSettingService.get("1").getData();
+                ////SysSettingUtil.setSysSettingMap(sysSettingVo);
+                //redisSettingMap.updateSysSettingMap();
+                //log.info(redisSettingMap.getSysSettingMap().toString());
+                ////系统启动时获取数据库数据,设置到公用静态集合sysSettingTaskMap
+                ////SysSettingTaskVo sysSettingTaskVo = sysSettingTaskService.get("1").getData();
+                ////SysSettingTaskUtil.setSysSettingTaskMap(sysSettingTaskVo);
+                //redisSettingMap.updateSysSettingTaskMap();
+                //log.info(redisSettingMap.getSysSettingTaskMap().toString());
+                ////限制登录ip
+                ////SysSettingLimitVo sysSettingLimitVo = sysSettingLimitService.get("1").getData();
+                ////SysSettingLimitUtil.setSysSettingLimitMap(sysSettingLimitVo);
+                //redisSettingMap.updateSysSettingLimitMap();
+                //log.info(redisSettingMap.getSysSettingLimitMap().toString());
+                ////更新com config 的 Redis数据
+                //comConfigService.updateList();
+                ////更新com setting 的redis数据
+                //redisSettingMap.updateComSettingMap();
+                //获取本机内网IP
+                log.info("启动成功:" + "http://" + InetAddress.getLocalHost().getHostAddress() + ":" + port + contextPath);
+            } catch (UnknownHostException e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+        };
+    }
+
+    /**
+     * 跳转登录页面
+     */
+    @GetMapping("loginPage")
+    public ModelAndView login(){
+        ModelAndView modelAndView = new ModelAndView("login");
+
+        //系统信息 SysSettingUtil.getSysSetting()
+        modelAndView.addObject("sys",redisSettingMap.getSysSettingMap());
+
+        //系统审查信息 SysSettingTaskUtil.getSysSettingTask()
+        modelAndView.addObject("sysSettingTask", redisSettingMap.getSysSettingTaskMap());
+
+        //系统限制信息 SysSettingLimitUtil.getSysSettingLimit()
+        modelAndView.addObject("sysSettingLimit", redisSettingMap.getSysSettingLimitMap());
+
+
+        //后端公钥
+        String publicKey = RsaUtil.getPublicKey();
+        log.info("login后端公钥:" + publicKey);
+        modelAndView.addObject("publicKey", publicKey);
+
+        return modelAndView;
+    }
+
+    /**
+     * 跳转首页
+     */
+    @GetMapping("")
+    public void index1(HttpServletResponse response){
+        //内部重定向
+        try {
+            response.sendRedirect(contextPath+"/index");
+        } catch (IOException e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+    }
+    @GetMapping("index")
+    public ModelAndView index(){
+        ModelAndView modelAndView = new ModelAndView("index");
+
+        //系统信息 SysSettingUtil.getSysSetting()
+        modelAndView.addObject("sys",redisSettingMap.getSysSettingMap());
+
+        //系统审查信息 SysSettingTaskUtil.getSysSettingTask()
+        modelAndView.addObject("sysSettingTask", redisSettingMap.getSysSettingTaskMap());
+
+        //系统限制信息 SysSettingLimitUtil.getSysSettingLimit()
+        modelAndView.addObject("sysSettingLimit", redisSettingMap.getSysSettingLimitMap());
+
+        //登录用户
+        SysUserVo sysUserVo = sysUserService.findByLoginName(SecurityUtil.getLoginUser().getUsername()).getData();
+        sysUserVo.setPassword(null);//隐藏部分属性
+        modelAndView.addObject( "loginUser", sysUserVo);
+
+        //登录用户系统菜单
+        List<SysMenuVo> menuVoList = sysUserMenuService.findByUserId(sysUserVo.getUserId()).getData();
+        modelAndView.addObject("menuList",menuVoList);
+
+        //登录用户快捷菜单
+        List<SysShortcutMenuVo> shortcutMenuVoList= sysShortcutMenuService.findByUserId(sysUserVo.getUserId()).getData();
+        modelAndView.addObject("shortcutMenuList",shortcutMenuVoList);
+
+        //后端公钥
+        String publicKey = RsaUtil.getPublicKey();
+        log.info("index后端公钥:" + publicKey);
+        modelAndView.addObject("publicKey", publicKey);
+
+        //获取一个全平台的用户数据
+        Long allComUserCount =  comUsersService.findAllCount();
+        modelAndView.addObject("allComUserCount", allComUserCount);
+
+        Long todayComUserCount = comUsersService.newToday();
+        modelAndView.addObject("todayComUserCount", todayComUserCount);
+
+
+        return modelAndView;
+    }
+
+    /**
+     * 获取验证码图片和文本(验证码文本会保存在HttpSession中)
+     */
+    @RequestMapping("getVerifyCodeImage")
+    public void getVerifyCodeImage(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        //设置页面不缓存
+        response.setHeader("Pragma", "no-cache");
+        response.setHeader("Cache-Control", "no-cache");
+        response.setDateHeader("Expires", 0);
+        response.getOutputStream();
+        String verifyCode = VerifyCodeImageUtil.generateTextCode(VerifyCodeImageUtil.TYPE_NUM_UPPER, 4, null);
+
+        //将验证码放到HttpSession里面
+        request.getSession().setAttribute("verifyCode", verifyCode);
+         log.info("本次生成的验证码为:" + verifyCode + ",已存放到HttpSession中");
+
+        //设置输出的内容的类型为JPEG图像
+        response.setContentType("image/jpeg");
+        BufferedImage bufferedImage = VerifyCodeImageUtil.generateImageCode(verifyCode, 90, 30, 3, true, Color.WHITE, Color.BLACK, null);
+
+        //写给浏览器
+        ImageIO.write(bufferedImage, "JPEG", response.getOutputStream());
+    }
+
+    /**
+     * 跳转实时系统硬件监控
+     */
+    @GetMapping("monitor")
+    public ModelAndView monitor() {
+        return new ModelAndView("monitor.html","port",port);
+    }
+
+    /**
+     * 跳转实时日志
+     */
+    @GetMapping("logging")
+    public ModelAndView logging() {
+        return new ModelAndView("logging.html","port",port);
+    }
+}

+ 21 - 0
src/main/java/com/td/WaDa/annotation/Between.java

@@ -0,0 +1,21 @@
+package com.td.WaDa.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Between {
+
+    /**
+     * 最小值的实体属性名
+     */
+    String min();
+
+    /**
+     * 最大值的实体属性名
+     */
+    String max();
+}

+ 12 - 0
src/main/java/com/td/WaDa/annotation/Decrypt.java

@@ -0,0 +1,12 @@
+package com.td.WaDa.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Decrypt {
+
+}

+ 12 - 0
src/main/java/com/td/WaDa/annotation/Encrypt.java

@@ -0,0 +1,12 @@
+package com.td.WaDa.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Encrypt {
+
+}

+ 16 - 0
src/main/java/com/td/WaDa/annotation/In.java

@@ -0,0 +1,16 @@
+package com.td.WaDa.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface In {
+
+    /**
+     * in的具体集合的属性名
+     */
+    String values();
+}

+ 13 - 0
src/main/java/com/td/WaDa/annotation/Like.java

@@ -0,0 +1,13 @@
+package com.td.WaDa.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Like {
+
+}

+ 170 - 0
src/main/java/com/td/WaDa/aspect/SafetyAspect.java

@@ -0,0 +1,170 @@
+package com.td.WaDa.aspect;
+
+import com.td.WaDa.annotation.Decrypt;
+import com.td.WaDa.annotation.Encrypt;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.util.*;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.text.SimpleDateFormat;
+
+/**
+ * AES + RSA 加解密AOP处理
+ */
+@Slf4j
+@Aspect
+@Component
+public class SafetyAspect {
+
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    private final JwtTokenUtil jwtTokenUtil;
+    private final String tokenHeader;
+
+    public SafetyAspect(JwtTokenUtil jwtTokenUtil, @Value("${jwt.token}") String tokenHeader) {
+        this.jwtTokenUtil = jwtTokenUtil;
+        this.tokenHeader = tokenHeader;
+    }
+    /**
+     * Pointcut 切入点
+     * 匹配
+     * com.td.boss.sys.*.controller、
+     * com.td.boss.*.controller包下面的所有方法
+     * "execution(public * com.td.boss.*.controller.*.*(..))" && ! execution(public * com.td.boss.game.*.controller.*.*(..))
+     *
+     * 下面需要验证加密
+     *  "execution(public * com.td.boss.game.*.controller.*.*(..))"
+     */
+    @Pointcut(value = "execution(public * com.td.WaDa.sys.*.controller.*.*(..)) || " +
+            "execution(public * com.td.WaDa.*.controller.*.*(..))")
+    public void safetyAspect() {}
+
+    /**
+     * 环绕通知
+     */
+    @Around(value = "safetyAspect()")
+    public Object around(ProceedingJoinPoint pjp) {
+       try {
+            log.info("---------------进入aop---------------");
+           //判断api加密开关是否开启 SysSettingUtil.getSysSetting()
+           if("N".equals(redisSettingMap.getSysSettingMap().getSysApiEncrypt())){
+               return pjp.proceed(pjp.getArgs());
+           }
+
+
+            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+            assert attributes != null;
+            //request对象
+            HttpServletRequest request = attributes.getRequest();
+
+            //http请求方法  post get
+            String httpMethod = request.getMethod().toLowerCase();
+
+            //method方法
+            Method method = ((MethodSignature) pjp.getSignature()).getMethod();
+
+            //method方法上面的注解
+            Annotation[] annotations = method.getAnnotations();
+
+            //方法的形参参数
+            Object[] args = pjp.getArgs();
+
+            //是否有@Decrypt
+            boolean hasDecrypt = false;
+            //是否有@Encrypt
+            boolean hasEncrypt = false;
+            for (Annotation annotation : annotations) {
+                if (annotation.annotationType() == Decrypt.class) {
+                    hasDecrypt = true;
+                }
+                if (annotation.annotationType() == Encrypt.class) {
+                    hasEncrypt = true;
+                }
+            }
+
+            //前端公钥
+            String publicKey = null;
+
+            //jackson
+            ObjectMapper mapper = new ObjectMapper();
+            //jackson 序列化和反序列化 date处理
+            mapper.setDateFormat( new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+
+            //执行方法之前解密,且只拦截post请求
+            if ("post".equals(httpMethod) && hasDecrypt) {
+                //AES加密后的数据
+                String data = request.getParameter("data");
+                //后端RSA公钥加密后的AES的key
+                String aesKey = request.getParameter("aesKey");
+                //前端公钥
+                publicKey = request.getParameter("publicKey");
+
+                log.info("前端公钥:" + publicKey);
+
+                //后端私钥解密的到AES的key
+                byte[] plaintext = RsaUtil.decryptByPrivateKey(Base64.decodeBase64(aesKey), RsaUtil.getPrivateKey());
+                aesKey = new String(plaintext);
+                log.info("解密出来的AES的key:" + aesKey);
+
+
+                //AES解密得到明文data数据
+                String decrypt = AesUtil.decrypt(data, aesKey);
+                log.info("解密出来的data数据:" + decrypt);
+
+                //设置到方法的形参中,目前只能设置只有一个参数的情况
+                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+                //注:参数最好用Vo对象来接参,单用String来接,args有长度但获取为空,很奇怪不知道为什么
+                if(args.length > 0){
+                    args[0] = mapper.readValue(decrypt, args[0].getClass());
+                }
+            }
+
+            //执行并替换最新形参参数   PS:这里有一个需要注意的地方,method方法必须是要public修饰的才能设置值,private的设置不了
+            Object o = pjp.proceed(args);
+
+            //返回结果之前加密
+            if (hasEncrypt) {
+                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+                //每次响应之前随机获取AES的key,加密data数据
+                String key = AesUtil.getKey();
+                log.info("AES的key:" + key);
+                String dataString = mapper.writeValueAsString(o);
+                log.info("需要加密的data数据:" + dataString);
+                String data = AesUtil.encrypt(dataString, key);
+
+                //用前端的公钥来解密AES的key,并转成Base64
+                String aesKey = Base64.encodeBase64String(RsaUtil.encryptByPublicKey(key.getBytes(), publicKey));
+
+                //转json字符串并转成Object对象,设置到Result中并赋值给返回值o
+                o = Result.of(mapper.readValue("{\"data\":\"" + data + "\",\"aesKey\":\"" + aesKey + "\"}", Object.class));
+            }
+
+            //返回
+            return o;
+
+        } catch (Throwable e) {
+           //输出到日志文件中
+           log.error(ErrorUtil.errorInfoToString(e));
+            return Result.of(null, false, "加解密异常:\n\t" + e.getMessage());
+        }
+    }
+
+}

+ 77 - 0
src/main/java/com/td/WaDa/common/controller/CommonController.java

@@ -0,0 +1,77 @@
+package com.td.WaDa.common.controller;
+
+import com.td.WaDa.annotation.Decrypt;
+import com.td.WaDa.annotation.Encrypt;
+import com.td.WaDa.common.pojo.PageInfo;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.common.service.CommonService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+
+import java.util.List;
+
+/**
+ * 通用Controller
+ *
+ * @param <V> 实体类Vo
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+public class CommonController<V, E, T> {
+
+    @Autowired
+    private CommonService<V, E, T> commonService;
+
+    /*
+        CRUD、分页、排序测试
+     */
+    @PostMapping("page")
+    @Decrypt
+    @Encrypt
+    public Result<PageInfo<V>> page(V entityVo) {
+        return commonService.page(entityVo);
+    }
+
+    @PostMapping("list")
+    @Decrypt
+    @Encrypt
+    public Result<List<V>> list(V entityVo) {
+        return commonService.list(entityVo);
+    }
+
+    @GetMapping("get/{id}")
+    public Result<V> get(@PathVariable("id") T id) {
+        return commonService.get(id);
+    }
+
+    @PostMapping("save")
+    @Decrypt
+    @Encrypt
+    public Result<V> save(V entityVo) {
+        return commonService.save(entityVo);
+    }
+
+    @DeleteMapping("delete/{id}")
+    public Result<T> delete( @PathVariable("id") T id) {
+        /*
+        批量删除
+        @DeleteMapping("deleteBatch")
+        public Result<T> deleteBatch(@RequestBody List<String> ids){}
+        前端调用:
+        $.ajax({
+            url: ctx + "deleteBatch",
+            type: "DELETE",
+            data: JSON.stringify([id1,id2]),
+            dataType: "JSON",
+            contentType: 'application/json',
+            success: function (data) {
+
+            }
+        });
+         */
+        return commonService.delete(id);
+    }
+}

+ 16 - 0
src/main/java/com/td/WaDa/common/pojo/ComConfig.java

@@ -0,0 +1,16 @@
+package com.td.WaDa.common.pojo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+@Entity
+@Data
+@Table(name = "com_config")
+public class ComConfig implements Serializable {
+     @Id
+     @GeneratedValue(strategy = GenerationType.AUTO)
+     private String configKey;
+     private String configValue;
+}

+ 27 - 0
src/main/java/com/td/WaDa/common/pojo/CultivateKeys.java

@@ -0,0 +1,27 @@
+package com.td.WaDa.common.pojo;
+
+/**
+ * 牧场养殖渔场需求
+ */
+public class CultivateKeys {
+
+    /**
+     * 1、牧场 2、养殖 3、渔场淡水区 4、渔场海水区
+     */
+    public static final Integer[] mallType = new Integer[]{1, 2, 3, 4};
+
+    public static final long dayLong = 1000 * 60 * 60 * 24;
+
+    /**
+     * 获取土地最大养殖数量。是个数组。对应1234类型
+     */
+    public static final String maxAmount = "max_amount";
+    /**
+     * 获取枯萎最大天数
+     */
+    public static final String witheredDay = "withered_day";
+    /**
+     * 获取 喂粮饲料 key
+     */
+    public static final String cultivateFood = "cultivate_food";
+}

+ 22 - 0
src/main/java/com/td/WaDa/common/pojo/IpVo.java

@@ -0,0 +1,22 @@
+package com.td.WaDa.common.pojo;
+
+import lombok.Data;
+
+/**
+ * ip
+ */
+@Data
+public class IpVo {
+    private String ip;//IP地址
+    private String pro;//省
+    private String proCode;//省编码
+    private String city;//城市
+    private String cityCode;//城市编码
+    private String region;//区
+    private String regionCode;//区编码
+    private String addr;//详细地址 + 运营商
+
+    //主要用于接参,无实际意义
+    private String regionNames;
+    private String err;
+}

+ 31 - 0
src/main/java/com/td/WaDa/common/pojo/MonitorVo.java

@@ -0,0 +1,31 @@
+package com.td.WaDa.common.pojo;
+
+import lombok.Data;
+
+/**
+ * 系统监控信息Vo
+ */
+@Data
+public class MonitorVo {
+    private String os;//操作系统
+    private String runTime;//程序启动时间
+    private String jvmJavaVersion;//java版本
+
+    //jvm
+    private String jvmHeapInit;//jvm内存的初始大小
+    private String jvmHeapMax;//jvm最大可用内存量
+    private String jvmHeapUsed;//jvm已使用的内存量
+    private String jvmHeapCommitted;//jvm已申请的内存量
+    private String jvmNonHeapInit;//jvm内存的初始大小
+    private String jvmNonHeapMax;//jvm最大可用内存量
+    private String jvmNonHeapUsed;//jvm已使用的内存量
+    private String jvmNonHeapCommitted;//jvm已申请的内存量
+
+    //硬件信息
+    private String cpuInfo;//CPU信息
+    private String cpuUseRate;//CPU使用率
+    private String ramTotal;//系统内存总量
+    private String ramUsed;//已使用的系统内存量
+    private String diskTotal;//系统磁盘总量
+    private String diskUsed;//已使用的系统磁盘量
+}

+ 39 - 0
src/main/java/com/td/WaDa/common/pojo/PageCondition.java

@@ -0,0 +1,39 @@
+package com.td.WaDa.common.pojo;
+
+import lombok.Data;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.domain.Sort.Direction;
+import org.thymeleaf.util.StringUtils;
+
+/**
+ * 分页条件(参考JqGrid插件)
+ */
+@Data
+public class PageCondition {
+    private int page = 1;//当前页码
+    private int rows = 10;//页面大小
+    private String sidx;//排序字段
+    private String sord;//排序方式
+
+    /**
+     * 获取JPA的分页查询对象
+     */
+    public Pageable getPageable() {
+        //处理非法页码
+        if (page < 0) {
+            page = 1;
+        }
+        //处理非法页面大小
+        if (rows < 0) {
+            rows = 10;
+        }
+        //处理排序
+        if(!StringUtils.isEmpty(sidx) && !StringUtils.isEmpty(sord)){
+            Direction direction = "desc".equals(sidx.toLowerCase()) ? Direction.DESC : Direction.ASC;
+            return PageRequest.of(page - 1, rows, Sort.by(direction, sord));
+        }
+        return PageRequest.of(page - 1, rows);
+    }
+}

+ 62 - 0
src/main/java/com/td/WaDa/common/pojo/PageInfo.java

@@ -0,0 +1,62 @@
+package com.td.WaDa.common.pojo;
+
+import com.td.WaDa.util.CopyUtil;
+import lombok.Data;
+import org.hibernate.query.internal.NativeQueryImpl;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.repository.support.PageableExecutionUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.util.List;
+
+/**
+ * 分页对象(参考JqGrid插件)
+ */
+@Data
+public class PageInfo<M> {
+    private int page;//当前页码
+    private int pageSize;//页面大小
+    private String sidx;//排序字段
+    private String sord;//排序方式
+
+    private List<M> rows;//分页结果
+    private int records;//总记录数
+    private int total;//总页数
+
+    /**
+     * 获取统一分页结果
+     */
+    public static <M> PageInfo<M> of(Page page, Class<M> entityModelClass) {
+        int records = (int) page.getTotalElements();
+        int pageSize = page.getSize();
+        int total = records % pageSize == 0 ? records / pageSize : records / pageSize + 1;
+
+        PageInfo<M> pageInfo = new PageInfo<>();
+        pageInfo.setPage(page.getNumber() + 1);//页码
+        pageInfo.setPageSize(pageSize);//页面大小
+        pageInfo.setRows(CopyUtil.copyList(page.getContent(), entityModelClass));//分页结果
+        pageInfo.setRecords(records);//总记录数
+        pageInfo.setTotal(total);//总页数
+        return pageInfo;
+    }
+
+    /**
+     * 获取JPA的分页对象
+     */
+    public static Page getJPAPage(Query query, PageRequest pageRequest, EntityManager em) {
+        query.setFirstResult((int) pageRequest.getOffset());
+        query.setMaxResults(pageRequest.getPageSize());
+
+        //获取分页结果
+        return PageableExecutionUtils.getPage(query.getResultList(), pageRequest, () -> {
+            //设置countQuerySQL语句
+            Query countQuery = em.createNativeQuery("select count(*) from ( " + ((NativeQueryImpl) query).getQueryString() + " ) count_table");
+            //设置countQuerySQL参数
+            query.getParameters().forEach(parameter -> countQuery.setParameter(parameter.getName(), query.getParameterValue(parameter.getName())));
+            //返回一个总数
+            return Long.valueOf(countQuery.getResultList().get(0).toString());
+        });
+    }
+}

+ 42 - 0
src/main/java/com/td/WaDa/common/pojo/ParameterRequestWrapper.java

@@ -0,0 +1,42 @@
+package com.td.WaDa.common.pojo;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 重写一个RequestWrapper,实现可修改Parameter的值
+ */
+public class ParameterRequestWrapper extends HttpServletRequestWrapper {
+
+    private Map<String , String[]> params = new HashMap<String, String[]>();
+
+    public ParameterRequestWrapper(HttpServletRequest request) {
+        super(request);
+        this.params.putAll(request.getParameterMap());
+    }
+
+    //重写getParameter,从当前类中的map获取(查看UsernamePasswordAuthenticationFilter可知)
+    @Override
+    public String getParameter(String name) {
+        String[]values = params.get(name);
+        if(values == null || values.length == 0) {
+            return null;
+        }
+        return values[0];
+    }
+
+    //增加参数
+    public void addParameter(String name, Object value) {
+        if(value != null) {
+            if(value instanceof String[]) {
+                params.put(name , (String[])value);
+            }else if(value instanceof String) {
+                params.put(name , new String[] {(String)value});
+            }else {
+                params.put(name , new String[] {String.valueOf(value)});
+            }
+        }
+    }
+}

+ 74 - 0
src/main/java/com/td/WaDa/common/pojo/Result.java

@@ -0,0 +1,74 @@
+package com.td.WaDa.common.pojo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 统一返回对象
+ */
+
+@Data
+public class Result<T> implements Serializable {
+    /**
+     * 通信数据
+     */
+    private T data;
+    /**
+     * 通信状态
+     */
+    private boolean flag = true;
+    /**
+     * 通信描述
+     */
+    private String msg = "操作成功";
+
+    /**
+     * 通信code
+     */
+    private Integer code = 0;
+
+    /**
+     * 通过静态方法获取实例
+     */
+    public static <T> Result<T> of(T data) {
+        return new Result<>(data);
+    }
+
+    public static <T> Result<T> of(T data, boolean flag) {
+        return new Result<>(data, flag);
+    }
+
+    public static <T> Result<T> of(T data, boolean flag, String msg) {
+        return new Result<>(data, flag, msg);
+    }
+    public static <T> Result<T> of(T data, boolean flag, String msg,Integer code) {
+        return new Result<>(data, flag, msg,code);
+    }
+    @Deprecated
+    public Result() {
+
+    }
+
+    private Result(T data) {
+        this.data = data;
+    }
+
+    private Result(T data, boolean flag) {
+        this.data = data;
+        this.flag = flag;
+    }
+
+    private Result(T data, boolean flag, String msg) {
+        this.data = data;
+        this.flag = flag;
+        this.msg = msg;
+    }
+
+    private Result(T data, boolean flag, String msg ,Integer code) {
+        this.data = data;
+        this.flag = flag;
+        this.msg = msg;
+        this.code = code;
+    }
+}

+ 14 - 0
src/main/java/com/td/WaDa/common/repository/ComConfigRepository.java

@@ -0,0 +1,14 @@
+package com.td.WaDa.common.repository;
+
+import com.td.WaDa.common.pojo.ComConfig;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface ComConfigRepository extends CommonRepository<ComConfig, Integer> {
+
+    @Query(value = "select * from com_config", nativeQuery = true)
+    public List<ComConfig> list();
+}

+ 16 - 0
src/main/java/com/td/WaDa/common/repository/CommonRepository.java

@@ -0,0 +1,16 @@
+package com.td.WaDa.common.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.repository.NoRepositoryBean;
+
+/**
+ * 通用Repository
+ *
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+@NoRepositoryBean
+public interface CommonRepository<E,T> extends JpaRepository<E,T>, JpaSpecificationExecutor<E> {
+
+}

+ 23 - 0
src/main/java/com/td/WaDa/common/service/ComConfigService.java

@@ -0,0 +1,23 @@
+package com.td.WaDa.common.service;
+
+import com.td.WaDa.common.pojo.ComConfig;
+import com.td.WaDa.game.complayersattri.vo.ComPlayersLuckyLandLevelUpVo;
+
+import java.util.List;
+
+public interface ComConfigService {
+    String selectByKey(String key);
+
+    List<ComPlayersLuckyLandLevelUpVo> selectLandLevel();
+
+    <T> List<T> selectListByKey(String key, Class<T> clazz);
+    <T> T selectByKey(String key, Class<T> clazz);
+
+    List<ComConfig> selectAllComConfig();
+
+    /**
+     * 更新一个redis缓存list
+     * @return
+     */
+    List<ComConfig> updateList();
+}

+ 89 - 0
src/main/java/com/td/WaDa/common/service/ComConfigServiceImpl.java

@@ -0,0 +1,89 @@
+package com.td.WaDa.common.service;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.td.WaDa.common.pojo.ComConfig;
+import com.td.WaDa.common.repository.ComConfigRepository;
+import com.td.WaDa.game.complayersattri.vo.ComPlayersLuckyLandLevelUpVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class ComConfigServiceImpl implements ComConfigService {
+
+    private String redisKey = "data:com:config";
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    @Autowired
+    private ComConfigRepository repository;
+
+    private List<ComConfig> list() {
+        List<ComConfig> list;
+        String s = redisTemplate.opsForValue().get(redisKey);
+        if (StrUtil.isBlank(s)) {
+            list = repository.list();
+            redisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(list));
+        } else {
+            list = JSONUtil.toList(s, ComConfig.class);
+        }
+        return list;
+    }
+
+    @Override
+    public List<ComConfig> updateList() {
+        List<ComConfig> list = repository.list();
+        redisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(list));
+        return list;
+    }
+
+    @Override
+    public List<ComConfig> selectAllComConfig() {
+        return list();
+    }
+
+    @Override
+    public String selectByKey(String key) {
+        List<ComConfig> list = list();
+        return list.stream().filter(a -> a.getConfigKey().equals(key)).map(a -> a.getConfigValue()).findFirst().orElse("");
+    }
+
+    /**
+     * 获取种植土地级别配置
+     *
+     * @return
+     */
+    @Override
+    public List<ComPlayersLuckyLandLevelUpVo> selectLandLevel() {
+        String land_tools = selectByKey("land_level");
+        if (StrUtil.isBlank(land_tools)) {
+            return new ArrayList<>();
+        } else {
+            return JSONUtil.toList(land_tools, ComPlayersLuckyLandLevelUpVo.class);
+        }
+    }
+
+    @Override
+    public <T> List<T> selectListByKey(String key, Class<T> clazz) {
+        String json = selectByKey(key);
+        if (StrUtil.isBlank(json)) {
+            return new ArrayList<>();
+        } else {
+            return JSONUtil.toList(json, clazz);
+        }
+    }
+    @Override
+    public <T> T selectByKey(String key, Class<T> clazz) {
+        String json = selectByKey(key);
+        if (StrUtil.isBlank(json)) {
+            return null;
+        } else {
+            return JSON.parseObject(json, clazz);
+        }
+    }
+}

+ 27 - 0
src/main/java/com/td/WaDa/common/service/CommonService.java

@@ -0,0 +1,27 @@
+package com.td.WaDa.common.service;
+
+
+import com.td.WaDa.common.pojo.PageInfo;
+import com.td.WaDa.common.pojo.Result;
+
+import java.util.List;
+
+/**
+ * 通用Service
+ *
+ * @param <V> 实体类Vo
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+public interface CommonService<V, E,T> {
+
+    Result<PageInfo<V>> page(V entityVo);
+
+    Result<List<V>> list(V entityVo);
+
+    Result<V> get(T id);
+
+    Result<V> save(V entityVo);
+
+    Result<T> delete(T id);
+}

+ 159 - 0
src/main/java/com/td/WaDa/common/service/CommonServiceImpl.java

@@ -0,0 +1,159 @@
+package com.td.WaDa.common.service;
+
+import com.td.WaDa.common.pojo.PageCondition;
+import com.td.WaDa.common.pojo.PageInfo;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.common.repository.CommonRepository;
+import com.td.WaDa.util.CopyUtil;
+import com.td.WaDa.util.ErrorUtil;
+import com.td.WaDa.util.UUIDUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.annotations.NotFound;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.data.domain.Page;
+import org.springframework.util.StringUtils;
+
+import javax.persistence.Id;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * 通用Service实现类
+ *
+ * @param <V> 实体类Vo
+ * @param <E> 实体类
+ * @param <T> id主键类型
+ */
+@Slf4j
+public class CommonServiceImpl<V, E, T> implements CommonService<V, E, T> {
+
+    private Class<V> entityVoClass;//实体类Vo
+
+    private Class<E> entityClass;//实体类
+
+    @Autowired
+    private CommonRepository<E, T> commonRepository;//注入实体类仓库
+
+    public CommonServiceImpl() {
+        Type[] types = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
+        this.entityVoClass = (Class<V>) types[0];
+        this.entityClass = (Class<E>) types[1];
+    }
+
+    @Override
+    public Result<PageInfo<V>> page(V entityVo) {
+        //实体类缺失分页信息
+        if (!(entityVo instanceof PageCondition)) {
+            throw new RuntimeException("实体类" + entityVoClass.getName() + "未继承PageCondition。");
+        }
+        PageCondition pageCondition = (PageCondition) entityVo;
+        Page<E> page = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)), pageCondition.getPageable());
+        return Result.of(PageInfo.of(page, entityVoClass));
+    }
+
+    @Override
+    public Result<List<V>> list(V entityVo) {
+        List<E> entityList = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)));
+        List<V> entityModelList = CopyUtil.copyList(entityList, entityVoClass);
+        return Result.of(entityModelList);
+    }
+
+    @Override
+    public Result<V> get(T id) {
+        Optional<E> optionalE = commonRepository.findById(id);
+        if (!optionalE.isPresent()) {
+            return Result.of(null,false,"ID不存在!");
+        }
+        return Result.of(CopyUtil.copy(optionalE.get(), entityVoClass));
+    }
+
+    @Override
+    public Result<V> save(V entityVo) {
+        //传进来的对象(属性可能残缺)
+        E entity = CopyUtil.copy(entityVo, entityClass);
+
+        //最终要保存的对象
+        E entityFull = entity;
+
+        //为空的属性值,忽略属性,BeanUtils复制的时候用到
+        List<String> ignoreProperties = new ArrayList<String>();
+
+        //获取最新数据,解决部分更新时jpa其他字段设置null问题
+        try {
+            //新增 true,更新 false,要求实体类的Id属性排在第一位,因为for循环读取是按照顺序的
+            boolean isInsert = false;
+
+            //反射获取Class的属性(Field表示类中的成员变量)
+            for (Field field : entity.getClass().getDeclaredFields()) {
+                //获取授权
+                field.setAccessible(true);
+                //属性名称
+                String fieldName = field.getName();
+                //属性的值
+                Object fieldValue = field.get(entity);
+
+                //找出Id主键
+                if (field.isAnnotationPresent(Id.class)) {
+                    if(!StringUtils.isEmpty(fieldValue)){
+                        //如果Id主键不为空,则为更新
+                        Optional<E> one = commonRepository.findById((T) fieldValue);
+                        if (one.isPresent()) {
+                            entityFull = one.get();
+                        }
+                    }else{
+                        //如果Id主键为空,则为新增
+                        fieldValue = UUIDUtil.getUUID();
+                        //set方法,第一个参数是对象
+                        field.set(entity, fieldValue);
+                        isInsert = true;
+                    }
+                }
+                //如果前端不传这两个值,后台来维护创建时间、更新时间
+                if(isInsert && "createTime".equals(fieldName) && StringUtils.isEmpty(fieldValue)){
+                    //先赋值给fieldValue,以免后续进行copy对象判断属性是否为忽略属性是出错
+                    fieldValue = new Date();
+
+                    //set方法,第一个参数是对象
+                    field.set(entity, fieldValue);
+                }
+                if("updateTime".equals(fieldName) && StringUtils.isEmpty(fieldValue)){
+                    //先赋值给fieldValue,以免后续进行copy对象判断属性是否为忽略属性是出错
+                    fieldValue = new Date();
+
+                    //set方法,第一个参数是对象
+                    field.set(entity, fieldValue);
+                }
+
+                //找出值为空的属性,值为空则为忽略属性,或者被NotFound标注,我们复制的时候不进行赋值
+                if(null == fieldValue || field.isAnnotationPresent(NotFound.class)){
+                    ignoreProperties.add(fieldName);
+                }
+            }
+            /*
+                org.springframework.beans BeanUtils.copyProperties(A,B); 是A中的值付给B
+                org.apache.commons.beanutils; BeanUtils.copyProperties(A,B);是B中的值付给A
+                把entity的值赋给entityFull,第三个参数是忽略属性,表示不进行赋值
+             */
+            BeanUtils.copyProperties(entity, entityFull, ignoreProperties.toArray(new String[0]));
+        } catch (IllegalAccessException e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+
+        E e = commonRepository.save(entityFull);
+        return Result.of(CopyUtil.copy(e, entityVoClass));
+    }
+
+    @Override
+    public Result<T> delete(T id) {
+        commonRepository.deleteById(id);
+        return Result.of(id);
+    }
+}

+ 27 - 0
src/main/java/com/td/WaDa/config/async/AsyncConfig.java

@@ -0,0 +1,27 @@
+package com.td.WaDa.config.async;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.task.AsyncTaskExecutor;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+/**
+ * 线程池的配置
+ */
+@Configuration
+public class AsyncConfig {
+
+    private static final int MAX_POOL_SIZE = 50;
+
+    private static final int CORE_POOL_SIZE = 20;
+
+    @Bean("asyncTaskExecutor")
+    public AsyncTaskExecutor asyncTaskExecutor() {
+        ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
+        asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
+        asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
+        asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-");
+        asyncTaskExecutor.initialize();
+        return asyncTaskExecutor;
+    }
+}

+ 137 - 0
src/main/java/com/td/WaDa/config/enums/ResultEnum.java

@@ -0,0 +1,137 @@
+package com.td.WaDa.config.enums;
+
+import lombok.Getter;
+
+/**
+ * 返回的
+ * @author:slambb
+ * @date:2019/12/5
+ */
+@Getter
+public enum ResultEnum {
+    SUCCESS(0,"成功"),
+    //token数据
+    TOKEN_SUCCESS(300,"用户授权认证通过!"),
+    TOKEN_IS_ILLEGAL(301,"用户授权认证没有通过!客户端请求参数TOKEN信息无效"),
+    TOKEN_DOES_NOT_EXIST(302,"用户授权认证没有通过!客户端请求参数中无TOKEN信息"),
+    TOKEN_OUT_OF_DATE(303,"用户授权认证没有通过!TOKEN过期,重新获取"),
+    TOKEN_DOES_NOT_HAVE_USER_ID(304,"用户授权认证没有通过!TOKEN不存在用户id"),
+    NO_PARAMETERS_CARRIED(305,"输入对应参数"),
+    //setting部分
+    SETTING_IS_NULL(306,"配置信息不存在"),
+    //redis部分
+    REDIS_IS_LOCK(307,"操作过于频繁,稍后再试!"),
+    REDIS_IS_LOCK_ERROR(308,"操作失败,稍后再试!"),
+
+    //特定接口访问部分限制
+    LOGIN_IP_IS_ERROR(309,"IP异常?!"),
+    //用户数据
+    USER_DOES_NOT_EXIST(400,"不能存在用户信息!"),
+    USER_ENERGY_IS_INSUFFICIENT(401,"用户能量不足!"),
+    USER_VERIFICATION_ERROR(402,"签名校验失败"),
+
+    USER_NOT_ADDRESS(403,"用户地址不存在!"),
+    USER_LIMIT_LOGIN(404,"用户限制登录!"),
+
+    USER_LOGIN_LOCK(405,"用户保存繁忙,请重试操作!"),
+    //角色数据
+    PLAYER_DOES_NOT_EXIST(500,"不存在角色信息!"),
+    PLAYER_DOES_NOT_ATTRIBUTES(501,"battle player 数据不存在!"),
+
+    PLAYER_GOODS_LIMIT_ERROR(510,"背包超过预设长度!"),
+    PLAYER_NO_CHEST_INFO(511,"没有对应宝箱类型信息"),
+    PLAYER_NO_EQUIP_TYPE(512,"没有对应装备信息"),
+    PLAYER_GOODS_NO_CHEST(513,"背包没有对应宝箱"),
+    PLAYER_GOODS_NOT_CHEST_TYPE(514,"不是宝箱类型对象"),
+    PLAYER_GOODS_WEAR_NUM_ERROR(515,"请输入对应的参数,isWear:0或者1"),
+    PLAYER_GOODS_NO_QUIP_REQUIRED(516,"不用获取多余装备"),
+
+    PLAYER_GOODS_SEEDS_AMOUNT_ERROR(517,"土地消耗种子数量不足"),
+
+    PLAYER_ATTRIBUTE_STRENGTH_IS_NOT(518,"用户体力不足"),
+
+    PLAYER_GOODS_SAVE_LOCK(520,"操作繁忙,保存背包失败,稍后再试!"),
+    //钱包数据
+    WALLET_CNT_PLAY_ERROR(601,"钱包CNT支付参数数据错误!"),
+    WALLET_SNB_INSUFFICIENT_QUANTITY(602,"snb不足以支付!"),
+    WALLET_SNB_SUCCESS_NOT_ZERO(603,"snb不可操作"),
+    WALLET_SNB_SIGN_ERROR(604,"钱包SNB参数签名错误!"),
+
+    APPLY_SNB_AMOUNT_ERROR(605,"snb参数错误!"),
+    APPLY_SNB_TOO_MUCH(606,"snb申请过多,待审核完成后再申请!"),
+    APPLY_SNB_HAS_APPLY(607,"已有一笔snb申请中,待审核完成后再申请!"),
+    APPLY_SNB_STATE_ERROR(608,"状态信息错误!"),
+
+    WALLET_SNB_ABNORMAL(609,"SNB异常状态"),
+    //土地数据
+    LAND_DATA_ERROR(701,"土地数据不能初始化!"),
+    LAND_NOT_LEASE(702,"土地未租赁!"),
+    LAND_IS_LEASE(703,"土地已租赁!"),
+    LAND_IS_PLANT(704,"土地已种植!"),
+    LAND_NOT_PLANT(705,"土地未种植!"),
+    LAND_LEASE_EXPIRED(706,"土地租赁已过期!"),
+    LAND_HARVEST_STOLEN(707,"土地已收成过!"),
+    LAND_STEAL_ALL(708,"土地已无多余收成!"),
+    LAND_STEAL_LOCK(709,"当前偷取人数过多,稍后再试!"),
+    LAND_PLANT_FLAG_IS_NULL(710,"土地标识为空,不能偷取"),
+    LAND_CAN_STEAL_IS_ZERO(711,"没有可收取果实的土地不存在!"),
+    LAND_CAN_STEAL_IS_NULL(712,"没有可收取果实的土地!"),
+
+    LAND_CAN_STEAL_IS_MAX(713,"已无多余利润!"),//达到最大值
+    LAND_USE_TOOL(714,"该土地正在使用工具中!"),
+    LAND_LAND_LEVELUPPING(715,"该土地正在升级中!"),
+
+    //土地受灾中,稍后重试!
+    LAND_DISATER_LOCK(716,"土地正在遭受灾害,稍后重试!"),
+    LAND_MALL_TYPE_ERROR(717,"种植或养殖类型不对!"),
+    LAND_MULTIPLE_ERROR(718,"土地倍数异常!"),
+    LAND_MULTIPLE_CONFIG_ERROR(719,"土地倍数与配置不符!"),
+
+    LAND_CAN_STEAL_SELF(720,"不能偷取自己的土地!"),
+
+    //种子数据不能存在
+    SEED_DATA_ERROR(801,"种子数据不存在!"),
+    FRUIT_DATA_ERROR(802,"果实数据不存在!"),
+    FRUIT_AMOUNT_ERROR(803,"果实数据出错!"),
+    FRUIT_SEND_SELF(804,"不能赠送给自己!"),
+    SEED_DATE_ERROR(805,"未到成熟时间!"),
+    SEED_AMOUNT_ERROR(806,"背包数量不对!"),
+    SEED_PLAY_ERROR(807,"支付价格不对!"),
+    SEED_PLAY_DIAMOND_ERROR(808,"钻石不足以兑换支付!"),
+    SEED_IS_EXCHANGE(809,"种子已经兑换过!"),
+
+    FOOD_DATA_ERROR(810,"食物数据不存在"),
+    FOOD_DOT_NOT(811,"狗粮不足!"),
+
+    SEED_SALE_SAVE_LOCK(810,"操作繁忙,出售失败,稍后再试!"),
+    SEED_NO_LAND_ERROR(812,"种子土地不匹配!"),
+    SEED_LAND_TIME_ERROR(813,"土地租赁时间不足!"),
+
+    LAND_NO_TIMES_ERROR(814,"次数不足,租赁失败!"),
+    FOOD_NO_TYPE_ERROR(815,"粮食和养殖类型不匹配!"),
+    LAND_NO_PLANT_ERROR(816,"土地未养殖,喂养失败!"),
+    FOOD_NO_ERROR(817,"未找到养料!"),
+    FOOD_REPEAT_ERROR(818,"今日已喂养!"),
+    SEED_LAND_WITHERED(819,"果实已枯萎!"),
+    //装备相关
+    MALL_OTHER_IS_NULL(810,"商城装备不存在!"),
+    MALL_OTHER_IS_HAVE(811,"商城装备已经存在!"),
+    PLAYER_OTHER_IS_NULL(812,"商城装备不存在!"),
+    PLAYER_OTHER_IS_HAVE(813,"商城装备已经存在!"),
+    MALL_ID_LIMIT(820,"商城装备不符合购买需求!"),
+    MALL_FOOD_ID_LIMIT(821,"粮食不符合购买需求!"),
+
+    DOG_SHOW_STATE_ERROR(822,"装备狗状态错误!"),
+
+
+    FRUIT_AMOUNT_IS_ZERO_AND_NOT_MULTIPLE(814,"请输入出售果实的数量!"),
+    ;
+    private Integer code;
+
+    private String message;
+
+    ResultEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+}

+ 25 - 0
src/main/java/com/td/WaDa/config/exception/AuthorizeException.java

@@ -0,0 +1,25 @@
+package com.td.WaDa.config.exception;
+
+import com.td.WaDa.config.enums.ResultEnum;
+import lombok.Getter;
+
+/**
+ * @author:slambb
+ * @date:2019/12/13
+ */
+@Getter
+public class AuthorizeException extends RuntimeException {
+
+    private Integer code;
+
+    public AuthorizeException(ResultEnum resultEnum) {
+        super(resultEnum.getMessage());
+
+        this.code = resultEnum.getCode();
+    }
+
+    public AuthorizeException(Integer code, String message) {
+        super(message);
+        this.code = code;
+    }
+}

+ 175 - 0
src/main/java/com/td/WaDa/config/logback/LoggingWSServer.java

@@ -0,0 +1,175 @@
+package com.td.WaDa.config.logback;
+
+
+import com.td.WaDa.config.websocket.MyEndpointConfigure;
+import com.td.WaDa.util.ErrorUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.thymeleaf.util.StringUtils;
+
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * WebSocket获取实时日志并输出到Web页面
+ */
+@Slf4j
+@Component
+@ServerEndpoint(value = "/websocket/logging", configurator = MyEndpointConfigure.class)
+public class LoggingWSServer {
+
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    /**
+     * 连接集合
+     */
+    private static Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();
+    private static Map<String, Integer> lengthMap = new ConcurrentHashMap<String, Integer>();
+
+    /**
+     * 连接建立成功调用的方法
+     */
+    @OnOpen
+    public void onOpen(Session session) {
+        //添加到集合中
+        sessionMap.put(session.getId(), session);
+        lengthMap.put(session.getId(), 1);//默认从第一行开始
+
+        //获取日志信息
+        new Thread(()->{
+            log.info("LoggingWebSocketServer 任务开始");
+            boolean first = true;
+            BufferedReader reader = null;
+            while (sessionMap.get(session.getId()) != null) {
+                try {
+                    //日志文件,获取最新的
+                    FileReader fileReader = new FileReader(System.getProperty("user.home") + "/log/" + new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + applicationName + ".log");
+
+                    //字符流
+                    reader = new BufferedReader(fileReader);
+                    Object[] lines = reader.lines().toArray();
+
+                    //只取从上次之后产生的日志
+                    Object[] copyOfRange = Arrays.copyOfRange(lines, lengthMap.get(session.getId()), lines.length);
+
+                    //对日志进行着色,更加美观  PS:注意,这里要根据日志生成规则来操作
+                    for (int i = 0; i < copyOfRange.length; i++) {
+                        String line = String.valueOf(copyOfRange[i]);
+                        //先转义
+                        line = line.replaceAll("&", "&amp;")
+                                .replaceAll("<", "&lt;")
+                                .replaceAll(">", "&gt;")
+                                .replaceAll("\"", "&quot;");
+
+                        //处理等级
+                        line = line.replace("DEBUG", "<span style='color: blue;'>DEBUG</span>");
+                        line = line.replace("INFO", "<span style='color: green;'>INFO</span>");
+                        line = line.replace("WARN", "<span style='color: orange;'>WARN</span>");
+                        line = line.replace("ERROR", "<span style='color: red;'>ERROR</span>");
+
+                        //处理类名
+                        String[] split = line.split("]");
+                        if (split.length >= 2) {
+                            String[] split1 = split[1].split("-");
+                            if (split1.length >= 2) {
+                                line = split[0] + "]" + "<span style='color: #298a8a;'>" + split1[0] + "</span>" + "-" + split1[1];
+                            }
+                        }
+
+                        // 匹配日期开头加换行,2019-08-12 14:15:04
+                        Pattern r = Pattern.compile("[\\d+][\\d+][\\d+][\\d+]-[\\d+][\\d+]-[\\d+][\\d+] [\\d+][\\d+]:[\\d+][\\d+]:[\\d+][\\d+]");
+                        Matcher m = r.matcher(line);
+                        if (m.find( )) {
+                            //找到下标
+                            int start = m.start();
+                            //插入
+                            StringBuilder  sb = new StringBuilder (line);
+                            sb.insert(start,"<br/><br/>");
+                            line = sb.toString();
+                        }
+
+                        copyOfRange[i] = line;
+                    }
+
+                    //存储最新一行开始
+                    lengthMap.replace(session.getId(), lines.length);
+
+                    //第一次如果太大,截取最新的200行就够了,避免传输的数据太大
+                    if(first && copyOfRange.length > 200){
+                        copyOfRange = Arrays.copyOfRange(copyOfRange, copyOfRange.length - 200, copyOfRange.length);
+                        first = false;
+                    }
+
+                    String result = StringUtils.join(copyOfRange, "<br/>");
+
+                    //发送
+                    send(session, result);
+
+                    //休眠一秒
+                    Thread.sleep(1000);
+                } catch (Exception e) {
+                    //输出到日志文件中
+                    log.error(ErrorUtil.errorInfoToString(e));
+                }
+            }
+            try {
+                reader.close();
+            } catch (IOException e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+            log.info("LoggingWebSocketServer 任务结束");
+        }).start();
+    }
+
+    /**
+     * 连接关闭调用的方法
+     */
+    @OnClose
+    public void onClose(Session session) {
+        //从集合中删除
+        sessionMap.remove(session.getId());
+        lengthMap.remove(session.getId());
+    }
+
+    /**
+     * 发生错误时调用
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        //输出到日志文件中
+        log.error(ErrorUtil.errorInfoToString(error));
+    }
+
+    /**
+     * 服务器接收到客户端消息时调用的方法
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+
+    }
+
+    /**
+     * 封装一个send方法,发送消息到前端
+     */
+    private void send(Session session, String message) {
+        try {
+            session.getBasicRemote().sendText(message);
+        } catch (Exception e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+    }
+}

+ 104 - 0
src/main/java/com/td/WaDa/config/monitor/MonitorWSServer.java

@@ -0,0 +1,104 @@
+package com.td.WaDa.config.monitor;
+
+
+import com.td.WaDa.config.websocket.MyEndpointConfigure;
+import com.td.WaDa.util.ErrorUtil;
+import com.td.WaDa.util.SystemMonitorUtil;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.ServerEndpoint;
+import java.text.SimpleDateFormat;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * WebSocket获取实时系统监控并输出到Web页面
+ */
+@Slf4j
+@Component
+@ServerEndpoint(value = "/websocket/monitor", configurator = MyEndpointConfigure.class)
+public class MonitorWSServer {
+
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    /**
+     * 连接集合
+     */
+    private static Map<String, Session> sessionMap = new ConcurrentHashMap<String, Session>();
+
+    /**
+     * 连接建立成功调用的方法
+     */
+    @OnOpen
+    public void onOpen(Session session) {
+        //添加到集合中
+        sessionMap.put(session.getId(), session);
+
+        //获取系统监控信息
+        new Thread(()->{
+            log.info("MonitorWSServer 任务开始");
+            ObjectMapper mapper = new ObjectMapper();
+            //当属性的值为空(null或者"")时,不进行序列化,可以减少数据传输
+            mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+            //设置日期格式
+            mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+            while (sessionMap.get(session.getId()) != null) {
+                try {
+                    //获取系统监控信息 发送
+                    send(session,  mapper.writeValueAsString(SystemMonitorUtil.getSysMonitor()));
+
+                    //休眠一秒
+                    Thread.sleep(1000);
+                } catch (Exception e) {
+                    //输出到日志文件中
+                    log.error(ErrorUtil.errorInfoToString(e));
+                }
+            }
+            log.info("MonitorWSServer 任务结束");
+        }).start();
+    }
+
+    /**
+     * 连接关闭调用的方法
+     */
+    @OnClose
+    public void onClose(Session session) {
+        //从集合中删除
+        sessionMap.remove(session.getId());
+    }
+
+    /**
+     * 发生错误时调用
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        //输出到日志文件中
+        log.error(ErrorUtil.errorInfoToString(error));
+    }
+
+    /**
+     * 服务器接收到客户端消息时调用的方法
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+
+    }
+
+    /**
+     * 封装一个send方法,发送消息到前端
+     */
+    private void send(Session session, String message) {
+        try {
+            session.getBasicRemote().sendText(message);
+        } catch (Exception e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+    }
+}

+ 166 - 0
src/main/java/com/td/WaDa/config/security/CaptchaFilterConfig.java

@@ -0,0 +1,166 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.common.pojo.ParameterRequestWrapper;
+import com.td.WaDa.util.*;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.HashMap;
+
+/**
+ * 校验账号、密码前,先进行验证码处理,需要在这里进行登录解密操作
+ */
+@Component
+@Slf4j
+public class CaptchaFilterConfig implements Filter {
+
+    @Value("${captcha.enable}")
+    private Boolean captchaEnable;
+
+    @Value("${server.servlet.context-path:}")
+    private String contextPath;
+
+    @Autowired
+    private SessionRegistry sessionRegistry;
+
+    @Autowired
+    private UserConfig userConfig;
+
+    @Autowired
+    private JwtTokenUtil jwtTokenUtil;
+    @Value("${jwt.token}")
+    private String tokenHeader;
+
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+        HttpSession session = request.getSession();
+
+        /*
+            注:详情可在SessionManagementFilter中进行断点调试查看
+            security框架会在session的attribute存储登录信息,先从session.getAttribute(this.springSecurityContextKey)中获取登录用户信息
+            ,如果没有,再从本地上下文SecurityContextHolder.getContext().getAuthentication()获取,因此想要强制用户下线得进行如下操作
+
+            另外,虽然重启了服务,sessionRegistry.getAllSessions()为空,但之前的用户session未过期同样能访问系统,也是这个原因
+         */
+        SessionInformation sessionInformation = sessionRegistry.getSessionInformation(session.getId());
+        if (sessionInformation == null && session.getAttribute("SPRING_SECURITY_CONTEXT") != null) {
+            //直接输出js脚本跳转强制用户下线
+            response.setContentType("text/html;charset=UTF-8");
+            response.getWriter().print("<script type='text/javascript'>window.location.href = '" + contextPath + "/logout'</script>");
+        }
+
+        //只拦截登录请求,且开发环境下不拦截
+        if ("POST".equals(request.getMethod()) && "/login".equals(request.getRequestURI().replaceFirst(contextPath, ""))) {
+            //前端公钥
+            String publicKey = null;
+
+            //jackson
+            ObjectMapper mapper = new ObjectMapper();
+            //jackson 序列化和反序列化 date处理
+            mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+
+            //判断api加密开关是否开启
+            if ("Y".equals(redisSettingMap.getSysSettingMap().getSysApiEncrypt())) {
+                //解密
+                try {
+                    //AES加密后的数据
+                    String data = request.getParameter("data");
+                    //后端RSA公钥加密后的AES的key
+                    String aesKey = request.getParameter("aesKey");
+                    //前端公钥
+                    publicKey = request.getParameter("publicKey");
+                    log.info("前端data:" + data);
+                    log.info("前端aesKey:" + aesKey);
+                    log.info("前端公钥:" + publicKey);
+                    log.info("私钥:" + RsaUtil.getPrivateKey());
+                    String _aesKey2 = aesKey;
+                    //后端私钥解密的到AES的key
+                    byte[] plaintext = RsaUtil.decryptByPrivateKey(Base64.decodeBase64(aesKey), RsaUtil.getPrivateKey());
+                    aesKey = new String(plaintext);
+                    log.info("解密出来的AES的key:" + aesKey);
+                    //log.info("前端aesKey2:" + _aesKey2);
+                    //String base64String = new Base64().encodeToString(_aesKey2.getBytes());
+                    //byte[] plaintext2 = RsaUtil.decryptByPrivateKey(Base64.decodeBase64(_aesKey2), RsaUtil.getPrivateKey());
+                    //String aesKey2 = new String(plaintext2);
+                    //log.info("解密出来的AES的key2:" + aesKey2);
+                    //AES解密得到明文data数据
+                    String decrypt = AesUtil.decrypt(data, aesKey);
+                    log.info("解密出来的data数据:" + decrypt);
+
+                    //设置到方法的形参中,目前只能设置只有一个参数的情况
+                    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+                    //new一个自定义RequestWrapper
+                    HashMap hashMap = mapper.readValue(decrypt, HashMap.class);
+                    ParameterRequestWrapper parameterRequestWrapper = new ParameterRequestWrapper(request);
+                    for (Object key : hashMap.keySet()) {
+                        parameterRequestWrapper.addParameter(String.valueOf(key), hashMap.get(key));
+                    }
+
+                    servletRequest = parameterRequestWrapper;
+                    request = (HttpServletRequest) servletRequest;
+                } catch (Throwable e) {
+                    //输出到日志文件中
+                    log.error(ErrorUtil.errorInfoToString(e));
+                }
+            }
+
+            //从session中获取生成的验证码
+            String verifyCode = session.getAttribute("verifyCode").toString();
+
+            if (captchaEnable && !verifyCode.toLowerCase().equals(request.getParameter("captcha").toLowerCase())) {
+                String dataString = "{\"code\":\"400\",\"msg\":\"验证码错误\"}";
+
+                //判断api加密开关是否开启
+                if ("Y".equals(redisSettingMap.getSysSettingMap().getSysApiEncrypt())) {
+                    //加密
+                    try {
+                        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+                        //每次响应之前随机获取AES的key,加密data数据
+                        String key = AesUtil.getKey();
+                        log.info("AES的key:" + key);
+                        log.info("需要加密的data数据:" + dataString);
+                        String data = AesUtil.encrypt(dataString, key);
+
+                        //用前端的公钥来解密AES的key,并转成Base64
+                        String aesKey = Base64.encodeBase64String(RsaUtil.encryptByPublicKey(key.getBytes(), publicKey));
+                        dataString = "{\"data\":{\"data\":\"" + data + "\",\"aesKey\":\"" + aesKey + "\"}}";
+                    } catch (Throwable e) {
+                        //输出到日志文件中
+                        log.error(ErrorUtil.errorInfoToString(e));
+                    }
+                }
+
+                //转json字符串并转成Object对象,设置到Result中并赋值给返回值o
+                response.setCharacterEncoding("UTF-8");
+                response.setContentType("application/json; charset=utf-8");
+                PrintWriter out = response.getWriter();
+                out.print(dataString);
+                out.flush();
+                out.close();
+                return;
+            }
+        }
+
+        filterChain.doFilter(servletRequest, servletResponse);
+    }
+}

+ 88 - 0
src/main/java/com/td/WaDa/config/security/DynamicallyUrlInterceptor.java

@@ -0,0 +1,88 @@
+package com.td.WaDa.config.security;
+
+import org.springframework.security.access.AccessDecisionManager;
+import org.springframework.security.access.SecurityMetadataSource;
+import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
+import org.springframework.security.access.intercept.InterceptorStatusToken;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+
+import javax.servlet.*;
+import java.io.IOException;
+
+/**
+ * 自定义动态数据拦截器
+ */
+public class DynamicallyUrlInterceptor extends AbstractSecurityInterceptor implements Filter {
+
+    //标记自定义的url拦截器已经加载
+    private static final String FILTER_APPLIED = "__spring_security_filterSecurityInterceptor_filterApplied_dynamically";
+
+    private FilterInvocationSecurityMetadataSource securityMetadataSource;
+    private boolean observeOncePerRequest = true;
+
+
+    @Override
+    public Class<?> getSecureObjectClass() {
+        return FilterInvocation.class;
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        FilterInvocation fi = new FilterInvocation(request, response, chain);
+        invoke(fi);
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
+        return this.securityMetadataSource;
+    }
+
+    public SecurityMetadataSource obtainSecurityMetadataSource() {
+        return this.securityMetadataSource;
+    }
+
+    public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
+        this.securityMetadataSource = newSource;
+    }
+
+    @Override
+    public void setAccessDecisionManager(AccessDecisionManager accessDecisionManager) {
+        super.setAccessDecisionManager(accessDecisionManager);
+    }
+
+    public void invoke(FilterInvocation fi) throws IOException, ServletException {
+
+        if ((fi.getRequest() != null)
+                && (fi.getRequest().getAttribute(FILTER_APPLIED) != null)
+                && observeOncePerRequest) {
+            // filter already applied to this request and user wants us to observe
+            // once-per-request handling, so don't re-do security checking
+            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+        }
+        else {
+            // first time this request being called, so perform security checking
+            if (fi.getRequest() != null) {
+                fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
+            }
+
+            InterceptorStatusToken token = super.beforeInvocation(fi);
+
+            try {
+                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
+            }
+            finally {
+                super.finallyInvocation(token);
+            }
+
+            super.afterInvocation(token, null);
+        }
+    }
+}

+ 55 - 0
src/main/java/com/td/WaDa/config/security/ErrorPageConfig.java

@@ -0,0 +1,55 @@
+package com.td.WaDa.config.security;
+
+import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.server.ErrorPageRegistrar;
+import org.springframework.boot.web.server.ErrorPageRegistry;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+/**
+ * 自定义errorPage
+ */
+@Component
+public class ErrorPageConfig implements ErrorPageRegistrar {
+
+    @Override
+    public void registerErrorPages(ErrorPageRegistry registry) {
+
+        /**
+         * ErrorPage 有两个参数
+         * 参数1 响应状态码
+         * 参数2 出现响应状态码的时候的跳转路径  可以自定义跳转路径
+         */
+
+        //将ErrorPage 注册到注册器中
+        registry.addErrorPages(
+                new ErrorPage(HttpStatus.FORBIDDEN, "/error/403"),
+                new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"),
+                new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500")
+                );
+    }
+}
+
+/**
+ * 错误页面跳转
+ */
+@Controller
+class ErrorPageController {
+    @GetMapping("/error/403")
+    public ModelAndView error403(){
+        return new ModelAndView("common/error/403");
+    }
+
+    @GetMapping("/error/404")
+    public ModelAndView error404(){
+        return new ModelAndView("common/error/404");
+    }
+
+    @GetMapping("/error/500")
+    public ModelAndView error500(){
+        return new ModelAndView("common/error/500");
+    }
+}

+ 70 - 0
src/main/java/com/td/WaDa/config/security/LoginFailureHandlerConfig.java

@@ -0,0 +1,70 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.util.*;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+
+/**
+ * 登录失败处理
+ */
+@Component
+@Slf4j
+public class LoginFailureHandlerConfig implements AuthenticationFailureHandler {
+
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    @Override
+    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
+        String msg = "{\"code\":\"400\",\"msg\":\"用户名或密码错误\"}";
+
+        //判断api加密开关是否开启
+        if("Y".equals(redisSettingMap.getSysSettingMap().getSysApiEncrypt())){
+            //加密
+            try {
+                //前端公钥
+                String publicKey = httpServletRequest.getParameter("publicKey");
+
+                log.info("前端公钥:" + publicKey);
+
+                //jackson
+                ObjectMapper mapper = new ObjectMapper();
+                //jackson 序列化和反序列化 date处理
+                mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+                //每次响应之前随机获取AES的key,加密data数据
+                String key = AesUtil.getKey();
+                log.info("AES的key:" + key);
+                log.info("需要加密的data数据:" + msg);
+                String data = AesUtil.encrypt(msg, key);
+
+                //用前端的公钥来解密AES的key,并转成Base64
+                String aesKey = Base64.encodeBase64String(RsaUtil.encryptByPublicKey(key.getBytes(), publicKey));
+                msg = "{\"data\":{\"data\":\"" + data + "\",\"aesKey\":\"" + aesKey + "\"}}";
+            } catch (Throwable ee) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(ee));
+            }
+        }
+
+        //转json字符串并转成Object对象,设置到Result中并赋值给返回值o
+        httpServletResponse.setCharacterEncoding("UTF-8");
+        httpServletResponse.setContentType("application/json; charset=utf-8");
+        PrintWriter out = httpServletResponse.getWriter();
+        out.print(msg);
+        out.flush();
+        out.close();
+    }
+}

+ 154 - 0
src/main/java/com/td/WaDa/config/security/LoginSuccessHandlerConfig.java

@@ -0,0 +1,154 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.sys.sysuser.service.SysUserService;
+import com.td.WaDa.sys.sysuser.vo.SysUserVo;
+import com.td.WaDa.util.*;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
+import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 登录成功处理,登陆成功后还需要验证账号的有效性
+ */
+@Component
+@Slf4j
+public class LoginSuccessHandlerConfig implements AuthenticationSuccessHandler {
+    @Autowired
+    private SessionRegistry sessionRegistry;
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    @Override
+    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
+        //从全局注册表中获取所有登陆用户,做用户单登陆判断
+        ArrayList<String> allSessionIdList = new ArrayList<>();
+        List<SessionInformation> allSessions = sessionRegistry.getAllSessions(authentication.getPrincipal(), false);
+        for (SessionInformation sessionInformation : allSessions) {
+            allSessionIdList.add(sessionInformation.getSessionId());
+        }
+
+        //查询当前与系统交互的用户,存储在本地线程安全上下文,校验账号有效性
+        User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        SysUserVo sysUserVo = sysUserService.findByLoginName(user.getUsername()).getData();
+
+        //默认登陆成功
+        String msg = "{\"code\":\"300\",\"msg\":\"登录成功\",\"url\":\"/index\"}";
+        boolean flag = false;
+
+        //登陆IP不在白名单
+        String ipAddr = IpUtil.getIpAddr(httpServletRequest);
+        String limitedIp = sysUserVo.getLimitedIp();
+        if(!StringUtils.isEmpty(limitedIp) && !Arrays.asList(limitedIp.split(",")).contains(ipAddr)){
+            msg = "{\"code\":\"400\",\"msg\":\"登陆IP不在白名单,请联系管理员\"}";
+            flag = true;
+        }
+
+        //禁止多人在线
+        if("N".equals(sysUserVo.getLimitMultiLogin()) &&  allSessionIdList.size() > 0){
+            msg = "{\"code\":\"400\",\"msg\":\"该账号禁止多人在线,请联系管理员\"}";
+            flag = true;
+        }
+
+        //超出有效时间
+        if(!StringUtils.isEmpty(sysUserVo.getExpiredTime()) && new Date().getTime() > sysUserVo.getExpiredTime().getTime()){
+            msg = "{\"code\":\"400\",\"msg\":\"该账号已失效,请联系管理员\"}";
+            flag = true;
+        }
+
+        //禁止登陆系统
+        if("N".equals(sysUserVo.getValid())){
+            msg = "{\"code\":\"400\",\"msg\":\"该账号已被禁止登陆系统,请联系管理员\"}";
+            flag = true;
+        }
+
+        //校验不通过
+        if(flag){
+            //清除当前的上下文
+            SecurityContextHolder.clearContext();
+
+            //清除remember-me持久化tokens
+            persistentTokenRepository1().removeUserTokens(user.getUsername());
+        }
+        else{
+            //校验通过,注册session
+            sessionRegistry.registerNewSession(httpServletRequest.getSession().getId(),user);
+        }
+
+        //判断api加密开关是否开启
+        if("Y".equals(redisSettingMap.getSysSettingMap().getSysApiEncrypt())) {
+            //加密
+            try {
+                //前端公钥
+                String publicKey = httpServletRequest.getParameter("publicKey");
+
+                log.info("前端公钥:" + publicKey);
+
+                //jackson
+                ObjectMapper mapper = new ObjectMapper();
+                //jackson 序列化和反序列化 date处理
+                mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+                //每次响应之前随机获取AES的key,加密data数据
+                String key = AesUtil.getKey();
+                log.info("AES的key:" + key);
+                log.info("需要加密的data数据:" + msg);
+                String data = AesUtil.encrypt(msg, key);
+
+                //用前端的公钥来解密AES的key,并转成Base64
+                String aesKey = Base64.encodeBase64String(RsaUtil.encryptByPublicKey(key.getBytes(), publicKey));
+
+                msg = "{\"data\":{\"data\":\"" + data + "\",\"aesKey\":\"" + aesKey + "\"}}";
+            } catch (Throwable e) {
+                //输出到日志文件中
+                log.error(ErrorUtil.errorInfoToString(e));
+            }
+        }
+
+        //转json字符串并转成Object对象,设置到Result中并赋值给返回值o
+        httpServletResponse.setCharacterEncoding("UTF-8");
+        httpServletResponse.setContentType("application/json; charset=utf-8");
+        PrintWriter out = httpServletResponse.getWriter();
+        out.print(msg);
+        out.flush();
+        out.close();
+    }
+
+    @Bean
+    public PersistentTokenRepository persistentTokenRepository1() {
+        JdbcTokenRepositoryImpl persistentTokenRepository = new JdbcTokenRepositoryImpl();
+        persistentTokenRepository.setDataSource(dataSource);
+        return persistentTokenRepository;
+    }
+}

+ 37 - 0
src/main/java/com/td/WaDa/config/security/LogoutHandlerConfig.java

@@ -0,0 +1,37 @@
+package com.td.WaDa.config.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 注销处理
+ */
+@Component
+public class LogoutHandlerConfig implements LogoutHandler {
+    @Autowired
+    private SessionRegistry sessionRegistry;
+
+    @Override
+    public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
+        //剔除退出用户
+        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        if (principal !=null){
+            List<SessionInformation> allSessions = sessionRegistry.getAllSessions(principal, false);
+            if (allSessions != null) {
+                for (SessionInformation sessionInformation : allSessions) {
+                    sessionInformation.expireNow();
+                    sessionRegistry.removeSessionInformation(sessionInformation.getSessionId());
+                }
+            }
+        }
+    }
+}

+ 56 - 0
src/main/java/com/td/WaDa/config/security/MyAccessDecisionManager.java

@@ -0,0 +1,56 @@
+package com.td.WaDa.config.security;
+
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.vote.AbstractAccessDecisionManager;
+import org.springframework.security.authentication.InsufficientAuthenticationException;
+import org.springframework.security.core.Authentication;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 提供一个认证管理器
+ */
+public class MyAccessDecisionManager extends AbstractAccessDecisionManager {
+
+    MyAccessDecisionManager(List<AccessDecisionVoter<?>> decisionVoters) {
+        super(decisionVoters);
+    }
+
+    @Override
+    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
+            throws AccessDeniedException, InsufficientAuthenticationException {
+        int deny = 0;
+
+        for (AccessDecisionVoter voter : getDecisionVoters()) {
+            int result = voter.vote(authentication, object, configAttributes);
+
+            if (logger.isDebugEnabled()) {
+                logger.debug("Voter: " + voter + ", returned: " + result);
+            }
+
+            switch (result) {
+                case AccessDecisionVoter.ACCESS_GRANTED:
+                    return;
+
+                case AccessDecisionVoter.ACCESS_DENIED:
+                    deny++;
+
+                    break;
+
+                default:
+                    break;
+            }
+        }
+
+        if (deny > 0) {
+            throw new AccessDeniedException(messages.getMessage(
+                    "AbstractAccessDecisionManager.accessDenied", "Access is denied"));
+        }
+
+        // To get this far, every AccessDecisionVoter abstained
+        checkAllowIfAllAbstainDecisions();
+    }
+}

+ 77 - 0
src/main/java/com/td/WaDa/config/security/MyFilterInvocationSecurityMetadataSource.java

@@ -0,0 +1,77 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.sys.sysauthority.vo.SysAuthorityVo;
+import org.springframework.security.access.ConfigAttribute;
+import org.springframework.security.access.SecurityConfig;
+import org.springframework.security.web.FilterInvocation;
+import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 配置认证数据源,实现动态权限加载(注意:不要手动new,把它交给spring管理,spring默认单例)
+ */
+@Component
+public class MyFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
+    //权限数据
+    private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap;
+
+    /**
+     * 在我们初始化的权限数据中找到对应当前url的权限数据
+     */
+    @Override
+    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
+        FilterInvocation fi = (FilterInvocation) object;
+        HttpServletRequest request = fi.getRequest();
+
+        //遍历我们初始化的权限数据,找到对应的url对应的权限
+        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap
+                .entrySet()) {
+            if (entry.getKey().matches(request)) {
+                return entry.getValue();
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public Collection<ConfigAttribute> getAllConfigAttributes() {
+        return null;
+    }
+
+    @Override
+    public boolean supports(Class<?> clazz) {
+        return FilterInvocation.class.isAssignableFrom(clazz);
+    }
+
+    /**
+     * 更新权限集合
+     */
+    public void setRequestMap(List<SysAuthorityVo> authorityVoList){
+        Map<RequestMatcher, Collection<ConfigAttribute>> map = new ConcurrentHashMap<>();
+        for (SysAuthorityVo sysAuthorityVo : authorityVoList) {
+            String authorityName = sysAuthorityVo.getAuthorityName();
+            if (StringUtils.isEmpty(sysAuthorityVo.getAuthorityContent())) continue;
+            for (String url : sysAuthorityVo.getAuthorityContent().split(",")) {
+                Collection<ConfigAttribute> value = map.get(new AntPathRequestMatcher(url));
+                if (StringUtils.isEmpty(value)) {
+                    ArrayList<ConfigAttribute> configs = new ArrayList<>();
+                    configs.add(new SecurityConfig(authorityName));
+                    map.put(new AntPathRequestMatcher(url), configs);
+                } else {
+                    value.add(new SecurityConfig(authorityName));
+                }
+            }
+        }
+        this.requestMap = map;
+    }
+}

+ 51 - 0
src/main/java/com/td/WaDa/config/security/MyInvalidSessionStrategy.java

@@ -0,0 +1,51 @@
+package com.td.WaDa.config.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.web.session.InvalidSessionStrategy;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+
+/**
+ * 自定义session失效策略
+ */
+@Component
+@Slf4j
+public class MyInvalidSessionStrategy implements InvalidSessionStrategy {
+    @Autowired
+    private SessionRegistry sessionRegistry;
+
+    @Value("${server.servlet.context-path:}")
+    private String contextPath;
+
+    @Override
+    public void onInvalidSessionDetected(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException {
+        HttpSession session = httpServletRequest.getSession();
+        String sessionId = httpServletRequest.getRequestedSessionId();
+        if(!session.isNew()){
+            //内部重定向
+            httpServletResponse.sendRedirect("/loginPage");
+        }else{
+            //直接输出js脚本跳转
+            httpServletResponse.setContentType("text/html;charset=UTF-8");
+            httpServletResponse.getWriter().print("<script type='text/javascript'>window.location.href = \"" + contextPath + "/loginPage\"</script>");
+        }
+        SessionInformation sessionInformation = sessionRegistry.getSessionInformation(sessionId);
+        if(sessionInformation != null){
+            User user = (User) sessionInformation.getPrincipal();
+            sessionRegistry.removeSessionInformation(sessionId);
+            log.info("剔除过期用户:"+user.getUsername());
+        }
+        log.info("session失效处理 " + sessionRegistry.getAllPrincipals().size()+"");
+        httpServletResponse.flushBuffer();
+    }
+}

+ 20 - 0
src/main/java/com/td/WaDa/config/security/PasswordConfig.java

@@ -0,0 +1,20 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.util.MD5Util;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PasswordConfig implements PasswordEncoder {
+
+    @Override
+    public String encode(CharSequence charSequence) {
+        //charSequence是用户输入的密码,password是存库的密码
+        return MD5Util.getMD5(charSequence.toString());
+    }
+
+    @Override
+    public boolean matches(CharSequence charSequence, String password) {
+        return password.contentEquals(encode(charSequence));
+    }
+}

+ 148 - 0
src/main/java/com/td/WaDa/config/security/SecurityConfig.java

@@ -0,0 +1,148 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.sys.sysauthority.service.SysAuthorityService;
+import com.td.WaDa.sys.sysauthority.vo.SysAuthorityVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.access.AccessDecisionVoter;
+import org.springframework.security.access.vote.RoleVoter;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
+import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.List;
+
+@EnableWebSecurity
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Autowired
+    private CaptchaFilterConfig captchaFilterConfig;
+
+    @Autowired
+    private UserConfig userConfig;
+
+    @Autowired
+    private PasswordConfig passwordConfig;
+
+    @Autowired
+    private LoginFailureHandlerConfig loginFailureHandlerConfig;
+
+    @Autowired
+    private LoginSuccessHandlerConfig loginSuccessHandlerConfig;
+
+    @Autowired
+    private LogoutHandlerConfig logoutHandlerConfig;
+
+    @Autowired
+    private SysAuthorityService sysAuthorityService;
+
+    @Autowired
+    private MyFilterInvocationSecurityMetadataSource myFilterInvocationSecurityMetadataSource;
+
+    @Autowired
+    private MyInvalidSessionStrategy myInvalidSessionStrategy;
+
+    @Autowired
+    private DataSource dataSource;
+
+    @Override
+    public void configure(WebSecurity web) throws Exception {
+        // game 走 token验证流程
+        web.ignoring().antMatchers("/game/**","/game_websocket/**","/static/**");
+    }
+
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+        auth
+                //用户认证处理
+                .userDetailsService(userConfig)
+                //密码处理
+                .passwordEncoder(passwordConfig);
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http
+                // 关闭csrf防护
+                .csrf().disable()
+                .headers().frameOptions().disable()
+                .and();
+
+        http
+                //登录处理
+                .addFilterBefore(captchaFilterConfig, UsernamePasswordAuthenticationFilter.class)
+                .formLogin()
+                .loginProcessingUrl("/login")
+                //未登录时默认跳转页面
+                .loginPage("/loginPage")
+                .failureHandler(loginFailureHandlerConfig)
+                .successHandler(loginSuccessHandlerConfig)
+                .permitAll()
+                .and();
+        http
+                //登出处理
+                .logout()
+                .addLogoutHandler(logoutHandlerConfig)
+                .logoutUrl("/logout")
+                .logoutSuccessUrl("/loginPage")
+                .permitAll()
+                .and();
+        http
+                //"play_back"
+                //.mvcMatcher("/game")
+                //定制url访问权限,动态权限读取,参考:https://www.jianshu.com/p/0a06496e75ea
+                .addFilterAfter(dynamicallyUrlInterceptor(), FilterSecurityInterceptor.class)
+                .authorizeRequests()
+                //无需权限访问
+                .antMatchers("/favicon.ico","/common/**", "/webjars/**", "/getVerifyCodeImage","/error/*"
+                ).permitAll()
+                 //其他接口需要登录后才能访问
+                .anyRequest().authenticated()
+                .and();
+        http.sessionManagement()
+                //session无效处理策略
+                .invalidSessionStrategy(myInvalidSessionStrategy)
+                .and();
+        http
+                //开启记住我
+                .rememberMe()
+                .tokenValiditySeconds(604800)//七天免登陆
+                .tokenRepository(persistentTokenRepository())
+                .userDetailsService(userConfig)
+                .and();
+    }
+
+    @Bean
+    public PersistentTokenRepository persistentTokenRepository() {
+        JdbcTokenRepositoryImpl persistentTokenRepository = new JdbcTokenRepositoryImpl();
+        persistentTokenRepository.setDataSource(dataSource);
+        return persistentTokenRepository;
+    }
+
+    //配置filter
+    @Bean
+    public DynamicallyUrlInterceptor dynamicallyUrlInterceptor(){
+        //首次获取
+        List<SysAuthorityVo> authorityVoList = sysAuthorityService.list(new SysAuthorityVo()).getData();
+        myFilterInvocationSecurityMetadataSource.setRequestMap(authorityVoList);
+        //初始化拦截器并添加数据源
+        DynamicallyUrlInterceptor interceptor = new DynamicallyUrlInterceptor();
+        interceptor.setSecurityMetadataSource(myFilterInvocationSecurityMetadataSource);
+
+        //配置RoleVoter决策
+        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
+        decisionVoters.add(new RoleVoter());
+
+        //设置认证决策管理器
+        interceptor.setAccessDecisionManager(new MyAccessDecisionManager(decisionVoters));
+        return interceptor;
+    }
+}

+ 51 - 0
src/main/java/com/td/WaDa/config/security/UserConfig.java

@@ -0,0 +1,51 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.sys.sysuser.service.SysUserService;
+import com.td.WaDa.sys.sysuser.vo.SysUserVo;
+import com.td.WaDa.sys.sysuserauthority.service.SysUserAuthorityService;
+import com.td.WaDa.sys.sysuserauthority.vo.SysUserAuthorityVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+@Component
+public class UserConfig implements UserDetailsService {
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @Autowired
+    private SysUserAuthorityService sysUserAuthorityService;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        //查询用户
+        SysUserVo sysUserVo = sysUserService.findByLoginName(username).getData();
+        //查询权限
+        List<SysUserAuthorityVo> sysUserAuthorityVoList = sysUserAuthorityService.findByUserId(sysUserVo.getUserId()).getData();
+        StringBuilder authorityList = new StringBuilder();
+        for (int i = 0; i < sysUserAuthorityVoList.size(); i++) {
+            SysUserAuthorityVo sysUserAuthorityVo = sysUserAuthorityVoList.get(i);
+            authorityList.append(sysUserAuthorityVo.getSysAuthority().getAuthorityName());
+            if (i != sysUserAuthorityVoList.size() - 1) {
+                authorityList.append(",");
+            }
+        }
+
+        //查无此用户
+        if(StringUtils.isEmpty(sysUserVo.getUserId())){
+            sysUserVo.setLoginName("查无此用户");
+            sysUserVo.setPassword("查无此用户");
+        }
+
+        // 封装用户信息,并返回。参数分别是:用户名,密码,用户权限
+        return new User(sysUserVo.getLoginName(), sysUserVo.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList(authorityList.toString()));
+    }
+}

+ 51 - 0
src/main/java/com/td/WaDa/config/security/gameConfig.java

@@ -0,0 +1,51 @@
+package com.td.WaDa.config.security;
+
+import com.td.WaDa.sys.sysuser.service.SysUserService;
+import com.td.WaDa.sys.sysuser.vo.SysUserVo;
+import com.td.WaDa.sys.sysuserauthority.service.SysUserAuthorityService;
+import com.td.WaDa.sys.sysuserauthority.vo.SysUserAuthorityVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+@Component
+public class gameConfig implements UserDetailsService {
+
+    @Autowired
+    private SysUserService sysUserService;
+
+    @Autowired
+    private SysUserAuthorityService sysUserAuthorityService;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        //查询用户
+        SysUserVo sysUserVo = sysUserService.findByLoginName(username).getData();
+        //查询权限
+        List<SysUserAuthorityVo> sysUserAuthorityVoList = sysUserAuthorityService.findByUserId(sysUserVo.getUserId()).getData();
+        StringBuilder authorityList = new StringBuilder();
+        for (int i = 0; i < sysUserAuthorityVoList.size(); i++) {
+            SysUserAuthorityVo sysUserAuthorityVo = sysUserAuthorityVoList.get(i);
+            authorityList.append(sysUserAuthorityVo.getSysAuthority().getAuthorityName());
+            if (i != sysUserAuthorityVoList.size() - 1) {
+                authorityList.append(",");
+            }
+        }
+
+        //查无此用户
+        if(StringUtils.isEmpty(sysUserVo.getUserId())){
+            sysUserVo.setLoginName("查无此用户");
+            sysUserVo.setPassword("查无此用户");
+        }
+
+        // 封装用户信息,并返回。参数分别是:用户名,密码,用户权限
+        return new User(sysUserVo.getLoginName(), sysUserVo.getPassword(), AuthorityUtils.commaSeparatedStringToAuthorityList(authorityList.toString()));
+    }
+}

+ 34 - 0
src/main/java/com/td/WaDa/config/token/WebConfig.java

@@ -0,0 +1,34 @@
+package com.td.WaDa.config.token;
+
+import com.td.WaDa.filter.gameFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import javax.servlet.Filter;
+
+/**
+ * @author:slambb
+ * @date:2021/03/27
+ */
+@Configuration
+public class WebConfig {
+
+    @Bean
+    public Filter gameFilter() {
+        return new gameFilter();
+    }
+
+
+    @Bean
+    public FilterRegistrationBean authorizeFilterRegistration() {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new DelegatingFilterProxy("gameFilter"));
+        registration.addUrlPatterns("/game/*");
+        registration.setName("gameFilter");
+        registration.setOrder(1);
+        return registration;
+    }
+
+}

+ 26 - 0
src/main/java/com/td/WaDa/config/websocket/MyEndpointConfigure.java

@@ -0,0 +1,26 @@
+package com.td.WaDa.config.websocket;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import javax.websocket.server.ServerEndpointConfig;
+
+/**
+ * 解决注入其他类的问题,详情参考这篇帖子:webSocket无法注入其他类:https://blog.csdn.net/tornadojava/article/details/78781474
+ */
+public class MyEndpointConfigure extends ServerEndpointConfig.Configurator implements ApplicationContextAware {
+
+    private static volatile BeanFactory context;
+
+    @Override
+    public <T> T getEndpointInstance(Class<T> clazz){
+        return context.getBean(clazz);
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        MyEndpointConfigure.context = applicationContext;
+    }
+}

+ 32 - 0
src/main/java/com/td/WaDa/config/websocket/WebSocketConfig.java

@@ -0,0 +1,32 @@
+package com.td.WaDa.config.websocket;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+/**
+ * WebSocket配置
+ */
+@Configuration
+public class WebSocketConfig {
+
+
+    /**
+     * 用途:扫描并注册所有携带@ServerEndpoint注解的实例。 @ServerEndpoint("/websocket")
+     * PS:如果使用外部容器 则无需提供ServerEndpointExporter。
+     */
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
+
+    /**
+     * 支持注入其他类
+     */
+    @Bean
+    public MyEndpointConfigure newMyEndpointConfigure (){
+        return new MyEndpointConfigure ();
+    }
+
+
+}

+ 184 - 0
src/main/java/com/td/WaDa/filter/gameFilter.java

@@ -0,0 +1,184 @@
+package com.td.WaDa.filter;
+
+
+import cn.hutool.core.convert.Convert;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.config.enums.ResultEnum;
+import com.td.WaDa.util.*;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.SignatureException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author:slambb
+ * @date:2021/03/27
+ */
+@Slf4j
+public class gameFilter implements Filter {
+    @Value("${jwt.token}")
+    private String tokenHeader;
+
+    @Autowired
+    private JwtTokenUtil jwtTokenUtil;
+
+    //添加redis 防止恶意请求
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    @Autowired
+    private RedisSettingMap redisSettingMap;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    @Override
+    public void destroy() {
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        //处理跨域请求
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+        response.setHeader("Access-Control-Allow-Origin", "*");
+        response.setHeader("Access-Control-Allow-Credentials", "true");
+        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
+        response.setHeader("Access-Control-Max-Age", "3600");
+        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept , Authorization");
+
+        //log.info("********进入GameFilter过滤器********");
+        HttpServletRequest req = (HttpServletRequest) servletRequest;
+        //String method = req.getMethod();
+        //if (method.equals("OPTIONS")) {
+        //    response.setStatus(200);
+        //    response.flushBuffer();
+        //    return;
+        //}
+        //登陆IP不在白名单
+        String ipAddr = IpUtil.getIpAddr(req);
+
+        String token = req.getHeader(tokenHeader);
+        String path = req.getServletPath();
+
+        //这里三个接口给DApp后台调用,需要指定ip访问
+        if (path.indexOf("getSNBAndFreeze") > -1
+                || path.indexOf("setSNBAndUnfreeze") > -1
+                || path.indexOf("cntPlayback") > -1) {
+            log.info("ipAddr:" + ipAddr);
+            //IpVo ipVo = IpUtil.getIpVoByRequest(req);
+            //log.info("ip2Addr:"+ ipVo.toString());
+            String limitedIp = redisSettingMap.getSysSettingLimitMap().getLimitedIp();
+            if (StringUtils.hasText(limitedIp) && !Arrays.asList(limitedIp.split(",")).contains(ipAddr)) {
+                response.setCharacterEncoding("UTF-8");
+                response.setContentType("application/json; charset=utf-8");
+                PrintWriter out = response.getWriter();
+
+                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.LOGIN_IP_IS_ERROR.getMessage(), ResultEnum.LOGIN_IP_IS_ERROR.getCode())));
+                out.flush();
+                out.close();
+                return;
+            }
+            filterChain.doFilter(servletRequest, response);
+            return;
+        }
+
+        /**
+         * 除了上面三个提供给DApp的接口,剩下的game接口都需要限制访问
+         */
+        //设置20秒内可以访问10次,同一个接口
+        String redisKey = "limit-req:".concat(req.getRequestURL().toString()).concat(":").concat(ipAddr);
+        if (!redisTemplate.hasKey(redisKey)) {
+            redisTemplate.opsForValue().set(redisKey, String.valueOf(1), 20, TimeUnit.SECONDS);
+        } else {
+            int increment = Convert.toInt(redisTemplate.opsForValue().get(redisKey));
+            if (increment > 10) {
+                response.setCharacterEncoding("UTF-8");
+                response.setContentType("application/json; charset=utf-8");
+                PrintWriter out = response.getWriter();
+                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.REDIS_IS_LOCK.getMessage(), ResultEnum.REDIS_IS_LOCK.getCode())));
+                out.flush();
+                out.close();
+                return;
+            } else {
+                redisTemplate.opsForValue().set(redisKey, String.valueOf(++increment), 20, TimeUnit.SECONDS);
+            }
+        }
+
+        //登录,获取验证码,不用登录的接口
+        // 存在game字段,需要检验token
+        if (!(path.indexOf("game") > -1)
+                || path.indexOf("loginToken") > -1
+                || path.indexOf("login") > -1
+                || path.indexOf("hutoolRSAConfig") > -1
+        ) {
+            //登录情况直接放行
+            filterChain.doFilter(servletRequest, response);
+            return;
+        }
+
+
+        if (null == token || token.isEmpty() || !token.startsWith("Bearer ")) {
+            //没有token信息
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/json; charset=utf-8");
+            PrintWriter out = response.getWriter();
+            out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.TOKEN_DOES_NOT_EXIST.getMessage(), ResultEnum.TOKEN_DOES_NOT_EXIST.getCode())));
+            out.flush();
+            out.close();
+            return;
+        } else {
+            String authToken = token.substring(7);
+            try {
+                String userId = jwtTokenUtil.getUserIdFromToken(authToken);
+                //log.info("userId:{}", userId);
+                //todo 后面需要校验时间,加入可切换 secret 校验
+                //log.info("validateToken:{}", jwtTokenUtil.validateToken(authToken, userId));
+                // 加入secret校验
+                if (!jwtTokenUtil.validateToken(authToken, userId)) {
+                    log.info("secret 不可靠,validateToken:{}", jwtTokenUtil.validateToken(authToken, userId));
+                }
+                if (StringUtils.hasText(userId)) {
+                    filterChain.doFilter(new TokenRequestWrapper((HttpServletRequest) servletRequest, userId), response);
+                } else {
+                    //不存在用户信息
+                    response.setCharacterEncoding("UTF-8");
+                    response.setContentType("application/json; charset=utf-8");
+                    PrintWriter out = response.getWriter();
+                    out.print(JsonUtils.toJson(Result.of(authToken, false, ResultEnum.TOKEN_DOES_NOT_HAVE_USER_ID.getMessage(), ResultEnum.TOKEN_DOES_NOT_HAVE_USER_ID.getCode())));
+                    out.flush();
+                    out.close();
+                }
+            } catch (ExpiredJwtException e) {
+                //token过期
+                response.setCharacterEncoding("UTF-8");
+                response.setContentType("application/json; charset=utf-8");
+                PrintWriter out = response.getWriter();
+                out.print(JsonUtils.toJson(Result.of(null, false, ResultEnum.TOKEN_OUT_OF_DATE.getMessage(), ResultEnum.TOKEN_OUT_OF_DATE.getCode())));
+                out.flush();
+                out.close();
+            } catch (SignatureException e) {
+                //secret校验密钥不对
+                response.setCharacterEncoding("UTF-8");
+                response.setContentType("application/json; charset=utf-8");
+                PrintWriter out = response.getWriter();
+                out.print(JsonUtils.toJson(Result.of(authToken, false, ResultEnum.TOKEN_IS_ILLEGAL.getMessage(), ResultEnum.TOKEN_IS_ILLEGAL.getCode())));
+                out.flush();
+                out.close();
+            }
+
+        }
+
+    }
+}

+ 15 - 0
src/main/java/com/td/WaDa/game/comcntorder/controller/ComCntOrderController.java

@@ -0,0 +1,15 @@
+package com.td.WaDa.game.comcntorder.controller;
+
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.game.comcntorder.pojo.ComCntOrder;
+import com.td.WaDa.game.comcntorder.vo.ComCntOrderVo;
+import com.td.WaDa.game.comcntorder.service.ComCntOrderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/game/comCntOrder/")
+public class ComCntOrderController extends CommonController<ComCntOrderVo, ComCntOrder, String> {
+    @Autowired
+    private ComCntOrderService comCntOrderService;
+}

+ 33 - 0
src/main/java/com/td/WaDa/game/comcntorder/pojo/ComCntOrder.java

@@ -0,0 +1,33 @@
+package com.td.WaDa.game.comcntorder.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_cnt_order")
+@Data
+public class ComCntOrder implements Serializable {
+    @Id
+    private String id;//
+
+    private String userId;//
+
+    private String address;//
+
+    private Integer payType;//
+
+    private String payAmount;//
+
+    private String itemType;
+
+    private String txHash;//
+
+    private String cntDescribe;
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+
+}

+ 40 - 0
src/main/java/com/td/WaDa/game/comcntorder/repository/ComCntOrderRepository.java

@@ -0,0 +1,40 @@
+package com.td.WaDa.game.comcntorder.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.comcntorder.pojo.ComCntOrder;
+import com.td.WaDa.game.comcntorder.vo.ComCntOrderPayTypeSumVo;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface ComCntOrderRepository extends CommonRepository<ComCntOrder, String> {
+
+    Optional<ComCntOrder> findByTxHash(String tx);
+
+    List<ComCntOrder> findByUserIdAndPayType(String userId,Integer payType);
+
+    //SELECT pay_type,sum(pay_amount) from com_cnt_order WHERE pay_type = 4
+
+    /**
+     * 返回一个降序的pay_type 统计
+     *
+     * @return
+     */
+    @Query(value = "SELECT new com.td.WaDa.game.comcntorder.vo.ComCntOrderPayTypeSumVo(u.payType,sum(u.payAmount)) from ComCntOrder u GROUP BY u.payType ORDER BY sum(u.payAmount) desc", nativeQuery = false)
+    List<ComCntOrderPayTypeSumVo> findCNTSumByPayType();
+
+
+    /**
+     * 根据开始结束时间获取payType 统计数据
+     * @param startTime
+     * @param endTime
+     * @return
+     */
+    @Query(value = "SELECT new com.td.WaDa.game.comcntorder.vo.ComCntOrderPayTypeSumVo(u.payType,sum(u.payAmount)) FROM  ComCntOrder u  where u.createTime >= :startTime and u.createTime<= :endTime GROUP BY u.payType ORDER BY sum(u.payAmount) desc")
+    List<ComCntOrderPayTypeSumVo> findCNTSumByPayTypeFromDate(Date startTime, Date endTime);
+
+}

+ 25 - 0
src/main/java/com/td/WaDa/game/comcntorder/service/ComCntOrderService.java

@@ -0,0 +1,25 @@
+package com.td.WaDa.game.comcntorder.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comcntorder.pojo.ComCntOrder;
+import com.td.WaDa.game.comcntorder.vo.ComCntOrderPayTypeSumVo;
+import com.td.WaDa.game.comcntorder.vo.ComCntOrderVo;
+
+import java.util.Date;
+import java.util.List;
+
+public interface ComCntOrderService extends CommonService<ComCntOrderVo, ComCntOrder, String> {
+
+    ComCntOrderVo findByTx(String tx);
+
+    List<ComCntOrder>  findByUserIdAndPayType(String userId,Integer payType);
+
+    //返回一个全部总量,需要去除负数情况,负数另外计算
+    List<ComCntOrderPayTypeSumVo> findAllCNTSumGroupByPayType();
+
+    //返回一个日期查找的总量,需要去除负数情况,负数另外计算
+    List<ComCntOrderPayTypeSumVo> findAllCNTSumGroupByPayTypeFromDate(Date startTime, Date endTime);
+
+
+
+}

+ 54 - 0
src/main/java/com/td/WaDa/game/comcntorder/service/ComCntOrderServiceImpl.java

@@ -0,0 +1,54 @@
+package com.td.WaDa.game.comcntorder.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comcntorder.pojo.ComCntOrder;
+import com.td.WaDa.game.comcntorder.vo.ComCntOrderPayTypeSumVo;
+import com.td.WaDa.game.comcntorder.vo.ComCntOrderVo;
+import com.td.WaDa.game.comcntorder.repository.ComCntOrderRepository;
+import com.td.WaDa.util.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@Transactional
+public class ComCntOrderServiceImpl extends CommonServiceImpl<ComCntOrderVo, ComCntOrder, String> implements ComCntOrderService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComCntOrderRepository comCntOrderRepository;
+
+
+    @Override
+    public ComCntOrderVo findByTx(String tx) {
+        Optional<ComCntOrder> comCntOrder =  comCntOrderRepository.findByTxHash(tx);
+        if(comCntOrder.orElse(null) == null){
+            return null;
+        }else{
+            return CopyUtil.copy(comCntOrder.get(), ComCntOrderVo.class);
+        }
+    }
+
+    @Override
+    public List<ComCntOrder> findByUserIdAndPayType(String userId, Integer payType) {
+        return comCntOrderRepository.findByUserIdAndPayType(userId,payType);
+    }
+
+    @Override
+    public List<ComCntOrderPayTypeSumVo> findAllCNTSumGroupByPayType() {
+        return comCntOrderRepository.findCNTSumByPayType();
+    }
+
+
+    @Override
+    public List<ComCntOrderPayTypeSumVo> findAllCNTSumGroupByPayTypeFromDate(Date startTime,Date endTime) {
+        return comCntOrderRepository.findCNTSumByPayTypeFromDate(startTime, endTime);
+    }
+
+}

+ 18 - 0
src/main/java/com/td/WaDa/game/comcntorder/vo/ComCntOrderDateVo.java

@@ -0,0 +1,18 @@
+package com.td.WaDa.game.comcntorder.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author:slambb
+ * @date:2022/1/25
+ */
+@Data
+public class ComCntOrderDateVo {
+    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
+    private Date startTime;
+    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")
+    private Date endTime;
+}

+ 23 - 0
src/main/java/com/td/WaDa/game/comcntorder/vo/ComCntOrderPayTypeSumVo.java

@@ -0,0 +1,23 @@
+package com.td.WaDa.game.comcntorder.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * @author:slambb
+ * @date:2022/1/25
+ */
+@Getter
+@Setter
+@ToString
+public class ComCntOrderPayTypeSumVo {
+    private Integer payType;
+    private String cntSum;
+
+    public ComCntOrderPayTypeSumVo(Integer payType, String cntSum) {
+        this.payType = payType;
+        this.cntSum = cntSum;
+    }
+
+}

+ 28 - 0
src/main/java/com/td/WaDa/game/comcntorder/vo/ComCntOrderVo.java

@@ -0,0 +1,28 @@
+package com.td.WaDa.game.comcntorder.vo;
+
+import com.td.WaDa. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComCntOrderVo extends PageCondition implements Serializable {
+    private String id;//
+
+    private String userId;//
+
+    private String address;//
+
+    private Integer payType;//
+
+    private String payAmount;//
+
+    private String itemType;
+
+    private String txHash;//
+
+    private String cntDescribe;
+
+    private Date createTime;//创建时间
+
+    private Date updateTime;//修改时间
+}

+ 29 - 0
src/main/java/com/td/WaDa/game/comcnttosnb/controller/ComCntToSnbController.java

@@ -0,0 +1,29 @@
+package com.td.WaDa.game.comcnttosnb.controller;
+
+import com.td.WaDa.common.controller.CommonController;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.game.comcnttosnb.pojo.ComCntToSnb;
+import com.td.WaDa.game.comcnttosnb.service.ComCntToSnbService;
+import com.td.WaDa.game.comcnttosnb.vo.ComCntToSnbVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/game/comCntToSnb/")
+public class ComCntToSnbController extends CommonController<ComCntToSnbVo, ComCntToSnb, Integer> {
+    @Autowired
+    private ComCntToSnbService comCntToSnbService;
+
+    @GetMapping("get")
+    public Result<ComCntToSnbVo> get(@RequestParam(value = "userId") String userId) {
+        return Result.of(comCntToSnbService.findByUserId(userId));
+    }
+
+    @GetMapping("receive")
+    public Result<String> receive(@RequestParam(value = "userId") String userId) {
+        return comCntToSnbService.receiveByUserId(userId);
+    }
+}

+ 52 - 0
src/main/java/com/td/WaDa/game/comcnttosnb/pojo/ComCntToSnb.java

@@ -0,0 +1,52 @@
+package com.td.WaDa.game.comcnttosnb.pojo;
+
+import lombok.Data;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * cnt转snb
+ *
+ * @author why
+ * @date 2022/03/05
+ */
+@Data
+@Entity
+@Table(name = "com_cnt_to_snb")
+public class ComCntToSnb implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Long id;
+    /**
+     * 钱包地址
+     */
+    private String address;
+    /**
+     * 需要返还的总数
+     */
+    private BigDecimal totalQuantity;
+    /**
+     * 已领取数量
+     */
+    private BigDecimal receivedQuantity;
+
+    /**
+     * 领取总天数
+     */
+    private Integer totalDay;
+    /**
+     * 已领取天数
+     */
+    private Integer receivedDay;
+    /**
+     * 开始时间
+     */
+    private Date beginTime;
+    /**
+     * 状态(0=不可领取,1=可以领取)
+     */
+    private Integer status;
+}

+ 11 - 0
src/main/java/com/td/WaDa/game/comcnttosnb/repository/ComCntToSnbRespository.java

@@ -0,0 +1,11 @@
+package com.td.WaDa.game.comcnttosnb.repository;
+
+import com.td.WaDa.common.repository.CommonRepository;
+import com.td.WaDa.game.comcnttosnb.pojo.ComCntToSnb;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComCntToSnbRespository extends CommonRepository<ComCntToSnb, Integer> {
+
+    ComCntToSnb findByAddress(String address);
+}

+ 37 - 0
src/main/java/com/td/WaDa/game/comcnttosnb/service/ComCntToSnbService.java

@@ -0,0 +1,37 @@
+package com.td.WaDa.game.comcnttosnb.service;
+
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.common.service.CommonService;
+import com.td.WaDa.game.comcnttosnb.pojo.ComCntToSnb;
+import com.td.WaDa.game.comcnttosnb.vo.ComCntToSnbVo;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Cnt转Snb服务实现
+ *
+ * @author why
+ * @date 2022/03/05
+ */
+public interface ComCntToSnbService extends CommonService<ComCntToSnbVo, ComCntToSnb, Integer> {
+    /**
+     * 通过userid查看snb领取情况
+     *
+     * @param userId 用户id
+     * @return {@link ComCntToSnbVo}
+     */
+    ComCntToSnbVo findByUserId(String userId);
+
+    /**
+     * 通过userid领取snb
+     *
+     * @param userId 用户id
+     */
+    Result<String> receiveByUserId(String userId);
+
+
+    //根据时间段,导出全部数据
+    List<ComCntToSnb> getBetweenTimeList(Date begin, Date end);
+
+}

+ 185 - 0
src/main/java/com/td/WaDa/game/comcnttosnb/service/ComCntToSnbServiceImpl.java

@@ -0,0 +1,185 @@
+package com.td.WaDa.game.comcnttosnb.service;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.core.util.StrUtil;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.common.service.CommonServiceImpl;
+import com.td.WaDa.config.enums.ResultEnum;
+import com.td.WaDa.game.comcnttosnb.pojo.ComCntToSnb;
+import com.td.WaDa.game.comcnttosnb.repository.ComCntToSnbRespository;
+import com.td.WaDa.game.comcnttosnb.vo.ComCntToSnbVo;
+import com.td.WaDa.game.comsnbtran.service.ComSnbTranService;
+import com.td.WaDa.game.comsnbtran.vo.ComSnbTranVo;
+import com.td.WaDa.game.comusers.service.ComUsersService;
+import com.td.WaDa.game.comusers.vo.ComUsersVo;
+import com.td.WaDa.util.CopyUtil;
+import com.td.WaDa.util.RedisData;
+import com.td.WaDa.util.RedisLock;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@Service
+public class ComCntToSnbServiceImpl extends CommonServiceImpl<ComCntToSnbVo, ComCntToSnb, Integer> implements ComCntToSnbService {
+
+    @Autowired
+    private ComCntToSnbRespository comCntToSnbRespository;
+    @Autowired
+    private ComUsersService comUsersService;
+    @Autowired
+    private ComSnbTranService comSnbTranService;
+    @Autowired
+    private RedisLock redisLock;
+
+    /**
+     * 通过userid查看snb领取情况
+     *
+     * @param userId 用户id
+     * @return {@link ComCntToSnbVo}
+     */
+    @Override
+    public ComCntToSnbVo findByUserId(String userId) {
+        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
+        if (comUsersVo == null || StrUtil.isBlank(comUsersVo.getAddress())) {
+            return null;
+        }
+        ComCntToSnb comCntToSnb = comCntToSnbRespository.findByAddress(comUsersVo.getAddress());
+        return comCntToSnb == null ? null : CopyUtil.copy(comCntToSnb, ComCntToSnbVo.class);
+    }
+
+    /**
+     * 通过userid领取snb
+     *
+     * @param userId 用户id
+     * @return {@link Result}<{@link String}>
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Result<String> receiveByUserId(String userId) {
+        ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
+        if (comUsersVo == null || StrUtil.isBlank(comUsersVo.getAddress())) {
+            return Result.of(null, false, "未找到用户或钱包地址");
+        }
+        ComCntToSnb comCntToSnb = comCntToSnbRespository.findByAddress(comUsersVo.getAddress());
+        if (comCntToSnb == null || comCntToSnb.getStatus().equals(0)) {
+            return Result.of(null, false, "非法领取");
+        }
+        if (comCntToSnb.getReceivedDay() >= comCntToSnb.getTotalDay()) {
+            return Result.of(null, false, "已全部领取完毕");
+        }
+        if (comCntToSnb.getBeginTime() == null) {
+            return Result.of(null, false, "未设置领取开始时间");
+        }
+        // 服务器时间
+        Date serverDate = new Date();
+        // 未到领取时间
+        if (DateUtil.compare(comCntToSnb.getBeginTime(), serverDate) > 0) {
+            return Result.of(null, false, "未到领取时间");
+        }
+        // 计算本次可领天数. 服务器时间 - 开始时间 - 已领取天数
+        Integer day = Convert.toInt(DateUtil.betweenDay(comCntToSnb.getBeginTime(), serverDate, true)) - comCntToSnb.getReceivedDay() + 1;
+        log.info("领取人:" + userId);
+        log.info("领取开始时间:" + DateUtil.format(comCntToSnb.getBeginTime(), "yyyy-MM-dd"));
+        log.info("服务器时间:" + DateUtil.format(serverDate, "yyyy-MM-dd"));
+        log.info("已领取:" + comCntToSnb.getReceivedDay() + "天,本次领取天数:" + day + "天");
+        if (day <= 0) {
+            return Result.of(null, false, "领取失败,今日已领取");
+        }
+        long time = System.currentTimeMillis() + RedisData.getSnbTimeout();
+        String redisKey = StrUtil.format("SNB_SAVE_{}", userId);
+
+        try {
+            // redis锁
+            if (!redisLock.lock(redisKey, String.valueOf(time))) {
+                return Result.of(null, false, ResultEnum.SEED_SALE_SAVE_LOCK.getMessage(), ResultEnum.SEED_SALE_SAVE_LOCK.getCode());
+            }
+            // 单次领取数量
+            BigDecimal receiveNum = NumberUtil.round(NumberUtil.div(comCntToSnb.getTotalQuantity(), comCntToSnb.getTotalDay()), 2, RoundingMode.DOWN);
+            log.info("每天领取数量:" + receiveNum);
+            // 本次领取量
+            BigDecimal thisReceiveQuantity;
+            // 特例:领取周期100天,这个人间隔100以后上线
+            if (day >= comCntToSnb.getTotalDay() - comCntToSnb.getReceivedDay()) {
+                day = comCntToSnb.getTotalDay() - comCntToSnb.getReceivedDay();
+                log.info("由于本次领取天数大于剩余领取天数,所以最终领取天数:" + day);
+                thisReceiveQuantity = NumberUtil.sub(comCntToSnb.getTotalQuantity(), NumberUtil.mul(comCntToSnb.getReceivedDay(), receiveNum));
+            } else {
+                // 本次领取量
+                thisReceiveQuantity = NumberUtil.mul(receiveNum, day);
+            }
+
+            comCntToSnb.setReceivedQuantity(comCntToSnb.getReceivedQuantity().add(thisReceiveQuantity));
+            // 本次领取天数
+            comCntToSnb.setReceivedDay(comCntToSnb.getReceivedDay() + day);
+            // 更新领取信息
+            comCntToSnbRespository.save(comCntToSnb);
+
+            // 更新comUsers snb+
+            comUsersVo.setSnbPart(comUsersVo.getSnbPart() + Convert.toDouble(thisReceiveQuantity));
+            comUsersService.save(comUsersVo);
+
+            // 插入comSnbTran
+            ComSnbTranVo snbTran = new ComSnbTranVo();
+            //记录兑换id
+            snbTran.setTranId(Convert.toStr(comCntToSnb.getId()));
+            snbTran.setUserId(userId);
+            snbTran.setTranName("领取SNB");
+            snbTran.setTranType(8);
+            snbTran.setTranAmount(1);
+            snbTran.setTranPrice(0);
+            snbTran.setTranDescribe(StrUtil.format("user领取SNB、本次领取:{},剩余:{}", thisReceiveQuantity, comCntToSnb.getTotalQuantity().subtract(comCntToSnb.getReceivedQuantity())));
+            snbTran.setIsAdd(1);
+            snbTran.setBeforeSnb(comUsersVo.getSnb());
+            snbTran.setTranSnb(0);
+            snbTran.setAfterSnb(comUsersVo.getSnb());
+            // 交易的部分数据
+            snbTran.setTranAmountPart(Convert.toDouble(thisReceiveQuantity));
+            // 交易的snb
+            snbTran.setTranSnbPart(Convert.toDouble(thisReceiveQuantity));
+            // 交易之前的snb
+            snbTran.setBeforeSnbPart(Convert.toDouble(comCntToSnb.getReceivedQuantity().subtract(thisReceiveQuantity)));
+            // 交易完成后的snb
+            snbTran.setAfterSnbPart(Convert.toDouble(comCntToSnb.getReceivedQuantity()));
+            snbTran.setCreateTime(serverDate);
+            comSnbTranService.save(snbTran);
+
+            return Result.of(null, false, "领取成功");
+
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        } finally {
+            // redis解锁
+            redisLock.unlock(redisKey, String.valueOf(time));
+        }
+    }
+
+
+
+    @Override
+    public List<ComCntToSnb> getBetweenTimeList(Date begin, Date end) {
+        Specification specification = new Specification<ComCntToSnb>() {
+            @Override
+            public Predicate toPredicate(Root<ComCntToSnb> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
+                List<Predicate> predicates = new ArrayList<>();
+                predicates.add(criteriaBuilder.between(root.get("beginTime"), begin, end));
+                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
+            }
+        };
+        return comCntToSnbRespository.findAll(specification);
+    }
+}

+ 50 - 0
src/main/java/com/td/WaDa/game/comcnttosnb/vo/ComCntToSnbVo.java

@@ -0,0 +1,50 @@
+package com.td.WaDa.game.comcnttosnb.vo;
+
+import com.td.WaDa.common.pojo.PageCondition;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * cnt转snb
+ *
+ * @author why
+ * @date 2022/03/05
+ */
+@Data
+public class ComCntToSnbVo extends PageCondition implements Serializable {
+
+    private Long id;
+
+    /**
+     * 钱包地址
+     */
+    private String address;
+
+    /**
+     * 需要返还的总数
+     */
+    private BigDecimal totalQuantity;
+    /**
+     * 已领取数量
+     */
+    private BigDecimal receivedQuantity;
+    /**
+     * 领取总天数
+     */
+    private Integer totalDay;
+    /**
+     * 已领取天数
+     */
+    private Integer receivedDay;
+    /**
+     * 开始时间
+     */
+    private Date beginTime;
+    /**
+     * 状态(0=不可领取,1=可以领取)
+     */
+    private Integer status;
+}

+ 31 - 0
src/main/java/com/td/WaDa/game/comconfigland/controller/ComConfigLandController.java

@@ -0,0 +1,31 @@
+package com.td.WaDa.game.comconfigland.controller;
+
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.game.comconfigland.pojo.ComConfigLand;
+import com.td.WaDa.game.comconfigland.vo.ComConfigLandVo;
+import com.td.WaDa.game.comconfigland.service.ComConfigLandService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/game/configLand/")
+public class ComConfigLandController extends CommonController<ComConfigLandVo, ComConfigLand, Integer> {
+    @Autowired
+    private ComConfigLandService comConfigLandService;
+
+
+    /**
+     * 获取土地数据
+     * @param userId
+     * @return
+     */
+    @GetMapping("getList")
+    public Result<List<ComConfigLandVo>> getSNBFunction(@RequestParam(value = "userId") String userId) {
+        ComConfigLandVo comConfigLandVo = new ComConfigLandVo();
+        Result result = comConfigLandService.list(comConfigLandVo);
+        return result;
+    }
+}

+ 55 - 0
src/main/java/com/td/WaDa/game/comconfigland/pojo/ComConfigLand.java

@@ -0,0 +1,55 @@
+package com.td.WaDa.game.comconfigland.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_config_land")
+@Data
+public class ComConfigLand implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private String name;//
+
+    private Integer posX;//
+
+    private Integer posY;//
+
+    private Integer sizeX;//
+
+    private Integer sizeY;//
+
+    private Integer isInit;//是否在游戏中初始化租赁等数据
+
+    private Integer initMultiple;//初始化土地的倍数
+
+    private Integer isLease;//是否租凭
+
+    private Date leaseTime;//租凭时间
+
+    private Double leaseMultiple;//租赁的倍数
+
+    private Integer rental1;//3个月租赁费用CNT
+
+    private Integer rental2;//1年租赁费用CNT
+
+    private Integer rental3;//5年月租赁费用CNT
+
+    private Integer isPlant;//是否种植
+
+    private Date plantStart;//种植开始时间
+
+    private Integer plantMature;//成熟期
+
+    private String landDescribe;//土地描述
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+    private Integer mallType;
+}

+ 9 - 0
src/main/java/com/td/WaDa/game/comconfigland/repository/ComConfigLandRepository.java

@@ -0,0 +1,9 @@
+package com.td.WaDa.game.comconfigland.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.comconfigland.pojo.ComConfigLand;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComConfigLandRepository extends CommonRepository<ComConfigLand, Integer> {
+}

+ 13 - 0
src/main/java/com/td/WaDa/game/comconfigland/service/ComConfigLandService.java

@@ -0,0 +1,13 @@
+package com.td.WaDa.game.comconfigland.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comconfigland.pojo.ComConfigLand;
+import com.td.WaDa.game.comconfigland.vo.ComConfigLandVo;
+
+import java.util.List;
+
+public interface ComConfigLandService extends CommonService<ComConfigLandVo, ComConfigLand, Integer> {
+    ComConfigLand findById(Integer id);
+
+    List<ComConfigLand> findConfigLandAll();
+}

+ 33 - 0
src/main/java/com/td/WaDa/game/comconfigland/service/ComConfigLandServiceImpl.java

@@ -0,0 +1,33 @@
+package com.td.WaDa.game.comconfigland.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comconfigland.pojo.ComConfigLand;
+import com.td.WaDa.game.comconfigland.vo.ComConfigLandVo;
+import com.td.WaDa.game.comconfigland.repository.ComConfigLandRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.List;
+
+@Service
+@Transactional
+public class ComConfigLandServiceImpl extends CommonServiceImpl<ComConfigLandVo, ComConfigLand, Integer> implements ComConfigLandService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComConfigLandRepository comConfigLandRepository;
+
+
+    @Override
+    public ComConfigLand findById(Integer id) {
+        return comConfigLandRepository.findById(id).orElse(null);
+    }
+
+    @Override
+    public List<ComConfigLand> findConfigLandAll() {
+        return comConfigLandRepository.findAll();
+    }
+}

+ 54 - 0
src/main/java/com/td/WaDa/game/comconfigland/vo/ComConfigLandVo.java

@@ -0,0 +1,54 @@
+package com.td.WaDa.game.comconfigland.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComConfigLandVo  implements Serializable { //extends PageCondition
+    private Integer id;//
+
+    private String name;//
+
+    private Integer posX;//
+
+    private Integer posY;//
+
+    private Integer sizeX;//
+
+    private Integer sizeY;//
+
+    private Integer isInit;//是否在游戏中初始化租赁等数据
+
+    private Integer initMultiple;//初始化土地的倍数
+
+    private Integer isLease;//是否租凭
+
+    private Date leaseTime;//租凭时间
+
+    private Double leaseMultiple;//租赁的倍数
+
+    private Integer rental1;//3个月租赁费用CNT
+
+    private Integer rental2;//1年租赁费用CNT
+
+    private Integer rental3;//5年月租赁费用CNT
+
+    private Integer isPlant;//是否种植
+
+    private Date plantStart;//种植开始时间
+
+    private Integer plantMature;//成熟期
+
+    private String landDescribe;//土地描述
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+    /**
+     * 需求 牧场养殖渔场,新增字段,
+     * 原有需求种地值0 牧场1 养殖2 淡水区3 海水区4
+     */
+    private Integer mallType;
+}

+ 15 - 0
src/main/java/com/td/WaDa/game/comexplainland/controller/ComExplainLandController.java

@@ -0,0 +1,15 @@
+package com.td.WaDa.game.comexplainland.controller;
+
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.game.comexplainland.pojo.ComExplainLand;
+import com.td.WaDa.game.comexplainland.vo.ComExplainLandVo;
+import com.td.WaDa.game.comexplainland.service.ComExplainLandService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/game/comExplainLand/")
+public class ComExplainLandController extends CommonController<ComExplainLandVo, ComExplainLand, String> {
+    @Autowired
+    private ComExplainLandService comExplainLandService;
+}

+ 52 - 0
src/main/java/com/td/WaDa/game/comexplainland/pojo/ComExplainLand.java

@@ -0,0 +1,52 @@
+package com.td.WaDa.game.comexplainland.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_explain_land")
+@Data
+public class ComExplainLand implements Serializable {
+    @Id
+    private String eId;//
+
+    private String userId;//
+
+    private Integer landId;//过期的租赁土地的id
+
+    private Date landCreate;//过期的租赁土地时候土地创建的日期
+
+    private Date leaseTime;//过期的土地租赁的时间
+
+    private Integer leaseMultiple;//过期的土地租赁倍数
+
+    private Integer leaseDate;//过期的土地租赁日期,1是3个月,2是1年,3是5年
+
+    private Integer isPlant;//过期的土地种子状态 是否种植:N:0,Y:1
+
+    private Integer plantId;//过期土地的种植id
+
+    private Date plantStart;//过期土地开始种植的时间
+
+    private Integer plantMature;//过期土地种植成熟期
+
+    private String landDescribe;//过期土地的描述
+
+    private Double rentalExpenses;//过期的土地的租赁费用
+
+    private Integer explainType;//过期类型。0:租赁到期
+
+    private String explainDescribe;//记录描述
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+    /**
+     * 需求 牧场养殖渔场,新增字段,
+     * 原有需求种地值0 牧场1 养殖2 淡水区3 海水区4
+     */
+    private Integer mallType;
+}

+ 9 - 0
src/main/java/com/td/WaDa/game/comexplainland/repository/ComExplainLandRepository.java

@@ -0,0 +1,9 @@
+package com.td.WaDa.game.comexplainland.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.comexplainland.pojo.ComExplainLand;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComExplainLandRepository extends CommonRepository<ComExplainLand, String> {
+}

+ 8 - 0
src/main/java/com/td/WaDa/game/comexplainland/service/ComExplainLandService.java

@@ -0,0 +1,8 @@
+package com.td.WaDa.game.comexplainland.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comexplainland.pojo.ComExplainLand;
+import com.td.WaDa.game.comexplainland.vo.ComExplainLandVo;
+
+public interface ComExplainLandService extends CommonService<ComExplainLandVo, ComExplainLand, String> {
+}

+ 21 - 0
src/main/java/com/td/WaDa/game/comexplainland/service/ComExplainLandServiceImpl.java

@@ -0,0 +1,21 @@
+package com.td.WaDa.game.comexplainland.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comexplainland.pojo.ComExplainLand;
+import com.td.WaDa.game.comexplainland.vo.ComExplainLandVo;
+import com.td.WaDa.game.comexplainland.repository.ComExplainLandRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class ComExplainLandServiceImpl extends CommonServiceImpl<ComExplainLandVo, ComExplainLand, String> implements ComExplainLandService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComExplainLandRepository comExplainLandRepository;
+}

+ 48 - 0
src/main/java/com/td/WaDa/game/comexplainland/vo/ComExplainLandVo.java

@@ -0,0 +1,48 @@
+package com.td.WaDa.game.comexplainland.vo;
+
+import com.td.WaDa. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComExplainLandVo extends PageCondition implements Serializable {
+    private String eId;//
+
+    private String userId;//
+
+    private Integer landId;//过期的租赁土地的id
+
+    private Date landCreate;//过期的租赁土地时候土地创建的日期
+
+    private Date leaseTime;//过期的土地租赁的时间
+
+    private Integer leaseMultiple;//过期的土地租赁倍数
+
+    private Integer leaseDate;//过期的土地租赁日期,1是3个月,2是1年,3是5年
+
+    private Integer isPlant;//过期的土地种子状态 是否种植:N:0,Y:1
+
+    private Integer plantId;//过期土地的种植id
+
+    private Date plantStart;//过期土地开始种植的时间
+
+    private Integer plantMature;//过期土地种植成熟期
+
+    private String landDescribe;//过期土地的描述
+
+    private Double rentalExpenses;//过期的土地的租赁费用
+
+    private Integer explainType;//过期类型。0:租赁到期
+
+    private String explainDescribe;//记录描述
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+    /**
+     * 需求 牧场养殖渔场,新增字段,
+     * 原有需求种地值0 牧场1 养殖2 淡水区3 海水区4
+     */
+    private Integer mallType;
+}

+ 15 - 0
src/main/java/com/td/WaDa/game/comfruit/controller/ComFruitController.java

@@ -0,0 +1,15 @@
+package com.td.WaDa.game.comfruit.controller;
+
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.game.comfruit.pojo.ComFruit;
+import com.td.WaDa.game.comfruit.vo.ComFruitVo;
+import com.td.WaDa.game.comfruit.service.ComFruitService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/game/comFruit/")
+public class ComFruitController extends CommonController<ComFruitVo, ComFruit, Integer> {
+    @Autowired
+    private ComFruitService comFruitService;
+}

+ 30 - 0
src/main/java/com/td/WaDa/game/comfruit/pojo/ComFruit.java

@@ -0,0 +1,30 @@
+package com.td.WaDa.game.comfruit.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_fruit")
+@Data
+public class ComFruit implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//
+
+    private String fruitDescribe;
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 9 - 0
src/main/java/com/td/WaDa/game/comfruit/repository/ComFruitRepository.java

@@ -0,0 +1,9 @@
+package com.td.WaDa.game.comfruit.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.comfruit.pojo.ComFruit;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComFruitRepository extends CommonRepository<ComFruit, Integer> {
+}

+ 13 - 0
src/main/java/com/td/WaDa/game/comfruit/service/ComFruitService.java

@@ -0,0 +1,13 @@
+package com.td.WaDa.game.comfruit.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comfruit.pojo.ComFruit;
+import com.td.WaDa.game.comfruit.vo.ComFruitVo;
+
+import java.util.List;
+
+public interface ComFruitService extends CommonService<ComFruitVo, ComFruit, Integer> {
+    ComFruitVo findById(Integer id);
+
+    List<ComFruit> findFruitAll();
+}

+ 40 - 0
src/main/java/com/td/WaDa/game/comfruit/service/ComFruitServiceImpl.java

@@ -0,0 +1,40 @@
+package com.td.WaDa.game.comfruit.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.comfruit.pojo.ComFruit;
+import com.td.WaDa.game.comfruit.vo.ComFruitVo;
+import com.td.WaDa.game.comfruit.repository.ComFruitRepository;
+import com.td.WaDa.util.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@Transactional
+public class ComFruitServiceImpl extends CommonServiceImpl<ComFruitVo, ComFruit, Integer> implements ComFruitService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComFruitRepository comFruitRepository;
+
+    @Override
+    public ComFruitVo findById(Integer id) {
+        Optional<ComFruit> comMallSeed = comFruitRepository.findById(id);
+        if(comMallSeed.orElse(null) == null){
+            return null;
+        }else{
+            return CopyUtil.copy(comMallSeed.get(), ComFruitVo.class);
+        }
+    }
+
+
+    @Override
+    public List<ComFruit> findFruitAll() {
+        return comFruitRepository.findAll();
+    }
+}

+ 37 - 0
src/main/java/com/td/WaDa/game/comfruit/vo/ComFruitAmountVo.java

@@ -0,0 +1,37 @@
+package com.td.WaDa.game.comfruit.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComFruitAmountVo implements Serializable {
+    private Integer id;//
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//
+
+    private String fruitDescribe;
+
+    private Integer amount;//这里添加一个数量,但是数据库是没有的,以背包为主
+
+    private Double amountPart;//用户收取其他的部分数据
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+    /**
+     * 需求 牧场养殖渔场,新增字段,
+     * 原有需求种地值0 牧场1 养殖2 淡水区3 海水区4
+     */
+    private Integer mallType;
+
+
+}

+ 25 - 0
src/main/java/com/td/WaDa/game/comfruit/vo/ComFruitVo.java

@@ -0,0 +1,25 @@
+package com.td.WaDa.game.comfruit.vo;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComFruitVo implements Serializable {
+    private Integer id;//
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//
+
+    private String fruitDescribe;
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 35 - 0
src/main/java/com/td/WaDa/game/commallfood/controller/ComMallFoodController.java

@@ -0,0 +1,35 @@
+package com.td.WaDa.game.commallfood.controller;
+
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.game.commallfood.pojo.ComMallFood;
+import com.td.WaDa.game.commallfood.vo.ComMallFoodSimpleVo;
+import com.td.WaDa.game.commallfood.vo.ComMallFoodVo;
+import com.td.WaDa.game.commallfood.service.ComMallFoodService;
+import com.td.WaDa.util.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/game/comMallFood/")
+public class ComMallFoodController extends CommonController<ComMallFoodVo, ComMallFood, Integer> {
+    @Autowired
+    private ComMallFoodService comMallFoodService;
+
+
+
+    @GetMapping("getMallFoodList")
+    public Result<List<ComMallFoodSimpleVo>> getEquipmentByTypeFunction(@RequestParam(value = "userId") String userId) {
+
+        ComMallFoodVo comMallFoodVo = new ComMallFoodVo();
+
+        List<ComMallFoodSimpleVo> comMallFoodSimpleVoList = comMallFoodService.list(comMallFoodVo).getData().stream().map(e->{
+            return  CopyUtil.copy(e, ComMallFoodSimpleVo.class);
+        }).collect(Collectors.toList());
+
+        return Result.of(comMallFoodSimpleVoList);
+    }
+}

+ 36 - 0
src/main/java/com/td/WaDa/game/commallfood/pojo/ComMallFood.java

@@ -0,0 +1,36 @@
+package com.td.WaDa.game.commallfood.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_mall_food")
+@Data
+public class ComMallFood implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private Integer mallType;//商城类型,默认是狗粮0
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer weight;//大包食物
+
+    private Integer priceCnt;//
+
+    private Integer priceSnb;//
+
+    private Integer amount;//库存数量
+
+    private String foodDescribe;//描述一下
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 9 - 0
src/main/java/com/td/WaDa/game/commallfood/repository/ComMallFoodRepository.java

@@ -0,0 +1,9 @@
+package com.td.WaDa.game.commallfood.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.commallfood.pojo.ComMallFood;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComMallFoodRepository extends CommonRepository<ComMallFood, Integer> {
+}

+ 8 - 0
src/main/java/com/td/WaDa/game/commallfood/service/ComMallFoodService.java

@@ -0,0 +1,8 @@
+package com.td.WaDa.game.commallfood.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.commallfood.pojo.ComMallFood;
+import com.td.WaDa.game.commallfood.vo.ComMallFoodVo;
+
+public interface ComMallFoodService extends CommonService<ComMallFoodVo, ComMallFood, Integer> {
+}

+ 21 - 0
src/main/java/com/td/WaDa/game/commallfood/service/ComMallFoodServiceImpl.java

@@ -0,0 +1,21 @@
+package com.td.WaDa.game.commallfood.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.commallfood.pojo.ComMallFood;
+import com.td.WaDa.game.commallfood.vo.ComMallFoodVo;
+import com.td.WaDa.game.commallfood.repository.ComMallFoodRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class ComMallFoodServiceImpl extends CommonServiceImpl<ComMallFoodVo, ComMallFood, Integer> implements ComMallFoodService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComMallFoodRepository comMallFoodRepository;
+}

+ 32 - 0
src/main/java/com/td/WaDa/game/commallfood/vo/ComMallFoodSimpleVo.java

@@ -0,0 +1,32 @@
+package com.td.WaDa.game.commallfood.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComMallFoodSimpleVo implements Serializable {
+    private Integer id;//
+
+    private Integer mallType;//商城类型,默认是狗粮0
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer weight;//大包食物
+
+    private Integer priceCnt;//
+
+    private Integer priceSnb;//
+
+    private Integer amount;//库存数量
+
+    private String foodDescribe;//描述一下
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 31 - 0
src/main/java/com/td/WaDa/game/commallfood/vo/ComMallFoodVo.java

@@ -0,0 +1,31 @@
+package com.td.WaDa.game.commallfood.vo;
+
+import com.td.WaDa. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComMallFoodVo extends PageCondition implements Serializable {
+    private Integer id;//
+
+    private Integer mallType;//商城类型,默认是狗粮0
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer weight;//大包食物
+
+    private Integer priceCnt;//
+
+    private Integer priceSnb;//
+
+    private Integer amount;//库存数量
+
+    private String foodDescribe;//描述一下
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 34 - 0
src/main/java/com/td/WaDa/game/commallother/controller/ComMallOtherController.java

@@ -0,0 +1,34 @@
+package com.td.WaDa.game.commallother.controller;
+
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.game.commallother.pojo.ComMallOther;
+import com.td.WaDa.game.commallother.vo.ComMallOtherSimpleVo;
+import com.td.WaDa.game.commallother.vo.ComMallOtherVo;
+import com.td.WaDa.game.commallother.service.ComMallOtherService;
+import com.td.WaDa.util.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/game/comMallOther/")
+public class ComMallOtherController extends CommonController<ComMallOtherVo, ComMallOther, Integer> {
+    @Autowired
+    private ComMallOtherService comMallOtherService;
+
+    /**
+     * 获取商城装备栏列表
+     *
+     * @param userId
+     * @return
+     */
+    @GetMapping("getMallEquipmentList")
+    public Result<List<ComMallOtherSimpleVo>> getEquipmentListFunction(@RequestParam(value = "userId") String userId) {
+        ComMallOtherVo comMallOtherVo = new ComMallOtherVo();
+        Result result = comMallOtherService.list(comMallOtherVo);
+        List<ComMallOtherSimpleVo> comMallOtherSimpleVos = CopyUtil.copyList((List<ComMallOtherSimpleVo>) result.getData(), ComMallOtherSimpleVo.class);
+        return Result.of(comMallOtherSimpleVos);
+    }
+}

+ 38 - 0
src/main/java/com/td/WaDa/game/commallother/pojo/ComMallOther.java

@@ -0,0 +1,38 @@
+package com.td.WaDa.game.commallother.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_mall_other")
+@Data
+public class ComMallOther implements Serializable {
+    @Id
+    @GeneratedValue(strategy= GenerationType.IDENTITY)
+    private Integer id;//
+
+    private Integer otherType;//商城类型,默认是小狗0,1打狗棒
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//新增一个cnt字段
+
+    private Integer amount;//库存数量
+
+    private String itemDescribe;//描述一下生产周期
+
+    private Integer effectiveDay;//物品的有效时间
+
+    private Double triggerPro;//触发概率,狗就是触发咬的事件
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 13 - 0
src/main/java/com/td/WaDa/game/commallother/repository/ComMallOtherRepository.java

@@ -0,0 +1,13 @@
+package com.td.WaDa.game.commallother.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.commallother.pojo.ComMallOther;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface ComMallOtherRepository extends CommonRepository<ComMallOther, Integer> {
+
+    Optional<ComMallOther> findByOtherType(Integer otherType);
+}

+ 11 - 0
src/main/java/com/td/WaDa/game/commallother/service/ComMallOtherService.java

@@ -0,0 +1,11 @@
+package com.td.WaDa.game.commallother.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.commallother.pojo.ComMallOther;
+import com.td.WaDa.game.commallother.vo.ComMallOtherVo;
+
+public interface ComMallOtherService extends CommonService<ComMallOtherVo, ComMallOther, Integer> {
+
+    ComMallOther findByOtherType(Integer otherType);
+
+}

+ 27 - 0
src/main/java/com/td/WaDa/game/commallother/service/ComMallOtherServiceImpl.java

@@ -0,0 +1,27 @@
+package com.td.WaDa.game.commallother.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.commallother.pojo.ComMallOther;
+import com.td.WaDa.game.commallother.vo.ComMallOtherVo;
+import com.td.WaDa.game.commallother.repository.ComMallOtherRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+
+@Service
+@Transactional
+public class ComMallOtherServiceImpl extends CommonServiceImpl<ComMallOtherVo, ComMallOther, Integer> implements ComMallOtherService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComMallOtherRepository comMallOtherRepository;
+
+
+    @Override
+    public ComMallOther findByOtherType(Integer otherType) {
+        return comMallOtherRepository.findByOtherType(otherType).orElse(null);
+    }
+}

+ 34 - 0
src/main/java/com/td/WaDa/game/commallother/vo/ComMallOtherSimpleVo.java

@@ -0,0 +1,34 @@
+package com.td.WaDa.game.commallother.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComMallOtherSimpleVo  implements Serializable {
+    private Integer id;//
+
+    private Integer otherType;//商城类型,默认是小狗0,1打狗棒
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//新增一个cnt字段
+
+    private Integer amount;//库存数量
+
+    private String itemDescribe;//描述一下生产周期
+
+    private Integer effectiveDay;//物品的有效时间
+
+    private Double triggerPro;//触发概率,狗就是触发咬的事件
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 33 - 0
src/main/java/com/td/WaDa/game/commallother/vo/ComMallOtherVo.java

@@ -0,0 +1,33 @@
+package com.td.WaDa.game.commallother.vo;
+
+import com.td.WaDa. common.pojo.PageCondition;import lombok.Data;
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+public class ComMallOtherVo extends PageCondition implements Serializable {
+    private Integer id;//
+
+    private Integer otherType;//商城类型,默认是小狗0,1打狗棒
+
+    private String picture;//图片名字,前端存储
+
+    private String name;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//新增一个cnt字段
+
+    private Integer amount;//库存数量
+
+    private String itemDescribe;//描述一下生产周期
+
+    private Integer effectiveDay;//物品的有效时间
+
+    private Double triggerPro;//触发概率,狗就是触发咬的事件
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 291 - 0
src/main/java/com/td/WaDa/game/commallseed/controller/ComMallSeedController.java

@@ -0,0 +1,291 @@
+package com.td.WaDa.game.commallseed.controller;
+
+import cn.hutool.core.convert.Convert;
+import com.td.WaDa.common.controller.*;
+import com.td.WaDa.common.pojo.Result;
+import com.td.WaDa.config.enums.ResultEnum;
+import com.td.WaDa.game.commallseed.pojo.ComMallSeed;
+import com.td.WaDa.game.commallseed.service.ComMallSeedService;
+import com.td.WaDa.game.commallseed.vo.ComMallSeedVo;
+import com.td.WaDa.game.complayergoods.pojo.ComPlayerGoods;
+import com.td.WaDa.game.complayergoods.service.ComPlayerGoodsService;
+import com.td.WaDa.game.complayergoods.vo.ComPlayerGoodsVo;
+import com.td.WaDa.game.complayerlog.pojo.ComPlayerLog;
+import com.td.WaDa.game.complayerlog.service.ComPlayerLogService;
+import com.td.WaDa.game.complayerlog.vo.ComPlayerLogVo;
+import com.td.WaDa.game.complayers.pojo.ComPlayers;
+import com.td.WaDa.game.complayers.service.ComPlayersService;
+import com.td.WaDa.game.comsnbtran.service.ComSnbTranService;
+import com.td.WaDa.game.comsnbtran.vo.ComSnbTranVo;
+import com.td.WaDa.game.comusers.service.ComUsersService;
+import com.td.WaDa.game.comusers.vo.ComUsersVo;
+import com.td.WaDa.util.CopyUtil;
+import com.td.WaDa.util.DoubleUtil;
+import com.td.WaDa.util.RedisData;
+import com.td.WaDa.util.RedisLock;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/game/comMallSeed/")
+public class ComMallSeedController extends CommonController<ComMallSeedVo, ComMallSeed, Integer> {
+    @Autowired
+    private ComMallSeedService comMallSeedService;
+
+    @Autowired
+    private ComPlayerGoodsService comPlayerGoodsService;
+
+    @Autowired
+    private ComUsersService comUsersService;
+
+    @Autowired
+    private ComSnbTranService comSnbTranService;
+
+    @Autowired
+    private ComPlayerLogService comPlayerLogService;
+
+    @Autowired
+    private ComPlayersService comPlayersService;
+
+    @Autowired
+    private RedisLock redisLock;
+
+    /**
+     * 获取商城种子
+     *
+     * @param userId
+     * @return
+     */
+    @GetMapping("getMallSeed")
+    public Result<List<ComMallSeedVo>> getSNBFunction(@RequestParam(value = "userId") String userId) {
+        //log.info(userId);
+        ComMallSeedVo comMallSeedVo = new ComMallSeedVo();
+        Result result = comMallSeedService.list(comMallSeedVo);
+        return result;
+    }
+
+    /**
+     * 神农呗购买种子
+     *
+     * @param userId
+     * @return
+     */
+    @PostMapping("snbBuySeeds")
+    @ResponseBody
+    @Transactional(rollbackFor = Exception.class)
+    public Result<Map> snbBuySeedsFunction(
+            @RequestParam(value = "userId") String userId,
+            @RequestParam(value = "payAmount") Integer payAmount,
+            @RequestParam(value = "seedId") Integer seedId
+    ) {
+        //校验如果前台输入负数
+        Map map = new HashMap();
+        if(payAmount<=0){
+            return Result.of(map, false, ResultEnum.SEED_PLAY_ERROR.getMessage(), ResultEnum.SEED_PLAY_ERROR.getCode());
+        }
+        // 处理itemType,种子id ,获取种子类型,设置种子不同的数据
+        Integer itemType = seedId;
+        ComMallSeedVo seedVo = comMallSeedService.findById(seedId);
+        if (seedVo == null) {
+
+            map.put("msg", "非法操作:所修改的种子不存在服务器中!");
+            //return Result.of(map);
+            return Result.of(map, false, ResultEnum.SEED_DATA_ERROR.getMessage(), ResultEnum.SEED_DATA_ERROR.getCode());
+        }
+        if (!StringUtils.hasText(payAmount.toString())||payAmount.equals(0) || payAmount % seedVo.getPriceSnb() != 0 ) {
+            //支付价格不能为零,如果价格 不和种子相当,也不是种子的倍数,也是不行的
+            map.put("msg", "订单非法操作,已记录相关信息!");
+            //return Result.of(map);
+            return Result.of(map, false, ResultEnum.SEED_PLAY_ERROR.getMessage(), ResultEnum.SEED_PLAY_ERROR.getCode());
+        }
+
+        //todo snb冻结加锁
+        long time = System.currentTimeMillis() + RedisData.getSnbTimeout();
+        String _redisKey = "SNB_SAVE_" + userId;
+
+        try{
+            //todo snb冻结加锁
+            if (!redisLock.lock(_redisKey, String.valueOf(time))) {
+                return Result.of(null, false, ResultEnum.SEED_SALE_SAVE_LOCK.getMessage(), ResultEnum.SEED_SALE_SAVE_LOCK.getCode());
+            }
+
+            //todo 操作snb数量
+            ComUsersVo comUsersVo = comUsersService.findByUserId(userId);
+            if ( comUsersVo.getSnb() < payAmount || comUsersVo.getSnb()<=0) {
+                map.put("msg", "账户snb不足");
+                //WALLET_SNB_INSUFFICIENT_QUANTITY(602,"snb不足以支付!")
+                return Result.of(map, false, ResultEnum.WALLET_SNB_INSUFFICIENT_QUANTITY.getMessage(), ResultEnum.WALLET_SNB_INSUFFICIENT_QUANTITY.getCode());
+            }
+            //如果数量够,写入修改对应操作
+            Integer _oldSnb =  comUsersVo.getSnb();
+            Integer _snb =  comUsersVo.getSnb() - payAmount;
+            comUsersVo.setSnb(_snb);
+            comUsersService.save( comUsersVo);
+
+            //合法操作记录到仓库中
+            ComPlayerGoods entityVo = comPlayerGoodsService.findByUserIdAndIndexAndType(userId, itemType, 0);
+            //这里计算一个购买种子的数量,用种子除去单价
+            int _paySeedAmount = (int) (payAmount / seedVo.getPriceSnb());
+            if (entityVo == null) {
+                //创建一个新种子
+                entityVo = new ComPlayerGoods();
+                entityVo.setGoodsIndex(itemType);
+                entityVo.setGoodsType(0);
+                entityVo.setAmount(_paySeedAmount);
+                entityVo.setAmountPart(0d);
+                entityVo.setName(seedVo.getName());
+                entityVo.setPictureName(seedVo.getPicture());
+                entityVo.setUserId(userId);
+                //[xst]此处新增获取种子的类型
+                entityVo.setMallType(Convert.toInt(seedVo.getMallType(),0));
+            } else {
+                Integer _amount = entityVo.getAmount() + _paySeedAmount;
+                entityVo.setAmount(_amount);
+            }
+            /** 购买成功后,记录到仓库中*/
+            ComPlayerGoodsVo comPlayerGoodsVo = CopyUtil.copy(entityVo, ComPlayerGoodsVo.class);
+            comPlayerGoodsService.save(comPlayerGoodsVo);
+
+            /**
+             * todo 购买种子的交易记录
+             */
+            ComSnbTranVo _snbTran = new ComSnbTranVo();
+            //记录兑换id
+            _snbTran.setTranId(itemType.toString());
+            _snbTran.setUserId(userId);
+            if(seedVo.getMallType().equals(0)){
+                _snbTran.setTranName("使用SNB购买"+seedVo.getName()+"种子");
+            }else{
+                _snbTran.setTranName("使用SNB购买"+seedVo.getName());
+            }
+            _snbTran.setTranType(3);
+            _snbTran.setTranAmount(_paySeedAmount); //此数量会操作背包记录
+            _snbTran.setTranPrice(payAmount);
+            _snbTran.setTranDescribe("SNB购买种子的价格:"+seedVo.getPriceSnb()+",支付金额:"+payAmount);
+            _snbTran.setIsAdd(0);//减少snb
+            _snbTran.setBeforeSnb(_oldSnb);
+            _snbTran.setTranSnb(payAmount);
+            _snbTran.setAfterSnb(_snb);
+            //不涉及交易的设置为0
+            _snbTran.setTranAmountPart(0d);
+            _snbTran.setTranSnbPart(0d);
+            _snbTran.setBeforeSnbPart( comUsersVo.getSnbPart());
+            _snbTran.setAfterSnbPart( comUsersVo.getSnbPart());
+            comSnbTranService.save(_snbTran);
+
+            redisLock.unlock(_redisKey, String.valueOf(time));
+
+            map.put("seed", entityVo.getGoodsIndex());
+            map.put("snb", comUsersVo.getSnb());
+            return Result.of(map);
+        }catch (Exception e) {
+            redisLock.unlock(_redisKey, String.valueOf(time));
+            throw new RuntimeException(e.getMessage());
+        }
+
+    }
+
+
+
+    /**
+     * 用钻石兑换一份辣椒种子
+     *
+     * @param userId
+     * @return
+     */
+    @PostMapping("exchangeSeeds")
+    @ResponseBody
+    @Transactional(rollbackFor = Exception.class)
+    public Result<Map> exchangeSeedsFunction(
+            @RequestParam(value = "userId") String userId,
+            @RequestParam(value = "diamondAmount") Integer diamondAmount,
+            @RequestParam(value = "seedId") Integer seedId
+    ) {
+        if(diamondAmount< 30000){
+            return Result.of(null, false, ResultEnum.SEED_PLAY_ERROR.getMessage(), ResultEnum.SEED_PLAY_ERROR.getCode());
+        }
+        // 处理itemType,种子id ,获取种子类型,设置种子不同的数据
+        Integer itemType = seedId;
+        ComMallSeedVo seedVo = comMallSeedService.findById(seedId);
+        Map map = new HashMap();
+        if (seedVo == null) {
+            map.put("msg", "非法操作:所修改的种子不存在服务器中!");
+            //return Result.of(map);
+            return Result.of(map, false, ResultEnum.SEED_DATA_ERROR.getMessage(), ResultEnum.SEED_DATA_ERROR.getCode());
+        }
+
+        ComPlayers player = comPlayersService.findByUserId(userId);
+        if(player.getIsExchange().equals(1)){
+            map.put("msg", "非法操作:已兑换过种子!");
+            return Result.of(map, false, ResultEnum.SEED_IS_EXCHANGE.getMessage(), ResultEnum.SEED_IS_EXCHANGE.getCode());
+        }
+
+        //JSONObject jsonObject = JSONObject.parseObject(player.getData());
+        //Integer _diamond = Integer.parseInt(jsonObject.getString("Diamond"));
+        Double _diamond = player.getDiamond();
+        if(DoubleUtil.compare(_diamond,diamondAmount.doubleValue()).equals(-1)){
+            return Result.of(map, false, ResultEnum.SEED_PLAY_DIAMOND_ERROR.getMessage(), ResultEnum.SEED_PLAY_DIAMOND_ERROR.getCode());
+        }
+        //jsonObject.put("Diamond",_diamond - diamondAmount);
+        Double _endDiamond = DoubleUtil.sub(_diamond , diamondAmount.doubleValue());
+        //设置已经兑换的状态
+        player.setIsExchange(1);
+        //更新游戏状态
+        //player.setData(jsonObject.toString());
+        player.setDiamond(_endDiamond);
+        comPlayersService.addComPlayers(player);
+        //合法操作记录到仓库中
+        //todo 添加一个辣椒种子
+        ComPlayerGoods entityVo = comPlayerGoodsService.findByUserIdAndIndexAndType(userId, itemType, 0);
+        Integer _selfBeforeAmount = 0;
+        if (entityVo == null) {
+            //创建一个新种子
+            entityVo = new ComPlayerGoods();
+            entityVo.setGoodsIndex(itemType);
+            entityVo.setGoodsType(0);
+            entityVo.setAmount(1);
+            entityVo.setAmountPart(0d);
+            entityVo.setName(seedVo.getName());
+            entityVo.setPictureName(seedVo.getPicture());
+            entityVo.setUserId(userId);
+        } else {
+            _selfBeforeAmount = entityVo.getAmount();
+            Integer _amount = entityVo.getAmount() + 1;
+            entityVo.setAmount(_amount);
+        }
+        /** 购买成功后,记录到仓库中*/
+        ComPlayerGoodsVo comPlayerGoodsVo = CopyUtil.copy(entityVo, ComPlayerGoodsVo.class);
+        comPlayerGoodsService.save(comPlayerGoodsVo);
+
+        /**
+         * todo 记录 PlayerLog
+         */
+        //当前用户
+        ComPlayerLog _selfPlayerLog = new ComPlayerLog();
+        _selfPlayerLog.setUserId(userId);
+        _selfPlayerLog.setTId(entityVo.getGoodsIndex());
+        _selfPlayerLog.setTName(entityVo.getName());
+        _selfPlayerLog.setTType(4);//兑换种子
+        _selfPlayerLog.setTAmount(1);
+        _selfPlayerLog.setBeforeAmount(_selfBeforeAmount);
+        ////交易后的数据
+        _selfPlayerLog.setAfterAmount(entityVo.getAmount());
+        _selfPlayerLog.setLMultiple(0);//收获时候,会有一个倍数
+        _selfPlayerLog.setWithered(0); //枯萎就设置 1
+        ComPlayerLogVo _selfPlayerLogVo = CopyUtil.copy(_selfPlayerLog, ComPlayerLogVo.class);
+        comPlayerLogService.save(_selfPlayerLogVo);
+
+        map.put("seed", entityVo.getGoodsIndex());
+        map.put("playerData",player.getData());
+        map.put("isExchange",player.getIsExchange());
+
+        return Result.of(map);
+    }
+
+}

+ 50 - 0
src/main/java/com/td/WaDa/game/commallseed/pojo/ComMallSeed.java

@@ -0,0 +1,50 @@
+package com.td.WaDa.game.commallseed.pojo;
+
+import lombok.Data;
+import javax.persistence.*;
+import java.io.Serializable;
+import java.util.Date;
+
+@Entity
+@Table(name = "com_mall_seed")
+@Data
+public class ComMallSeed implements Serializable {
+    @Id
+    private Integer id;//
+
+    private Integer mallType;//商城类型,默认是种子0
+
+    private String picture;
+
+    private String name;//
+
+    private Integer maturity;//
+
+    private Integer planting;//
+
+    private Integer harvestId;
+    private Integer harvestQuantity;//
+
+    private Integer harvestCount;//
+
+    private Integer harvest1;//
+    private Integer harvest2;//
+    private Integer harvest3;//
+
+    private String harvestName;//
+
+    private Integer priceSnb;//
+
+    private Integer priceCnt;//
+
+    private Integer amount;
+
+    private String seedDescribe;//
+
+    private Integer withered;//
+
+    private Date createTime;//
+
+    private Date updateTime;//
+
+}

+ 9 - 0
src/main/java/com/td/WaDa/game/commallseed/repository/ComMallSeedRepository.java

@@ -0,0 +1,9 @@
+package com.td.WaDa.game.commallseed.repository;
+
+import com.td.WaDa.common.repository.*;
+import com.td.WaDa.game.commallseed.pojo.ComMallSeed;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ComMallSeedRepository extends CommonRepository<ComMallSeed, Integer> {
+}

+ 14 - 0
src/main/java/com/td/WaDa/game/commallseed/service/ComMallSeedService.java

@@ -0,0 +1,14 @@
+package com.td.WaDa.game.commallseed.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.commallseed.pojo.ComMallSeed;
+import com.td.WaDa.game.commallseed.vo.ComMallSeedVo;
+
+import java.util.List;
+
+public interface ComMallSeedService extends CommonService<ComMallSeedVo, ComMallSeed, Integer> {
+
+    ComMallSeedVo findById(Integer id);
+
+    List<ComMallSeed>  findMallSeedAll();
+}

+ 41 - 0
src/main/java/com/td/WaDa/game/commallseed/service/ComMallSeedServiceImpl.java

@@ -0,0 +1,41 @@
+package com.td.WaDa.game.commallseed.service;
+
+import com.td.WaDa.common.service.*;
+import com.td.WaDa.game.commallseed.pojo.ComMallSeed;
+import com.td.WaDa.game.commallseed.vo.ComMallSeedVo;
+import com.td.WaDa.game.commallseed.repository.ComMallSeedRepository;
+import com.td.WaDa.util.CopyUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@Transactional
+public class ComMallSeedServiceImpl extends CommonServiceImpl<ComMallSeedVo, ComMallSeed, Integer> implements ComMallSeedService{
+
+    @PersistenceContext
+    private EntityManager em;
+    @Autowired
+    private ComMallSeedRepository comMallSeedRepository;
+
+
+    @Override
+    public ComMallSeedVo findById(Integer id) {
+
+        Optional<ComMallSeed> comMallSeed = comMallSeedRepository.findById(id);
+        if(comMallSeed.orElse(null) == null){
+            return null;
+        }else{
+            return CopyUtil.copy(comMallSeed.get(), ComMallSeedVo.class);
+        }
+    }
+
+    @Override
+    public List<ComMallSeed> findMallSeedAll() {
+        return comMallSeedRepository.findAll();
+    }
+}

Неке датотеке нису приказане због велике количине промена