qzyReal 1 жил өмнө
commit
ba47bf65a8
100 өөрчлөгдсөн 8450 нэмэгдсэн , 0 устгасан
  1. 55 0
      .gitignore
  2. 18 0
      README.md
  3. 94 0
      pom.xml
  4. 20 0
      sp-core/pom.xml
  5. 36 0
      sp-core/sp-api/pom.xml
  6. 27 0
      sp-core/sp-api/src/main/java/com/pj/api/FeignInterceptor.java
  7. 32 0
      sp-core/sp-api/src/main/java/com/pj/api/client/SpCfgInterface.java
  8. 45 0
      sp-core/sp-api/src/main/java/com/pj/api/client/SpCfgInterfaceFallback.java
  9. 15 0
      sp-core/sp-api/src/main/java/com/pj/api/consts/FeignConsts.java
  10. 29 0
      sp-core/sp-api/src/main/java/com/pj/api/consts/FeignFactory.java
  11. 157 0
      sp-core/sp-base/pom.xml
  12. 65 0
      sp-core/sp-base/src/main/java/com/pj/current/SpCloudUtil.java
  13. 41 0
      sp-core/sp-base/src/main/java/com/pj/current/config/MyConfig.java
  14. 77 0
      sp-core/sp-base/src/main/java/com/pj/current/config/RemoveDruidAdConfig.java
  15. 43 0
      sp-core/sp-base/src/main/java/com/pj/current/config/SystemObject.java
  16. 60 0
      sp-core/sp-base/src/main/java/com/pj/current/global/GlobalAspect.java
  17. 81 0
      sp-core/sp-base/src/main/java/com/pj/current/global/GlobalException.java
  18. 150 0
      sp-core/sp-base/src/main/java/com/pj/current/mybatis/MybatisMapperDynamicLoader.java
  19. 75 0
      sp-core/sp-base/src/main/java/com/pj/current/mybatis/MybatisStdOutImpl.java
  20. 36 0
      sp-core/sp-base/src/main/java/com/pj/current/mybatis/RefConfig.java
  21. 42 0
      sp-core/sp-base/src/main/java/com/pj/current/satoken/AuthConst.java
  22. 69 0
      sp-core/sp-base/src/main/java/com/pj/current/satoken/SaTokenConfigure.java
  23. 856 0
      sp-core/sp-base/src/main/java/com/pj/current/satoken/StpUserUtil.java
  24. 51 0
      sp-core/sp-base/src/main/java/com/pj/current/sentinel/SentinelConfig.java
  25. 26 0
      sp-core/sp-base/src/main/java/com/pj/current/sentinel/SpBlockHandler.java
  26. 6 0
      sp-core/sp-base/src/main/java/com/pj/project/package-info.java
  27. 40 0
      sp-core/sp-base/src/main/java/com/pj/project/test/TestController.java
  28. 53 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/SP.java
  29. 99 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilog.java
  30. 77 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogControlle.java
  31. 69 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogMapper.java
  32. 114 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogMapper.xml
  33. 147 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogUtil.java
  34. 16 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaBegin.java
  35. 18 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaBeginRet.java
  36. 16 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaRollback.java
  37. 17 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaRollbackRet.java
  38. 296 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/PublicMapper.java
  39. 164 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/PublicMapper.xml
  40. 83 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/PublicService.java
  41. 38 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/spcfg/SpCfgService.java
  42. 101 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/spcfg/SpCfgUtil.java
  43. 35 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/uploadfile/UploadConfig.java
  44. 106 0
      sp-core/sp-base/src/main/java/com/pj/project4sp/uploadfile/UploadUtil.java
  45. 31 0
      sp-core/sp-base/src/main/java/com/pj/utils/LogUtil.java
  46. 63 0
      sp-core/sp-base/src/main/java/com/pj/utils/Ttime.java
  47. 70 0
      sp-core/sp-base/src/main/java/com/pj/utils/cache/IpCheckUtil.java
  48. 116 0
      sp-core/sp-base/src/main/java/com/pj/utils/cache/RedisUtil.java
  49. 150 0
      sp-core/sp-base/src/main/java/com/pj/utils/sg/AjaxError.java
  50. 233 0
      sp-core/sp-base/src/main/java/com/pj/utils/sg/AjaxJson.java
  51. 283 0
      sp-core/sp-base/src/main/java/com/pj/utils/sg/NbUtil.java
  52. 214 0
      sp-core/sp-base/src/main/java/com/pj/utils/sg/WebNbUtil.java
  53. 749 0
      sp-core/sp-base/src/main/java/com/pj/utils/so/SoMap.java
  54. 10 0
      sp-core/sp-base/src/main/resources/banner.txt
  55. 16 0
      sp-core/sp-nacos/pom.xml
  56. 39 0
      sp-core/sp-nacos/src/main/resources/bootstrap.properties
  57. 124 0
      sp-core/sp-nacos/src/main/resources/logback.xml
  58. 61 0
      sp-native/pom.xml
  59. 64 0
      sp-native/sp-boot-admin/pom.xml
  60. 24 0
      sp-native/sp-boot-admin/src/main/java/com/pj/SpBootAdminApplication.java
  61. 16 0
      sp-native/sp-boot-admin/src/main/resources/bootstrap.yml
  62. 97 0
      sp-native/sp-gateway/pom.xml
  63. 29 0
      sp-native/sp-gateway/src/main/java/com/pj/SpGatewayApplication.java
  64. 24 0
      sp-native/sp-gateway/src/main/java/com/pj/more/RouteConfigure.java
  65. 33 0
      sp-native/sp-gateway/src/main/java/com/pj/more/SaIdTokenFilter.java
  66. 52 0
      sp-native/sp-gateway/src/main/java/com/pj/more/SaTokenConfigure.java
  67. 10 0
      sp-native/sp-gateway/src/main/resources/bootstrap.yml
  68. 30 0
      sp-service/level-one-server/pom.xml
  69. 36 0
      sp-service/level-one-server/src/main/java/com/pj/LevelOneServer.java
  70. 9 0
      sp-service/level-one-server/src/main/resources/bootstrap.yml
  71. 33 0
      sp-service/level-two-server/.gitignore
  72. BIN
      sp-service/level-two-server/.mvn/wrapper/maven-wrapper.jar
  73. 18 0
      sp-service/level-two-server/.mvn/wrapper/maven-wrapper.properties
  74. 316 0
      sp-service/level-two-server/mvnw
  75. 188 0
      sp-service/level-two-server/mvnw.cmd
  76. 26 0
      sp-service/level-two-server/pom.xml
  77. 31 0
      sp-service/level-two-server/src/main/java/com/pj/LevelTwoServerApplication.java
  78. 5 0
      sp-service/level-two-server/src/main/resources/bootstrap.yml
  79. 66 0
      sp-service/pom.xml
  80. 33 0
      sp-service/sp-admin/pom.xml
  81. 37 0
      sp-service/sp-admin/src/main/java/com/pj/SpAdminApplication.java
  82. 76 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdmin.java
  83. 163 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminController.java
  84. 68 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminMapper.java
  85. 100 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminMapper.xml
  86. 55 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminService.java
  87. 99 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminUtil.java
  88. 73 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminController.java
  89. 22 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminMapper.java
  90. 17 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminMapper.xml
  91. 136 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminService.java
  92. 50 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4password/SpAdminPasswordController.java
  93. 34 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4password/SpAdminPasswordService.java
  94. 6 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/package-info.java
  95. 90 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/redis4console/RedisConsoleController.java
  96. 181 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/redis4console/RedisConsoleUtil.java
  97. 35 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRole.java
  98. 92 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRoleController.java
  99. 60 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRoleMapper.java
  100. 62 0
      sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRoleMapper.xml

+ 55 - 0
.gitignore

@@ -0,0 +1,55 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+.idea/
+*.iml
+.factorypath
+
+target/
+.project
+.classpath
+.settings
+
+/.idea/
+
+node_modules/
+bin/
+.settings/
+unpackage/
+/.apt_generated/
+/.apt_generated_tests/
+
+
+
+
+# 隐藏部分目录 
+
+sp-service/sp-more/src/main/java/com/pj/project/*
+doc/nacos
+doc/sentinel-dashboard
+logs/
+
+
+
+

+ 18 - 0
README.md

@@ -0,0 +1,18 @@
+
+
+## 启动流程
+- 登录nacos后台,导入配置文件doc目录下的DEFAULT-GROUP.zip,修改common-dev.yml里面的redis配置信息为本地信息
+- 启动网关SpGatewayApplication.java
+- 启动SpAdminApplication.java后台管理
+- 启动其他服务....
+
+
+## 在线资料
+- 官网首页:[http://sa-plus.dev33.cn/](http://sa-plus.dev33.cn/)
+- 在线演示:[http://demo.dev33.cn/sp-admin/index.html](http://demo.dev33.cn/sp-admin/index.html)
+- 在线文档: [http://sa-plus.dev33.cn/doc/index.html#/sp-cloud/README](http://sa-plus.dev33.cn/doc/index.html#/sp-cloud/README)
+- 需求提交:[我们深知一个优秀的项目需要海纳百川,点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-plus)
+- Gitee地址: [https://gitee.com/click33/sp-cloud](https://gitee.com/click33/sp-cloud)
+
+
+

+ 94 - 0
pom.xml

@@ -0,0 +1,94 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>com.pj</groupId>
+	<artifactId>market-server</artifactId>
+	<packaging>pom</packaging>
+    <version>0.0.1-SNAPSHOT</version>
+    <modules>
+        <module>sp-core</module>
+        <module>sp-native</module>
+        <module>sp-service</module>
+    </modules>
+	<!-- 指定一些属性 -->
+	<properties> 
+		<java.version>1.8</java.version>
+		<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
+    	<resource.delimiter>@</resource.delimiter>
+	    <maven.compiler.source>${java.version}</maven.compiler.source>
+	    <maven.compiler.target>${java.version}</maven.compiler.target>
+	    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+	    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+	</properties>
+	
+	<!-- 依赖管理 (不会真正的引入依赖,只会限定其版本) -->
+	<dependencyManagement>
+		<dependencies>
+		
+			<!-- SpringCloud -->
+			<dependency>
+				<groupId>org.springframework.cloud</groupId>
+				<artifactId>spring-cloud-dependencies</artifactId>
+				<version>Hoxton.RELEASE</version>
+				<!-- <version>Hoxton.SR4</version> -->
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+			
+			<!-- SpringCloud Alibaba -->
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <!-- <version>2.2.3.RELEASE</version> -->
+                <version>2.2.2.RELEASE</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            
+            <!-- Alibaba Nacos -->
+			<dependency>
+			    <groupId>com.alibaba.nacos</groupId>
+			    <artifactId>nacos-client</artifactId>
+			    <version>1.3.2</version>
+			</dependency>
+			
+			<!-- SpringBoot -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>2.3.3.RELEASE</version> 
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+		</dependencies>
+	</dependencyManagement>
+	
+	
+	<dependencies>
+	    
+	</dependencies>
+	
+	
+	<!-- 构建配置 -->
+    <build>
+        <!-- 配置资源目录, 主要解决idea无法将代码中的mapper.xml编译的问题  -->
+    	<resources>
+			<resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                </includes>
+			</resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.*</include>
+                </includes>
+            </resource>
+		</resources>
+    </build>
+	
+</project>

+ 20 - 0
sp-core/pom.xml

@@ -0,0 +1,20 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>market-server</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>sp-core</artifactId>
+    <packaging>pom</packaging>
+    <modules>
+        <module>sp-nacos</module>
+        <module>sp-api</module>
+        <module>sp-base</module>
+    </modules>
+
+</project>

+ 36 - 0
sp-core/sp-api/pom.xml

@@ -0,0 +1,36 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.pj</groupId>
+        <artifactId>sp-core</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sp-api</artifactId>
+    <packaging>jar</packaging>
+    
+    
+    <dependencies>
+    
+	    <!-- Sa-Token 权限认证(core核心包), 在线文档:http://sa-token.dev33.cn/ -->
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-core</artifactId>
+		    <version>1.27.0</version>
+		    <optional>true</optional>
+		</dependency>
+    
+		<!-- feign依赖 -->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-feign</artifactId>
+            <version>1.4.0.RELEASE</version>
+        </dependency>
+        
+    </dependencies>
+
+</project>

+ 27 - 0
sp-core/sp-api/src/main/java/com/pj/api/FeignInterceptor.java

@@ -0,0 +1,27 @@
+package com.pj.api;
+
+import org.springframework.stereotype.Component;
+
+import cn.dev33.satoken.id.SaIdUtil;
+import feign.RequestInterceptor;
+import feign.RequestTemplate;
+
+/**
+ * feign拦截器, 在feign请求发出之前,加入一些操作
+ * 
+ * @author kong
+ *
+ */
+@Component
+public class FeignInterceptor implements RequestInterceptor {
+	
+	/**
+	 * 为 Feign 的 RCP调用 添加请求头Id-Token ,否则无法通过请求验证 
+	 */
+	@Override
+	public void apply(RequestTemplate requestTemplate) {
+//		System.out.println("------------------------");
+		requestTemplate.header(SaIdUtil.ID_TOKEN, SaIdUtil.getToken());
+	}
+	
+}

+ 32 - 0
sp-core/sp-api/src/main/java/com/pj/api/client/SpCfgInterface.java

@@ -0,0 +1,32 @@
+package com.pj.api.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import com.pj.api.FeignInterceptor;
+import com.pj.api.consts.FeignConsts;
+
+/**
+ * 系统配置 服务
+ * @author kong
+ *
+ */
+@FeignClient(
+		name = FeignConsts.SP_HOME, 				// 服务名称 
+		configuration = FeignInterceptor.class,		// 请求拦截器 
+		fallbackFactory = SpCfgInterfaceFallback.class	// 服务降级 
+		)	
+public interface SpCfgInterface {
+
+	
+	// 获取server端指定配置信息
+	@RequestMapping("/SpCfgApi/getServerCfg")
+	public String getServerCfg(@RequestParam("key")String key, @RequestParam("defaultValue")String defaultValue);
+	
+	// 获取App端指定配置信息 
+	@RequestMapping("/SpCfgApi/getAppCfg")
+	public String getAppCfg(@RequestParam("key")String key, @RequestParam("defaultValue")String defaultValue);
+	
+	
+}

+ 45 - 0
sp-core/sp-api/src/main/java/com/pj/api/client/SpCfgInterfaceFallback.java

@@ -0,0 +1,45 @@
+package com.pj.api.client;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import feign.hystrix.FallbackFactory;
+
+/**
+ * 系统配置 服务降级处理
+ * @author kong
+ *
+ */
+@Component
+public class SpCfgInterfaceFallback implements FallbackFactory<SpCfgInterface>
+{
+
+	private static final Logger log = LoggerFactory.getLogger(SpCfgInterfaceFallback.class);
+	
+	/**
+	 * 服务降级时触发的方法 
+	 */
+	@Override
+	public SpCfgInterface create(Throwable cause) {
+		
+		
+		log.error("--------------------系统配置服务异常,触发降级: {}", cause.getMessage());
+		
+		// 返回熔断后的对象 
+		return new SpCfgInterface() {
+			
+			@Override
+			public String getServerCfg(String key, String defaultValue) {
+				return defaultValue;
+			}
+			
+			@Override
+			public String getAppCfg(String key, String defaultValue) {
+				return defaultValue;
+			}
+			
+		};
+	}
+
+}

+ 15 - 0
sp-core/sp-api/src/main/java/com/pj/api/consts/FeignConsts.java

@@ -0,0 +1,15 @@
+package com.pj.api.consts;
+
+public class FeignConsts {
+
+	
+	/**
+	 * 服务名:sp-home 
+	 */
+	public static final String SP_HOME = "sp-home";
+	
+	
+	
+	
+	
+}

+ 29 - 0
sp-core/sp-api/src/main/java/com/pj/api/consts/FeignFactory.java

@@ -0,0 +1,29 @@
+package com.pj.api.consts;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.pj.api.client.SpCfgInterface;
+
+/**
+ * Feign bean工厂类
+ * @author kong
+ *
+ */
+@Component
+public class FeignFactory {
+
+	/**
+	 *  系统配置 通信接口
+	 */
+	public static SpCfgInterface spCfgInterface;
+	@Autowired
+	public void setSpCfgInterface(SpCfgInterface spCfgInterface) {
+		FeignFactory.spCfgInterface = spCfgInterface;
+	}
+	
+	
+	
+	
+	
+}

+ 157 - 0
sp-core/sp-base/pom.xml

@@ -0,0 +1,157 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.pj</groupId>
+        <artifactId>sp-core</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sp-base</artifactId>
+    <packaging>jar</packaging>
+    
+    <dependencies>
+    
+		<!-- ================= 模块依赖 start ================= -->
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-nacos</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+		<!-- ================= 模块依赖 end ================= -->
+    
+    
+	    <!-- nacos 注册中心 -->
+	    <dependency>
+		    <groupId>com.alibaba.cloud</groupId>
+		    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+		</dependency>
+	    <!-- nacos 分布式配置中心 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <!-- Sentinel 熔断、降级、限流 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+            <!-- 排除jackson-dataformat-xml依赖,否则接口中返回的json会变成xml -->
+            <exclusions>
+            	<exclusion>
+		            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            		<artifactId>jackson-dataformat-xml</artifactId>
+            	</exclusion>
+            </exclusions>
+        </dependency>
+        <!-- 使用过滤器捕获全局BlockException -->
+		<dependency>
+		    <groupId>com.alibaba.csp</groupId>
+		    <artifactId>sentinel-spring-webmvc-adapter</artifactId>
+		</dependency>
+		<!-- sentinel配置持久化到nacos -->
+		<dependency>
+	        <groupId>com.alibaba.csp</groupId>
+	        <artifactId>sentinel-datasource-nacos</artifactId>
+	    </dependency>
+		
+
+		<!-- springboot依赖 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-aop</artifactId>
+		</dependency>
+
+       	<!-- springboot集成 mybatis-plus -->
+		<dependency>
+		    <groupId>com.baomidou</groupId>
+		    <artifactId>mybatis-plus-boot-starter</artifactId>
+		    <version>3.3.2</version>
+		</dependency>
+		
+        <!-- pagehelper分页插件 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>1.2.13</version>
+        </dependency>
+        
+		<!-- mysql -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+		</dependency>
+		
+		<!-- 阿里 druid 连接池  -->
+		<dependency>
+	        <groupId>com.alibaba</groupId>
+	        <artifactId>druid-spring-boot-starter</artifactId>
+	        <version>1.1.10</version>
+	    </dependency>
+
+		<!-- 神器lombok插件 -->
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+			<!-- <optional>true</optional> -->
+		</dependency>
+		
+		<!-- 集成redis -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+
+		<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-spring-boot-starter</artifactId>
+		    <version>1.27.0</version>
+		</dependency>
+		<!-- Sa-Token 整合 Redis (使用jdk默认序列化方式) -->
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-dao-redis-jackson</artifactId>
+		    <version>1.27.0</version>
+		</dependency>
+		
+        <!-- 工具类大全 - 在线文档:https://hutool.cn/docs/#/ -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.0.7</version>
+        </dependency>
+        
+        <!--Alijson插件-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.73</version>
+        </dependency>
+
+		<!-- ConfigurationProperties -->
+        <dependency>
+        	<groupId>org.springframework.boot</groupId>
+        	<artifactId>spring-boot-configuration-processor</artifactId>
+        	<!-- <optional>true</optional> -->
+        </dependency>
+        
+        
+    </dependencies>
+
+</project>

+ 65 - 0
sp-core/sp-base/src/main/java/com/pj/current/SpCloudUtil.java

@@ -0,0 +1,65 @@
+package com.pj.current;
+
+import java.net.InetAddress;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import com.pj.utils.sg.NbUtil;
+
+/**
+ * springboot启动之后 
+ */
+@Order(Integer.MAX_VALUE)
+@Component
+public class SpCloudUtil {
+    
+	@Value("${server.port:8080}")
+    private String port;
+
+    @Value("${server.servlet.context-path:}")
+    private String path;
+
+    @Value("${spring.application.name:}")
+    private String applicationName;
+
+    @Value("${spring.profiles.active:}")
+    private String active;
+   
+    
+    public void run() throws Exception {
+        String ip = InetAddress.getLocalHost().getHostAddress();
+        String str = "\n------------- " + applicationName + " (" + active + ") 启动成功 --by " + NbUtil.getNow() + " -------------\n" + 
+                "\t- Local:   http://localhost:" + port + path + "\n" +
+                "\t- Local2:  http://127.0.0.1:" + port + path + "\n" +
+                "\t- Network: http://" + ip + ":" + port + path + "\n";
+        System.out.println(str);
+    }
+
+
+
+    
+    static SpCloudUtil saPlusStartup;
+    @Autowired
+	public void setSaPlusStartup(SpCloudUtil saPlusStartup) {
+    	SpCloudUtil.saPlusStartup = saPlusStartup;
+	}
+    
+    
+    /**
+     * 打印当前服务信息 
+     */
+    public static void printCurrentServiceInfo() {
+    	try {
+    		saPlusStartup.run();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+    }
+    
+    
+
+}
+

+ 41 - 0
sp-core/sp-base/src/main/java/com/pj/current/config/MyConfig.java

@@ -0,0 +1,41 @@
+package com.pj.current.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+
+import lombok.Data;
+
+/**
+ * 项目自定义配置 
+ * @author kong
+ *
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix="spring.myconfig")	
+public class MyConfig {
+
+	/**
+	 * md5的盐 
+	 */
+	private String md5Salt;		
+	
+	/** 
+	 * 是否明文存储密码 
+	 */
+	private Boolean isPw;		
+	
+	/** 
+	 * 本项目部署到的服务器域名(文件上传、微信支付等等模块  要用到) 
+	 */
+	private String domain;			
+	
+	/**
+	 * 是否彩色SQL日志 
+	 */
+	private Boolean colorSql = true;		
+	
+	
+	
+}

+ 77 - 0
sp-core/sp-base/src/main/java/com/pj/current/config/RemoveDruidAdConfig.java

@@ -0,0 +1,77 @@
+package com.pj.current.config;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
+import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.util.Utils;
+
+/**
+ * 类名称:RemoveDruidAdConfig 类描述: 去除druid底部的广告配置类 
+ */
+@Configuration
+@ConditionalOnWebApplication
+@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
+@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
+public class RemoveDruidAdConfig {
+
+	/**
+	 * 方法名: removeDruidAdFilterRegistrationBean 方法描述: 除去页面底部的广告 @param
+	 * properties @return
+	 * org.springframework.boot.web.servlet.FilterRegistrationBean @throws
+	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@Bean
+	public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
+		// 获取web监控页面的参数
+		DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
+		// 提取common.js的配置路径
+		String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
+		String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
+
+		final String filePath = "support/http/resources/js/common.js";
+
+		// 创建filter进行过滤
+		Filter filter = new Filter() {
+			@Override
+			public void init(FilterConfig filterConfig) throws ServletException {
+			}
+
+			@Override
+			public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+					throws IOException, ServletException {
+				chain.doFilter(request, response);
+				// 重置缓冲区,响应头不会被重置
+				response.resetBuffer();
+				// 获取common.js
+				String text = Utils.readFromResource(filePath);
+				// 正则替换banner, 除去底部的广告信息
+				text = text.replaceAll("<a.*?banner\"></a><br/>", "");
+				text = text.replaceAll("powered.*?shrek.wang</a>", "");
+				response.getWriter().write(text);
+			}
+
+			@Override
+			public void destroy() {
+			}
+		};
+		FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+		registrationBean.setFilter(filter);
+		registrationBean.addUrlPatterns(commonJsPattern);
+		return registrationBean;
+	}
+}

+ 43 - 0
sp-core/sp-base/src/main/java/com/pj/current/config/SystemObject.java

@@ -0,0 +1,43 @@
+package com.pj.current.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import cn.hutool.crypto.SecureUtil;
+
+/**
+ * 有关当前项目的一些全局工具方法封装 
+ * @author kong
+ *
+ */
+@Component
+public class SystemObject {
+
+	// ===================================== 一些二次封装的方法 ===================================================
+	
+	/** 返回md5加密后的密码,根据当前配置的salt
+	 *   格式为: md5(salt + userid + password) 
+	 */ 
+	public static String getPasswordMd5(long userId, String password) {
+		return SecureUtil.md5(config.getMd5Salt() + userId + password).toUpperCase();
+	}
+	
+	/** 返回md5加密后的密码,根据当前配置的salt
+	 *  格式为: md5(salt + 0 + password) 
+	 */ 
+	public static String getPasswordMd5(String password) {
+		return getPasswordMd5(0, password);
+	}
+	
+	
+	
+	// ===================================== yml自定义配置信息 ===================================================
+	
+	public static MyConfig config;
+	@Autowired
+	void setMyConfig(MyConfig config) {
+		SystemObject.config = config;
+	}
+		
+	
+}

+ 60 - 0
sp-core/sp-base/src/main/java/com/pj/current/global/GlobalAspect.java

@@ -0,0 +1,60 @@
+package com.pj.current.global;
+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.springframework.stereotype.Component;
+
+import com.pj.project4sp.apilog.SpApilogUtil;
+import com.pj.utils.sg.AjaxJson;
+
+/**
+ *  全局日志切面, 拦截所有controller请求,写入日志 
+ * @author kong
+ *
+ */
+@Aspect
+@Component
+public class GlobalAspect {
+    
+	/**
+	 * 定义AOP签名 --> 项目代码(所有class名成带有Controller字符的)
+	 */
+	@Pointcut("execution(* com.pj..*Controller*.*(..))")
+    public void webLogProject(){}
+
+	
+    /**
+     * 环绕通知,环绕增强,相当于MethodInterceptor
+     * @param pjp
+     * @return
+     * @throws Throwable
+     */
+    @Around("webLogProject()")
+    public Object surround(ProceedingJoinPoint pjp) throws Throwable {
+    	// 1、开始时  移入 
+    	SpApilogUtil.startRequest();
+        try {
+        	// 2、执行时 
+            Object obj =  pjp.proceed();
+            // 如果是 AjaxJson 
+            if(obj instanceof AjaxJson){	
+            	SpApilogUtil.endRequest((AjaxJson)obj);
+            } 
+            // 如果是 String  
+            else if (obj instanceof String) {	
+            	SpApilogUtil.endRequest(AjaxJson.get(901, String.valueOf(obj)));
+            } 
+            // 如果都不是 
+            else {	 
+            	SpApilogUtil.endRequest(AjaxJson.get(902, String.valueOf(obj)));
+            }
+            return obj;
+        } catch (Throwable e) {
+        	throw e;
+        }
+    }
+    
+    
+    
+}

+ 81 - 0
sp-core/sp-base/src/main/java/com/pj/current/global/GlobalException.java

@@ -0,0 +1,81 @@
+package com.pj.current.global;
+
+import java.sql.SQLException;
+
+import org.springframework.data.redis.RedisConnectionFailureException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.pj.project4sp.apilog.SpApilogUtil;
+import com.pj.project4sp.spcfg.SpCfgUtil;
+import com.pj.utils.sg.AjaxError;
+import com.pj.utils.sg.AjaxJson;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+
+/**
+ * 全局异常拦截 
+ * <p> @ControllerAdvice 可指定包前缀,例如:(basePackages = "com.pj.controller.admin")
+ * @author kong
+ *
+ */
+@ControllerAdvice
+public class GlobalException {
+
+	/** 全局异常拦截  */
+	@ResponseBody
+	@ExceptionHandler
+	public AjaxJson handlerException(Exception e) {
+
+		// 打印堆栈,以供调试
+		e.printStackTrace(); 
+
+    	// 记录日志信息
+    	AjaxJson aj = null;
+		Throwable e2 = e.getCause();
+		
+		// ------------- 判断异常类型,提供个性化提示信息 
+		
+    	// 如果是未登录异常 
+		if(e instanceof NotLoginException){	
+			aj = AjaxJson.getNotLogin();
+		} 
+		// 如果是权限异常
+		else if(e instanceof NotPermissionException) {	
+			NotPermissionException ee = (NotPermissionException) e;
+			aj = AjaxJson.getNotJur("无此权限:" + ee.getCode());
+		} 
+		// 如果是AjaxError,则获取其具体code码 
+		else if(e instanceof AjaxError) {		
+			AjaxError ee = (AjaxError) e;
+			aj = AjaxJson.get(ee.getCode(), ee.getMessage());
+		}  
+		// 如果是SQLException,并且指定了hideSql,则只返回sql error 
+		else if((e instanceof SQLException || e2 instanceof SQLException) && SpCfgUtil.throwOutSql() == false) {	
+			// 无论是否打开隐藏sql,日志表记录的都是真实异常信息 
+			aj = AjaxJson.getError(e2.getMessage());
+			SpApilogUtil.endRequest(aj);	
+			return AjaxJson.getError("Sql Error").set("reqId", SpApilogUtil.getCurrReqId());
+		}
+		// 如果是redis连接异常 ( 由于redis连接异常,系统已经无法正常工作,所以此处需要立即返回 )
+		else if(e instanceof RedisConnectionFailureException) {	
+			aj = AjaxJson.getError("Redis异常,请检查连接信息");
+			aj.set("reqId", SpApilogUtil.getCurrReqId());
+			return aj;
+		}
+		// 普通异常输出:500 + 异常信息 
+		else {
+			aj = AjaxJson.getError(e.getMessage());
+		}
+		
+		// 插入到日志表 
+		SpApilogUtil.endRequest(aj);
+		
+		// 返回到前台 
+		aj.set("reqId", SpApilogUtil.getCurrReqId());
+		return aj;
+	}
+
+}

+ 150 - 0
sp-core/sp-base/src/main/java/com/pj/current/mybatis/MybatisMapperDynamicLoader.java

@@ -0,0 +1,150 @@
+package com.pj.current.mybatis;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import org.apache.ibatis.executor.ErrorContext;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+
+/**
+ * mapper.xml热刷新操作类
+ * @author kong 
+ */
+public class MybatisMapperDynamicLoader implements InitializingBean, ApplicationContextAware {
+
+	public boolean enabled = true;	
+	public MybatisMapperDynamicLoader(boolean enabled) {
+		this.enabled = enabled;
+	}
+	
+    private final HashMap<String, String> mappers = new HashMap<String, String>();
+    private volatile ConfigurableApplicationContext context = null;
+    private volatile Scanner scanner = null;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        this.context = (ConfigurableApplicationContext) applicationContext;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+    	// 如果未开启 直接返回
+    	if(!enabled) {
+    		return;
+    	}
+        try {
+            scanner = new Scanner();
+            new Timer(true).schedule(new TimerTask() {
+            	@Override
+                public void run() {
+                    try {
+                        if (scanner.isChanged()) {
+                            // System.out.println("load mapper.xml");
+                        	String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
+                        	System.out.println("mapper.xml热刷新成功,当前时间:" + now);
+                            scanner.reloadXml();
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            }, 10 * 1000, 3 * 1000);
+        } catch (Exception e1) {
+            e1.printStackTrace();
+        }
+    }
+
+    class Scanner {
+        private static final String XML_RESOURCE_PATTERN = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "**/*Mapper.xml";
+        private final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+        public Scanner() throws IOException {
+            Resource[] resources = findResource();
+            if (resources != null) {
+                for (Resource resource : resources) {
+                    String key = resource.getURI().toString();
+                    String value = getMd(resource);
+                    mappers.put(key, value);
+                }
+            }
+        }
+        public void reloadXml() throws Exception {
+            SqlSessionFactory factory = context.getBean(SqlSessionFactory.class);
+            Configuration configuration = factory.getConfiguration();
+            
+//            org.apache.ibatis.session.Configuration
+//            com.baomidou.mybatisplus.core.MybatisConfiguration
+            
+            removeConfig(configuration);
+            for (Resource resource : findResource()) {
+                try {
+                    XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(), configuration, resource.toString(), configuration.getSqlFragments());
+                    xmlMapperBuilder.parse();
+                } finally {
+                    ErrorContext.instance().reset();
+                }
+            }
+        }
+        private void removeConfig(Configuration configuration) throws Exception {
+            Class<?> classConfig = configuration.getClass();
+            // 如果使用了mybatis-plus,可能会获取不到真正的 Configuration类,需要加上以下代码,才能正确运行   ====== start
+            if(classConfig.equals(org.apache.ibatis.session.Configuration.class) == false) {
+//            	System.err.println("开始 转化");
+            	classConfig = classConfig.getSuperclass();
+            }
+            //  ====== end 
+            clearMap(classConfig, configuration, "mappedStatements");
+            clearMap(classConfig, configuration, "caches");
+            clearMap(classConfig, configuration, "resultMaps");
+            clearMap(classConfig, configuration, "parameterMaps");
+            clearMap(classConfig, configuration, "keyGenerators");
+            clearMap(classConfig, configuration, "sqlFragments");
+            clearSet(classConfig, configuration, "loadedResources");
+        }
+        @SuppressWarnings("rawtypes")
+		private void clearMap(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
+            Field field = classConfig.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            ((Map) field.get(configuration)).clear();
+        }
+        @SuppressWarnings("rawtypes")
+		private void clearSet(Class<?> classConfig, Configuration configuration, String fieldName) throws Exception {
+            Field field = classConfig.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            ((Set) field.get(configuration)).clear();
+        }
+        public boolean isChanged() throws IOException {
+            boolean isChanged = false;
+            for (Resource resource : findResource()) {
+                String key = resource.getURI().toString();
+                String value = getMd(resource);
+                if (!value.equals(mappers.get(key))) {
+                    isChanged = true;
+                    mappers.put(key, value);
+                }
+            }
+            return isChanged;
+        }
+        private Resource[] findResource() throws IOException {
+            return resourcePatternResolver.getResources(XML_RESOURCE_PATTERN);
+        }
+        private String getMd(Resource resource) throws IOException {
+            return new StringBuilder().append(resource.contentLength()).append("-").append(resource.lastModified()).toString();
+        }
+    }
+}

+ 75 - 0
sp-core/sp-base/src/main/java/com/pj/current/mybatis/MybatisStdOutImpl.java

@@ -0,0 +1,75 @@
+package com.pj.current.mybatis;
+
+import org.apache.ibatis.logging.Log;
+
+import com.pj.current.config.SystemObject;
+
+/**
+ * 自定义mybatis日志层实现,优化mybatis日志输出,主要优化以下部分:
+ * <p> 1、删除无用日志信息
+ * <p> 2、SQL高亮显示
+ * @author kong
+ *
+ */
+public class MybatisStdOutImpl implements Log {
+	
+	public MybatisStdOutImpl(String clazz) {
+		// Do Nothing
+	}
+
+	@Override
+	public boolean isDebugEnabled() {
+		return true;
+	}
+
+	@Override
+	public boolean isTraceEnabled() {
+		return true;
+	}
+
+	@Override
+	public void error(String s, Throwable e) {
+		System.err.println(s);
+		e.printStackTrace(System.err);
+	}
+
+	@Override
+	public void error(String s) {
+		System.err.println(s);
+	}
+
+	/** 
+	 * MyBatis动作 打印 
+	 * 执行Sql与参数 打印
+	 */
+	@Override
+	public void debug(String s) {
+		// 以下日志,不再打印 
+		if(s.startsWith("Creating") || s.startsWith("SqlSession") || s.startsWith("Cache") || s.startsWith("JDBC") || s.startsWith("Closing")) {
+			return;
+		}
+		// 如果是sql语句,则: 蓝色、加粗、下划线 
+		// 参考:https://blog.csdn.net/soinice/article/details/97052030
+		if(SystemObject.config != null && SystemObject.config.getColorSql() && s.startsWith("==>  Preparing")) {
+			s = "\033[34;1;4m" + s + "\033[0m";
+//			s = s.replaceAll("==>  Preparing: ", "");
+//			s = "==>  Preparing: " + s;
+		}
+		System.out.println(s);
+	}
+
+	/** 
+	 * Sql执行结果,打印 
+	 */
+	@Override
+	public void trace(String s) {
+		System.out.println(s);
+	}
+
+	@Override
+	public void warn(String s) {
+		System.out.println(s);
+	}
+
+
+}

+ 36 - 0
sp-core/sp-base/src/main/java/com/pj/current/mybatis/RefConfig.java

@@ -0,0 +1,36 @@
+package com.pj.current.mybatis;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * mapper.xml相关配置注入 
+ * @author kong
+ *
+ */
+@Configuration
+public class RefConfig {
+	
+	@Value("${autof5:true}")
+	boolean autof5;
+	
+	@Bean(name="MybatisMapperDynamicLoader")
+	public MybatisMapperDynamicLoader get() {
+		// System.out.println("是啥===:" + autof5);
+		return new MybatisMapperDynamicLoader(autof5);
+	}
+	
+
+	/**
+	 * 注入日志组件 (从yml文件中配置的方式,打包后有概率无法启动项目且无法解决,故用此方法注入自定义日志组件)
+	 * @param sqlSessionFactory
+	 */
+	@Autowired
+	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
+		sqlSessionFactory.getConfiguration().setLogImpl(MybatisStdOutImpl.class);
+	}
+	
+}

+ 42 - 0
sp-core/sp-base/src/main/java/com/pj/current/satoken/AuthConst.java

@@ -0,0 +1,42 @@
+package com.pj.current.satoken;
+
+/**
+ * 权限码常量  
+ * @author kong
+ *
+ */
+public final class AuthConst {
+
+	/**
+	 *  私有构造方法 
+	 */
+	private AuthConst() {
+	}
+	
+	
+	// --------------- 代表身份的权限 --------------- 
+	
+	public static final String R1 = "1"; 			 // 角色_id_超级管理员 最高权限,超管身份的代表
+	public static final String R11 = "11"; 		 // 
+	public static final String R99 = "99";		  // 进入后台权限,没有此权限无法进入后台管理
+	
+	
+	// --------------- 所有权限码 --------------- 
+
+	public static final String AUTH = "auth";		   // 权限管理
+	public static final String ROLE_LIST = "role-list";		    // 权限管理 - 角色管理
+	public static final String MENU_LIST = "menu-list";		   // 权限管理 - 菜单列表
+	public static final String ADMIN_LIST = "admin-list";		   // 权限管理 - 管理员列表
+	public static final String ADMIN_ADD = "admin-add";		   // 权限管理 - 管理员添加
+
+	public static final String CONSOLE = "console";		   // 监控中心
+	public static final String SQL_CONSOLE = "sql-console";		      // 监控中心 - SQL监控
+	public static final String REDIS_CONSOLE = "redis-console";		   // 监控中心 - Redis 控制台
+	public static final String APILOG_LIST = "apilog-list";		   // 监控中心 - API 请求日志
+
+	public static final String SP_CFG = "sp-cfg";		  	 // 系统配置
+	public static final String SP_CFG_APP = "sp-cfg-app";		  	 // 系统配置 - 系统对公配置
+	public static final String SP_CFG_SERVER = "sp-cfg-server";		   // 系统配置 - 服务器私有配置
+	
+	
+}

+ 69 - 0
sp-core/sp-base/src/main/java/com/pj/current/satoken/SaTokenConfigure.java

@@ -0,0 +1,69 @@
+package com.pj.current.satoken;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import com.pj.utils.sg.AjaxJson;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.id.SaIdUtil;
+import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
+
+/**
+ * Sa-Token 代码方式进行配置 
+ * @author kong 
+ */
+@Configuration
+public class SaTokenConfigure implements WebMvcConfigurer {
+
+	/**
+	 * 注册 Sa-Token 的拦截器,打开注解式鉴权功能 
+	 */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**"); 
+    }
+    
+    /**
+     * 注册 Sa-Token全局过滤器,解决跨域问题 
+     */
+    @Bean
+    public SaServletFilter getSaServletFilter() {
+        return new SaServletFilter()
+        		// 拦截与排除 path 
+        		.addInclude("/**").addExclude("/favicon.ico")
+        		
+        		// 全局认证函数 
+        		.setAuth(obj -> {
+        			// 校验 Id-Token 身份凭证     —— 以下两句代码可简化为:SaIdUtil.checkCurrentRequestToken(); 
+                    String token = SaHolder.getRequest().getHeader(SaIdUtil.ID_TOKEN);
+                    SaIdUtil.checkToken(token);
+        		})
+        		
+        		// 异常处理函数  
+        		.setError(e -> {
+        			return AjaxJson.getError(e.getMessage());
+        		})
+        		
+        		// 前置函数:在每次认证函数之前执行
+        		.setBeforeAuth(obj -> {
+        			// ---------- 设置跨域响应头 ----------
+        			// 这里不需要处理跨域问题,因为我们已经在网关处处理过了  
+//        			SaHolder.getResponse()
+//        			.setHeader("Access-Control-Allow-Origin", "*")
+//        			.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+//        			.setHeader("Access-Control-Max-Age", "3600")
+//        			.setHeader("Access-Control-Allow-Headers", "*");
+//        			
+//        			// 如果是预检请求,则立即返回到前端 
+//        			SaRouter.match(SaHttpMethod.OPTIONS)
+//        				.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
+//        				.back();
+        		})
+        		;
+    }
+    
+}

+ 856 - 0
sp-core/sp-base/src/main/java/com/pj/current/satoken/StpUserUtil.java

@@ -0,0 +1,856 @@
+package com.pj.current.satoken;
+
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.SaTokenInfo;
+import cn.dev33.satoken.stp.StpLogic;
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Sa-Token 权限认证工具类 (User版本) 
+ * @author kong 
+ */
+@Component
+public class StpUserUtil {
+	
+	/**
+	 * 账号类型标识 
+	 */
+	public static final String TYPE = "user";
+	
+	/**
+	 * 底层的 StpLogic 对象  
+	 */
+	public static StpLogic stpLogic = new StpLogic(TYPE); 
+
+	/**
+	 * 获取当前 StpLogic 的账号类型
+	 * @return See Note 
+	 */
+	public static String getLoginType(){
+		return stpLogic.getLoginType();
+	}
+
+	/**
+	 * 重置 StpLogic 对象
+	 * @param stpLogic / 
+	 */
+	public static void setStpLogic(StpLogic stpLogic) {
+		StpUtil.stpLogic = stpLogic;
+		// 防止自定义 stpLogic 被覆盖 
+		SaManager.putStpLogic(stpLogic);
+	}
+	
+	
+	// =================== 获取token 相关 ===================
+
+	/**
+	 * 返回token名称 
+	 * @return 此StpLogic的token名称
+	 */
+	public static String getTokenName() {
+ 		return stpLogic.getTokenName();
+ 	}
+
+ 	/**
+ 	 * 在当前会话写入当前TokenValue 
+ 	 * @param tokenValue token值 
+ 	 * @param cookieTimeout Cookie存活时间(秒)
+ 	 */
+	public static void setTokenValue(String tokenValue, int cookieTimeout){
+		stpLogic.setTokenValue(tokenValue, cookieTimeout);
+	}
+ 	
+	/**
+	 * 获取当前TokenValue
+	 * @return 当前tokenValue
+	 */
+	public static String getTokenValue() {
+		return stpLogic.getTokenValue();
+	}
+
+	/**
+	 * 获取当前会话的Token信息 
+	 * @return token信息 
+	 */
+	public static SaTokenInfo getTokenInfo() {
+		return stpLogic.getTokenInfo();
+	}
+
+	
+	// =================== 登录相关操作 ===================
+
+	// --- 登录 
+	
+	/**
+	 * 会话登录 
+	 * @param id 账号id,建议的类型:(long | int | String)
+	 */
+	public static void login(Object id) {
+		stpLogic.login(id);
+	}
+
+	/**
+	 * 会话登录,并指定登录设备 
+	 * @param id 账号id,建议的类型:(long | int | String)
+	 * @param device 设备标识 
+	 */
+	public static void login(Object id, String device) {
+		stpLogic.login(id, device);
+	}
+
+	/**
+	 * 会话登录,并指定是否 [记住我] 
+	 * @param id 账号id,建议的类型:(long | int | String)
+	 * @param isLastingCookie 是否为持久Cookie 
+	 */
+	public static void login(Object id, boolean isLastingCookie) {
+		stpLogic.login(id, isLastingCookie);
+	}
+
+	/**
+	 * 会话登录,并指定所有登录参数Model 
+	 * @param id 登录id,建议的类型:(long | int | String)
+	 * @param loginModel 此次登录的参数Model 
+	 */
+	public static void login(Object id, SaLoginModel loginModel) {
+		stpLogic.login(id, loginModel);
+	}
+
+	// --- 注销 
+	
+	/** 
+	 * 会话注销 
+	 */
+	public static void logout() {
+		stpLogic.logout();
+	}
+
+	/**
+	 * 会话注销,根据账号id 
+	 * @param loginId 账号id 
+	 */
+	public static void logout(Object loginId) {
+		stpLogic.logout(loginId);
+	}
+
+	/**
+	 * 会话注销,根据账号id 和 设备标识 
+	 * 
+	 * @param loginId 账号id 
+	 * @param device 设备标识 (填null代表所有注销设备) 
+	 */
+	public static void logout(Object loginId, String device) {
+		stpLogic.logout(loginId, device);
+	}
+	
+	/**
+	 * 会话注销,根据指定 Token 
+	 * 
+	 * @param tokenValue 指定token
+	 */
+	public static void logoutByTokenValue(String tokenValue) {
+		stpLogic.logoutByTokenValue(tokenValue);
+	}
+	
+	/**
+	 * 踢人下线,根据账号id 
+	 * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-5 </p>
+	 * 
+	 * @param loginId 账号id 
+	 */
+	public static void kickout(Object loginId) {
+		stpLogic.kickout(loginId);
+	}
+	
+	/**
+	 * 踢人下线,根据账号id 和 设备标识 
+	 * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-5 </p>
+	 * 
+	 * @param loginId 账号id 
+	 * @param device 设备标识 (填null代表踢出所有设备) 
+	 */
+	public static void kickout(Object loginId, String device) {
+		stpLogic.kickout(loginId, device);
+	}
+
+	/**
+	 * 踢人下线,根据指定 Token 
+	 * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-5 </p>
+	 * 
+	 * @param tokenValue 指定token
+	 */
+	public static void kickoutByTokenValue(String tokenValue) {
+		stpLogic.kickoutByTokenValue(tokenValue);
+	}
+	
+	/**
+	 * 顶人下线,根据账号id 和 设备标识 
+	 * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-4 </p>
+	 * 
+	 * @param loginId 账号id 
+	 * @param device 设备标识 (填null代表顶替所有设备) 
+	 */
+	public static void replaced(Object loginId, String device) {
+		stpLogic.replaced(loginId, device);
+	}
+	
+	
+	// 查询相关
+
+	/** 
+ 	 * 当前会话是否已经登录 
+ 	 * @return 是否已登录 
+ 	 */
+	public static boolean isLogin() {
+		return stpLogic.isLogin();
+	}
+
+	/** 
+ 	 * 检验当前会话是否已经登录,如未登录,则抛出异常 
+ 	 */
+ 	public static void checkLogin() {
+ 		stpLogic.checkLogin();
+ 	}
+
+ 	/** 
+ 	 * 获取当前会话账号id, 如果未登录,则抛出异常 
+ 	 * @return 账号id
+ 	 */
+	public static Object getLoginId() {
+		return stpLogic.getLoginId();
+	}
+
+	/** 
+	 * 获取当前会话账号id, 如果未登录,则返回默认值 
+	 * @param <T> 返回类型 
+	 * @param defaultValue 默认值
+	 * @return 登录id 
+	 */
+	public static <T> T getLoginId(T defaultValue) {
+		return stpLogic.getLoginId(defaultValue);
+	}
+
+	/** 
+	 * 获取当前会话账号id, 如果未登录,则返回null 
+	 * @return 账号id 
+	 */
+	public static Object getLoginIdDefaultNull() {
+		return stpLogic.getLoginIdDefaultNull();
+ 	}
+
+	/** 
+	 * 获取当前会话账号id, 并转换为String类型
+	 * @return 账号id 
+	 */
+	public static String getLoginIdAsString() {
+		return stpLogic.getLoginIdAsString();
+	}
+
+	/** 
+	 * 获取当前会话账号id, 并转换为int类型
+	 * @return 账号id 
+	 */
+	public static int getLoginIdAsInt() {
+		return stpLogic.getLoginIdAsInt();
+	}
+
+	/**
+	 * 获取当前会话账号id, 并转换为long类型 
+	 * @return 账号id 
+	 */
+	public static long getLoginIdAsLong() {
+		return stpLogic.getLoginIdAsLong();
+	}
+
+	/** 
+ 	 * 获取指定Token对应的账号id,如果未登录,则返回 null 
+ 	 * @param tokenValue token
+ 	 * @return 账号id
+ 	 */
+ 	public static Object getLoginIdByToken(String tokenValue) {
+ 		return stpLogic.getLoginIdByToken(tokenValue);
+ 	}
+	
+ 	
+	// =================== User-Session 相关 ===================
+
+ 	/** 
+	 * 获取指定账号id的Session, 如果Session尚未创建,isCreate=是否新建并返回
+	 * @param loginId 账号id
+	 * @param isCreate 是否新建
+	 * @return Session对象
+	 */
+	public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
+		return stpLogic.getSessionByLoginId(loginId, isCreate);
+	}
+
+	/** 
+	 * 获取指定key的Session, 如果Session尚未创建,则返回null
+	 * @param sessionId SessionId
+	 * @return Session对象 
+	 */
+	public static SaSession getSessionBySessionId(String sessionId) {
+		return stpLogic.getSessionBySessionId(sessionId);
+	}
+
+	/** 
+	 * 获取指定账号id的Session,如果Session尚未创建,则新建并返回 
+	 * @param loginId 账号id 
+	 * @return Session对象 
+	 */
+	public static SaSession getSessionByLoginId(Object loginId) {
+		return stpLogic.getSessionByLoginId(loginId);
+	}
+
+	/** 
+	 * 获取当前会话的Session, 如果Session尚未创建,isCreate=是否新建并返回 
+	 * @param isCreate 是否新建 
+	 * @return Session对象 
+	 */
+	public static SaSession getSession(boolean isCreate) {
+		return stpLogic.getSession(isCreate);
+	}
+
+	/** 
+	 * 获取当前会话的Session,如果Session尚未创建,则新建并返回 
+	 * @return Session对象 
+	 */
+	public static SaSession getSession() {
+		return stpLogic.getSession();
+	}
+
+	
+	// =================== Token-Session 相关 ===================  
+	
+	/** 
+	 * 获取指定Token-Session,如果Session尚未创建,则新建并返回 
+	 * @param tokenValue Token值
+	 * @return Session对象  
+	 */
+	public static SaSession getTokenSessionByToken(String tokenValue) {
+		return stpLogic.getTokenSessionByToken(tokenValue);
+	}
+	
+	/** 
+	 * 获取当前Token-Session,如果Session尚未创建,则新建并返回
+	 * @return Session对象 
+	 */
+	public static SaSession getTokenSession() {
+		return stpLogic.getTokenSession();
+	}
+
+
+	// =================== [临时过期] 验证相关 ===================  
+
+	/**
+ 	 * 检查当前token 是否已经[临时过期],如果已经过期则抛出异常  
+ 	 */
+ 	public static void checkActivityTimeout() {
+ 		stpLogic.checkActivityTimeout();
+ 	}
+
+ 	/**
+ 	 * 续签当前token:(将 [最后操作时间] 更新为当前时间戳) 
+ 	 * <h1>请注意: 即时token已经 [临时过期] 也可续签成功,
+ 	 * 如果此场景下需要提示续签失败,可在此之前调用 checkActivityTimeout() 强制检查是否过期即可 </h1>
+ 	 */
+ 	public static void updateLastActivityToNow() {
+ 		stpLogic.updateLastActivityToNow();
+ 	}
+ 	
+
+	// =================== 过期时间相关 ===================  
+
+ 	/**
+ 	 * 获取当前登录者的 token 剩余有效时间 (单位: 秒)
+ 	 * @return token剩余有效时间
+ 	 */
+ 	public static long getTokenTimeout() {
+ 		return stpLogic.getTokenTimeout();
+ 	}
+ 	
+ 	/**
+ 	 * 获取当前登录者的 User-Session 剩余有效时间 (单位: 秒)
+ 	 * @return token剩余有效时间
+ 	 */
+ 	public static long getSessionTimeout() {
+ 		return stpLogic.getSessionTimeout();
+ 	}
+
+ 	/**
+ 	 * 获取当前 Token-Session 剩余有效时间 (单位: 秒) 
+ 	 * @return token剩余有效时间
+ 	 */
+ 	public static long getTokenSessionTimeout() {
+ 		return stpLogic.getTokenSessionTimeout();
+ 	}
+ 	
+ 	/**
+ 	 * 获取当前 token [临时过期] 剩余有效时间 (单位: 秒)
+ 	 * @return token [临时过期] 剩余有效时间
+ 	 */
+ 	public static long getTokenActivityTimeout() {
+ 		return stpLogic.getTokenActivityTimeout();
+ 	}
+ 	
+
+ 	
+	// =================== 角色验证操作 ===================  
+
+	/**
+	 * 获取:当前账号的角色集合 
+	 * @return /
+	 */
+	public static List<String> getRoleList() {
+		return stpLogic.getRoleList();
+	}
+
+	/**
+	 * 获取:指定账号的角色集合 
+	 * @param loginId 指定账号id 
+	 * @return /
+	 */
+	public static List<String> getRoleList(Object loginId) {
+		return stpLogic.getRoleList(loginId);
+	}
+
+ 	/** 
+ 	 * 判断:当前账号是否拥有指定角色, 返回true或false 
+ 	 * @param role 角色标识
+ 	 * @return 是否含有指定角色标识
+ 	 */
+ 	public static boolean hasRole(String role) {
+ 		return stpLogic.hasRole(role);
+ 	}
+
+ 	/** 
+ 	 * 判断:指定账号是否含有指定角色标识, 返回true或false 
+ 	 * @param loginId 账号id
+ 	 * @param role 角色标识
+ 	 * @return 是否含有指定角色标识
+ 	 */
+ 	public static boolean hasRole(Object loginId, String role) {
+ 		return stpLogic.hasRole(loginId, role);
+ 	}
+ 	
+ 	/** 
+ 	 * 判断:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] 
+ 	 * @param roleArray 角色标识数组
+ 	 * @return true或false
+ 	 */
+ 	public static boolean hasRoleAnd(String... roleArray){
+ 		return stpLogic.hasRoleAnd(roleArray);
+ 	}
+
+ 	/** 
+ 	 * 判断:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] 
+ 	 * @param roleArray 角色标识数组
+ 	 * @return true或false
+ 	 */
+ 	public static boolean hasRoleOr(String... roleArray){
+ 		return stpLogic.hasRoleOr(roleArray);
+ 	}
+ 	
+ 	/** 
+ 	 * 校验:当前账号是否含有指定角色标识, 如果验证未通过,则抛出异常: NotRoleException 
+ 	 * @param role 角色标识
+ 	 */
+ 	public static void checkRole(String role) {
+ 		stpLogic.checkRole(role);
+ 	}
+
+ 	/** 
+ 	 * 校验:当前账号是否含有指定角色标识 [指定多个,必须全部验证通过] 
+ 	 * @param roleArray 角色标识数组
+ 	 */
+ 	public static void checkRoleAnd(String... roleArray){
+ 		stpLogic.checkRoleAnd(roleArray);
+ 	}
+
+ 	/** 
+ 	 * 校验:当前账号是否含有指定角色标识 [指定多个,只要其一验证通过即可] 
+ 	 * @param roleArray 角色标识数组
+ 	 */
+ 	public static void checkRoleOr(String... roleArray){
+ 		stpLogic.checkRoleOr(roleArray);
+ 	}
+
+	
+	// =================== 权限验证操作 ===================
+
+	/**
+	 * 获取:当前账号的权限码集合 
+	 * @return / 
+	 */
+	public static List<String> getPermissionList() {
+		return stpLogic.getPermissionList();
+	}
+
+	/**
+	 * 获取:指定账号的权限码集合 
+	 * @param loginId 指定账号id
+	 * @return / 
+	 */
+	public static List<String> getPermissionList(Object loginId) {
+		return stpLogic.getPermissionList(loginId);
+	}
+
+ 	/** 
+ 	 * 判断:当前账号是否含有指定权限, 返回true或false 
+ 	 * @param permission 权限码
+ 	 * @return 是否含有指定权限
+ 	 */
+	public static boolean hasPermission(String permission) {
+		return stpLogic.hasPermission(permission);
+	}
+
+ 	/** 
+ 	 * 判断:指定账号id是否含有指定权限, 返回true或false 
+ 	 * @param loginId 账号id
+ 	 * @param permission 权限码
+ 	 * @return 是否含有指定权限
+ 	 */
+	public static boolean hasPermission(Object loginId, String permission) {
+		return stpLogic.hasPermission(loginId, permission);
+	}
+
+ 	/** 
+ 	 * 判断:当前账号是否含有指定权限, [指定多个,必须全部具有] 
+ 	 * @param permissionArray 权限码数组
+ 	 * @return true 或 false 
+ 	 */
+ 	public static boolean hasPermissionAnd(String... permissionArray){
+ 		return stpLogic.hasPermissionAnd(permissionArray);
+ 	}
+
+ 	/** 
+ 	 * 判断:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] 
+ 	 * @param permissionArray 权限码数组
+ 	 * @return true 或 false 
+ 	 */
+ 	public static boolean hasPermissionOr(String... permissionArray){
+ 		return stpLogic.hasPermissionOr(permissionArray);
+ 	}
+ 	
+ 	/** 
+ 	 * 校验:当前账号是否含有指定权限, 如果验证未通过,则抛出异常: NotPermissionException 
+ 	 * @param permission 权限码
+ 	 */
+	public static void checkPermission(String permission) {
+		stpLogic.checkPermission(permission);
+	}
+
+ 	/** 
+ 	 * 校验:当前账号是否含有指定权限 [指定多个,必须全部验证通过] 
+ 	 * @param permissionArray 权限码数组
+ 	 */
+	public static void checkPermissionAnd(String... permissionArray) {
+		stpLogic.checkPermissionAnd(permissionArray);
+	}
+
+ 	/** 
+ 	 * 校验:当前账号是否含有指定权限 [指定多个,只要其一验证通过即可] 
+ 	 * @param permissionArray 权限码数组
+ 	 */
+	public static void checkPermissionOr(String... permissionArray) {
+		stpLogic.checkPermissionOr(permissionArray);
+	}
+
+
+	// =================== id 反查token 相关操作 ===================  
+	
+	/** 
+	 * 获取指定账号id的tokenValue 
+	 * <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
+	 * 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId 
+	 * @param loginId 账号id
+	 * @return token值 
+	 */
+	public static String getTokenValueByLoginId(Object loginId) {
+		return stpLogic.getTokenValueByLoginId(loginId);
+	}
+
+	/** 
+	 * 获取指定账号id指定设备端的tokenValue 
+	 * <p> 在配置为允许并发登录时,此方法只会返回队列的最后一个token,
+	 * 如果你需要返回此账号id的所有token,请调用 getTokenValueListByLoginId 
+	 * @param loginId 账号id
+	 * @param device 设备标识 
+	 * @return token值 
+	 */
+	public static String getTokenValueByLoginId(Object loginId, String device) {
+		return stpLogic.getTokenValueByLoginId(loginId, device);
+	}
+	
+	/** 
+	 * 获取指定账号id的tokenValue集合 
+	 * @param loginId 账号id 
+	 * @return 此loginId的所有相关token 
+ 	 */
+	public static List<String> getTokenValueListByLoginId(Object loginId) {
+		return stpLogic.getTokenValueListByLoginId(loginId);
+	}
+
+	/** 
+	 * 获取指定账号id指定设备端的tokenValue 集合 
+	 * @param loginId 账号id 
+	 * @param device 设备标识 
+	 * @return 此loginId的所有相关token 
+ 	 */
+	public static List<String> getTokenValueListByLoginId(Object loginId, String device) {
+		return stpLogic.getTokenValueListByLoginId(loginId, device);
+	}
+	
+	/**
+	 * 返回当前会话的登录设备 
+	 * @return 当前令牌的登录设备 
+	 */
+	public static String getLoginDevice() {
+		return stpLogic.getLoginDevice(); 
+	}
+
+	
+	// =================== 会话管理 ===================  
+
+	/**
+	 * 根据条件查询Token 
+	 * @param keyword 关键字 
+	 * @param start 开始处索引 (-1代表查询所有) 
+	 * @param size 获取数量 
+	 * @return token集合 
+	 */
+	public static List<String> searchTokenValue(String keyword, int start, int size) {
+		return stpLogic.searchTokenValue(keyword, start, size);
+	}
+	
+	/**
+	 * 根据条件查询SessionId 
+	 * @param keyword 关键字 
+	 * @param start 开始处索引 (-1代表查询所有) 
+	 * @param size 获取数量 
+	 * @return sessionId集合 
+	 */
+	public static List<String> searchSessionId(String keyword, int start, int size) {
+		return stpLogic.searchSessionId(keyword, start, size);
+	}
+
+	/**
+	 * 根据条件查询Token专属Session的Id 
+	 * @param keyword 关键字 
+	 * @param start 开始处索引 (-1代表查询所有) 
+	 * @param size 获取数量 
+	 * @return sessionId集合 
+	 */
+	public static List<String> searchTokenSessionId(String keyword, int start, int size) {
+		return stpLogic.searchTokenSessionId(keyword, start, size);
+	}
+
+	
+	// ------------------- 账号封禁 -------------------  
+
+	/**
+	 * 封禁指定账号
+	 * <p> 此方法不会直接将此账号id踢下线,而是在对方再次登录时抛出`DisableLoginException`异常 
+	 * @param loginId 指定账号id 
+	 * @param disableTime 封禁时间, 单位: 秒 (-1=永久封禁)
+	 */
+	public static void disable(Object loginId, long disableTime) {
+		stpLogic.disable(loginId, disableTime);
+	}
+	
+	/**
+	 * 指定账号是否已被封禁 (true=已被封禁, false=未被封禁) 
+	 * @param loginId 账号id
+	 * @return see note
+	 */
+	public static boolean isDisable(Object loginId) {
+		return stpLogic.isDisable(loginId);
+	}
+	
+	/**
+	 * 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
+	 * @param loginId 账号id
+	 * @return see note 
+	 */
+	public static long getDisableTime(Object loginId) {
+		return stpLogic.getDisableTime(loginId);
+	}
+
+	/**
+	 * 解封指定账号
+	 * @param loginId 账号id 
+	 */
+	public static void untieDisable(Object loginId) {
+		stpLogic.untieDisable(loginId);
+	}
+	
+	
+	// =================== 身份切换 ===================  
+
+	/**
+	 * 临时切换身份为指定账号id 
+	 * @param loginId 指定loginId 
+	 */
+	public static void switchTo(Object loginId) {
+		stpLogic.switchTo(loginId);
+	}
+	
+	/**
+	 * 结束临时切换身份
+	 */
+	public static void endSwitch() {
+		stpLogic.endSwitch();
+	}
+
+	/**
+	 * 当前是否正处于[身份临时切换]中 
+	 * @return 是否正处于[身份临时切换]中 
+	 */
+	public static boolean isSwitch() {
+		return stpLogic.isSwitch();
+	}
+
+	/**
+	 * 在一个代码段里方法内,临时切换身份为指定账号id
+	 * @param loginId 指定账号id 
+	 * @param function 要执行的方法 
+	 */
+	public static void switchTo(Object loginId, SaFunction function) {
+		stpLogic.switchTo(loginId, function);
+	}
+	
+
+	// ------------------- 二级认证 -------------------  
+	
+	/**
+	 * 在当前会话 开启二级认证 
+	 * @param safeTime 维持时间 (单位: 秒) 
+	 */
+	public static void openSafe(long safeTime) {
+		stpLogic.openSafe(safeTime);
+	}
+
+	/**
+	 * 当前会话 是否处于二级认证时间内 
+	 * @return true=二级认证已通过, false=尚未进行二级认证或认证已超时 
+	 */
+	public static boolean isSafe() {
+		return stpLogic.isSafe();
+	}
+
+	/**
+	 * 检查当前会话是否已通过二级认证,如未通过则抛出异常 
+	 */
+	public static void checkSafe() {
+		stpLogic.checkSafe();
+	}
+	
+	/**
+	 * 获取当前会话的二级认证剩余有效时间 (单位: 秒, 返回-2代表尚未通过二级认证)
+	 * @return 剩余有效时间
+	 */
+	public static long getSafeTime() {
+		return stpLogic.getSafeTime();
+	}
+
+	/**
+	 * 在当前会话 结束二级认证 
+	 */
+	public static void closeSafe() {
+		stpLogic.closeSafe();
+	}
+
+
+	// =================== 历史API,兼容旧版本 ===================  
+
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.getLoginType() ,使用方式保持不变 </h1>
+	 * 
+	 * 获取当前StpLogin的loginKey 
+	 * @return 当前StpLogin的loginKey
+	 */
+	@Deprecated
+	public static String getLoginKey(){
+		return stpLogic.getLoginType();
+	}
+
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+	 * 
+	 * 在当前会话上登录id 
+	 * @param loginId 登录id,建议的类型:(long | int | String)
+	 */
+	@Deprecated
+	public static void setLoginId(Object loginId) {
+		stpLogic.login(loginId);
+	}
+
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+	 * 
+	 * 在当前会话上登录id, 并指定登录设备 
+	 * @param loginId 登录id,建议的类型:(long | int | String)
+	 * @param device 设备标识 
+	 */
+	@Deprecated
+	public static void setLoginId(Object loginId, String device) {
+		stpLogic.login(loginId, device);
+	}
+
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+	 * 
+	 * 在当前会话上登录id, 并指定登录设备 
+	 * @param loginId 登录id,建议的类型:(long | int | String)
+	 * @param isLastingCookie 是否为持久Cookie 
+	 */
+	@Deprecated
+	public static void setLoginId(Object loginId, boolean isLastingCookie) {
+		stpLogic.login(loginId, isLastingCookie);
+	}
+	
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.login() ,使用方式保持不变 </h1>
+	 * 
+	 * 在当前会话上登录id, 并指定所有登录参数Model 
+	 * @param loginId 登录id,建议的类型:(long | int | String)
+	 * @param loginModel 此次登录的参数Model 
+	 */
+	@Deprecated
+	public static void setLoginId(Object loginId, SaLoginModel loginModel) {
+		stpLogic.login(loginId, loginModel);
+	}
+	
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.kickout() ,使用方式保持不变 </h1>
+	 * 
+	 * 会话注销,根据账号id (踢人下线)
+	 * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2
+	 * @param loginId 账号id 
+	 */
+	@Deprecated
+	public static void logoutByLoginId(Object loginId) {
+		stpLogic.kickout(loginId);
+	}
+	
+	/**
+	 * <h1> 本函数设计已过时,未来版本可能移除此函数,请及时更换为 StpUtil.kickout() ,使用方式保持不变 </h1>
+	 * 
+	 * 会话注销,根据账号id and 设备标识 (踢人下线)
+	 * <p> 当对方再次访问系统时,会抛出NotLoginException异常,场景值=-2 </p>
+	 * @param loginId 账号id 
+	 * @param device 设备标识 (填null代表所有注销设备) 
+	 */
+	@Deprecated
+	public static void logoutByLoginId(Object loginId, String device) {
+		stpLogic.kickout(loginId, device);
+	}
+	
+}

+ 51 - 0
sp-core/sp-base/src/main/java/com/pj/current/sentinel/SentinelConfig.java

@@ -0,0 +1,51 @@
+package com.pj.current.sentinel;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
+
+/**
+ * Sentinel配置 
+ * @author kong
+ * 
+ */
+@Component
+public class SentinelConfig {
+
+	
+	/**
+	 * 注册Sentinel切面对象 
+	 * @return
+	 */
+	@Bean
+    public SentinelResourceAspect sentinelResourceAspect() {
+//		initFlowRules();
+        return new SentinelResourceAspect();
+    }
+	
+	
+	/**
+	 * 初始化降级规则 
+	 */
+//	private static void initFlowRules() {
+//		System.err.println("----------------------- 初始化限流规则 !!!");
+//		
+//        List<FlowRule> rules = new ArrayList<>();
+//
+//        // 规则  qps > 1 时,触发降级 
+//        FlowRule rule = new FlowRule();
+//        rule.setResource("testQPS");
+//        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
+//        rule.setCount(1);
+//        rules.add(rule);
+//
+//        // 可创建多个规则
+//        // ...
+//        
+//        FlowRuleManager.loadRules(rules);
+//    }
+	
+	
+	
+}

+ 26 - 0
sp-core/sp-base/src/main/java/com/pj/current/sentinel/SpBlockHandler.java

@@ -0,0 +1,26 @@
+package com.pj.current.sentinel;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.stereotype.Component;
+
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.pj.utils.sg.AjaxJson;
+
+/**
+ * 从sentinel-dashboard 控制台添加的限流规则,触发流控后,会在这里执行代码
+ */
+@Component
+public class SpBlockHandler implements BlockExceptionHandler {
+
+	@Override
+	public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
+		AjaxJson aj = AjaxJson.get(503, "系统繁忙,请稍后再试");
+		response.setContentType("application/json; charset=utf-8"); // http说明,我要返回JSON对象
+		response.getWriter().print(new ObjectMapper().writeValueAsString(aj));
+	}
+
+}

+ 6 - 0
sp-core/sp-base/src/main/java/com/pj/project/package-info.java

@@ -0,0 +1,6 @@
+
+
+/**
+ * 此包下放你的模块代码
+ */
+package com.pj.project;

+ 40 - 0
sp-core/sp-base/src/main/java/com/pj/project/test/TestController.java

@@ -0,0 +1,40 @@
+package com.pj.project.test;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.csp.sentinel.annotation.SentinelResource;
+import com.pj.utils.sg.AjaxJson;
+
+/**
+ * 测试controller 
+ * @author kong 
+ */
+@RestController
+public class TestController {
+
+	
+	/**
+	 * 测试请求,如果能正常访问此路由,则证明项目已经部署成功 
+	 * @return
+	 */
+	@RequestMapping("/test")
+	public AjaxJson test() {
+		System.out.println("------------------ 成功进入请求 ------------------");
+		return AjaxJson.getSuccess("请求成功");
+	}
+
+	/**
+	 * 测试sentinel,qps过多时触发服务器繁忙 
+	 * @return
+	 */
+	@RequestMapping("/testQPS")
+	@SentinelResource("testQPS")
+	public AjaxJson testQPS() {
+		System.out.println("------------------ 成功进入请求 ------------------");
+		return AjaxJson.getSuccess("请求成功, 正常返回");
+	}
+	
+	
+	
+}

+ 53 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/SP.java

@@ -0,0 +1,53 @@
+package com.pj.project4sp;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import com.pj.project4sp.public4mapper.PublicMapper;
+import com.pj.project4sp.public4mapper.PublicService;
+
+/**
+ * 公共Mapper 与 公共Service 
+ * @author kong
+ *
+ */
+@Component
+public class SP {
+
+	/**
+	 * 公共Mapper
+	 */
+	public static PublicMapper publicMapper;	
+	/**
+	 * 公共Service
+	 */
+	public static PublicService publicService;				
+	
+	// 注入 
+	@Autowired
+	public void setBean(
+			PublicMapper publicMapper,
+			PublicService publicService
+			) {
+		SP.publicMapper = publicMapper;
+		SP.publicService = publicService;
+	}
+	
+
+	// 返回RestTemplate实例 
+	@Bean
+	@LoadBalanced	// 使其可以解析自定义host并具有负载均衡的功能   (却使它丧失了解析正常 host 的能力 )
+	public RestTemplate getTestTemplate(){
+		return new RestTemplate();
+	}
+	// http操作类
+	public static RestTemplate restTemplate;
+	@Autowired
+	private void setRestTemplage(RestTemplate restTemplate) {
+		SP.restTemplate = restTemplate;
+	}
+	
+}

+ 99 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilog.java

@@ -0,0 +1,99 @@
+package com.pj.project4sp.apilog;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import lombok.Data;
+
+/**
+ * Model: api请求记录表
+ * @author kong 
+ */
+@Data
+public class SpApilog implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/** 记录id  */
+	private String id;	
+	
+	/** 客户端ip  */
+	private String reqIp;	
+	
+	/** 请求api  */
+	private String reqApi;		
+	
+	/** 请求参数  */
+	private String reqParame;	
+	
+	/** 请求方式 */
+	private String reqType;	
+	
+	/** 请求token */
+	private String reqToken;	
+	
+	/** 请求header */
+	private String reqHeader;	
+
+	
+	/** 返回-状态码  */
+	private int resCode;	
+	
+	/** 返回-信息描述  */
+	private String resMsg;		
+	
+	/** 返回-整个信息字符串形式  */
+	private String resString;		
+
+	
+	/**  user_id  */
+	private long userId;		
+	
+	/** admin_id  */
+	private long adminId;		
+
+	/** 请求开始时间   */
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone="GMT+8")
+	private Date startTime;	
+	/** 请求结束时间   */
+	@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone="GMT+8")
+	private Date endTime;	
+	/** 花费时间,单位ms   */
+	private int costTime;	
+	
+	
+	/**
+	 * 构造一个普通 实体类
+	 */
+	public SpApilog() {}
+	
+	// 构造一个 save 实体类 
+	public SpApilog(String id, String reqIp, String reqApi, String reqParame, String reqToken, long userId, long adminId) {
+		super();
+		this.id = id;
+		this.reqIp = reqIp;
+		this.reqApi = reqApi;
+		this.reqParame = reqParame;
+		this.reqToken = reqToken;
+		this.userId = userId;
+		this.adminId = adminId;
+	}
+
+	// 构造一个 update 实体类 
+	public SpApilog(String id, int resCode, String resMsg, String resString, int costTime) {
+		super();
+		this.id = id;
+		this.resCode = resCode;
+		this.resMsg = resMsg;
+		this.resString = resString;
+		this.costTime = costTime;
+	}
+
+	
+	
+	
+	
+
+}

+ 77 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogControlle.java

@@ -0,0 +1,77 @@
+package com.pj.project4sp.apilog;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.pj.current.satoken.AuthConst;
+import com.pj.project4sp.SP;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.so.SoMap;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Controller: api请求记录表
+ * @author kong 
+ */
+@RestController
+@RequestMapping("/SgApilog/")
+public class SpApilogControlle {
+
+	/** 底层 Mapper 对象 */
+	@Autowired
+	SpApilogMapper spApilogMapper;
+	
+
+	/** 删 */
+	@RequestMapping("delete")
+	AjaxJson delete(String id){
+		StpUtil.checkPermission(AuthConst.APILOG_LIST);
+		int line = spApilogMapper.delete(id);
+		return AjaxJson.getByLine(line);
+	}
+
+	/** 删 - 根据id列表 */
+	@RequestMapping("deleteByIds")
+	AjaxJson deleteByIds(){
+		// 鉴权
+		StpUtil.checkPermission(AuthConst.APILOG_LIST);	
+		// 开始删除 
+		List<Long> ids = SoMap.getRequestSoMap().getListByComma("ids", long.class); 
+		int line = SP.publicMapper.deleteByIds("sp_apilog", ids);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 删 - 根据日期范围 */
+	@RequestMapping("deleteByStartEnd")
+	AjaxJson deleteByStartEnd(String startTime, String endTime){
+		StpUtil.checkPermission(AuthConst.APILOG_LIST);
+		int line = spApilogMapper.deleteByStartEnd(startTime, endTime);
+		return AjaxJson.getSuccessData(line);
+	}
+	
+	/** 查 - 集合(参数为null或0时默认忽略此条件)   */
+	@RequestMapping("getList")
+	AjaxJson getList() { 
+		StpUtil.checkPermission(AuthConst.APILOG_LIST);	
+		SoMap so = SoMap.getRequestSoMap();
+		List<SpApilog> list = spApilogMapper.getList(so.startPage());
+		return AjaxJson.getPageData(so.getDataCount(), list);
+	}
+
+	/** 统计  */
+	@RequestMapping("staBy")
+	AjaxJson staBy() { 
+		StpUtil.checkPermission(AuthConst.APILOG_LIST);
+		SoMap so = SoMap.getRequestSoMap();
+		SoMap data = spApilogMapper.staBy(so);
+		return AjaxJson.getSuccessData(data);
+	}
+	
+
+	
+	
+}

+ 69 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogMapper.java

@@ -0,0 +1,69 @@
+package com.pj.project4sp.apilog;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.pj.utils.so.SoMap;
+
+import io.lettuce.core.dynamic.annotation.Param;
+
+/**
+ * Mapper: api请求记录表
+ * @author kong 
+ */
+@Mapper
+public interface SpApilogMapper {
+
+	/**
+	 * 保存入库 
+	 * @param apiLog
+	 * @return
+	 */
+	int saveObj(SpApilog apiLog);
+	
+	/**
+	 * 增 
+	 * @param apiLog
+	 * @return
+	 */
+	int add(SpApilog apiLog);
+
+	/**
+	 * 删 
+	 * @param id
+	 * @return
+	 */
+	int delete(String id);	 
+
+	/**
+	 * 删 - 根据日期范围 
+	 * @param startTime
+	 * @param endTime
+	 * @return
+	 */
+	int deleteByStartEnd(@Param("startTime")String startTime, @Param("endTime")String endTime);	 
+	
+	/**
+	 * 改 
+	 * @param apiLog
+	 * @return
+	 */
+	int update(SpApilog apiLog);
+	
+	/**
+	 * 查 - 集合 
+	 * @param so
+	 * @return
+	 */
+	List<SpApilog> getList(SoMap so);
+
+	/**
+	 * 查 - 集合 
+	 * @param so
+	 * @return
+	 */
+	SoMap staBy(SoMap so);
+
+
+}

+ 114 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogMapper.xml

@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pj.project4sp.apilog.SpApilogMapper">
+
+	
+	<!-- 保存入库 -->
+	<insert id="saveObj">
+		insert into 
+		sp_apilog (
+			id, req_ip, req_api, req_parame, req_type, req_token, req_header, user_id, admin_id, start_time,
+			res_code, res_msg, res_string, end_time, cost_time) 
+		values (
+			#{id}, #{reqIp}, #{reqApi}, #{reqParame}, #{reqType}, #{reqToken}, #{reqHeader}, #{userId}, #{adminId}, #{startTime},
+			#{resCode}, #{resMsg}, #{resString}, #{endTime}, #{costTime}) 
+	</insert>
+	
+	
+	<!-- 增 -->
+	<insert id="add">
+		insert into 
+		sp_apilog (id, req_ip, req_api, req_parame, req_token, user_id, admin_id, start_time) 
+		values (#{id}, #{reqIp}, #{reqApi}, #{reqParame}, #{reqToken}, #{userId}, #{adminId}, now(3)) 
+	</insert>
+
+	<!-- 删 -->
+	<delete id="delete">
+		delete from sp_apilog 
+		where id = #{id}
+	</delete>
+
+	<!-- 删 -->
+	<delete id="deleteByStartEnd">
+		delete from sp_apilog 
+		where start_time BETWEEN #{startTime} AND #{endTime} 
+	</delete>
+	
+	<!-- 改 -->
+	<update id="update">
+		update sp_apilog set
+		res_code = #{resCode}, 
+		res_msg = #{resMsg}, 
+		res_string = #{resString}, 
+		end_time = now(3), 
+		cost_time = #{costTime} 
+		where id = #{id}
+	</update>
+	
+	<!-- ================================== 查询相关 ================================== -->
+	
+	<!-- 通用映射 -->
+	<resultMap id="model" type="com.pj.project4sp.apilog.SpApilog">
+		<result property="id" column="id" />
+		<result property="reqIp" column="req_ip" />
+		<result property="reqApi" column="req_api" />
+		<result property="reqParame" column="req_parame" />
+		<result property="reqType" column="req_type" />
+		<result property="reqToken" column="req_token" />
+		<result property="reqHeader" column="req_header" />
+		<result property="resCode" column="res_code" />
+		<result property="resMsg" column="res_msg" />
+		<result property="resString" column="res_string" />
+		<result property="userId" column="user_id" />
+		<result property="adminId" column="admin_id" />
+		<result property="startTime" column="start_time" />
+		<result property="endTime" column="end_time" />
+		<result property="costTime" column="cost_time" />
+	</resultMap>
+	
+	<!-- 公共查询sql片段 -->
+	<sql id="select_sql">
+		select * from sp_apilog 
+	</sql>
+	
+	<!-- 查询,根据条件(参数为null或0时默认忽略此条件) -->
+	<select id="getList" resultMap="model" >
+		<include refid="select_sql"></include>
+		where 1 = 1 
+		<if test=' this.has("id")  '>and id = #{id} </if>
+		<if test=' this.has("reqToken") '>and req_token = #{reqToken} </if>
+		<if test=' this.has("reqIp") '> and req_ip = #{reqIp} </if>
+		<if test=' this.has("reqApi") '>and req_api = #{reqApi} </if>
+		<if test=' this.has("resCode") '>and res_code = #{resCode} </if>
+		<if test=' this.has("userId") '>and user_id = #{userId} </if>
+		<if test=' this.has("adminId") '>and admin_id = #{adminId} </if>
+		<if test=' this.has("sTime") '>and start_time &gt;= #{sTime} </if>
+		<if test=' this.has("eTime") '>and start_time &lt;= #{eTime} </if>
+		order by 
+		<choose>
+			<when test='sortType == 0'>id desc</when> 
+			<when test='sortType == 1'>start_time desc, id desc</when> 
+			<when test='sortType == 2'>cost_time desc, id desc</when> 
+		 	<otherwise>id desc</otherwise>
+		 </choose>
+	</select>
+	
+	
+	
+	<!-- 统计 -->
+	<select id="staBy" resultType="somap">
+		select sum(cost_time) as cost_time_count from sp_apilog 
+		where 1 = 1 
+		<if test=' this.has("id")  '>and id = #{id} </if>
+		<if test=' this.has("reqToken") '>and req_token = #{reqToken} </if>
+		<if test=' this.has("reqIp") '> and req_ip = #{reqIp} </if>
+		<if test=' this.has("reqApi") '>and req_api = #{reqApi} </if>
+		<if test=' this.has("resCode") '>and res_code = #{resCode} </if>
+		<if test=' this.has("userId") '>and user_id = #{userId} </if>
+		<if test=' this.has("adminId") '>and admin_id = #{adminId} </if>
+		<if test=' this.has("sTime") '>and start_time &gt;= #{sTime} </if>
+		<if test=' this.has("eTime") '>and start_time &lt;= #{eTime} </if>
+	</select>
+
+
+</mapper>

+ 147 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/apilog/SpApilogUtil.java

@@ -0,0 +1,147 @@
+package com.pj.project4sp.apilog;
+
+import java.util.Date;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.pj.current.satoken.StpUserUtil;
+import com.pj.utils.LogUtil;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.sg.WebNbUtil;
+
+import cn.dev33.satoken.spring.SpringMVCUtil;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.IdUtil;
+
+/**
+ * 工具类:api请求记录表
+ * @author kong 
+ *
+ */
+@Component
+public class SpApilogUtil {
+
+	/** 底层 Mapper 对象 */
+	static SpApilogMapper spApilogMapper;
+	@Autowired
+	public void setSpApilogMapper(SpApilogMapper spApilogMapper) {
+		SpApilogUtil.spApilogMapper = spApilogMapper;
+	}
+	
+	static final String APILOG_OBJ_SAVE_KEY = "APILOG_OBJ_SAVE_KEY";
+	static final String APILOG_OBJ_SAVE_ID_KEY = "APILOG_OBJ_SAVE_ID_KEY";
+	
+	/**
+	 * 请求开始时调用,开始计时 
+	 */
+	public static void startRequest() {
+		if(isWeb() == false)  {
+			return;
+		}
+		
+		// 1、开始时 
+    	HttpServletRequest request = SpringMVCUtil.getRequest();
+    	SpApilog a = new SpApilog();
+    	a.setId(getSnowflakeId());		
+    	a.setReqIp(WebNbUtil.getIP(request));	
+    	a.setReqApi(request.getRequestURI());;		
+    	a.setReqParame(JSON.toJSONString(WebNbUtil.getParamsMap2(request)));	
+    	a.setReqToken(StpUtil.getTokenValue());			
+    	a.setReqHeader(JSON.toJSONString(WebNbUtil.getHeaderMap(request)));		
+    	a.setReqType(request.getMethod());		
+    	a.setAdminId(StpUtil.getLoginId(0L));	
+    	a.setUserId(StpUserUtil.getLoginId(0L));		
+    	a.setStartTime(new Date());			
+    	request.setAttribute(APILOG_OBJ_SAVE_KEY, a);
+    	
+    	// 控制台日志 
+    	LogUtil.info("----------------------------------------------------------------");
+		LogUtil.info("IP: " + a.getReqIp() + "\tr-> " + a.getReqApi()+ "\tp-> " + a.getReqParame());
+	}
+	
+
+	/**
+	 * 请求结束时调用,结束计时 
+	 * @param aj
+	 */
+	public static void endRequest(AjaxJson aj) {
+		if(isWeb() == false)  {
+			return;
+		}
+		
+		// 读取本次请求的 ApiLog 对象 
+		HttpServletRequest request = SpringMVCUtil.getRequest();
+		SpApilog a = (SpApilog)request.getAttribute(APILOG_OBJ_SAVE_KEY);
+		if(a == null) {
+//	    	LogUtil.info("未找到相应ApiLog对象(可能原因:全局异常),aj=" + aj);
+	    	SpApilogUtil.startRequest();	
+	    	a = (SpApilog)request.getAttribute(APILOG_OBJ_SAVE_KEY);
+		}
+
+		// 保存数据库
+		try {
+			// 开始结束计时 
+			a.setResCode(aj.getCode()); 	
+			a.setResMsg(aj.getMsg());	
+			a.setResString(new ObjectMapper().writeValueAsString(aj));		
+			a.setEndTime(new Date());		
+			a.setCostTime((int)(a.getEndTime().getTime() - a.getStartTime().getTime()));
+			
+			// res 字符串过长时禁止写入  
+			if(a.getResString().length() > 50000) {
+				a.setResString("{\"msg\": \"数据过长,无法写入 (length=" + a.getResString().length() + ")\"}");		
+			}
+		
+        	LogUtil.info("本次请求耗时:" + ((a.getCostTime() + 0.0) / 1000) + "s, 返回:" + a.getResString());
+        	spApilogMapper.saveObj(a);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+	
+	
+	
+
+	/**
+	 * 当前是否为web环境 
+	 */
+	public static boolean isWeb() {
+		// 大善人SpringMVC提供的封装 
+		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+		if(servletRequestAttributes != null) {
+			return true;
+		}
+		return false;
+	}
+
+
+	/** 获取当前请求的id */
+	public static String getCurrReqId() {
+		HttpServletRequest request = SpringMVCUtil.getRequest();
+		String id = (String)request.getAttribute(APILOG_OBJ_SAVE_ID_KEY);
+		if(id == null) {
+			id = IdUtil.simpleUUID();
+			request.setAttribute(APILOG_OBJ_SAVE_ID_KEY, id);
+		}
+		return id;
+	}
+
+
+	/**
+	 * 根据雪花算法,返回唯一id 
+	 * (此地方将workerId写死为1,如果你在分布式场景中应用此方法,你需要对workerId生成策略进行改造)
+	 * @return
+	 */
+	public static String getSnowflakeId() {
+		return IdUtil.getSnowflake(1, 1).nextIdStr();
+	}
+	
+}

+ 16 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaBegin.java

@@ -0,0 +1,16 @@
+package com.pj.project4sp.public4mapper;
+
+/**
+ * 以lambda表达式开启事务的辅助类
+ * @author kong
+ *
+ */
+public interface JdbcLambdaBegin {
+
+	/**
+	 * 执行事务的方法 
+	 */
+	public void run();
+	
+	
+}

+ 18 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaBeginRet.java

@@ -0,0 +1,18 @@
+package com.pj.project4sp.public4mapper;
+
+/**
+ * 以lambda表达式开启事务的辅助类
+ * @author kong
+ *
+ */
+public interface JdbcLambdaBeginRet {
+	
+
+	/**
+	 * 执行事务的方法 
+	 * @return
+	 */
+	public Object run();
+	
+	
+}

+ 16 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaRollback.java

@@ -0,0 +1,16 @@
+package com.pj.project4sp.public4mapper;
+
+/**
+ * 以lambda表达式回滚事务的辅助类
+ * @author kong
+ *
+ */
+public interface JdbcLambdaRollback {
+	
+	/**
+	 * 事务发生异常的方法 
+	 * @param e
+	 */
+	public void run(Exception e);
+	
+}

+ 17 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/JdbcLambdaRollbackRet.java

@@ -0,0 +1,17 @@
+package com.pj.project4sp.public4mapper;
+
+/**
+ * 以lambda表达式回滚事务的辅助类
+ * @author kong
+ *
+ */
+public interface JdbcLambdaRollbackRet {
+	
+	/**
+	 * 事务发生异常的方法 
+	 * @param e
+	 * @return
+	 */
+	public Object run(Exception e);
+	
+}

+ 296 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/PublicMapper.java

@@ -0,0 +1,296 @@
+package com.pj.project4sp.public4mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import com.pj.utils.so.SoMap;
+
+/**
+ * 公用Mapper,封装一些常见的Mapper操作,避免某些及其简单的逻辑也要写一堆xml方法
+ * @author kong
+ * 更新于2020-12-1 新增部分方法 
+ *
+ */
+@Mapper
+public interface PublicMapper {
+
+	
+	// ------------------------ 一些工具方法 ------------------------
+
+	/**
+	 * 返回上一句SQL插入的自增主键值 
+	 * @return
+	 */
+	public long getPrimarykey();
+
+	
+	// ------------------------ 新增SQL相关 ------------------------
+
+	
+	// ------------------------ 删除SQL相关 ------------------------
+
+	/**
+	 * 根据id删除一条记录 
+	 * @param tableName 表名字 
+	 * @param id id值
+	 * @return
+	 */
+	public int deleteById(
+			@Param("tableName")String tableName, 
+			@Param("id")Object id
+			); 
+
+	/**
+	 * 根据指定列指定值删除一条记录 
+	 * @param tableName 表名
+	 * @param whereName 条件列
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public int deleteBy(
+			@Param("tableName")String tableName, 
+			@Param("whereName") String whereName, 
+			@Param("whereValue") Object whereValue
+			);
+
+	/**
+	 * 根据id列表批量删除
+	 * @param tableName 表名字
+	 * @param ids id列表
+	 * @return
+	 */
+	public int deleteByIds(
+			@Param("tableName")String tableName, 
+			@Param("ids")List<?> ids
+			); 
+
+	/**
+	 * 根据指定列指定值删除多条记录 
+	 * @param tableName 表名
+	 * @param whereName 条件列名
+	 * @param whereList 条件列值 
+	 * @return
+	 */
+	public int deleteByWhereList(
+			@Param("tableName")String tableName, 
+			@Param("whereName") String whereName, 
+			@Param("whereList") List<?> whereList
+			);
+	
+	
+	// ------------------------ 修改SQL相关 ------------------------
+
+	/**
+	 * 指定表的指定字段增加指定值,可以为负值 
+	 * @param tableName 表名字
+	 * @param columnName 列值 
+	 * @param num 增加的值
+	 * @param id id值 
+	 * @return
+	 */
+	public int columnAdd(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("num") long num,  
+			@Param("id") Object id 
+			);
+
+	/**
+	 * 指定表的指定字段增加指定值,可以为负值 
+	 * @param tableName 表名字
+	 * @param columnName 列名字 
+	 * @param num 增加的值
+	 * @param ids id列表  
+	 * @return
+	 */
+	public int columnAddByIds(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("num") long num,  
+			@Param("ids") List<?> ids
+			);
+
+	/**
+	 * 指定表的指定字段更新为指定值,根据指定id  
+	 * @param tableName 表名子
+	 * @param columnName 列名
+	 * @param value 值
+	 * @param id id值 
+	 * @return
+	 */
+	public int updateColumnById(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("value") Object value, 
+			@Param("id") Object id
+			);
+
+	/**
+	 * 指定表的指定字段更新为指定值,根据指定id列表 
+	 * @param tableName 表名子
+	 * @param columnName 列名
+	 * @param value 值
+	 * @param ids id值 
+	 * @return
+	 */
+	public int updateColumnByIds(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("value") Object value, 
+			@Param("ids") List<?> ids
+			);
+
+	/**
+	 * 指定表的指定字段更新为指定值, 根据指定列的指定值 
+	 * @param tableName 表名 
+	 * @param columnName 列名 
+	 * @param columnValue 列值 
+	 * @param whereName 条件列名 
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public int updateColumnBy(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("columnValue") Object columnValue, 
+			@Param("whereName") String whereName, 
+			@Param("whereValue") Object whereValue
+			);
+
+	/**
+	 * 指定表的指定字段SoMap集合更新为指定值,根据指定id 
+	 * @param tableName 表名
+	 * @param soMap 要修改的列
+	 * @param id id值
+	 * @return
+	 */
+	public int updateBySoMapById(
+			@Param("tableName") String tableName, 
+			@Param("soMap") SoMap soMap,
+			@Param("id") Object id
+			);
+
+	/**
+	 * 指定表的指定字段SoMap集合更新为指定值,指定列的指定值
+	 * @param tableName 表名子
+	 * @param soMap 要修改的列
+	 * @param whereName 条件列值
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public int updateBySoMapBy(
+			@Param("tableName") String tableName, 
+			@Param("soMap") SoMap soMap,
+			@Param("whereName") String whereName, 
+			@Param("whereValue") Object whereValue
+			);
+	
+	
+	// ------------------------ 查询SQL相关 ------------------------
+	
+	/**
+	 * 获取指定表的指定字段值,根据id值 
+	 * @param tableName 表名
+	 * @param columnName 列名
+	 * @param id id值 
+	 * @return
+	 */
+	public String getColumnById(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("id") Object id
+			);
+
+	/**
+	 * 获取指定表的指定字段值,并转化为long,根据id值 
+	 * @param tableName 表名
+	 * @param columnName 列名
+	 * @param id id值 
+	 * @return
+	 */
+	public long getColumnByIdToLong(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("id") Object id
+			);
+
+	/**
+	 * 获取指定表的指定字段值,根据指定条件(whereName=whereValue) 
+	 * @param tableName 表名
+	 * @param columnName 列名 
+	 * @param whereName 条件列名
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public String getColumnByWhere(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("whereName") String whereName, 
+			@Param("whereValue") Object whereValue
+			);
+	
+	/**
+	 * 获取指定表的指定字段值列表,并转化为long, 根据指定条件(whereName=whereValue) 
+	 * @param tableName 表名
+	 * @param columnName 列名
+	 * @param whereName 条件列名 
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public List<Long> getColumnListToLongByWhere(
+			@Param("tableName") String tableName, 
+			@Param("columnName") String columnName, 
+			@Param("whereName") String whereName, 
+			@Param("whereValue") Object whereValue
+			);
+
+	/**
+	 * 获取指定表的count数据,根据指定条件(whereName=whereValue)
+	 * @param tableName 表名
+	 * @param whereName 条件列名 
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public long getCountBy(
+			@Param("tableName") String tableName,
+			@Param("whereName") String whereName,
+			@Param("whereValue") Object whereValue
+	);
+
+	// ------------------------ 查询集合SQL相关 ------------------------
+	
+	/**
+	 * 获取指定表的全部字段全部数据转化为Map
+	 * @param tableName 表名子 
+	 * @return
+	 */
+	public List<SoMap> getListMap(@Param("tableName") String tableName);
+	
+	/**
+	 * 获取指定表的全部字段全部数据转化为Map, 根据指定条件(whereName=whereValue)
+	 * @param tableName 表名字 
+	 * @param whereName 条件列名 
+	 * @param whereValue 条件列值 
+	 * @return
+	 */
+	public List<SoMap> getListMapByWhere(
+			@Param("tableName") String tableName, 
+			@Param("whereName") String whereName, 
+			@Param("whereValue") Object whereValue
+			);
+
+	/**
+	 * 获取指定表的全部字段全部数据转化为Map, 根据指定条件(id=id) 
+	 * @param tableName 表名子
+	 * @param id id值 
+	 * @return
+	 */
+	public List<SoMap> getListMapById(
+			@Param("tableName") String tableName, 
+			@Param("id") Object id
+			);
+
+	
+}

+ 164 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/PublicMapper.xml

@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pj.project4sp.public4mapper.PublicMapper">
+
+	<!-- ======================== 一些工具方法 ======================== -->
+	
+	<!-- 返回上一句SQL插入的自增主键值 -->
+	<select id="getPrimarykey" resultType="long">
+		SELECT @@identity 
+	</select>
+	
+	
+	<!-- ======================== 新增SQL相关 ======================== -->
+	
+	
+	
+	<!-- ======================== 删除SQL相关 ======================== -->
+	
+	<!-- 删除一条记录,指定表名,id -->
+	<delete id="deleteById">
+		delete from ${tableName} where id = #{id}
+	</delete>
+	
+	<!-- 根据指定列指定值删除一条记录,// 参数: 表名、条件列表、条件列值  -->
+	<delete id="deleteBy">
+		delete from ${tableName} where ${whereName} = #{whereValue} 
+	</delete>
+	
+	<!-- 删除一条记录,指定表名,id列表 -->
+	<delete id="deleteByIds">
+		delete from ${tableName} 
+		where id in 
+		<foreach collection="ids" item="id" open="(" separator="," close=")">
+			#{id}
+		</foreach>
+	</delete>
+	
+	<!-- 根据指定列指定值删除多条记录  -->
+	<delete id="deleteByWhereList">
+		delete from ${tableName} 
+		where ${whereName} in 
+		<foreach collection="whereList" item="item" open="(" separator="," close=")">
+			#{item}
+		</foreach>
+	</delete>
+	
+	
+	<!-- ======================== 修改SQL相关 ======================== -->
+	
+	<!-- 指定表的指定字段加num(可以小于0 ),根据指定id -->
+	<update id="columnAdd">
+		update ${tableName} set 
+		${columnName} = IFNULL(${columnName}, 0) + #{num} 
+		where id = #{id};
+	</update>
+	
+	<!-- 指定表的指定字段增加指定值,可以为负值  -->
+	<update id="columnAddByIds">
+		update ${tableName} set 
+		${columnName} = ${columnName} + #{num} 
+		where id in
+		<foreach collection="ids" item="id" open="(" separator="," close=")">
+			#{id}
+		</foreach>
+	</update>
+
+	<!-- 指定表的指定字段更新为指定值,根据指定id -->
+	<update id="updateColumnById">
+		update ${tableName} set 
+		${columnName} = #{value} 
+		where id = #{id} 
+	</update>
+
+	<!-- 指定表的指定字段更新为指定值,根据指定id列表 -->
+	<update id="updateColumnByIds">
+		update ${tableName} set 
+		${columnName} = #{value} 
+		where id in 
+		<foreach collection="ids" item="id" open="(" separator="," close=")">
+			#{id}
+		</foreach>
+	</update>
+
+	<!-- 指定表的指定字段更新为指定值, 根据指定列的指定值 -->
+	<update id="updateColumnBy">
+		update ${tableName} set 
+		${columnName} = #{columnValue} 
+		where ${whereName} = #{whereValue} 
+	</update>
+	
+	<!-- 指定表的指定字段SoMap集合更新为指定值,根据指定id   -->
+	<update id="updateBySoMapById">
+		update ${tableName} set 
+		<foreach collection="soMap.entrySet()" item="value"  index="key" separator=",">
+			${key} = #{value} 
+		</foreach>
+		where id = #{id} 
+	</update>
+	
+	<!-- 指定表的指定字段SoMap集合更新为指定值,根据指定id   -->
+	<update id="updateBySoMapBy">
+		update ${tableName} set 
+		<foreach collection="soMap.entrySet()" item="value"  index="key" separator=",">
+			${key} = #{value}
+		</foreach>
+		where ${whereName} = #{whereValue} 
+	</update>
+	
+	
+	<!-- ======================== 查询SQL相关 ======================== -->
+
+	<!-- 获取指定表的指定字段值,根据id值 -->
+	<select id="getColumnById" resultType="String">
+		select ${columnName} from ${tableName} 
+		where id = #{id}
+	</select>
+
+	<!-- 获取指定表的指定字段值,并转化为long,根据id值  -->
+	<select id="getColumnByIdToLong" resultType="long">
+		select ${columnName} from ${tableName} 
+		where id = #{id}
+	</select>
+
+	<!-- 获取指定表的指定字段值,根据指定条件(whereName=whereValue) -->
+	<select id="getColumnByWhere" resultType="String">
+		select ${columnName} from ${tableName} 
+		where ${whereName} = #{whereValue} 
+	</select>
+
+	<!-- 获取指定表的指定字段值列表,并转化为long, 根据指定条件(whereName=whereValue) -->
+	<select id="getColumnListToLongByWhere" resultType="long">
+		select ${columnName} from ${tableName} 
+		where ${whereName} = #{whereValue} 
+	</select>
+
+	<!-- 获取指定表的count数据,根据指定条件(whereName=whereValue) -->
+	<select id="getCountBy" resultType="long">
+		select count(*) from ${tableName}
+		where ${whereName} = #{whereValue}
+	</select>
+
+
+	<!-- ======================== 查询集合SQL相关 ======================== -->
+
+	<!-- 获取指定表的全部字段全部数据 -->
+	<select id="getListMap" resultType="somap">
+		select * from ${tableName} 
+	</select>
+
+	<!-- 获取指定表的全部字段全部数据转化为Map, 根据指定条件(whereName=whereValue) -->
+	<select id="getListMapByWhere" resultType="somap">
+		select * from ${tableName} 
+		where ${whereName} = #{whereValue} 
+	</select>
+
+	<!-- 获取指定表的全部字段全部数据转化为Map, 根据指定条件(id=id) -->
+	<select id="getListMapById" resultType="somap">
+		select * from ${tableName} 
+		where id = #{id} 
+	</select>
+
+	
+
+</mapper>

+ 83 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/public4mapper/PublicService.java

@@ -0,0 +1,83 @@
+package com.pj.project4sp.public4mapper;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+
+/**
+ * 公共service,一大堆常见方法 
+ * @author kong
+ *
+ */
+@Service
+public class PublicService {
+
+	
+	
+	/**
+	 * 以lambda方式开始事务
+	 * @param code args
+	 */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)
+	public void begin(JdbcLambdaBegin code) {
+		code.run();
+	}
+	
+	/**
+	 * 以lambda方式开始事务
+	 * @param begin begin
+	 * @param rollback rollback
+	 */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)
+	public void begin(JdbcLambdaBegin begin, JdbcLambdaRollback rollback) {
+		try {
+			begin.run();
+		} catch (Exception e) {
+			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+			if(rollback == null) {
+				throw e;
+			}
+			rollback.run(e);
+		}
+	}
+	
+	
+	/**
+	 * 已lambda方式开启事务,并返回一个值 
+	 * @param begin begin
+	 * @return v
+	 */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)
+	@SuppressWarnings("unchecked")
+	public <T> T beginRet(JdbcLambdaBeginRet begin) {
+		Object returnObj =  begin.run();
+		return (T)returnObj;
+	}
+
+	/**
+	 *  已lambda方式开启事务,并返回一个值 
+	 * @param begin begin
+	 * @param rollback rollback
+	 * @return v
+	 */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)
+	@SuppressWarnings("unchecked")
+	public <T> T beginRet(JdbcLambdaBeginRet begin, JdbcLambdaRollbackRet rollback) {
+		Object returnObj = null;
+		try {
+			returnObj = begin.run();
+		} catch (Exception e) {
+			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+			if(rollback == null) {
+				throw e;
+			}
+			returnObj = rollback.run(e);
+		}
+		return (T)returnObj;
+	}
+	
+	
+	
+	
+}

+ 38 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/spcfg/SpCfgService.java

@@ -0,0 +1,38 @@
+package com.pj.project4sp.spcfg;
+
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import com.pj.project4sp.SP;
+
+/**
+ * 配置类:sp_cfg
+ * @author kong
+ *
+ */
+@Service
+public class SpCfgService {
+
+	
+	/** 获得cfg_value 根据cfgName */
+	@Cacheable(value="sp_cfg_", key="#cfgName")	
+	public String getCfgValue(String cfgName){
+		return SP.publicMapper.getColumnByWhere("sp_cfg", "cfg_value", "cfg_name", cfgName);
+	}
+	
+	
+	/** 修改cfg_value 根据cfgName */
+	@CacheEvict(value="sp_cfg_", key="#cfgName")
+	public int updateCfgValue(String cfgName, String cfgValue){
+		return SP.publicMapper.updateColumnBy("sp_cfg", "cfg_value", cfgValue, "cfg_name", cfgName);
+	}
+	
+	
+	
+		
+	
+	
+	
+	
+}

+ 101 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/spcfg/SpCfgUtil.java

@@ -0,0 +1,101 @@
+package com.pj.project4sp.spcfg;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson.JSON;
+
+/**
+ * DB活动配置操作工具类
+ * 
+ * @author kong
+ *
+ */
+@Component
+public class SpCfgUtil {
+
+	private static SpCfgService sysCfgService;
+	@Autowired
+	public void setSysCfgService(SpCfgService sysCfgService) {
+		SpCfgUtil.sysCfgService = sysCfgService;
+	}
+
+	
+	// ====================== 快捷读取 DB 配置信息 ========================== 
+
+	/**
+	 * 获取指定【cfgName】的配置,指定key项,并转化为String值 , 取不到值时,给默认值【defaultValue】
+	 * @param cfgName
+	 * @param key
+	 * @param defaultValue
+	 * @return
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	private static String getCfgBy(String cfgName, String key, String defaultValue) {
+		// 1、获取配置字符串 
+		String cfgJson = sysCfgService.getCfgValue(cfgName);
+		// 2、转换成Map
+		Map<String, Object> maps = (Map)JSON.parse(cfgJson);
+		// 3、取值
+		Object value = maps.get(key);
+		if (value == null) {
+			return defaultValue;
+		}
+		return value.toString();
+	}
+	
+	/**
+	 * 获取server端指定配置信息 
+	 * @param key
+	 * @param defaultValue
+	 * @return
+	 */
+	public static String getServerCfg(String key, String defaultValue) {
+		return SpCfgUtil.getCfgBy("server_cfg", key, defaultValue);
+	}
+	
+	/**
+	 * 获取App端指定配置信息 
+	 * @param key
+	 * @param defaultValue
+	 * @return
+	 */
+	public static String getAppCfg(String key, String defaultValue) {
+		return SpCfgUtil.getCfgBy("app_cfg", key, defaultValue);
+	}
+	
+	
+	// ====================== 获取指定配置 ========================== 
+
+	/** 获取app端全部配置信息 */
+	public static String getAppCfg() {
+		return sysCfgService.getCfgValue("AppCfg");
+	}
+
+	// --- app  
+	/** 获取配置信息:系统名称  */
+	public static String appName() {
+		return SpCfgUtil.getAppCfg("appName", "");
+	}
+	/** 获取配置信息:版本号  */
+	public static String appVersionNo() {
+		return SpCfgUtil.getAppCfg("appVersionNo", "");
+	}
+
+	// --- server  
+	/** 预留信息  */
+	public static String reserveInfo() {
+		return SpCfgUtil.getServerCfg("reserveInfo", "");
+	}
+	/** 是否在发生sql异常时,抛出sql,方便调试   */
+	public static boolean throwOutSql() {
+		return SpCfgUtil.getServerCfg("throwOutSql", "2").equals("1");
+	}
+
+	
+	
+	
+	
+}

+ 35 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/uploadfile/UploadConfig.java

@@ -0,0 +1,35 @@
+package com.pj.project4sp.uploadfile;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import lombok.Data;
+
+/**
+ * 文件上传配置类  (基于应用服务器的文件上传)
+ * @author kong
+ *
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "spring.upload-config")
+public class UploadConfig {
+
+	public String rootFolder = "/upload-file";			// 文件保存的根目录,所有文件都保存在这个目录下  
+	public String httpPrefix = "/upload";						// http路由前缀,用于向前台暴露文件url  
+	
+	public String imageFolder = "/image";						// 图片保存文件夹 
+	public String videoFolder = "/video";						// 视频保存文件夹 
+	public String audioFolder = "/audio";						// 音频保存地址 
+	public String apkFolder = "/apk";							// apk保存地址 
+	public String fileFolder = "/file";							// file保存地址 (任意类型文件)
+	
+	public String imageSuffix = "jpg,jpeg,png,gif,ico,bmp,tiff,raw";			// 图片允许的后缀 
+	public String videoSuffix = "mp4,avi,rmvb,mov,flv";						// 视频允许的后缀 
+	public String audioSuffix = "mp3,aac,wav,wma,cda,flac,m4a,mid,mka,mp2,mpa,mpc,ape,ofr,ogg,ra,wv,tta,ac3,dts";			// 音频允许的后缀 
+	public String apkSuffix = "apk";						// apk允许的后缀  
+	public String fileSuffix = "jpg";						// file允许的后缀 (为防止上传恶意文件,这里必须手动指定可上传的类型) 
+	
+	public long maxSize = 1024 * 1024 * 1024 ;	// 文件最大大小,单位/B , 此为1G 
+	
+}

+ 106 - 0
sp-core/sp-base/src/main/java/com/pj/project4sp/uploadfile/UploadUtil.java

@@ -0,0 +1,106 @@
+package com.pj.project4sp.uploadfile;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Random;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.pj.current.config.SystemObject;
+
+/**
+ * 文件上传工具类(基于应用服务器的文件上传)
+ * @author kong
+ *
+ */
+@Component
+public class UploadUtil {
+
+	/** 注入配置  */
+	public static UploadConfig uploadConfig;
+	@Autowired
+	public void setUploadConfig(UploadConfig uploadConfig) {
+		UploadUtil.uploadConfig = uploadConfig;
+	}
+	
+	/** 将文件名保存在服务器硬盘上,并把文件对应的http地址返回给前台  */
+	public static String saveFile(MultipartFile file, String flieTypeFolder) {
+		
+		// 1、计算路径  
+		// 根据日期计算需要保存的文件夹 
+		String currDateFolder = getCurrDateFolder();		
+		// 文件名 
+		String fileName = getMarking28() + '.' + getSuffixName(file.getOriginalFilename());				
+		// 需要保存到的文件夹地址 
+		String fileFolder = new File(uploadConfig.rootFolder).getAbsolutePath() + "/" +
+				uploadConfig.httpPrefix + flieTypeFolder + currDateFolder + "/";	
+		// 对外暴露的http路径
+		String httpUrl = getDoMain() + uploadConfig.httpPrefix + flieTypeFolder + currDateFolder + "/" + fileName;	
+		
+		// 2、如果文件夹不存在,则先创建 
+		File dirFile = new File(fileFolder);
+		if(dirFile.exists() == false) {
+			dirFile.mkdirs();
+		}
+
+		// 3、开始转存文件 
+		try {
+			File outFile = new File(fileFolder + fileName);
+	        file.transferTo(outFile);		
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+		
+		// 4、将文件外网地址返回给前台
+		return httpUrl;
+	}
+	
+	/** 验证文件大小  */
+	static void checkFileSize(MultipartFile file) {
+		// 文件大小(B)
+		long size = file.getSize();
+        if (size > uploadConfig.maxSize) {
+        	throw new RuntimeException("文件大小超出限制");
+        }
+	}
+	
+	/** 
+	 * 验证指定文件名是否存在于指定后缀列表中 
+	 * 参数:文件名、后缀列表	
+	 * case:checkSubffix("123.jpg", "jpg,png,gif")	验证通过  
+	 */
+	static void checkSubffix(String fileName, String suffixList) {
+		// 获取后缀,并转为小写 
+		String ext = getSuffixName(fileName).toLowerCase();	
+		// 去空格,加逗号   
+		String yxSuffix = suffixList.replace(" ", "") + ",";		
+		if(yxSuffix.indexOf(ext + ",") == -1) {
+			throw new RuntimeException("文件后缀验证未通过:" + ext);
+		}
+	}
+	
+	/** 返回随机生成的唯一标示28位唯一标示符 */
+	static String getMarking28() {
+		return System.currentTimeMillis() + "" + new Random().nextInt(Integer.MAX_VALUE);
+	}
+
+	/** 取文件后缀 */
+	static String getSuffixName(String fileName) {
+		return fileName.substring(fileName.lastIndexOf(".") + 1);
+	}
+	
+	/** 返回今天的日期文件夹  */
+	static String getCurrDateFolder() {
+		String currDateFolder = new SimpleDateFormat("/yyyy/MM-dd").format(new Date()); 
+		return currDateFolder;
+	}
+	
+	/** 返回本服务器域名信息  */
+	static String getDoMain() {
+		return SystemObject.config.getDomain();
+	}
+	
+}

+ 31 - 0
sp-core/sp-base/src/main/java/com/pj/utils/LogUtil.java

@@ -0,0 +1,31 @@
+package com.pj.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 日志输出工具类
+ */
+@Slf4j
+public class LogUtil {
+
+	
+	/**
+	 * 输出
+	 */
+	public static void info(String str){
+		//System.err.println(str);
+		//System.out.println(str);
+		log.info(str);
+	}
+	
+	
+	// 输出日志并且抛出异常
+    public static void throwRuntimeException( String str, String logStr) throws RuntimeException{
+        if(logStr != null){
+            log.info(logStr);
+        }
+        throw new RuntimeException(str);
+    }
+    
+	
+}

+ 63 - 0
sp-core/sp-base/src/main/java/com/pj/utils/Ttime.java

@@ -0,0 +1,63 @@
+package com.pj.utils;
+
+
+/**
+ * 用于测试用时
+ * @author kong
+ *
+ */
+public class Ttime {
+
+	private long start=0;	//开始时间
+	private long end=0;		//结束时间
+	
+	public static Ttime t = new Ttime();	//static快捷使用
+	
+	/**
+	 * 开始计时
+	 * @return
+	 */
+	public Ttime start() {
+		start=System.currentTimeMillis();
+		return this;
+	}
+	
+	
+	/**
+	 * 结束计时
+	 */
+	public Ttime end() {
+		end=System.currentTimeMillis();
+		return this;
+	}
+
+	
+	/**
+	 * 返回所用毫秒数
+	 */
+	public long returnMs() {
+		return end-start;
+	}
+	
+	/**
+	 * 格式化输出结果
+	 */
+	public void outTime() {
+		System.out.println(this.toString());
+	}
+	
+	/**
+	 * 结束并格式化输出结果
+	 */
+	public void endOutTime() {
+		this.end().outTime();
+	}
+	
+	@Override
+	public String toString() {
+		return (returnMs() + 0.0) / 1000 + "s";		// 格式化为:0.01s
+	}
+	
+	
+	
+}

+ 70 - 0
sp-core/sp-base/src/main/java/com/pj/utils/cache/IpCheckUtil.java

@@ -0,0 +1,70 @@
+package com.pj.utils.cache;
+
+import com.pj.utils.sg.AjaxError;
+import com.pj.utils.sg.WebNbUtil;
+
+import cn.dev33.satoken.spring.SpringMVCUtil;
+
+/**
+ * IP限流util
+ * @author kong
+ *
+ */
+public class IpCheckUtil {
+
+	/**
+	 *  持久化的key 
+	 */
+	static String key = "sys_ck_ip:";
+	
+	
+	/**
+	 * 指定ip的访问点设置为
+	 * @param ip
+	 */
+	public static void setNow(String ip){
+		RedisUtil.set(key + ip, System.currentTimeMillis() + "");
+	}
+	public static void setNow(){
+		setNow(getMyIp());
+	}
+	
+	/**
+	 * 返回指定ip上一次接入是几秒前
+	 * @param ip
+	 * @return
+	 */
+	public static long getTs(String ip){
+		String str = RedisUtil.get(key + ip);
+		if(str == null) {
+			str = "0";
+		}
+		return (System.currentTimeMillis() - Long.parseLong(str)) / 1000;
+	}
+	public static long getTs(){
+		return getTs(getMyIp());
+	}
+	
+	/**
+	 * 检查指定ip是否属于频繁访问 ,如果是,则抛出异常 , 参数:ip、频繁秒数 
+	 * @param ip
+	 * @param s
+	 */
+	public static void checkIp(String ip, int s) {
+		if(IpCheckUtil.getTs(ip) < s){
+			throw AjaxError.get("操作频繁,请稍后尝试");
+		}
+	}
+	public static void checkIp(int s) {
+		checkIp(getMyIp(), s);
+	}
+	
+	
+	
+	// 返回我的ip
+	private static String getMyIp() {
+		String ip = WebNbUtil.getIP(SpringMVCUtil.getRequest());
+		return ip;
+	}
+	
+}

+ 116 - 0
sp-core/sp-base/src/main/java/com/pj/utils/cache/RedisUtil.java

@@ -0,0 +1,116 @@
+package com.pj.utils.cache;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+/**
+ * Redis工具类
+ * @author kongyongshun
+ *
+ */
+@Component
+public class RedisUtil {
+
+
+	public static long ttl = 24* 7;	//默认超时时间,单位周,此为一周
+
+
+	/**
+	 * 对象专用
+	 */
+	public static RedisTemplate<String, Object> redisTemplate;
+	@Autowired
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public void setRedisTemplate(RedisTemplate redisTemplate) {
+		RedisUtil.redisTemplate = redisTemplate;
+	}
+
+	/**
+	 * string专用
+	 */
+	static StringRedisTemplate stringRedisTemplate;
+	@Autowired
+	public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplates) {
+		RedisUtil.stringRedisTemplate = stringRedisTemplates;
+	}
+
+
+
+	/* * * * * * * * * * * * * * * * String操作 * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+	// 默认7*24小时
+	public static void set(String key, String value) {
+		stringRedisTemplate.opsForValue().set(key, value, ttl, TimeUnit.HOURS);
+	}
+
+	// 写入,并设置时长,单位 Hours
+	public static void setByHour(String key, String value, int timeout) {
+		stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.HOURS);
+	}
+	
+	// 写入,并设置时长,单位 分钟 MINUTES
+	public static void setByMINUTES(String key, String value, int timeout) {
+		stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.MINUTES);
+	}
+
+	// 读取
+	public static String get(String key) {
+		return stringRedisTemplate.opsForValue().get(key);
+	}
+
+
+	// 删除
+	public static void del(String key) {
+		stringRedisTemplate.delete(key);
+	}
+
+
+	/* * * * * * * * * * * * * * * * List集合操作 * * * * * * * * * * * * * * * * * * * * * * * * */
+
+	// 查询
+	public static List<Object> forListGet(String key){
+		return redisTemplate.opsForList().range(key, 0, -1);
+	}
+
+	// 追加键值
+	public static void forListAdd(String key, Object... args){
+		redisTemplate.opsForList().rightPushAll(key,  args);
+	}
+
+	// 移除所有键值
+	public static void forListRemove(String key){
+		List<Object> list = forListGet(key);
+		for (int i = 0; i < list.size(); i++) {
+			redisTemplate.opsForList().remove(key, -1,list.get(i));
+		}
+	}
+
+
+	/* * * * * * * * * * * * * * * * Object值操作 * * * * * * * * * * * * * * * * * * * * * * * * */
+
+	// 写入值
+	public static void forValueSet(String key, Object value){
+		redisTemplate.opsForValue().set(key, value, ttl, TimeUnit.HOURS);
+	}
+
+	// 读取值
+	@SuppressWarnings("unchecked")
+	public static <T>T forValueGet(String key, Class<T> cs){
+		return (T) redisTemplate.opsForValue().get(key);
+	}
+
+
+
+
+
+
+
+
+
+}

+ 150 - 0
sp-core/sp-base/src/main/java/com/pj/utils/sg/AjaxError.java

@@ -0,0 +1,150 @@
+package com.pj.utils.sg;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Ajax发生异常时,直接抛出此异常即可   (比AjaxException更先进的版本)
+ * @author kong
+ *
+ */
+public class AjaxError extends RuntimeException {
+
+	
+	/** 以下元素会在isNull函数中被判定为Null, */
+	public static final Object[] NULL_ELEMENT_ARRAY = {null, "", 0, "0", "0.0"};
+	public static final List<Object> NULL_ELEMENT_LIST;
+
+	static {
+		NULL_ELEMENT_LIST = Arrays.asList(NULL_ELEMENT_ARRAY);
+	}
+
+	
+	// ========================= 定义属性 =========================  
+	
+	private static final long serialVersionUID = 1L; 
+	
+	private int code = 500;		// 底层code码 
+	/**
+	 * @return 获取code码  
+	 */
+	public int getCode() {
+		return code;
+	}
+	/**
+	 * @return 写入code码 ,连缀风格 
+	 */
+	public AjaxError setCode(int code) {
+		this.code = code;
+		return this;
+	}
+	
+	
+	// ========================= 构造方法 =========================  
+
+	public AjaxError(int code, String message) {
+        super(message);
+		setCode(code);
+    }
+	public AjaxError(String message) {
+        super(message);
+    }
+	public AjaxError(Throwable e) {
+        super(e);
+    }
+	public AjaxError(String message, Throwable e) {
+        super(message, e);
+    }
+	
+
+	// ========================= 获取相关 =========================  
+	
+	/** 获得一个异常AjaxError */
+	public static AjaxError get(String errorMsg){
+		return new AjaxError(errorMsg);
+	}
+	/** 获得一个异常AjaxError */
+	public static AjaxError get(int code, String errorMsg){
+		return new AjaxError(code, errorMsg);
+	}
+	/** 获得一个异常AjaxError */
+	public static AjaxError get(Throwable e){
+		return new AjaxError(e);
+	}
+	
+
+	// ========================= 获取并抛出 =========================  
+	
+	/** 获得一个异常,并直接抛出 */
+	public static void getAndThrow(String errorMsg) {
+		throw new AjaxError(errorMsg);
+	}
+
+	/** 如果条件为true,则抛出异常 */
+	public static void throwBy(boolean bo, int code, String errorMsg) {
+		if(bo) {
+			throw get(code, errorMsg);
+		}
+	}
+	/** 如果条件为true,则抛出异常 */
+	public static void throwBy(boolean bo, String errorMsg) {
+		if(bo) {
+			throw get(errorMsg);
+		}
+	}
+	/** 如果条件为true,则抛出异常 */
+	public static void throwBy(boolean bo) {
+		if(bo) {
+			throw get("error");
+		}
+	}
+	
+
+	/** 根据受影响行数的(大于0通过,小于等于0抛出error) */ 
+	public static void throwByLine(int line, int code, String errorMsg){
+		if(line <= 0){
+			throw get(code, errorMsg);
+		}
+	}
+	/** 根据受影响行数的(大于0通过,小于等于0抛出error) */ 
+	public static void throwByLine(int line, String errorMsg){
+		if(line <= 0){
+			throw get(errorMsg);
+		}
+	}
+	/** 根据受影响行数的(大于0通过,小于等于0抛出error) */ 
+	public static void throwByLine(int line){
+		if(line <= 0){
+			throw get("受影响行数:0");
+		}
+	}
+	
+
+
+	/** 抛出异常,根据: 是否为空 */ 
+	public static void throwByIsNull(Object value, int code, String errorMsg){
+		if(isNull(value)){
+			throw get(code, errorMsg);
+		}
+	}
+	/** 抛出异常,根据: 是否为空 */ 
+	public static void throwByIsNull(Object value, String errorMsg){
+		if(isNull(value)){
+			throw get(errorMsg);
+		}
+	}
+	/** 抛出异常,根据: 是否为空 */ 
+	public static void throwByIsNull(Object value){
+		if(isNull(value)){
+			throw get("不能为空");
+		}
+	}
+	
+	/** 
+	 * 指定值是否为以下其一:null、""、0、"0"  
+	 */
+	public static boolean isNull(Object value) {
+		return NULL_ELEMENT_LIST.contains(value);
+	}
+	
+}

+ 233 - 0
sp-core/sp-base/src/main/java/com/pj/utils/sg/AjaxJson.java

@@ -0,0 +1,233 @@
+package com.pj.utils.sg;
+
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.pj.utils.so.SoMap;
+
+
+/**
+ * ajax请求返回Json格式数据的封装 <br>
+ * 所有预留字段:<br>
+ * code=状态码 <br>
+ * msg=描述信息 <br>
+ * data=携带对象 <br>
+ * pageNo=当前页 <br>
+ * pageSize=页大小 <br>
+ * startIndex=起始索引 <br>
+ * dataCount=数据总数 <br>
+ * pageCount=分页总数 <br>
+ * <p> 返回范例:</p>
+ *  <pre>
+	{
+		"code": 200,    // 成功时=200, 失败时=500  msg=失败原因
+		"msg": "ok",
+		"data": {}
+	} 
+	</pre>
+ */
+public class AjaxJson extends LinkedHashMap<String, Object> implements Serializable{
+
+	private static final long serialVersionUID = 1L;	// 序列化版本号
+	
+	public static final int CODE_SUCCESS = 200;			// 成功状态码
+	public static final int CODE_ERROR = 500;			// 错误状态码
+	public static final int CODE_WARNING = 501;			// 警告状态码
+	public static final int CODE_NOT_JUR = 403;			// 无权限状态码
+	public static final int CODE_NOT_LOGIN = 401;		// 未登录状态码
+	public static final int CODE_INVALID_REQUEST = 400;	// 无效请求状态码
+
+	
+	
+	// ============================  写值取值  ================================== 
+	
+	/** 给code赋值,连缀风格 */
+	public AjaxJson setCode(int code) {
+		this.put("code", code);
+		return this;
+	}
+	/** 返回code */
+	public Integer getCode() {
+		return (Integer)this.get("code");
+	}
+
+	/** 给msg赋值,连缀风格 */
+	public AjaxJson setMsg(String msg) {
+		this.put("msg", msg);
+		return this;
+	}
+	/** 获取msg */
+	public String getMsg() {
+		return (String)this.get("msg");
+	}
+
+	/** 给data赋值,连缀风格 */
+	public AjaxJson setData(Object data) {
+		this.put("data", data);
+		return this;
+	}
+	/** 获取data */
+	public String getData() {
+		return (String)this.get("data");
+	}
+	/** 将data还原为指定类型并返回 */
+	@SuppressWarnings("unchecked")
+	public <T> T getData(Class<T> cs) {
+		return (T) this.getData();
+	}
+
+	/** 给dataCount(数据总数)赋值,连缀风格 */
+	public AjaxJson setDataCount(Long dataCount) {
+		this.put("dataCount", dataCount);
+		// 如果提供了数据总数,则尝试计算page信息
+		if(dataCount != null && dataCount >= 0) {		
+			// 如果:已有page信息
+			if(get("pageNo") != null) {
+				this.initPageInfo();
+			} 
+			// 或者:是JavaWeb环境
+			else if(SoMap.isJavaWeb()) {
+				SoMap so = SoMap.getRequestSoMap();
+				this.setPageNoAndSize(so.getKeyPageNo(), so.getKeyPageSize());
+				this.initPageInfo();
+			}
+		}
+		return this;
+	}
+	/** 获取dataCount(数据总数) */
+	public String getDataCount() {
+		return (String)this.get("dataCount");
+	}
+	
+	/** 设置pageNo 和 pageSize,并计算出startIndex于pageCount */
+	public AjaxJson setPageNoAndSize(long pageNo, long pageSize) {
+		this.put("pageNo", pageNo);
+		this.put("pageSize", pageSize);
+		return this;
+	}
+
+	/** 根据 pageSize dataCount,计算startIndex 与 pageCount */
+	public AjaxJson initPageInfo() {
+		long pageNo = (long)this.get("pageNo");
+		long pageSize = (long)this.get("pageSize");
+		long dataCount = (long)this.get("dataCount");
+		this.set("startIndex", (pageNo - 1) * pageSize);
+		long pc = dataCount / pageSize;
+		this.set("pageCount", (dataCount % pageSize == 0 ?  pc : pc + 1));
+		return this;
+	}
+	
+	
+	/** 写入一个值 自定义key, 连缀风格 */
+	public AjaxJson set(String key, Object data) {
+		this.put(key, data);
+		return this;
+	}
+
+	/** 写入一个Map, 连缀风格 */
+	public AjaxJson setMap(Map<String, ?> map) {
+		for (String key : map.keySet()) {
+			this.put(key, map.get(key));
+		}
+		return this;
+	}
+	
+	
+	// ============================  构建  ================================== 
+	
+	public AjaxJson(int code, String msg, Object data, Long dataCount) {
+		this.setCode(code);
+		this.setMsg(msg);
+		this.setData(data);
+		this.setDataCount(dataCount == null ? -1 : dataCount);
+	}
+	
+	/** 返回成功 */
+	public static AjaxJson getSuccess() {
+		return new AjaxJson(CODE_SUCCESS, "ok", null, null);
+	}
+	public static AjaxJson getSuccess(String msg) {
+		return new AjaxJson(CODE_SUCCESS, msg, null, null);
+	}
+	public static AjaxJson getSuccess(String msg, Object data) {
+		return new AjaxJson(CODE_SUCCESS, msg, data, null);
+	}
+	public static AjaxJson getSuccessData(Object data) {
+		return new AjaxJson(CODE_SUCCESS, "ok", data, null);
+	}
+	
+	
+	/** 返回失败 */
+	public static AjaxJson getError() {
+		return new AjaxJson(CODE_ERROR, "error", null, null);
+	}
+	public static AjaxJson getError(String msg) {
+		return new AjaxJson(CODE_ERROR, msg, null, null);
+	}
+	
+	/** 返回警告  */
+	public static AjaxJson getWarning() {
+		return new AjaxJson(CODE_ERROR, "warning", null, null);
+	}
+	public static AjaxJson getWarning(String msg) {
+		return new AjaxJson(CODE_WARNING, msg, null, null);
+	}
+
+	/** 返回未登录  */
+	public static AjaxJson getNotLogin() {
+		return new AjaxJson(CODE_NOT_LOGIN, "未登录,请登录后再次访问", null, null);
+	}
+
+	/** 返回没有权限的  */
+	public static AjaxJson getNotJur(String msg) {
+		return new AjaxJson(CODE_NOT_JUR, msg, null, null);
+	}
+	
+	/** 返回一个自定义状态码的  */
+	public static AjaxJson get(int code, String msg){
+		return new AjaxJson(code, msg, null, null);
+	}
+	
+	/** 返回分页和数据的  */
+	public static AjaxJson getPageData(Long dataCount, Object data){
+		return new AjaxJson(CODE_SUCCESS, "ok", data, dataCount);
+	}
+	
+	/** 返回, 根据受影响行数的(大于0=ok,小于0=error)  */
+	public static AjaxJson getByLine(int line){
+		if(line > 0){
+			return getSuccess("ok", line);
+		}
+		return getError("error").setData(line); 
+	}
+
+	/** 返回,根据布尔值来确定最终结果的  (true=ok,false=error)  */
+	public static AjaxJson getByBoolean(boolean b){
+		return b ? getSuccess("ok") : getError("error"); 
+	}
+	
+	
+	// 重写toString,转json格式输出 
+	@Override
+	public String toString() {
+		try {
+			return new ObjectMapper().writeValueAsString(this);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	
+	
+//  // 历史版本遗留代码 
+//	public int code; 	// 状态码
+//	public String msg; 	// 描述信息 
+//	public Object data; // 携带对象
+//	public Long dataCount;	// 数据总数,用于分页 
+
+	
+	
+	
+}

+ 283 - 0
sp-core/sp-base/src/main/java/com/pj/utils/sg/NbUtil.java

@@ -0,0 +1,283 @@
+package com.pj.utils.sg;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Random;
+import java.util.regex.Pattern;
+
+import cn.hutool.core.util.IdUtil;
+
+/**
+ * 最nb的工具类
+ * @author kong
+ *
+ */
+public class NbUtil {
+
+	
+	
+	// 时间处理
+
+	/**
+	 * 返回指定时间的YYYY-MM-dd hh:mm:ss 字符串格式
+	 */
+	public static String getDtString(Date d){
+		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d);
+	}
+	
+	/**
+	 * 返回系统当前时间的YYYY-MM-dd hh:mm:ss 字符串格式
+	 */
+	public static String getNow(){
+		return getDtString(new Date());
+	}
+	/**
+	 * 将一个字符串转换为日期格式(YYYY-MM-dd HH:mm:ss)
+	 */
+	public static Date getDt(String d) {
+		try {
+			return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(d);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	/**
+	 * 返回当前时间的指定形式 如(YYYY_MM_dd_HH_mm_ss)
+	 * @return
+	 */
+	public static String getNowString(String geshi) {
+		return new SimpleDateFormat(geshi).format(new Date());
+	}
+	/** 指定日期,指定格式 */
+	public static String getDateString(Date date, String geshi) {
+		return new SimpleDateFormat(geshi).format(date);
+	}
+	
+	/**
+	 * 获取指定日期的1号
+	 */
+	public static Date getYueOne(Date date) {
+		Calendar calendar = Calendar.getInstance();  
+        calendar.setTime(date);  
+        calendar.set(Calendar.DAY_OF_MONTH, 1);  
+        calendar.set(Calendar.HOUR_OF_DAY, 0);  
+        calendar.set(Calendar.MINUTE, 0);  
+        calendar.set(Calendar.SECOND, 0);  
+        return calendar.getTime();  
+	}
+	
+	
+	
+	//基本字符处理
+
+	/**
+	 * 该字符串是否为null或者空串
+	 */
+	public static boolean isNull(String str) {
+		return (str == null || str.equals(""));
+	}
+	/**
+	 * 该字符串是否为null或者空串
+	 */
+	public static boolean isOneNull(String ...str) {
+		for (String string : str) {
+			 if ((string == null || string.equals(""))) {
+				return true;
+			}
+		}
+		return false;
+	}
+	/**
+	 * 如果一个字符串为(null,"","null"),则转化为指定值
+	 */
+	public static String toStr(String str, String toStr) {
+		if (str == null || str.equals("") || str.equals("null")) {
+			return toStr;
+		}
+		return str;
+	}
+
+	/**
+	 * 如果该货不能转成一个数字,则返回指定值
+	 */
+	public static Integer toInt(String str, Integer toInt) {
+		try {
+			return new Integer(str);
+		} catch (Exception e) {
+			return toInt;
+		}
+	}
+
+	private static Pattern patternNumberPattern = Pattern.compile("[0-9]*");
+	/**
+	 * 验证一个str是否为数字
+	 * @param str
+	 * @return
+	 */
+	public static boolean isNumber(String str){
+	    return patternNumberPattern.matcher(str).matches();   
+	}
+
+	private static Pattern patternNumberPhone = Pattern.compile("[1]\\d{10}");
+	/**
+	 * 验证一个str是否为手机号 
+	 * @param str
+	 * @return
+	 */
+	public static boolean isPhone(String str){
+		if(str == null) {
+			return false;
+		}
+	    return patternNumberPhone.matcher(str).matches();   
+	}
+
+	
+	/** 判断一个数是否在0、1、2、3...10、20、30...100、200、300... 数列里面 */	
+	private static Pattern patternSeries = Pattern.compile("[0-9]0*");
+	public static boolean isSeries(int num) {
+	    return patternSeries.matcher(num + "").matches();  
+	}
+	
+	
+	/**
+	 * 将一个字符串ISO-8859-1转码UTF-8
+	 */
+	public static String toUtf8(String str) {
+		try {
+			return new String(str.getBytes("ISO-8859-1"), "UTF-8");
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+		}
+		return str;
+	}
+
+	/**
+	 * 将字符串转化为指定数据类型
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T>T getObjectByClass(String str, Class<T> cs){
+		Object value = null;
+		if(str == null){
+			value = null;
+		}else if (cs.equals(String.class)) {
+			value = str;
+		} else if (cs.equals(int.class)||cs.equals(Integer.class)) {
+			value = new Integer(str);
+        } else if (cs.equals(long.class)||cs.equals(Long.class)) {
+        	value = new Long(str);
+        } else if (cs.equals(short.class)||cs.equals(Short.class)) {
+        	value = new Short(str);
+        } else if (cs.equals(float.class)||cs.equals(Float.class)) {
+        	value = new Float(str);
+        } else if (cs.equals(double.class)||cs.equals(Double.class)) {
+        	value = new Double(str);
+        } else if (cs.equals(boolean.class)||cs.equals(Boolean.class)) {
+        	value = new Boolean(str);
+        }else{
+        	throw new RuntimeException("超纲的类型:" + cs + ",未能转换值:" + str);
+        }
+		return (T)value;
+	}
+	
+	/** 返回随机数 */
+	public static int getRandom(int min, int max){
+		max = max + 1;
+	    Random random = new Random();
+	    return random.nextInt(max) % (max - min + 1) + min;
+	}
+	
+	/** 返回随机字符串 */
+	public static String getRandomString(int length){
+	     String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+	     Random random=new Random();
+	     StringBuffer sb=new StringBuffer();
+	     for(int i=0;i<length;i++){
+	       int number=random.nextInt(62);
+	       sb.append(str.charAt(number));
+	     }
+	     return sb.toString();
+	 }
+	
+	
+	/**
+	 * 返回唯一标示28位唯一标示符
+	 */
+	public static String getMarking28() {
+		return System.currentTimeMillis()+""+new Random().nextInt(Integer.MAX_VALUE);
+	}
+
+	/** 取文件后缀 */
+    public static String getSuffixName(String fileName){
+        return fileName.substring(fileName.lastIndexOf(".") + 1);
+    }
+	
+    
+	/** 指定Properties配置文件,读取成为Map, 返回null代表无此配置文件 */
+    public static Map<String, String> readPropToMap(String propertiesPath){
+    	Map<String, String> map = new HashMap<>();
+		try {
+	    	InputStream is = NbUtil.class.getClassLoader().getResourceAsStream(propertiesPath);	
+	    	if(is == null){
+	    		return null;
+	    	}
+			Properties prop = new Properties();
+			prop.load(is);
+			for (String key : prop.stringPropertyNames()) {
+				map.put(key, prop.getProperty(key));
+			}
+		} catch (IOException e) {
+			throw new RuntimeException("配置文件(" + propertiesPath + ")加载失败", e);
+		}
+		return map;
+    }
+    
+    
+	/** 初始化对象的属性,根据Map,支持直接为类static字段赋值 */
+    public static Object initPropByMap(Map<String, String> map, Object obj){
+    	Class<?> cs = null;
+    	if(obj instanceof Class){
+    		cs = (Class<?>)obj;		// 已经是类
+    		obj = null;
+    	}else{
+    		cs = obj.getClass();	// 实例对象
+    	}
+    	
+    	for (Field field : cs.getDeclaredFields()) {
+			String value = map.get(field.getName());
+			if (value == null) {
+				continue; // 为空代表没配置此项
+			}
+			try {
+				Object valueConvert = getObjectByClass(value, field.getType());
+				field.set(obj, valueConvert);
+			} catch (IllegalArgumentException | IllegalAccessException e) {
+				throw new RuntimeException("属性取值出错:" + field.getName(), e);
+			}
+		}
+    	return obj;
+    }
+    
+	/** 返回一个6位数手机验证码  */
+	public static String getcolde() {
+		return Double.toString(((Math.random()*9+1)*100000)).substring(0, 6);
+	}
+    
+	
+	// 返回雪花算法id
+	public static String getSnowflakeId() {
+		return IdUtil.getSnowflake(1, 1).nextIdStr();
+	}
+    
+	
+	
+	
+}

+ 214 - 0
sp-core/sp-base/src/main/java/com/pj/utils/sg/WebNbUtil.java

@@ -0,0 +1,214 @@
+package com.pj.utils.sg;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+
+
+/**
+ *  web工具类
+ * @author kong
+ *
+ */
+public class WebNbUtil {
+
+	// 工具方法
+
+	/**
+	 * 取出一个值,我保证不乱码,tomcat8及以上版本此方法废掉
+	 */
+	public static String getParam(HttpServletRequest request, String key) {
+		try {
+			request.setCharacterEncoding("UTF-8");
+			String value = request.getParameter(key); // 获得v
+			if (value != null && request.getMethod().equals("GET")) {
+				value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
+			}
+			return value;
+		} catch (UnsupportedEncodingException e) {
+			return null;
+		}
+	}
+	/**
+	 * 取出一个值,我保证不乱码,tomcat8及以上版本专用
+	 */
+	public static String getParam8(HttpServletRequest request, String key) {
+		try {
+			if(request.getCharacterEncoding()==null) {
+				request.setCharacterEncoding("UTF-8");
+			}
+			return request.getParameter(key);
+		} catch (UnsupportedEncodingException e) {
+			return null;
+		}
+	}
+	/**
+	 * 将一个值,强制转码ISO_8859_1-->utf-8
+	 */
+	public static String getISO_8859_1(String str) {
+		try {
+			if(str==null) {
+				return str;
+			}
+			return new String(str.getBytes("ISO-8859-1"), "UTF-8");
+		} catch (Exception e) {
+			//e.printStackTrace();
+		}
+		return str;
+	}
+
+	/**
+	 * 将一个request请求所携带的参数封装成map返回
+	 * <br/>对于数组型参数,此方法不能正确获得值
+	 * @param request
+	 * @return
+	 */
+	public static Map<String,String>getParamsMap(HttpServletRequest request){
+		Map<String,String>map=new HashMap<String, String>();
+		try {
+			Enumeration<String> paramNames = request.getParameterNames();//获得K列表
+			request.setCharacterEncoding("UTF-8");
+			while (paramNames.hasMoreElements()) {  
+				try {
+					String key =paramNames.nextElement();	//获得k
+					String value=request.getParameter(key);	//获得v
+					if(request.getMethod().equals("GET")){
+						//value=new String(value.getBytes("ISO-8859-1"),"UTF-8");
+					}
+					map.put(key,value);	
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			}
+		} catch (Exception e1) {
+			e1.printStackTrace();
+		}
+		return map;
+	}
+	
+	/**  将一个request请求所携带的参数封装成map返回 ,带集合的 */
+	public static Map<String, Object>getParamsMap2(HttpServletRequest request){
+		Map<String, Object> map = new HashMap<String, Object>();
+		Map<String, String[]> parameterMap = request.getParameterMap();	// 获取所有参数 
+		for (String key : parameterMap.keySet()) {
+			try {
+				String[] values = parameterMap.get(key); // 获得values 
+				if(values.length == 1) {
+					map.put(key, values[0]);
+				} else {
+					List<String> list = new ArrayList<String>();
+					for (String v : values) {
+						list.add(v);
+					}
+					map.put(key, list);
+				}
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+		return map;
+	}
+	
+
+	/**
+	 * 将一个request请求Header所携带的参数封装成map返回
+	 */
+	public static Map<String,String>getHeaderMap(HttpServletRequest request){
+		Map<String,String>map=new HashMap<String, String>();
+		try {
+			Enumeration<String> paramNames = request.getHeaderNames();//获得K列表
+			request.setCharacterEncoding("UTF-8");
+			while (paramNames.hasMoreElements()) {  
+				try {
+					String key =paramNames.nextElement();	//获得k
+					String value=request.getHeader(key);	//获得v
+					if(request.getMethod().equals("GET")){
+						new String(value.getBytes("ISO-8859-1"),"UTF-8");
+					}
+					map.put(key,value);	
+				} catch (UnsupportedEncodingException e) {
+					e.printStackTrace();
+				}
+			}
+		} catch (Exception e1) {
+			e1.printStackTrace();
+		}
+		return map;
+	}
+	
+	
+	/**
+	 * 返回请求端的IP地址
+	 */
+	public static String getIP(HttpServletRequest request) {
+		String ip = request.getHeader("x-forwarded-for");
+		ip = checkIp(ip) ? ip : (
+                checkIp(ip = request.getHeader("Proxy-Client-IP")) ? ip : (
+                        checkIp(ip = request.getHeader("WL-Proxy-Client-IP")) ? ip :
+                                request.getRemoteAddr()));
+		return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
+	}
+	
+	private static boolean checkIp(String ip) {
+        return !NbUtil.isNull(ip) && !"unknown".equalsIgnoreCase(ip);
+    }
+
+	/**
+	 * 返回指定地址在服务器上的绝对路径
+	 */
+	public static String getRealPath(HttpSession session, String path) {
+		return session.getServletContext().getRealPath(path);// 路径
+	}
+
+	/**
+	 * 返回项目的http地址
+	 */
+	public static String getHttpUrl(HttpServletRequest request, String port) {
+
+		String path = request.getServletContext().getContextPath();
+		StringBuffer url = request.getRequestURL();
+		String http = url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();	
+		
+		if(port != null && !port.equals("") && !port.equals("80") && !port.equals("443")){
+			if(http.endsWith(":" + port) == false){
+				http += ":" + port;
+			}
+		}
+		http += path;
+		if(http.endsWith("/") == false){
+			http += "/";
+		}
+		
+		return http;
+	}
+	
+	
+	/**
+	 * 检测request请求是否为ajax
+	 */
+	public static boolean isAjax(HttpServletRequest request) {
+		return !(request.getHeader("x-requested-with") == null);
+	}
+
+	/**
+	 * 将指定key的参数转化为int类型,转化不了的给默认值
+	 */
+	public static int getInt(HttpServletRequest request, String key, int default_value) {
+		try {
+			String arg_str = request.getParameter(key);
+			return Integer.valueOf(arg_str);
+		} catch (Exception e) {
+			return default_value;
+		}
+	}
+
+	
+	
+}

+ 749 - 0
sp-core/sp-base/src/main/java/com/pj/utils/so/SoMap.java

@@ -0,0 +1,749 @@
+package com.pj.utils.so;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Map< String, Object> 是最常用的一种Map类型,但是它写着麻烦 
+ * <p>所以特封装此类,继承Map,进行一些扩展,可以让Map更灵活使用 
+ * <p>最新:2020-12-10 新增部分构造方法
+ * @author kong
+ */
+public class SoMap extends LinkedHashMap<String, Object> {
+
+	private static final long serialVersionUID = 1L;
+
+	public SoMap() {
+	}
+	
+
+	/** 以下元素会在isNull函数中被判定为Null, */
+	public static final Object[] NULL_ELEMENT_ARRAY = {null, ""};
+	public static final List<Object> NULL_ELEMENT_LIST;
+
+	
+	static {
+		NULL_ELEMENT_LIST = Arrays.asList(NULL_ELEMENT_ARRAY);
+	}
+
+	// ============================= 读值 =============================
+
+	/** 获取一个值 */
+	@Override
+	public Object get(Object key) {
+		if("this".equals(key)) {
+			return this;
+		}
+		return super.get(key);
+	}
+
+	/** 如果为空,则返回默认值 */
+	public Object get(Object key, Object defaultValue) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return defaultValue;
+		}
+		return value;
+	}
+	
+	/** 转为String并返回 */
+	public String getString(String key) {
+		Object value = get(key);
+		if(value == null) {
+			return null;
+		}
+		return String.valueOf(value);
+	}
+
+	/** 如果为空,则返回默认值 */
+	public String getString(String key, String defaultValue) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return defaultValue;
+		}
+		return String.valueOf(value);
+	}
+
+	/** 转为int并返回 */
+	public int getInt(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return 0;
+		}
+		return Integer.valueOf(String.valueOf(value));
+	}
+	/** 转为int并返回,同时指定默认值 */
+	public int getInt(String key, int defaultValue) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return defaultValue;
+		}
+		return Integer.valueOf(String.valueOf(value));
+	}
+
+	/** 转为long并返回 */
+	public long getLong(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return 0;
+		}
+		return Long.valueOf(String.valueOf(value));
+	}
+
+	/** 转为double并返回 */
+	public double getDouble(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return 0.0;
+		}
+		return Double.valueOf(String.valueOf(value));
+	}
+
+	/** 转为boolean并返回 */
+	public boolean getBoolean(String key) {
+		Object value = get(key);
+		if(valueIsNull(value)) {
+			return false;
+		}
+		return Boolean.valueOf(String.valueOf(value));
+	}
+
+	/** 转为Date并返回,根据自定义格式 */
+	public Date getDateByFormat(String key, String format) {
+		try {
+			return new SimpleDateFormat(format).parse(getString(key));
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/** 转为Date并返回,根据格式: yyyy-MM-dd */
+	public Date getDate(String key) {
+		return getDateByFormat(key, "yyyy-MM-dd");
+	}
+
+	/** 转为Date并返回,根据格式: yyyy-MM-dd HH:mm:ss */
+	public Date getDateTime(String key) {
+		return getDateByFormat(key, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	/** 获取集合(必须原先就是个集合,否则会创建个新集合并返回) */
+	@SuppressWarnings("unchecked")
+	public List<Object> getList(String key) {
+		Object value = get(key);
+		List<Object> list = null;
+		if(value == null || value.equals("")) {
+			list = new ArrayList<Object>();
+		}
+		else if(value instanceof List) {
+			list = (List<Object>)value;
+		} else {
+			list = new ArrayList<Object>();
+			list.add(value);
+		}
+		return list;
+	}
+
+	/** 获取集合 (指定泛型类型) */
+	public <T> List<T> getList(String key, Class<T> cs) {
+		List<Object> list = getList(key);
+		List<T> list2 = new ArrayList<T>();
+		for (Object obj : list) {
+			T objC = getValueByClass(obj, cs);
+			list2.add(objC);
+		}
+		return list2;
+	}
+
+	/** 获取集合(逗号分隔式),(指定类型) */
+	public <T> List<T> getListByComma(String key, Class<T> cs) {
+		String listStr = getString(key);
+		if(listStr == null || listStr.equals("")) {
+			return new ArrayList<>();
+		}
+		// 开始转化
+		String [] arr = listStr.split(",");
+		List<T> list = new ArrayList<T>();
+		for (String str : arr) {
+			if(cs == int.class || cs == Integer.class || cs == long.class || cs == Long.class) {
+				str = str.trim();
+			}
+			T objC = getValueByClass(str, cs);
+			list.add(objC);
+		}
+		return list;
+	}
+
+
+	/** 根据指定类型从map中取值,返回实体对象 */
+	public <T> T getModel(Class<T> cs) {
+		try {
+			return getModelByObject(cs.newInstance());
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+	
+	/** 从map中取值,塞到一个对象中 */
+	public <T> T getModelByObject(T obj) {
+		// 获取类型 
+		Class<?> cs = obj.getClass();
+		// 循环复制  
+		for (Field field : cs.getDeclaredFields()) {
+			try {
+				// 获取对象 
+				Object value = this.get(field.getName());	
+				if(value == null) {
+					continue;
+				}
+				field.setAccessible(true);	
+				Object valueConvert = getValueByClass(value, field.getType());
+				field.set(obj, valueConvert);
+			} catch (IllegalArgumentException | IllegalAccessException e) {
+				throw new RuntimeException("属性取值出错:" + field.getName(), e);
+			}
+		}
+		return obj;
+	}
+
+	
+
+	/**
+	 * 将指定值转化为指定类型并返回
+	 * @param obj
+	 * @param cs
+	 * @param <T>
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T getValueByClass(Object obj, Class<T> cs) {
+		String obj2 = String.valueOf(obj);
+		Object obj3 = null;
+		if (cs.equals(String.class)) {
+			obj3 = obj2;
+		} else if (cs.equals(int.class) || cs.equals(Integer.class)) {
+			obj3 = Integer.valueOf(obj2);
+		} else if (cs.equals(long.class) || cs.equals(Long.class)) {
+			obj3 = Long.valueOf(obj2);
+		} else if (cs.equals(short.class) || cs.equals(Short.class)) {
+			obj3 = Short.valueOf(obj2);
+		} else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
+			obj3 = Byte.valueOf(obj2);
+		} else if (cs.equals(float.class) || cs.equals(Float.class)) {
+			obj3 = Float.valueOf(obj2);
+		} else if (cs.equals(double.class) || cs.equals(Double.class)) {
+			obj3 = Double.valueOf(obj2);
+		} else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
+			obj3 = Boolean.valueOf(obj2);
+		} else {
+			obj3 = (T)obj;
+		}
+		return (T)obj3;
+	}
+
+	
+	// ============================= 写值 =============================
+
+	/**
+	 * 给指定key添加一个默认值(只有在这个key原来无值的情况先才会set进去)
+	 */
+	public void setDefaultValue(String key, Object defaultValue) {
+		if(isNull(key)) {
+			set(key, defaultValue);
+		}
+	}
+
+	/** set一个值,连缀风格 */
+	public SoMap set(String key, Object value) {
+		// 防止敏感key 
+		if(key.toLowerCase().equals("this")) {		
+			return this;
+		}
+		put(key, value);
+		return this;
+	}
+
+	/** 将一个Map塞进SoMap */
+	public SoMap setMap(Map<String, ?> map) {
+		if(map != null) {
+			for (String key : map.keySet()) {
+				this.set(key, map.get(key));
+			}
+		}
+		return this;
+	}
+
+	/** 将一个对象解析塞进SoMap */
+	public SoMap setModel(Object model) {
+		if(model == null) {
+			return this;
+		}
+		Field[] fields = model.getClass().getDeclaredFields();
+	    for (Field field : fields) {
+	        try{
+	            field.setAccessible(true);
+	            boolean isStatic = Modifier.isStatic(field.getModifiers());
+	            if(!isStatic) {
+		            this.set(field.getName(), field.get(model));
+	            }
+	        }catch (Exception e){
+	        	throw new RuntimeException(e);
+	        }
+	    }
+		return this;
+	}
+
+	/** 将json字符串解析后塞进SoMap */
+	public SoMap setJsonString(String jsonString) {
+		try {
+			@SuppressWarnings("unchecked")
+			Map<String, Object> map = new ObjectMapper().readValue(jsonString, Map.class);
+			return this.setMap(map);
+		} catch (JsonProcessingException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	
+	// ============================= 删值 =============================
+
+	/** delete一个值,连缀风格 */
+	public SoMap delete(String key) {
+		remove(key);
+		return this;
+	}
+
+	/** 清理所有value为null的字段 */
+	public SoMap clearNull() {
+		Iterator<String> iterator = this.keySet().iterator();
+		while(iterator.hasNext()) {
+			String key = iterator.next();
+			if(this.isNull(key)) {
+				iterator.remove();
+				this.remove(key);
+			}
+
+		}
+		return this;
+	}
+	/** 清理指定key */
+	public SoMap clearIn(String ...keys) {
+		List<String> keys2 = Arrays.asList(keys);
+		Iterator<String> iterator = this.keySet().iterator();
+		while(iterator.hasNext()) {
+			String key = iterator.next();
+			if(keys2.contains(key) == true) {
+				iterator.remove();
+				this.remove(key);
+			}
+		}
+		return this;
+	}
+	/** 清理掉不在列表中的key */
+	public SoMap clearNotIn(String ...keys) {
+		List<String> keys2 = Arrays.asList(keys);
+		Iterator<String> iterator = this.keySet().iterator();
+		while(iterator.hasNext()) {
+			String key = iterator.next();
+			if(keys2.contains(key) == false) {
+				iterator.remove();
+				this.remove(key);
+			}
+
+		}
+		return this;
+	}
+	/** 清理掉所有key */
+	public SoMap clearAll() {
+		clear();
+		return this;
+	}
+	
+
+	// ============================= 快速构建 ============================= 
+
+	/** 构建一个SoMap并返回 */
+	public static SoMap getSoMap() {
+		return new SoMap();
+	}
+	/** 构建一个SoMap并返回 */
+	public static SoMap getSoMap(String key, Object value) {
+		return new SoMap().set(key, value);
+	}
+	/** 构建一个SoMap并返回 */
+	public static SoMap getSoMap(Map<String, ?> map) {
+		return new SoMap().setMap(map);
+	}
+
+	/** 将一个对象集合解析成为SoMap */
+	public static SoMap getSoMapByModel(Object model) {
+		return SoMap.getSoMap().setModel(model);
+	}
+	
+	/** 将一个对象集合解析成为SoMap集合 */
+	public static List<SoMap> getSoMapByList(List<?> list) {
+		List<SoMap> listMap = new ArrayList<SoMap>();
+		for (Object model : list) {
+			listMap.add(getSoMapByModel(model));
+		}
+		return listMap;
+	}
+	
+	/** 克隆指定key,返回一个新的SoMap */
+	public SoMap cloneKeys(String... keys) {
+		SoMap so = new SoMap();
+		for (String key : keys) {
+			so.set(key, this.get(key));
+		}
+		return so;
+	}
+	/** 克隆所有key,返回一个新的SoMap */
+	public SoMap cloneSoMap() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(key, this.get(key));
+		}
+		return so;
+	}
+
+	/** 将所有key转为大写 */
+	public SoMap toUpperCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(key.toUpperCase(), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key转为小写 */
+	public SoMap toLowerCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(key.toLowerCase(), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key中下划线转为中划线模式 (kebab-case风格) */
+	public SoMap toKebabCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(wordEachKebabCase(key), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key中下划线转为小驼峰模式 */
+	public SoMap toHumpCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(wordEachBigFs(key), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	/** 将所有key中小驼峰转为下划线模式 */
+	public SoMap humpToLineCase() {
+		SoMap so = new SoMap();
+		for (String key : this.keySet()) {
+			so.set(wordHumpToLine(key), this.get(key));
+		}
+		this.clearAll().setMap(so);
+		return this;
+	}
+	
+	
+	
+	
+	// ============================= 辅助方法 =============================
+
+
+	/** 指定key是否为null,判定标准为 NULL_ELEMENT_ARRAY 中的元素  */
+	public boolean isNull(String key) {
+		return valueIsNull(get(key));
+	}
+
+	/** 指定key列表中是否包含value为null的元素,只要有一个为null,就会返回true */
+	public boolean isContainNull(String ...keys) {
+		for (String key : keys) {
+			if(this.isNull(key)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	/** 与isNull()相反 */
+	public boolean isNotNull(String key) {
+		return !isNull(key);
+	}
+	/** 指定key的value是否为null,作用同isNotNull() */
+	public boolean has(String key) {
+		return !isNull(key);
+	}
+	
+	/** 指定value在此SoMap的判断标准中是否为null */
+	public boolean valueIsNull(Object value) {
+		return NULL_ELEMENT_LIST.contains(value);
+	}
+	
+	/** 验证指定key不为空,为空则抛出异常 */
+	public SoMap checkNull(String ...keys) {
+		for (String key : keys) {
+			if(this.isNull(key)) {
+				throw new RuntimeException("参数" + key + "不能为空");
+			}
+		}
+		return this;
+	}
+
+	static Pattern patternNumber = Pattern.compile("[0-9]*");
+	/** 指定key是否为数字 */
+	public boolean isNumber(String key) {
+		String value = getString(key);
+		if(value == null) {
+			return false;
+		}
+	    return patternNumber.matcher(value).matches();   
+	}
+
+	
+	
+	
+	/**
+	 * 转为JSON字符串
+	 */
+	public String toJsonString() {
+		try {
+//			SoMap so = SoMap.getSoMap(this);
+			return new ObjectMapper().writeValueAsString(this);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * 转为JSON字符串, 带格式的 
+	 */
+	public String toJsonFormatString() {
+		try {
+			return JSON.toJSONString(this, true); 
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	// ============================= web辅助 =============================
+
+
+	/**
+	 * 返回当前request请求的的所有参数 
+	 * @return
+	 */
+	public static SoMap getRequestSoMap() {
+		// 大善人SpringMVC提供的封装 
+		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+		if(servletRequestAttributes == null) {
+			throw new RuntimeException("当前线程非JavaWeb环境");
+		}
+		// 当前request
+		HttpServletRequest request = servletRequestAttributes.getRequest(); 
+		if (request.getAttribute("currentSoMap") == null || request.getAttribute("currentSoMap") instanceof SoMap == false ) {
+			initRequestSoMap(request);
+		}
+		return (SoMap)request.getAttribute("currentSoMap");
+	}
+
+	/** 初始化当前request的 SoMap */
+	private static void initRequestSoMap(HttpServletRequest request) {
+		SoMap soMap = new SoMap();
+		Map<String, String[]> parameterMap = request.getParameterMap();	// 获取所有参数 
+		for (String key : parameterMap.keySet()) {
+			try {
+				String[] values = parameterMap.get(key); // 获得values 
+				if(values.length == 1) {
+					soMap.set(key, values[0]);
+				} else {
+					List<String> list = new ArrayList<String>();
+					for (String v : values) {
+						list.add(v);
+					}
+					soMap.set(key, list);
+				}
+			} catch (Exception e) {
+				throw new RuntimeException(e);
+			}
+		}
+		request.setAttribute("currentSoMap", soMap);
+	}
+	
+	/**
+	 * 验证返回当前线程是否为JavaWeb环境 
+	 * @return
+	 */
+	public static boolean isJavaWeb() {
+		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装 
+		if(servletRequestAttributes == null) {
+			return false;
+		}
+		return true;
+	}
+	
+
+
+	// ============================= 常见key (以下key经常用,所以封装以下,方便写代码) =============================
+
+	/** get 当前页  */
+	public int getKeyPageNo() {
+		int pageNo = getInt("pageNo", 1);
+		if(pageNo <= 0) {
+			pageNo = 1;
+		}
+		return pageNo;
+	}
+	/** get 页大小  */
+	public int getKeyPageSize() {
+		int pageSize = getInt("pageSize", 10);
+		if(pageSize <= 0 || pageSize > 1000) {
+			pageSize = 10;
+		}
+		return pageSize;
+	}
+
+	/** get 排序方式 */
+	public int getKeySortType() {
+		return getInt("sortType");
+	}
+
+
+
+
+
+	// ============================= 分页相关(封装mybatis的page-help插件 ) =============================
+
+	/** 分页插件 */
+	private com.github.pagehelper.Page<?> pagePlug;
+	/** 分页插件 - 开始分页 */
+	public SoMap startPage() {
+		this.pagePlug= com.github.pagehelper.PageHelper.startPage(getKeyPageNo(), getKeyPageSize());
+		return this;
+	}
+	/** 获取上次分页的记录总数 */
+	public long getDataCount() {
+		if(pagePlug == null) {
+			return -1;
+		}
+		return pagePlug.getTotal();
+	}
+	/** 分页插件 - 结束分页, 返回总条数 (该方法已过时,请调用更加符合语义化的getDataCount() ) */
+	@Deprecated
+	public long endPage() {
+		return getDataCount();
+	}
+
+	
+	
+	
+
+	// ============================= 工具方法 =============================
+	
+
+	/**
+	 * 将一个一维集合转换为树形集合 
+	 * @param list         集合
+	 * @param idKey        id标识key
+	 * @param parentIdKey  父id标识key
+	 * @param childListKey 子节点标识key
+	 * @return 转换后的tree集合 
+	 */
+	public static List<SoMap> listToTree(List<SoMap> list, String idKey, String parentIdKey, String childListKey) {
+		// 声明新的集合,存储tree形数据 
+		List<SoMap> newTreeList = new ArrayList<SoMap>();
+		// 声明hash-Map,方便查找数据 
+		SoMap hash = new SoMap();
+		// 将数组转为Object的形式,key为数组中的id 
+		for (int i = 0; i < list.size(); i++) {
+			SoMap json = (SoMap) list.get(i);
+			hash.put(json.getString(idKey), json);
+		}
+		// 遍历结果集
+		for (int j = 0; j < list.size(); j++) {
+			// 单条记录
+			SoMap aVal = (SoMap) list.get(j);
+			// 在hash中取出key为单条记录中pid的值
+			SoMap hashVp = (SoMap) hash.get(aVal.get(parentIdKey, "").toString());
+			// 如果记录的pid存在,则说明它有父节点,将她添加到孩子节点的集合中
+			if (hashVp != null) {
+				// 检查是否有child属性,有则添加,没有则新建 
+				if (hashVp.get(childListKey) != null) {
+					@SuppressWarnings("unchecked")
+					List<SoMap> ch = (List<SoMap>) hashVp.get(childListKey);
+					ch.add(aVal);
+					hashVp.put(childListKey, ch);
+				} else {
+					List<SoMap> ch = new ArrayList<SoMap>();
+					ch.add(aVal);
+					hashVp.put(childListKey, ch);
+				}
+			} else {
+				newTreeList.add(aVal);
+			}
+		}
+		return newTreeList;
+	}
+	
+	
+
+	/** 指定字符串的字符串下划线转大写模式 */
+	private static String wordEachBig(String str){
+		String newStr = "";
+		for (String s : str.split("_")) {
+			newStr += wordFirstBig(s);
+		}
+		return newStr;
+	}
+	/** 返回下划线转小驼峰形式 */
+	private static String wordEachBigFs(String str){
+		return wordFirstSmall(wordEachBig(str));
+	}
+
+	/** 将指定单词首字母大写 */
+	private static String wordFirstBig(String str) {
+		return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
+	}
+
+	/** 将指定单词首字母小写 */
+	private static String wordFirstSmall(String str) {
+		return str.substring(0, 1).toLowerCase() + str.substring(1, str.length());
+	}
+
+	/** 下划线转中划线 */
+	private static String wordEachKebabCase(String str) {
+		return str.replaceAll("_", "-");
+	}
+
+	/** 驼峰转下划线  */
+	private static String wordHumpToLine(String str) {
+		return str.replaceAll("[A-Z]", "_$0").toLowerCase();
+	}
+	
+
+}

+ 10 - 0
sp-core/sp-base/src/main/resources/banner.txt

@@ -0,0 +1,10 @@
+                                __                __
+   _________              _____/ /___  __  ______/ /
+  / ___/ __ \   ______   / ___/ / __ \/ / / / __  / 
+ (__  ) /_/ /  /_____/  / /__/ / /_/ / /_/ / /_/ /  
+/____/ .___/            \___/_/\____/\__,_/\__,_/   
+    /_/                                             
+sp-cloud running Spring Boot ${spring-boot.version} 
+version: v1.26.0   updateTime: 2021-10-27
+devdoc: http://sa-plus.dev33.cn
+github: https://github.com/click33/sa-plus

+ 16 - 0
sp-core/sp-nacos/pom.xml

@@ -0,0 +1,16 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.pj</groupId>
+        <artifactId>sp-core</artifactId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sp-nacos</artifactId>
+    <packaging>jar</packaging>
+
+</project>

+ 39 - 0
sp-core/sp-nacos/src/main/resources/bootstrap.properties

@@ -0,0 +1,39 @@
+# --------------------- nacos注册中心 --------------------- 
+### nacos注册中心 - 地址
+spring.cloud.nacos.discovery.server-addr=47.101.143.145:4048
+### nacos注册中心 - 用户
+spring.cloud.nacos.discovery.username=nacos
+### nacos注册中心 - 密码
+spring.cloud.nacos.discovery.password=yie3Rjf@;1,43
+
+# --------------------- nacos配置中心 --------------------- 
+### nacos配置中心 - 地址 [注册中心地址]
+spring.cloud.nacos.config.server-addr=${spring.cloud.nacos.discovery.server-addr}
+### nacos配置中心 - 用户 [注册中心用户名]
+spring.cloud.nacos.config.username=${spring.cloud.nacos.discovery.username}
+### nacos配置中心 - 密码 [注册中心用密码]
+spring.cloud.nacos.config.password=${spring.cloud.nacos.discovery.password}
+### 配置文件前缀
+spring.cloud.nacos.config.prefix=${spring.application.name}
+### 配置文件后缀
+spring.cloud.nacos.config.file-extension=yml
+### 共享配置 (实时刷新) 
+spring.cloud.nacos.config.refreshable-dataids=application-common.yml, application-common-${spring.profiles.active}.yml
+
+# --------------------- sentinel-dashboard 控制台 --------------------- 
+# sentinel dashboard 控制台地址 
+spring.cloud.sentinel.transport.dashboard=127.0.0.1:8002
+
+# --------------------- sentinel-dashboard 集成nacos (将配置储存到nacos中) --------------------- 
+### 取消控制台懒加载 
+spring.cloud.sentinel.eager=true
+### nacos地址、用户名、密码等信息 
+spring.cloud.sentinel.datasource.ds.nacos.server-addr=${spring.cloud.nacos.discovery.server-addr}
+spring.cloud.sentinel.datasource.ds.nacos.username=${spring.cloud.nacos.discovery.username}
+spring.cloud.sentinel.datasource.ds.nacos.password=${spring.cloud.nacos.discovery.password}
+spring.cloud.sentinel.datasource.ds.nacos.dataId=${spring.application.name}-sentinel
+spring.cloud.sentinel.datasource.ds.nacos.groupId=DEFAULT_GROUP
+spring.cloud.sentinel.datasource.ds.nacos.data-type=json
+spring.cloud.sentinel.datasource.ds.nacos.rule-type=flow
+
+

+ 124 - 0
sp-core/sp-nacos/src/main/resources/logback.xml

@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <contextName>market</contextName>
+    <property name="LOG_PATH" value="logs"/>
+    <property name="log.maxFileSize" value="10MB"/>
+    <property name="log.maxFileCnt" value="90"/>
+    <property name="log.totalSizeCap" value="10GB"/>
+
+    <appender name="FILE_DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}/log_debug.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/debug/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>${log.maxFileSize}</maxFileSize>
+            <maxHistory>${log.maxFileCnt}</maxHistory>
+            <totalSizeCap>${log.totalSizeCap}</totalSizeCap>
+        </rollingPolicy>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level{10}[%25.25thread{24}]%-40.40logger{39}|-Line:%-3L:%msg%n
+            </pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <!--            <onMismatch>DENY</onMismatch>-->
+        </filter>
+    </appender>
+
+    <appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}/log_info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/info/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>${log.maxFileSize}</maxFileSize>
+            <maxHistory>${log.maxFileCnt}</maxHistory>
+            <totalSizeCap>${log.totalSizeCap}</totalSizeCap>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level{10}[%25.25thread{24}]%-40.40logger{39}|-Line:%-3L:%msg%n
+            </pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <!--encoder 默认配置为PatternLayoutEncoder-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd
+                HH:mm:ss.SSS}|%highlight(%-5level{10})[%boldYellow(%25.25thread{24})]%gray(%-50.50logger{49})|-Line:%boldYellow(%-3L):%msg%n
+            </pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>info</level>
+        </filter>
+    </appender>
+
+    <appender name="COMM_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}/comm_info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/comm/comm_info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>${log.maxFileSize}</maxFileSize>
+            <maxHistory>${log.maxFileCnt}</maxHistory>
+            <totalSizeCap>${log.totalSizeCap}</totalSizeCap>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <logger name="com.cryann.hsms.driver.netty" additivity="false">
+        <appender-ref ref="COMM_LOG"/>
+    </logger>
+
+    <appender name="SXFX_info_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_PATH}/SxFx_info.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/SxFx/SxFx_info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>${log.maxFileSize}</maxFileSize>
+            <maxHistory>${log.maxFileCnt}</maxHistory>
+            <totalSizeCap>${log.totalSizeCap}</totalSizeCap>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d{yyyy-MM-dd
+                HH:mm:ss.SSS}|%highlight(%-5level{10})[%boldYellow(%25.25thread{24})]%gray(%-50.50logger{49})|-Line:%boldYellow(%-3L):%msg%n
+            </pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+
+    <logger name="org.springframework" level="WARN"/>
+    <logger name="org.hibernate" level="WARN"/>
+    <logger name="com.apache.ibatis" level="TRACE"/>
+    <logger name="java.sql.Connection" level="DEBUG"/>
+    <logger name="java.sql.Statement" level="DEBUG"/>
+    <logger name="java.sql.PreparedStatement" level="DEBUG"/>
+
+    <!-- 生产环境下,将此级别配置为适合的级别,以免日志文件太多或影响程序性能 -->
+    <root level="INFO">
+        <!-- 生产环境将请stdout,testfile去掉 -->
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="FILE_DEBUG"/>
+        <!--<appender-ref ref="FILEWARN"/>-->
+        <appender-ref ref="FILE_INFO"/>
+    </root>
+</configuration>

+ 61 - 0
sp-native/pom.xml

@@ -0,0 +1,61 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>market-server</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>sp-native</artifactId>
+    <packaging>pom</packaging>
+    <modules>
+        <module>sp-gateway</module>
+        <module>sp-boot-admin</module>
+    </modules>
+
+	<!-- 构建配置 -->
+    <build>
+        <plugins>
+            <!-- 打包jar文件时,可配置manifest文件,加入lib包的jar依赖 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                           	<mainClass>${java.run.main.class}</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <!-- 拷贝依赖的jar包到lib目录 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>
+                                ${project.build.directory}/lib
+                            </outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 64 - 0
sp-native/sp-boot-admin/pom.xml

@@ -0,0 +1,64 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sp-native</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sp-boot-admin</artifactId>
+    <packaging>jar</packaging>
+
+	<!-- 指定一些属性 -->
+	<properties> 
+		<java.run.main.class>com.pj.SpBootAdminApplication</java.run.main.class>
+	</properties>
+
+    <dependencies>
+    
+    
+		<!-- ================= 模块依赖 start ================= -->
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-nacos</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+		<!-- ================= 模块依赖 end ================= -->
+    
+	    <!-- nacos 注册中心 -->
+	    <dependency>
+		    <groupId>com.alibaba.cloud</groupId>
+		    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+		</dependency>
+	    <!-- nacos 分布式配置中心 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        
+        <!-- spring-boot-admin 监控台 -->
+        <dependency>
+			<groupId>de.codecentric</groupId>
+			<artifactId>spring-boot-admin-starter-server</artifactId>
+			<version>2.3.0</version>
+		</dependency>
+        <!-- 集成security的登录验证 -->
+        <dependency>
+	        <groupId>org.springframework.boot</groupId>
+	        <artifactId>spring-boot-starter-security</artifactId>
+	    </dependency>
+
+    </dependencies>
+
+
+
+    
+	
+    
+    
+
+</project>

+ 24 - 0
sp-native/sp-boot-admin/src/main/java/com/pj/SpBootAdminApplication.java

@@ -0,0 +1,24 @@
+package com.pj;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+import de.codecentric.boot.admin.server.config.EnableAdminServer;
+
+
+/**
+ * SpringBoot-Admin 监控台
+ * @author kong 
+ */
+@EnableDiscoveryClient			// 
+@SpringBootApplication		// SpringBoot注解
+@EnableAdminServer			// 控制台 
+public class SpBootAdminApplication {
+	
+	public static void main(String[] args) {
+		SpringApplication.run(SpBootAdminApplication.class, args);		
+		System.out.println("\n--------------- SpBootAdminApplication 间空台启动成功 ---------------\n");
+	}
+	
+}

+ 16 - 0
sp-native/sp-boot-admin/src/main/resources/bootstrap.yml

@@ -0,0 +1,16 @@
+# 端口
+server:
+    port: 8003
+
+spring: 
+    # 服务名称 
+    application.name: sp-boot-admin
+    # 当前环境
+    profiles.active: dev
+    
+    # 配置访问用户名和密码 
+    security: 
+        user: 
+            name: admin
+            password: admin
+            

+ 97 - 0
sp-native/sp-gateway/pom.xml

@@ -0,0 +1,97 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sp-native</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>sp-gateway</artifactId>
+    <packaging>jar</packaging>
+
+	<!-- 指定一些属性 -->
+	<properties> 
+		<java.run.main.class>com.pj.SpGatewayApplication</java.run.main.class>
+	</properties>
+
+    <dependencies>
+    
+    
+		<!-- ================= 模块依赖 start ================= -->
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-nacos</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+		<!-- ================= 模块依赖 end ================= -->
+    
+    	<!-- gateway网关 -->
+    	<dependency>
+	        <groupId>org.springframework.cloud</groupId>
+	        <artifactId>spring-cloud-starter-gateway</artifactId>
+	    </dependency>
+	    <!-- nacos 注册中心 -->
+	    <dependency>
+		    <groupId>com.alibaba.cloud</groupId>
+		    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+		</dependency>
+	    <!-- nacos 分布式配置中心 -->
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        
+        <!-- Sa-Token 权限认证(Reactor响应式集成), 在线文档:http://sa-token.dev33.cn/ -->
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-reactor-spring-boot-starter</artifactId>
+		    <version>1.27.0</version>
+		</dependency>
+		<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-dao-redis-jackson</artifactId>
+		    <version>1.27.0</version>
+		</dependency>
+		<dependency>
+		    <groupId>org.apache.commons</groupId>
+		    <artifactId>commons-pool2</artifactId>
+		</dependency>
+        
+	    <!-- gateway 集成 sentinel  -->
+        <!-- <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
+        </dependency> -->
+        
+        <!-- servlet-api -->
+		<!-- <dependency>
+		    <groupId>javax.servlet</groupId>
+		    <artifactId>javax.servlet-api</artifactId>
+		</dependency> -->
+
+        <!-- validation-api -->
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-validator</artifactId>
+           <version>6.0.9.Final</version>
+        </dependency>
+        
+    </dependencies>
+
+
+
+    
+	
+    
+    
+
+</project>

+ 29 - 0
sp-native/sp-gateway/src/main/java/com/pj/SpGatewayApplication.java

@@ -0,0 +1,29 @@
+package com.pj;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+import java.io.File;
+import java.util.Properties;
+
+
+/**
+ * gateway 服务网关-启动 
+ * @author kong 
+ */
+@EnableDiscoveryClient			// 注册中心 
+@SpringBootApplication		// SpringBoot注解
+public class SpGatewayApplication {
+	
+	public static void main(String[] args) {
+		Properties properties = System.getProperties();
+		String rootPath = properties.getProperty("user.dir");
+		SpringApplication application = new SpringApplication(SpGatewayApplication.class);
+		application.addListeners(new ApplicationPidFileWriter(rootPath + File.separator + "app.pid"));
+		application.run(args);
+		System.out.println("\n--------------- SpGatewayApplication 服务网关启动成功 ---------------\n");
+	}
+	
+}

+ 24 - 0
sp-native/sp-gateway/src/main/java/com/pj/more/RouteConfigure.java

@@ -0,0 +1,24 @@
+package com.pj.more;
+
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 以代码方式配置路由转发规则
+ * 
+ * @author kong
+ *
+ */
+@Configuration
+public class RouteConfigure {
+	
+//	@Bean
+//	public RouteLocator myRoutes(RouteLocatorBuilder builder) {
+//	    return builder.routes()
+//	        .route(p -> p
+//	            .path("/sp-admin/**")
+//	            .filters(f -> f.stripPrefix(1).addRequestHeader(SaIdUtil.ID_TOKEN, SaIdUtil.getToken()))
+//	            .uri("lb://sp-admin")
+//	        ).build();
+//	}
+	
+}

+ 33 - 0
sp-native/sp-gateway/src/main/java/com/pj/more/SaIdTokenFilter.java

@@ -0,0 +1,33 @@
+package com.pj.more;
+
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+
+import cn.dev33.satoken.id.SaIdUtil;
+import reactor.core.publisher.Mono;
+
+/**
+ * 全局过滤器,为请求添加 Id-Token 
+ * 
+ * @author kong
+ *
+ */
+@Component
+public class SaIdTokenFilter implements GlobalFilter {
+	
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        ServerHttpRequest newRequest = exchange
+                .getRequest()
+                .mutate()
+                // 为请求追加 Id-Token 参数 
+                .header(SaIdUtil.ID_TOKEN, SaIdUtil.getToken())
+                .build();
+        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
+        return chain.filter(newExchange);
+    }
+    
+}

+ 52 - 0
sp-native/sp-gateway/src/main/java/com/pj/more/SaTokenConfigure.java

@@ -0,0 +1,52 @@
+package com.pj.more;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.reactor.filter.SaReactorFilter;
+import cn.dev33.satoken.router.SaHttpMethod;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.util.SaResult;
+
+/**
+ * Sa-Token 代码方式进行配置 
+ * @author kong 
+ */
+@Configuration
+public class SaTokenConfigure {
+
+    /**
+     * 注册 Sa-Token全局过滤器,解决跨域问题 
+     */
+    @Bean
+    public SaReactorFilter getSaServletFilter() {
+        return new SaReactorFilter()
+        		// 拦截与排除 path 
+        		.addInclude("/**").addExclude("/favicon.ico")
+        		// 全局认证函数 
+        		.setAuth(obj -> {})
+        		// 异常处理函数  
+        		.setError(e -> SaResult.error(e.getMessage()))
+        		// 前置函数:在每次认证函数之前执行
+        		.setBeforeAuth(obj -> {
+        			// ---------- 设置跨域响应头 ----------
+        			SaHolder.getResponse()
+        			// 允许指定域访问跨域资源
+        			.setHeader("Access-Control-Allow-Origin", "*")
+        			// 允许所有请求方式
+        			.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
+        			// 有效时间
+        			.setHeader("Access-Control-Max-Age", "3600")
+        			// 允许的header参数
+        			.setHeader("Access-Control-Allow-Headers", "*");
+        			
+        			// 如果是预检请求,则立即返回到前端 
+        			SaRouter.match(SaHttpMethod.OPTIONS)
+        				.free(r -> System.out.println("-------- OPTIONS预检请求,不做处理"))
+        				.back();
+        		})
+        		;
+    }
+    
+}

+ 10 - 0
sp-native/sp-gateway/src/main/resources/bootstrap.yml

@@ -0,0 +1,10 @@
+# 端口
+server:
+    port: 8080
+
+spring: 
+    # 服务名称 
+    application.name: sp-gateway
+    # 当前环境
+    profiles.active: dev
+    

+ 30 - 0
sp-service/level-one-server/pom.xml

@@ -0,0 +1,30 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sp-service</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>level-one-server</artifactId>
+    <packaging>jar</packaging>
+
+	<!-- 指定一些属性 -->
+	<properties> 
+		<java.run.main.class>com.pj.LevelOneServer</java.run.main.class>
+	</properties>
+
+
+    <dependencies>
+        <!-- 依赖base基础包 -->
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-base</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 36 - 0
sp-service/level-one-server/src/main/java/com/pj/LevelOneServer.java

@@ -0,0 +1,36 @@
+package com.pj;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import com.pj.current.SpCloudUtil;
+
+import java.io.File;
+import java.util.Properties;
+
+/**
+ * 启动类
+ * @author kong
+ */
+@EnableCaching // 启用缓存
+@EnableScheduling // 启动定时任务
+@SpringBootApplication // springboot本尊
+@EnableTransactionManagement // 启动注解事务管理
+@EnableFeignClients		// 启用Feign实现RPC调用  
+public class LevelOneServer {
+	
+	public static void main(String[] args) {
+		Properties properties = System.getProperties();
+		String rootPath = properties.getProperty("user.dir");
+		SpringApplication application = new SpringApplication(LevelOneServer.class);
+		application.addListeners(new ApplicationPidFileWriter(rootPath + File.separator + "app.pid"));
+		application.run(args);
+		SpCloudUtil.printCurrentServiceInfo();
+	}
+
+}

+ 9 - 0
sp-service/level-one-server/src/main/resources/bootstrap.yml

@@ -0,0 +1,9 @@
+# 端口
+server:
+    port: 8013
+
+spring: 
+    # 服务名称 
+    application.name: level-one-server
+    # 当前环境
+    profiles.active: dev

+ 33 - 0
sp-service/level-two-server/.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/

BIN
sp-service/level-two-server/.mvn/wrapper/maven-wrapper.jar


+ 18 - 0
sp-service/level-two-server/.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar

+ 316 - 0
sp-service/level-two-server/mvnw

@@ -0,0 +1,316 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /usr/local/etc/mavenrc ] ; then
+    . /usr/local/etc/mavenrc
+  fi
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        export JAVA_HOME="`/usr/libexec/java_home`"
+      else
+        export JAVA_HOME="/Library/Java/Home"
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+      PRG="$link"
+    else
+      PRG="`dirname "$PRG"`/$link"
+    fi
+  done
+
+  saveddir=`pwd`
+
+  M2_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  M2_HOME=`cd "$M2_HOME" && pwd`
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --unix "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="`which javac`"
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=`which readlink`
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+      if $darwin ; then
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+      else
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+      fi
+      javaHome="`dirname \"$javaExecutable\"`"
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="`\\unset -f command; \\command -v java`"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=`cd "$wdir/.."; pwd`
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' < "$1")"
+  fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    if [ -n "$MVNW_REPOURL" ]; then
+      jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+    else
+      jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+    fi
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+    if $cygwin; then
+      wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
+    fi
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        else
+            wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl -o "$wrapperJarPath" "$jarUrl" -f
+        else
+            curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+        fi
+
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaClass=`cygpath --path --windows "$javaClass"`
+        fi
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" \
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 188 - 0
sp-service/level-two-server/mvnw.cmd

@@ -0,0 +1,188 @@
+@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 "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\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/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
+
+FOR /F "usebackq 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%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.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 "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\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%
+
+cmd /C exit /B %ERROR_CODE%

+ 26 - 0
sp-service/level-two-server/pom.xml

@@ -0,0 +1,26 @@
+<?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>
+        <artifactId>sp-service</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>level-two-server</artifactId>
+    <name>level-two-server</name>
+    <properties>
+        <java.run.main.class>com.pj.LevelTwoServerApplication</java.run.main.class>
+    </properties>
+    <dependencies>
+        <!-- 依赖base基础包 -->
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-base</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 31 - 0
sp-service/level-two-server/src/main/java/com/pj/LevelTwoServerApplication.java

@@ -0,0 +1,31 @@
+package com.pj;
+
+import com.pj.current.SpCloudUtil;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import java.io.File;
+import java.util.Properties;
+
+@EnableCaching // 启用缓存
+@EnableScheduling // 启动定时任务
+@SpringBootApplication // springboot本尊
+@EnableTransactionManagement // 启动注解事务管理
+@EnableFeignClients        // 启用Feign实现RPC调用
+public class LevelTwoServerApplication {
+
+    public static void main(String[] args) {
+        Properties properties = System.getProperties();
+        String rootPath = properties.getProperty("user.dir");
+        SpringApplication application = new SpringApplication(LevelTwoServerApplication.class);
+        application.addListeners(new ApplicationPidFileWriter(rootPath + File.separator + "app.pid"));
+        application.run(args);
+        SpCloudUtil.printCurrentServiceInfo();
+    }
+
+}

+ 5 - 0
sp-service/level-two-server/src/main/resources/bootstrap.yml

@@ -0,0 +1,5 @@
+spring:
+  # ????
+  application.name: level-two-server
+  # ????
+  profiles.active: dev

+ 66 - 0
sp-service/pom.xml

@@ -0,0 +1,66 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>market-server</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>sp-service</artifactId>
+    <packaging>pom</packaging>
+    <modules>
+        <module>sp-admin</module>
+        <module>sp-home</module>
+        <module>level-one-server</module>
+        <module>level-two-server</module>
+        <module>transport-server</module>
+        <module>sp-task</module>
+    </modules>
+
+	<!-- 构建配置 -->
+    <build>
+        <plugins>
+            <!-- 打包jar文件时,可配置manifest文件,加入lib包的jar依赖 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                           	<mainClass>${java.run.main.class}</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+            </plugin>
+            <!-- 拷贝依赖的jar包到lib目录 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>
+                                ${project.build.directory}/lib
+                            </outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+
+</project>

+ 33 - 0
sp-service/sp-admin/pom.xml

@@ -0,0 +1,33 @@
+<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>sp-service</artifactId>
+        <groupId>com.pj</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>sp-admin</artifactId>
+    <packaging>jar</packaging>
+
+	<!-- 指定一些属性 -->
+	<properties> 
+		<java.run.main.class>com.pj.SpAdminApplication</java.run.main.class>
+	</properties>
+
+    <dependencies>
+
+       
+        <!-- 依赖base基础包 -->
+        <dependency>
+            <groupId>com.pj</groupId>
+            <artifactId>sp-base</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        
+    </dependencies>
+
+
+</project>

+ 37 - 0
sp-service/sp-admin/src/main/java/com/pj/SpAdminApplication.java

@@ -0,0 +1,37 @@
+package com.pj;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.ApplicationPidFileWriter;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import com.pj.current.SpCloudUtil;
+
+import java.io.File;
+import java.util.Properties;
+
+/**
+ * 启动类
+ * @author kong
+ */
+@EnableCaching // 启用缓存
+@EnableScheduling // 启动定时任务
+@SpringBootApplication // springboot本尊
+@EnableTransactionManagement // 启动注解事务管理
+@EnableFeignClients		// 启用Feign实现RPC调用 
+public class SpAdminApplication {
+	
+	public static void main(String[] args) {
+		Properties properties = System.getProperties();
+		String rootPath = properties.getProperty("user.dir");
+		SpringApplication application = new SpringApplication(SpAdminApplication.class);
+		application.addListeners(new ApplicationPidFileWriter(rootPath + File.separator + "app.pid"));
+		application.run(args);
+		SpCloudUtil.printCurrentServiceInfo();
+		// 测试服务调用  
+	}
+
+}

+ 76 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdmin.java

@@ -0,0 +1,76 @@
+package com.pj.project4sp.admin;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import lombok.Data;
+
+/**
+ * Model: 系统管理员表
+ * @author kong
+ */
+@Data
+public class SpAdmin implements Serializable  {
+
+	private static final long serialVersionUID = 1L;
+
+
+	/** id,--主键、自增 */
+	public Long id;	
+	
+	/** admin名称 */
+	public String name;	
+	
+	/** 头像地址 */
+	public String avatar;	
+	
+	/** 密码 */
+	public String password;	
+	
+	/** 明文密码 */
+	public String pw;	
+	
+	/** 手机号 */
+	public String phone;	
+	
+	/** 所属角色id */
+	public Integer roleId;	
+	
+	/** 账号状态(1=正常, 2=禁用) */
+	public Integer status;	
+	
+	/** 创建自哪个管理员 */
+	public Long createByAid;	
+	
+	/** 创建时间 */
+	public Date createTime;	
+	
+	/** 上次登陆时间 */
+	public Date loginTime;	
+	
+	/** 上次登陆IP */
+	public String loginIp;	
+	
+	/** 登陆次数 */
+	public Integer loginCount;	
+	
+	
+	// -------- 额外字段 
+	
+	/** 所属角色名称   */
+	private String roleName;	
+
+
+	/** 防止密码被传递到前台  */
+    public String getPassword(){
+    	return "********";
+    }
+    /** 获取真实密码   */
+    @JsonIgnore()
+    public String getPassword2(){
+    	return this.password;
+    }
+	
+}

+ 163 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminController.java

@@ -0,0 +1,163 @@
+package com.pj.project4sp.admin;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.pj.current.satoken.AuthConst;
+import com.pj.project4sp.SP;
+import com.pj.project4sp.admin4password.SpAdminPasswordService;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.so.SoMap;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Controller -- 系统管理员表
+ * @author kong
+ */
+@RestController
+@RequestMapping("/admin/")
+public class SpAdminController {
+
+	@Autowired
+	SpAdminMapper spAdminMapper;
+	
+	@Autowired
+	SpAdminService spAdminService;
+	
+	@Autowired
+	SpAdminPasswordService spAdminPasswordService;
+
+	/** 增  */
+	@RequestMapping("add")
+	AjaxJson add(SpAdmin admin){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);
+		long id = spAdminService.add(admin);
+		return AjaxJson.getSuccessData(id);
+	}
+
+	/** 删 */
+	@RequestMapping("delete")
+	AjaxJson delete(long id){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);	
+		// 不能自己删除自己
+		if(StpUtil.getLoginIdAsLong() == id) {
+			return AjaxJson.getError("不能自己删除自己");
+		}
+		int line = spAdminMapper.delete(id);
+		return AjaxJson.getByLine(line);
+	}
+
+	/** 删 - 根据id列表 */
+	@RequestMapping("deleteByIds")
+	AjaxJson deleteByIds(){
+		// 鉴权
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);	
+		// 不能自己删除自己
+		List<Long> ids = SoMap.getRequestSoMap().getListByComma("ids", long.class); 
+		if(ids.contains(StpUtil.getLoginIdAsLong())) {
+			return AjaxJson.getError("不能自己删除自己");
+		}
+		// 开始删除 
+		int line = SP.publicMapper.deleteByIds("sp_admin", ids);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 改  -  name */
+	@RequestMapping("update")
+	AjaxJson update(SpAdmin obj){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);	
+		SpAdminUtil.checkName(obj.getId(), obj.getName());
+		int line = spAdminMapper.update(obj);
+		return AjaxJson.getByLine(line);
+	}
+
+	/** 查  */
+	@RequestMapping("getById")
+	AjaxJson getById(long id){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);
+		Object data = spAdminMapper.getById(id);
+		return AjaxJson.getSuccessData(data);
+	}
+
+	/** 查 - 集合 */
+	@RequestMapping("getList")
+	AjaxJson getList(){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);	
+		SoMap so = SoMap.getRequestSoMap();
+		List<SpAdmin> list = spAdminMapper.getList(so.startPage());
+		return AjaxJson.getPageData(so.getDataCount(), list);
+	}
+
+	/** 改密码 */
+	@RequestMapping("updatePassword")
+	AjaxJson updatePassword(long id, String password){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);	
+		int line = spAdminPasswordService.updatePassword(id, password);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 改头像  */
+	@RequestMapping("updateAvatar")
+	AjaxJson updateAvatar(long id, String avatar){
+		StpUtil.checkPermission(AuthConst.ADMIN_LIST);	
+		int line = SP.publicMapper.updateColumnById("sp_admin", "avatar", avatar, id);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 改状态  */
+	@RequestMapping("updateStatus")
+	public AjaxJson updateStatus(long adminId, int status) {
+		StpUtil.checkPermission(AuthConst.R1);
+
+		// 验证对方是否为超管(保护超管不受摧残) 
+		if(StpUtil.hasPermission(adminId, AuthConst.R1)){
+			return AjaxJson.getError("抱歉,对方角色为系统超级管理员,您暂无权限操作");
+		}
+		
+		// 修改状态 
+		SP.publicMapper.updateColumnById("sp_admin", "status", status, adminId);
+		// 如果是禁用,就停掉其秘钥有效果性,使其账号的登录状态立即无效 
+		if(status == 2) {
+			StpUtil.logout(adminId);
+		}
+		return AjaxJson.getSuccess();
+	}
+	
+	/** 改角色  */
+	@RequestMapping("updateRole")
+	AjaxJson updateRole(long id, String roleId){
+		StpUtil.checkPermission(AuthConst.R1);
+		int line = SP.publicMapper.updateColumnById("sp_admin", "role_id", roleId, id);
+		return AjaxJson.getByLine(line);
+	}
+	
+	/** 返回当前admin信息  */
+	@RequestMapping("getByCurr")
+	AjaxJson getByCurr() {
+		SpAdmin admin = SpAdminUtil.getCurrAdmin();
+		return AjaxJson.getSuccessData(admin);
+	}
+	
+	/** 当前admin修改信息 */
+	@RequestMapping("updateInfo")
+	AjaxJson updateInfo(SpAdmin obj){
+		obj.setId(StpUtil.getLoginIdAsLong());
+		SpAdminUtil.checkName(obj.getId(), obj.getName());
+		int line = spAdminMapper.update(obj);
+		return AjaxJson.getByLine(line);
+	}
+	
+	
+	
+	
+	
+	
+	
+	
+
+
+}

+ 68 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminMapper.java

@@ -0,0 +1,68 @@
+package com.pj.project4sp.admin;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.pj.utils.so.SoMap;
+
+/**
+ * Mapper: 系统管理员表
+ * @author kong
+ */
+@Mapper
+public interface SpAdminMapper {
+
+
+	/**
+	 * 增 #{name}, #{password}, #{roleId} 
+	 * @param obj
+	 * @return
+	 */
+	int add(SpAdmin obj);
+
+	/**
+	 * 删 
+	 * @param id
+	 * @return
+	 */
+	int delete(long id);
+
+	/**
+	 * 改 
+	 * @param obj
+	 * @return
+	 */
+	int update(SpAdmin obj);
+
+	/**
+	 * 查 
+	 * @param id
+	 * @return
+	 */
+	SpAdmin getById(long id);
+
+	/**
+	 * 查  
+	 * @param so
+	 * @return
+	 */
+	List<SpAdmin> getList(SoMap so);
+
+	/**
+	 * 查询,根据name 
+	 * @param name
+	 * @return
+	 */
+	SpAdmin getByName(String name);
+	
+	/**
+	 * 查询,根据 phone  
+	 * @param phone
+	 * @return
+	 */
+	SpAdmin getByPhone(String phone);
+
+
+
+}

+ 100 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminMapper.xml

@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pj.project4sp.admin.SpAdminMapper">
+
+
+	<!-- 增 -->
+	<insert id="add">
+		insert into
+		sp_admin(name, avatar, phone, role_id, create_by_aid, create_time)
+		values (#{name}, #{avatar}, #{phone}, #{roleId}, #{createByAid}, now())
+	</insert>
+
+
+	<!-- 删 -->
+	<delete id="delete">
+		delete from sp_admin where id = #{id} 
+	</delete>
+
+
+	<!-- 改 -->
+	<delete id="update">
+		update sp_admin set 
+		name = #{name} 
+		where id = #{id} 
+	</delete>
+	
+	<!-- 自己改自己 -->
+	<!-- <delete id="updateBy">
+		update sp_admin set 
+		name = #{name} 
+		where id = #{id} 
+	</delete> -->
+
+	<!-- =================== 查询相关 =================== -->
+
+	<!-- 通用映射 -->
+	<resultMap id="model" type="com.pj.project4sp.admin.SpAdmin">
+		<result property="id" column="id" />
+		<result property="name" column="name" />
+		<result property="avatar" column="avatar" />
+		<result property="password" column="password" />
+		<result property="pw" column="pw" />
+		<result property="phone" column="phone" />
+		<result property="roleId" column="role_id" />
+		<result property="status" column="status" />
+		<result property="createByAid" column="create_by_aid" />
+		<result property="createTime" column="create_time" />
+		<result property="loginTime" column="login_time" />
+		<result property="loginIp" column="login_ip" />
+		<result property="loginCount" column="login_count" />
+		<result property="roleName" column="role_name" />
+	</resultMap>
+	
+	<!-- 查询sql -->
+	<sql id="select_sql">
+		select *,
+		(select name from sp_role where id = sp_admin.role_id) as role_name 
+		from sp_admin 
+	</sql>
+
+
+	<!-- 查询,根据id -->
+	<select id="getById" resultMap="model">
+		<include refid="select_sql"></include>
+		where id = #{id}
+	</select>
+
+	<!-- 查询,根据名称 -->
+	<select id="getByName" resultMap="model">
+		<include refid="select_sql"></include>
+		where name = #{name}
+	</select>
+
+	<!-- 查询,根据名称 -->
+	<select id="getByPhone" resultMap="model">
+		<include refid="select_sql"></include>
+		where phone = #{phone}
+	</select>
+
+
+	<!-- 查询 -->
+	<select id="getList" resultMap="model">
+		<include refid="select_sql"></include>
+		where 1=1
+		<if test=' this.has("id")  '>and id = #{id} </if>
+		<if test=' this.has("name")  '>and name like concat('%', #{name}, '%')  </if>
+		<if test=' this.has("roleId")  '>and role_id = #{roleId} </if>
+		order by 
+		<choose>
+			<when test='sort_type == 0'>id desc</when> 
+			<when test='sort_type == 1'>id asc</when> 
+			<when test='sort_type == 2'>login_time desc</when> 
+			<when test='sort_type == 3'>login_count desc</when> 
+		 	<otherwise>id desc</otherwise>
+		 </choose>
+	</select>
+	
+
+
+</mapper>

+ 55 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminService.java

@@ -0,0 +1,55 @@
+package com.pj.project4sp.admin;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.pj.project4sp.SP;
+import com.pj.project4sp.admin4password.SpAdminPasswordService;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Service: admin管理员
+ * @author kong
+ *
+ */
+@Service
+public class SpAdminService {
+
+	
+	@Autowired
+	SpAdminMapper spAdminMapper;
+	
+	@Autowired
+	SpAdminPasswordService spAdminPasswordService;
+	
+	
+	/**
+	 * 管理员添加一个管理员 
+	 * @param admin
+	 * @return
+	 */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)	
+	public long add(SpAdmin admin) {
+		// 检查姓名是否合法
+		SpAdminUtil.checkAdmin(admin);
+		
+		// 创建人,为当前账号  
+		admin.setCreateByAid(StpUtil.getLoginIdAsLong());	
+		// 开始添加
+		spAdminMapper.add(admin);	
+		// 获取主键
+		long id = SP.publicMapper.getPrimarykey();
+		// 更改密码(md5与明文)
+		spAdminPasswordService.updatePassword(id, admin.getPassword2());	
+		
+		// 返回主键 
+		return id;
+	}
+	
+	
+	
+	
+}

+ 99 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin/SpAdminUtil.java

@@ -0,0 +1,99 @@
+package com.pj.project4sp.admin;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.pj.utils.sg.AjaxError;
+import com.pj.utils.sg.NbUtil;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * admin工具类 
+ * @author kong
+ *
+ */
+@Component
+public class SpAdminUtil {
+
+	
+	static SpAdminMapper spAdminMapper;
+	@Autowired
+	public void setSpAdminMapper(SpAdminMapper spAdminMapper) {
+		SpAdminUtil.spAdminMapper = spAdminMapper;
+	}
+	
+	
+	/**
+	 * 当前admin
+	 * @return
+	 */
+	public static SpAdmin getCurrAdmin() {
+		long adminId = StpUtil.getLoginIdAsLong();
+		return spAdminMapper.getById(adminId);
+	}
+	
+	/**
+	 * 检查指定姓名是否合法 ,如果不合法,则抛出异常 
+	 * @param adminId
+	 * @param name
+	 * @return
+	 */
+	public static boolean checkName(long adminId, String name) {
+		if(NbUtil.isNull(name)) {
+			throw AjaxError.get("账号名称不能为空");
+		}
+		if(NbUtil.isNumber(name)) {
+			throw AjaxError.get("账号名称不能为纯数字");
+		}
+//		if(name.startsWith("a")) {
+//			throw AjaxException.get("账号名称不能以字母a开头");
+//		}
+		// 如果能查出来数据,而且不是本人,则代表与已有数据重复
+		SpAdmin a2 = spAdminMapper.getByName(name);
+		if(a2 != null && a2.getId() != adminId) {	
+			throw AjaxError.get("账号名称已有账号使用,请更换");
+		} 
+		return true;
+	}
+	
+	/**
+	 * 检查整个admin是否合格 
+	 * @param a
+	 * @return
+	 */
+	public static boolean checkAdmin(SpAdmin a) {
+		// 检查姓名 
+		checkName(a.getId(), a.getName());
+		// 检查密码 
+		if(a.getPassword2().length() < 4) {
+			throw new AjaxError("密码不得低于4位");
+		}
+		return true;
+	}
+	
+	
+	
+	/**
+	 * 指定的name是否可用 
+	 * @param name
+	 * @return
+	 */
+	public static boolean nameIsOk(String name) {
+		SpAdmin a2 = spAdminMapper.getByName(name);
+		if(a2 == null) {
+			return true;
+		}
+		return false;
+	}
+	
+	
+
+
+
+
+
+
+	
+	
+}

+ 73 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminController.java

@@ -0,0 +1,73 @@
+package com.pj.project4sp.admin4login;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.pj.project4sp.admin.SpAdmin;
+import com.pj.project4sp.admin.SpAdminUtil;
+import com.pj.project4sp.role4permission.SpRolePermissionService;
+import com.pj.project4sp.spcfg.SpCfgUtil;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.sg.NbUtil;
+import com.pj.utils.so.SoMap;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * admin账号相关的接口 
+ * @author kong
+ *
+ */
+@RestController
+@RequestMapping("/AccAdmin/")
+public class SpAccAdminController {
+
+	
+	@Autowired
+	SpAccAdminService spAccAdminService;
+	
+	@Autowired
+	SpRolePermissionService spRolePermissionService;
+	
+	
+	/** 账号、密码登录  */
+	@RequestMapping("doLogin")
+	AjaxJson doLogin(String key, String password) {
+		// 1、验证参数 
+		if(NbUtil.isOneNull(key, password)) {
+			return AjaxJson.getError("请提供key与password参数");
+		}
+		return spAccAdminService.doLogin(key, password);
+	}
+	
+	
+	/** 退出登录  */
+	@RequestMapping("doExit")
+	AjaxJson doExit() {
+		StpUtil.logout();
+		return AjaxJson.getSuccess();
+	}
+	
+
+	/** 管理员登录后台时需要返回的信息 */
+	@RequestMapping("fristOpenAdmin")
+	AjaxJson fristOpenAdmin(HttpServletRequest request) {
+		// 当前admin
+		SpAdmin admin = SpAdminUtil.getCurrAdmin();
+		
+		// 组织参数 (admin信息,权限信息,配置信息)
+		SoMap map = new SoMap();
+		map.set("admin", SpAdminUtil.getCurrAdmin());	
+		map.set("per_list", spRolePermissionService.getPcodeByRid2(admin.getRoleId()));				
+		map.set("app_cfg", SpCfgUtil.getAppCfg());	
+		return AjaxJson.getSuccessData(map); 
+	}
+	
+	
+	
+	
+	
+}

+ 22 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminMapper.java

@@ -0,0 +1,22 @@
+package com.pj.project4sp.admin4login;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 账号相关 
+ * @author kong
+ *
+ */
+@Mapper
+public interface SpAccAdminMapper {
+
+	/**
+	 * 指定id的账号成功登录一次 
+	 * @param id
+	 * @param loginIp
+	 * @return
+	 */
+	public int successLogin(@Param("id")long id, @Param("loginIp")String loginIp);
+	
+}

+ 17 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminMapper.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pj.project4sp.admin4login.SpAccAdminMapper">
+
+
+	<!-- 指定id的账号成功登录一次  -->
+	<update id="successLogin">
+		update sp_admin set 
+		login_ip = #{loginIp},
+		login_time = NOW(),
+		login_count = login_count + 1
+		where id = #{id}
+	</update>
+
+
+
+</mapper>

+ 136 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4login/SpAccAdminService.java

@@ -0,0 +1,136 @@
+package com.pj.project4sp.admin4login;
+
+
+import java.util.Date;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.pj.current.config.SystemObject;
+import com.pj.project4sp.SP;
+import com.pj.project4sp.admin.SpAdmin;
+import com.pj.project4sp.admin.SpAdminMapper;
+import com.pj.project4sp.role4permission.SpRolePermissionService;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.sg.NbUtil;
+import com.pj.utils.sg.WebNbUtil;
+import com.pj.utils.so.SoMap;
+
+import cn.dev33.satoken.spring.SpringMVCUtil;
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * service:admin账号相关
+ * @author kong
+ *
+ */
+@Service
+public class SpAccAdminService {
+
+	
+
+	@Autowired
+	SpAccAdminMapper spAccAdminMapper;
+
+	@Autowired
+	SpAdminMapper spAdminMapper;
+	
+	@Autowired
+	SpRolePermissionService spRolePermissionService;
+	
+	
+	/**
+	  * 登录 
+	 * @param name 店铺名称
+	 * @param password 店铺密码 
+	 * @return
+	 */
+	AjaxJson doLogin(String key, String password) {
+		
+		// 0、判断 way (1=ID, 2=昵称,3=手机号  )
+    	int way = 2;	
+    	if(NbUtil.isNumber(key) == true){
+    		way = 1;
+    		if(key.length() == 11){
+    			way = 3;
+    		}
+    	}
+		
+		// 2、获取admin
+        SpAdmin admin = null;	
+        if(way == 1) {
+        	admin = spAdminMapper.getById(Long.parseLong(key)); 
+        }
+        if(way == 2) {
+        	admin = spAdminMapper.getByName(key); 
+        }
+        if(way == 3) {
+        	admin = spAdminMapper.getByPhone(key); 
+        }
+        
+
+        // 3、开始验证
+        if(admin == null){
+        	return AjaxJson.getError("无此账号");	
+        }
+        if(NbUtil.isNull(admin.getPassword2())) {
+        	return AjaxJson.getError("此账号尚未设置密码,无法登陆");
+        }
+        String md5Password = SystemObject.getPasswordMd5(admin.getId(), password);
+        if(admin.getPassword2().equals(md5Password) == false){
+        	return AjaxJson.getError("密码错误");	
+        }
+        
+        // 4、是否禁用
+        if(admin.getStatus() == 2) {
+        	return AjaxJson.getError("此账号已被禁用,如有疑问,请联系管理员");	
+        }
+
+        // =========== 至此, 已登录成功 ============ 
+        successLogin(admin);
+        StpUtil.login(admin.getId()); 		
+        
+        // 组织返回参数  
+		SoMap map = new SoMap();
+		map.put("admin", admin);
+		map.put("per_list", spRolePermissionService.getPcodeByRid2(admin.getRoleId()));
+		map.put("tokenInfo", StpUtil.getTokenInfo());
+		return AjaxJson.getSuccessData(map);	
+	}
+	
+	
+	/**
+	 * 指定id的账号成功登录一次 (修改最后登录时间等数据 )
+	 * @param s
+	 * @return
+	 */
+	public int successLogin(SpAdmin s){
+		String loginIp = WebNbUtil.getIP(SpringMVCUtil.getRequest());
+		int line = spAccAdminMapper.successLogin(s.getId(), loginIp);
+		if(line > 0) {
+	        s.setLoginIp(loginIp);
+	        s.setLoginTime(new Date());
+	        s.setLoginCount(s.getLoginCount() + 1);
+		}
+        return line;
+	}
+	
+	/**
+	 * 修改手机号  
+	 * @param adminId
+	 * @param newPhone
+	 * @return
+	 */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)
+	public AjaxJson updatePhone(long adminId, String newPhone) {
+		// 修改admin手机号
+		int line = SP.publicMapper.updateColumnById("sys_admin", "phone", newPhone, adminId);
+		return AjaxJson.getByLine(line);
+	}
+	
+	
+	
+	
+}

+ 50 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4password/SpAdminPasswordController.java

@@ -0,0 +1,50 @@
+package com.pj.project4sp.admin4password;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.pj.current.config.SystemObject;
+import com.pj.project4sp.admin.SpAdmin;
+import com.pj.project4sp.admin.SpAdminUtil;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.sg.NbUtil;
+
+/**
+ * admin表 密码相关 
+ * 
+ * @author shengzhang
+ */
+@RestController
+@RequestMapping("/AdminPassword/")
+public class SpAdminPasswordController {
+
+	
+	@Autowired
+	SpAdminPasswordService spAdminPasswordService;
+
+	/** 指定用户修改自己密码 */
+	@RequestMapping("update")
+	AjaxJson updatePassword(String oldPwd, String newPwd) {
+		// 1、转md5
+		SpAdmin a = SpAdminUtil.getCurrAdmin();
+		String oldPwdMd5 = SystemObject.getPasswordMd5(a.getId(), oldPwd);
+		
+		// 2、验证
+		if(NbUtil.isNull(a.getPassword2()) && NbUtil.isNull(oldPwd)) {
+			// 如果没有旧密码,则不用取验证 
+		} else {
+			if(oldPwdMd5.equals(a.getPassword2()) == false) {
+				return AjaxJson.getError("旧密码输入错误");
+			}
+		}
+		
+		// 3、开始改 
+		int line = spAdminPasswordService.updatePassword(a.getId(), newPwd);
+		return AjaxJson.getByLine(line);
+	}
+	
+	
+	
+	
+}

+ 34 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/admin4password/SpAdminPasswordService.java

@@ -0,0 +1,34 @@
+package com.pj.project4sp.admin4password;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.pj.current.config.SystemObject;
+import com.pj.project4sp.SP;
+
+/**
+ * 用户表 密码相关 
+ * @author kong
+ *
+ */
+@Service
+public class SpAdminPasswordService {
+
+	
+	// REQUIRED=如果调用方有事务  就继续使用调用方的事务 
+	/** 修改一个admin的密码为  */
+	@Transactional(rollbackFor = Exception.class, propagation=Propagation.REQUIRED)	
+	public int updatePassword(long adminId, String password) {
+		// 更改密码 
+		SP.publicMapper.updateColumnById("sp_admin", "password", SystemObject.getPasswordMd5(adminId, password), adminId);
+		if(SystemObject.config.getIsPw()) {
+			// 明文密码 
+			SP.publicMapper.updateColumnById("sp_admin", "pw", password, adminId);		
+			return 2;
+		}
+		return 1;
+	}
+	
+	
+}

+ 6 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/package-info.java

@@ -0,0 +1,6 @@
+
+
+/**
+ * 此模块为sa-plus的代码
+ */
+package com.pj.project4sp;

+ 90 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/redis4console/RedisConsoleController.java

@@ -0,0 +1,90 @@
+package com.pj.project4sp.redis4console;
+
+import java.util.List;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.pj.current.satoken.AuthConst;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.so.SoMap;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * redis相关操作 
+ * @author kong 
+ *
+ */
+@RestController
+@RequestMapping("/RedisConsole/")
+public class RedisConsoleController {
+
+	/** 获取一些基本预览信息  */
+	@RequestMapping("getPreInfo")
+	public AjaxJson getPreInfo() {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		SoMap so = RedisConsoleUtil.getInfo();
+		return AjaxJson.getSuccessData(so);
+	}
+
+	/** 查询key集合   */
+	@RequestMapping("getKeys")
+	public AjaxJson getKeys(String k) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		List<String> keys = RedisConsoleUtil.getKeys(k);
+		return AjaxJson.getSuccessData(keys);
+	}
+	
+	/** 查询某个值的详细信息  */
+	@RequestMapping("getByKey")
+	public AjaxJson getByKey(String key) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		SoMap soMap = RedisConsoleUtil.getByKey(key);
+		return AjaxJson.getSuccessData(soMap);
+	}
+	
+	/** 添加一个键值  */
+	@RequestMapping("set")
+	public AjaxJson set(String key, String value, long ttl) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		RedisConsoleUtil.setBySeconds(key, value, ttl);
+		return AjaxJson.getSuccess();
+	}
+
+	/** 删除一个键值  */
+	@RequestMapping("del")
+	public AjaxJson del(String key) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		RedisConsoleUtil.del(key);
+		return AjaxJson.getSuccess();
+	}
+	
+	/** 修改一个值的value  */
+	@RequestMapping("updateValue")
+	public AjaxJson updateValue(String key, String value) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		RedisConsoleUtil.updateValue(key, value);
+		return AjaxJson.getSuccess();
+	}
+	
+	/** 修改一个值的ttl  */
+	@RequestMapping("updateTtl")
+	public AjaxJson updateTtl(String key, long ttl) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);
+		RedisConsoleUtil.updateTtl(key, ttl);
+		return AjaxJson.getSuccess();
+	}
+	
+	/** 删除多个键值  */
+	@RequestMapping("deleteByKeys")
+	public AjaxJson deleteByKeys(@RequestParam(value="key[]") List<String> key) {
+		StpUtil.checkPermission(AuthConst.REDIS_CONSOLE);	
+		for (String k : key) {
+			RedisConsoleUtil.del(k);
+		}
+		return AjaxJson.getSuccess();
+	}
+	
+}

+ 181 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/redis4console/RedisConsoleUtil.java

@@ -0,0 +1,181 @@
+package com.pj.project4sp.redis4console;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import com.pj.utils.sg.AjaxError;
+import com.pj.utils.so.SoMap;
+
+
+/**
+ * redis 控制台相关操作 util 
+ * @author kong
+ *
+ */
+@Component
+public class RedisConsoleUtil {
+
+	
+	static String dbN;
+
+	/** 默认超时时间,单位周,此为一周 */
+	public static long ttl = 24* 7;	
+
+	/** 最大加载数量 */
+	static long loadMax = 10000;
+
+	/** string专用 */
+	static StringRedisTemplate stringRedisTemplate;
+	@Autowired
+	public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplates, @Value("${spring.redis.database}") String dbN) {
+		RedisConsoleUtil.stringRedisTemplate = stringRedisTemplates;
+		RedisConsoleUtil.dbN = dbN;
+	}
+
+	
+	
+	/** 获取reids信息  */
+	public static SoMap getInfo() {
+		// 加载所有信息  
+		Properties info = stringRedisTemplate.getRequiredConnectionFactory().getConnection().info();
+//		System.out.println(info);
+		SoMap map = new SoMap();
+		for (String key : info.stringPropertyNames()) {
+			map.put(key, info.getProperty(key));
+		}
+		
+		// 加载所有信息 
+		SoMap so = new SoMap();
+		so.set("keys_count", getKeyCount(map));	// key 总数 
+		so.set("keyspace_hits", map.get("keyspace_hits"));	// 被命中个数 
+		so.set("used_memory_human", map.get("used_memory_human"));	// 已经占用内存数量 
+		so.set("used_memory_peak_human", map.get("used_memory_peak_human"));	// 内存消耗峰值 
+		so.set("uptime_in_seconds", map.get("uptime_in_seconds"));	// redis 已经启动的秒数 
+		so.set("isGtMax", so.getLong("keys_count") > loadMax);	// 是否已经超过了最大值 
+		
+		return so;
+	}
+	
+	
+
+	/** 获取keys列表   */
+	public static List<String> getKeys(String k) {
+
+		// 如果为空,则查询所有 
+		if(k == null || k.equals("")) {
+			k = "*";
+		}
+		
+		// 检查是否超过上限 
+		Set<String> keysSet = stringRedisTemplate.keys(k);
+		AjaxError.throwBy(keysSet.size() > loadMax, 501, "key值数量超" + loadMax + "<br/>为性能考虑无法返回数据,请更换筛选条件");
+		
+		// 排序
+		List<String> keys = new ArrayList<String>();
+		keys.addAll(keysSet);
+		
+		// 按照字典排序 
+		Collections.sort(keys, new Comparator<String>() {  
+            @Override  
+            public int compare(String o1, String o2) {  
+                Comparator<Object> com = Collator.getInstance(java.util.Locale.CHINA);  
+                return com.compare(o1, o2);  
+  
+            }  
+        });
+
+		return keys;
+	}
+
+
+	/** 获取单个的详情 */
+	public static SoMap getByKey(String key) {
+		// 键值 
+		String value = stringRedisTemplate.opsForValue().get(key);
+		// 过期时间 
+		long expire = stringRedisTemplate.getExpire(key);	
+		
+		SoMap soMap = new SoMap()
+				.set("key", key)
+				.set("value", value)
+				.set("ttl", expire);
+		return soMap;
+	}
+	
+	/** 写入一个值  */
+	public static void setBySeconds(String key, String value, long timeout) {
+		stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
+	}
+	
+	/**  删除一个值  */
+	public static void del(String key) {
+		stringRedisTemplate.delete(key);
+	}
+
+	/** 修改一个值的value  */
+	public static void updateValue(String key, String value) {
+		long expire = stringRedisTemplate.getExpire(key);
+//		System.err.println(expire);
+		// 1 = 永久 
+		if(expire == -1) {
+			stringRedisTemplate.opsForValue().set(key, value);
+			return;
+		}
+		// -2 = 无此键 
+		if(expire == -2) {
+			return;
+		}
+		stringRedisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
+	}
+
+	/** 修改一个值的ttl  */
+	public static void updateTtl(String key, long ttl) {
+		if(ttl <= 0) {
+			String value = stringRedisTemplate.opsForValue().get(key);
+			stringRedisTemplate.opsForValue().set(key, value);
+			return;
+		}
+		stringRedisTemplate.expire(key, ttl, TimeUnit.SECONDS);
+	}
+	
+	/** 根据info获取当前 key总数  */
+	private static long getKeyCount(SoMap map) {
+		long keysCount = 0;
+		try {
+			// 计算 key 总数
+			String dbName = dbN;
+			String dbInfo = map.getString("db" + dbName);
+			if(dbInfo != null) {
+				String[] arr = dbInfo.split(",");
+				for (String item : arr) {
+					String[] arr2 = item.split("=");
+					if("keys".equals(arr2[0])) {
+						keysCount = Long.valueOf(arr2[1]);
+					}
+				}
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return keysCount;
+	}
+	
+	
+	
+
+	
+	
+	
+	
+}

+ 35 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRole.java

@@ -0,0 +1,35 @@
+package com.pj.project4sp.role;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import lombok.Data;
+
+/**
+ * Model: 系统角色表
+ * @author kong
+ */
+@Data
+public class SpRole implements Serializable  {
+
+	private static final long serialVersionUID = 1L;
+
+	// ---------- 表中字段 ----------
+	/** 角色id,--主键、自增 */
+	public Long id;	
+	
+	/** 角色名称, 唯一约束 */
+	public String name;	
+	
+	/** 角色详细描述 */
+	public String info;	
+	
+	/** 是否锁定(1=是,2=否), 锁定之后不可随意删除, 防止用户误操作 */
+	public Integer isLock;	
+	
+	/** 创建时间 */
+	public Date createTime;	
+
+
+
+}

+ 92 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRoleController.java

@@ -0,0 +1,92 @@
+package com.pj.project4sp.role;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.pj.current.satoken.AuthConst;
+import com.pj.project4sp.SP;
+import com.pj.utils.sg.AjaxError;
+import com.pj.utils.sg.AjaxJson;
+import com.pj.utils.so.SoMap;
+
+import cn.dev33.satoken.stp.StpUtil;
+
+/**
+ * Controller: 系统角色表
+ * @author kong
+ */
+@RestController
+@RequestMapping("/role/")
+public class SpRoleController {
+
+	/** 底层Mapper依赖 */
+	@Autowired
+	SpRoleMapper spRoleMapper;
+
+	/** 增 */
+	@RequestMapping("add")
+	@Transactional(rollbackFor = Exception.class)
+	AjaxJson add(SpRole s, HttpServletRequest request){
+		StpUtil.checkPermission(AuthConst.ROLE_LIST);
+		// 检验
+		if(spRoleMapper.getById(s.getId()) != null) {
+			return AjaxJson.getError("此id已存在,请更换");
+		}
+		SpRoleUtil.checkRoleThrow(s);
+		int line = spRoleMapper.add(s);
+		AjaxError.throwByLine(line, "添加失败");
+		// 返回这个对象 
+		long id = s.getId();
+		if(id == 0) {
+			id = SP.publicMapper.getPrimarykey();
+		}
+		return AjaxJson.getSuccessData(spRoleMapper.getById(id));
+	}
+
+	/** 删 */
+	@RequestMapping("delete")
+	AjaxJson delete(long id, HttpServletRequest request){
+		StpUtil.checkPermission(AuthConst.R1);	
+		StpUtil.checkPermission(AuthConst.ROLE_LIST);	
+		int line = spRoleMapper.delete(id);
+		return AjaxJson.getByLine(line);
+	}
+
+	/** 改 */ 
+	@RequestMapping("update")
+	AjaxJson update(SpRole s){
+		StpUtil.checkPermission(AuthConst.R1);	
+		StpUtil.checkPermission(AuthConst.ROLE_LIST);	
+		SpRoleUtil.checkRoleThrow(s);
+		int line = spRoleMapper.update(s);
+		return AjaxJson.getByLine(line);
+	}
+
+	/** 查 */ 
+	@RequestMapping("getById")
+	AjaxJson getById(long id){
+		StpUtil.checkPermission(AuthConst.R99);	
+		SpRole s = spRoleMapper.getById(id);
+		return AjaxJson.getSuccessData(s);
+	}
+
+	/** 查 - 集合  */
+	@RequestMapping("getList")
+	AjaxJson getList(){
+		StpUtil.checkPermission(AuthConst.R99);	
+		SoMap so = SoMap.getRequestSoMap();
+		List<SpRole> list = spRoleMapper.getList(so);
+		return AjaxJson.getSuccessData(list);
+	}
+
+
+	
+	
+
+}

+ 60 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRoleMapper.java

@@ -0,0 +1,60 @@
+package com.pj.project4sp.role;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.pj.utils.so.SoMap;
+
+/**
+ * Mapper: 系统角色表
+ * @author kong
+ */
+@Mapper
+public interface SpRoleMapper {
+
+
+	/**
+	 * 增 
+	 * @param obj
+	 * @return
+	 */
+	int add(SpRole obj);
+
+	/**
+	 * 删
+	 * @param id
+	 * @return
+	 */
+	int delete(long id);
+
+	/**
+	 * 改 
+	 * @param obj
+	 * @return
+	 */
+	int update(SpRole obj);
+
+	/**
+	 *  查 
+	 * @param id
+	 * @return
+	 */
+	SpRole getById(long id);
+
+	/**
+	 * 查 
+	 * @param soMap
+	 * @return
+	 */
+	List<SpRole> getList(SoMap soMap);
+
+
+	/**
+	 * 查,根据角色名字
+	 * @param name
+	 * @return
+	 */
+	SpRole getByRoleName(String name);
+
+}

+ 62 - 0
sp-service/sp-admin/src/main/java/com/pj/project4sp/role/SpRoleMapper.xml

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.pj.project4sp.role.SpRoleMapper">
+
+
+	<!-- 增 -->
+	<insert id="add" >
+		insert into 
+		sp_role(id, name, info, is_lock, create_time) 
+		values (#{id}, #{name}, #{info}, 2, now())
+	</insert>
+
+
+	<!-- 删 -->
+	<delete id="delete" >
+		delete from sp_role 
+		where id = #{id}
+	</delete>
+
+
+	<!-- 改 -->
+	<update id="update" >
+		update sp_role set 
+		name = #{name}, 
+		info = #{info}
+		where id=#{id}
+	</update>
+
+
+	<!-- 通用映射 -->
+	<resultMap id="model" type="com.pj.project4sp.role.SpRole">
+		<result property="id" column="id" />
+		<result property="name" column="name" />
+		<result property="info" column="info" />
+		<result property="isLock" column="is_lock" />
+		<result property="createTime" column="create_time" />
+	</resultMap>
+
+	<!-- 查 -->
+	<select id="getById" resultMap="model" >
+		select * from sp_role 
+		where id = #{id}
+	</select>
+
+
+	<!-- 查询 -->
+	<select id="getList" resultMap="model" >
+		select * from sp_role where 1=1 
+		<if test=' this.has("name")  '>
+			and name like concat('%', #{name}, '%')
+		</if>
+	</select>
+
+	<!-- 查 - 根据角色名字 -->
+	<select id="getByRoleName" resultMap="model">
+		select * from sp_role 
+		where name = #{name}
+	</select>
+
+
+	
+</mapper>

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно