everydatestudy 3 anos atrás
pai
commit
684392c69a
58 arquivos alterados com 4088 adições e 641 exclusões
  1. 2 2
      .gitignore
  2. 33 0
      java/sp-app/bin/.gitignore
  3. 148 0
      java/sp-app/bin/pom.xml
  4. 33 0
      java/sp-app/bin/src/main/assembly/assembly.xml
  5. 5 0
      java/sp-app/bin/src/main/assembly/bin/restart.sh
  6. 42 0
      java/sp-app/bin/src/main/assembly/bin/start.bat
  7. 26 0
      java/sp-app/bin/src/main/assembly/bin/start.sh
  8. 10 0
      java/sp-app/bin/src/main/assembly/bin/stop.sh
  9. 39 0
      java/sp-app/bin/src/main/resources/application-dev.properties
  10. 1 0
      java/sp-app/bin/src/main/resources/application-prod.properties
  11. 142 0
      java/sp-app/bin/src/main/resources/application.properties
  12. 652 0
      java/sp-app/bin/src/main/resources/db/aj_app_sp.sql
  13. BIN
      java/sp-app/bin/src/main/resources/db/ip/ip2region.db
  14. 29 0
      java/sp-app/bin/src/main/resources/mapper/SpAppLogMapper.xml
  15. 13 0
      java/sp-app/bin/src/main/resources/mapper/SpApplicationMapper.xml
  16. 42 0
      java/sp-app/bin/src/main/resources/mapper/SpDictMapper.xml
  17. 14 0
      java/sp-app/bin/src/main/resources/mapper/SpRoleMenuMapper.xml
  18. 55 0
      java/sp-app/bin/src/main/resources/mapper/SpUserAppRoleMapper.xml
  19. 34 0
      java/sp-app/bin/src/main/resources/mapper/UserMapper.xml
  20. 9 0
      java/sp-app/pom.xml
  21. 37 20
      java/sp-app/src/main/java/com/anji/sp/controller/SpAppReqController.java
  22. 15 0
      java/sp-app/src/main/java/com/anji/sp/model/vo/AppUpdateReqVo.java
  23. 29 0
      java/sp-app/src/main/java/com/anji/sp/model/vo/AppUpdateRespVo.java
  24. 4 3
      java/sp-app/src/main/java/com/anji/sp/model/vo/SpAppReqDataVO.java
  25. 29 25
      java/sp-app/src/main/java/com/anji/sp/service/SpAppReqService.java
  26. 515 470
      java/sp-app/src/main/java/com/anji/sp/service/impl/SpAppReqServiceImpl.java
  27. 3 3
      java/sp-app/src/main/resources/application.properties
  28. 33 0
      java/sp-auth/bin/.gitignore
  29. 40 0
      java/sp-auth/bin/pom.xml
  30. 1 0
      java/sp-auth/bin/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService
  31. BIN
      java/sp-auth/bin/src/main/resources/ip/ip2region.db
  32. 47 0
      java/sp-auth/bin/src/main/resources/logback.xml
  33. 1 0
      java/sp-auth/src/main/java/com/anji/sp/config/SecurityConfig.java
  34. 33 0
      java/sp-common/bin/.gitignore
  35. 26 0
      java/sp-common/bin/pom.xml
  36. 33 0
      java/sp-notice/bin/.gitignore
  37. 33 0
      java/sp-notice/bin/pom.xml
  38. 8 0
      java/sp-notice/bin/src/main/resources/mapper/SpNoticeMapper.xml
  39. 130 0
      java/sp-push/bin/pom.xml
  40. 20 0
      java/sp-push/bin/src/main/resources/AJPushUrl.properties
  41. 152 0
      java/sp-push/bin/src/main/resources/mapper/PushConfiguresMapper.xml
  42. 129 0
      java/sp-push/bin/src/main/resources/mapper/PushHistoryMapper.xml
  43. 93 0
      java/sp-push/bin/src/main/resources/mapper/PushMessageMapper.xml
  44. 92 0
      java/sp-push/bin/src/main/resources/mapper/PushUserMapper.xml
  45. 33 0
      java/sp-version/bin/.gitignore
  46. 46 0
      java/sp-version/bin/pom.xml
  47. 46 0
      java/sp-version/bin/src/main/resources/mapper/SpVersionMapper.xml
  48. 4 0
      java/sp-version/src/main/java/com/anji/sp/model/po/SpFilePO.java
  49. 3 0
      java/sp-version/src/main/java/com/anji/sp/model/vo/SpUploadFileVO.java
  50. 128 116
      java/sp-version/src/main/java/com/anji/sp/service/impl/SpUploadServiceImpl.java
  51. 13 2
      java/sp-version/src/main/java/com/anji/sp/util/file/FileUploadUtils.java
  52. 108 0
      java/sp-version/src/main/java/com/anji/sp/utils/AspectJUtils.java
  53. 339 0
      java/sp-version/src/main/java/com/anji/sp/utils/DateUtils.java
  54. 73 0
      java/sp-version/src/main/java/com/anji/sp/utils/FileUtils.java
  55. 142 0
      java/sp-version/src/main/java/com/anji/sp/utils/IpUtils.java
  56. 93 0
      java/sp-version/src/main/java/com/anji/sp/utils/Md5Utils.java
  57. 119 0
      java/sp-version/src/main/java/com/anji/sp/utils/RandomGUID.java
  58. 109 0
      java/sp-version/src/main/java/com/anji/sp/utils/TokenUtils.java

+ 2 - 2
.gitignore

@@ -2,12 +2,12 @@
 .DS_Store
 target
 *.iml
+*.apk
 **/*.log
 dist
-build
 # Compiled class file
 *.class
-
+logs
 .DS_Store
 .idea/
 *.iml

+ 33 - 0
java/sp-app/bin/.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/

+ 148 - 0
java/sp-app/bin/pom.xml

@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.anji-plus.sp</groupId>
+		<artifactId>sp-parent</artifactId>
+		<version>1.0.0</version>
+	</parent>
+	<artifactId>sp-app</artifactId>
+	<name>sp-app</name>
+	<packaging>jar</packaging>
+	<description>Demo project for Spring Boot</description>
+
+
+	<dependencies>
+		<dependency>
+			<groupId>com.anji-plus.sp</groupId>
+			<artifactId>sp-version</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+
+		<dependency>
+			<groupId>com.anji-plus.sp</groupId>
+			<artifactId>sp-notice</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+		<dependency>
+			<groupId>com.anji-plus.sp</groupId>
+			<artifactId>sp-push</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+		<!-- 本地加载 -->
+		<dependency>
+			<groupId>com.vivo.push.sdk</groupId>
+			<artifactId>vpush-server-sdk</artifactId>
+			<version>2.2</version>
+			<scope>system</scope>
+			<systemPath>${pom.basedir}/src/main/resources/libs/vpush-server-sdk-2.2.jar
+			</systemPath>
+		</dependency>
+		<dependency>
+			<groupId>com.oppo.push.sdk</groupId>
+			<artifactId>opush-server-sdk</artifactId>
+			<version>1.0.6</version>
+			<scope>system</scope>
+			<systemPath>${pom.basedir}/src/main/resources/libs/opush-server-sdk-1.0.6.jar
+			</systemPath>
+		</dependency>
+		<dependency>
+			<groupId>com.xiaomi.xmpush</groupId>
+			<artifactId>MiPush_SDK_Server_Http</artifactId>
+			<version>2_1.0.9</version>
+			<scope>system</scope>
+			<systemPath>${pom.basedir}/src/main/resources/libs/MiPush_SDK_Server_Http2_1.0.9.jar
+			</systemPath>
+		</dependency>
+
+	</dependencies>
+
+	<developers>
+		<developer>
+			<name>develop.anji-plus.com</name>
+			<email>MS@anji-plus.com</email>
+			<url>https://github.com/anji-plus</url>
+		</developer>
+	</developers>
+
+	<profiles>
+		<profile>
+			<id>dev</id>
+			<properties>
+				<spring.profiles.active>dev</spring.profiles.active>
+			</properties>
+			<activation>
+				<activeByDefault>true</activeByDefault>
+			</activation>
+		</profile>
+	</profiles>
+
+	<build>
+		<resources>
+			<resource>
+				<directory>src/main/resources</directory>
+				<filtering>true</filtering>
+			</resource>
+		</resources>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>repackage</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<includeSystemScope>true</includeSystemScope>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-resources-plugin</artifactId>
+				<configuration>
+					<encoding>UTF-8</encoding>
+					<nonFilteredFileExtensions>
+						<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
+						<nonFilteredFileExtension>woff</nonFilteredFileExtension>
+						<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
+					</nonFilteredFileExtensions>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-assembly-plugin</artifactId>
+				<version>3.3.0</version>
+				<configuration>
+					<encoding>UTF-8</encoding>
+					<descriptors>
+						<descriptor>src/main/assembly/assembly.xml</descriptor>
+					</descriptors>
+				</configuration>
+				<executions>
+					<execution>
+						<id>make-assembly</id>
+						<phase>package</phase>
+						<goals>
+							<goal>single</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<!-- 跳过单元测试 -->
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<skipTests>true</skipTests>
+				</configuration>
+			</plugin>
+		</plugins>
+
+	</build>
+
+</project>

+ 33 - 0
java/sp-app/bin/src/main/assembly/assembly.xml

@@ -0,0 +1,33 @@
+<assembly>
+	<id>assembly</id>
+	<formats>
+		<format>zip</format>
+	</formats>
+	<includeBaseDirectory>true</includeBaseDirectory>
+	<fileSets>
+		<fileSet>
+			<directory>src/main/assembly/bin</directory>
+			<outputDirectory>bin</outputDirectory>
+			<fileMode>0755</fileMode>
+		</fileSet>
+		<fileSet>
+			<directory>src/main/resources</directory>
+			<outputDirectory>conf</outputDirectory>
+			<includes>
+				<include>application.properties</include>
+			</includes>
+		</fileSet>
+		<fileSet>
+			<directory>target</directory>
+			<outputDirectory>lib</outputDirectory>
+			<includes>
+				<include>sp-app-*.jar</include>
+			</includes>
+			<excludes>
+				<exclude>*-javadoc.jar</exclude>
+				<exclude>*-sources.jar</exclude>
+			</excludes>
+			<fileMode>0755</fileMode>
+		</fileSet>
+	</fileSets>
+</assembly>

+ 5 - 0
java/sp-app/bin/src/main/assembly/bin/restart.sh

@@ -0,0 +1,5 @@
+#!/bin/bash
+cd `dirname $0`
+./stop.sh
+./start.sh
+

+ 42 - 0
java/sp-app/bin/src/main/assembly/bin/start.bat

@@ -0,0 +1,42 @@
+@echo off & setlocal enabledelayedexpansion
+
+rem 判断cmd中是否有JAVA_HOME
+rem set JAVA_HOME=D:\App\Java\jdk1.8.0_172
+IF "%JAVA_HOME%" == "" (
+	goto END
+) ELSE (
+    goto START
+)
+
+:END
+	rem cmd中未找到JAVA_HOME,请在此启动文件中第4行指定,然后尝试
+    echo Not JAVA_HOME Find, Please add JAVA_HOME in this file line 4
+	pause
+	exit
+
+:START
+	rem 获取应用的根目录
+	cd ../
+	set BIN_DIR=%cd%
+	set CONF_YML=%BIN_DIR%\conf\application.properties
+
+	cd %BIN_DIR%\lib
+	rem 查找sp-app*.jar启动文件,版本号每次会变
+	for /f "delims=" %%i in ('dir /a-d /b /on sp-app*.jar') do (
+	   set BOOT_JAR=%%i
+	)
+
+	rem 查找附加的驱动,加到java启动的classpath中
+	for %%i in ("*") do (
+		if "%%i" neq "%BOOT_JAR%" (
+			set LIB_JARS=!LIB_JARS!%BIN_DIR%\lib\%%i;
+		)
+	)
+
+	rem 启动内存设置,请根据自己需要调整
+	cd %BIN_DIR%\bin
+	set JAVA_OPTS= -server -Xms1g -Xmx2g -Xmn256m -XX:PermSize=128m -Xss256k
+
+	rem 正式启动
+	%JAVA_HOME%\bin\java %JAVA_OPTS% -Xbootclasspath/a:%LIB_JARS% -jar -Dspring.config.location=%CONF_YML% %BIN_DIR%\lib\%BOOT_JAR%
+	pause

+ 26 - 0
java/sp-app/bin/src/main/assembly/bin/start.sh

@@ -0,0 +1,26 @@
+#!/bin/bash
+
+#判断java是否存在
+command -v java >/dev/null 2>&1 || { echo >&2 "require java but it's not installed. Aborting."; sleep 5;exit 1; }
+
+cd `dirname $0`
+BIN_DIR=`pwd` #安装目录
+cd ../
+DEPLOY_DIR=`pwd`
+LIB_DIR=$DEPLOY_DIR/lib #jar目录
+CONF_DIR=$DEPLOY_DIR/conf #conf目录
+LOGS_DIR=$DEPLOY_DIR/logs #log目录
+
+LIB_JARS=`ls $LIB_DIR|grep -v sp-app|awk '{print "'$LIB_DIR'/"$0}'|tr "\n" ":"`
+
+PIDS=`ps -f | grep java | grep "sp-app" |awk '{print $2}'`
+if [ -n "$PIDS" ]; then
+    echo "ERROR: The sp-app already started!"
+    echo "PID: $PIDS"
+    exit 1
+fi
+
+JAVA_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k "
+nohup java $JAVA_OPTS -Xbootclasspath/a:$LIB_JARS -jar -Dspring.config.location=$CONF_DIR/application.properties $LIB_DIR/sp-app-*.jar >/dev/null 2>&1 &
+
+echo "The sp-app started!"

+ 10 - 0
java/sp-app/bin/src/main/assembly/bin/stop.sh

@@ -0,0 +1,10 @@
+#!/bin/bash
+pid=`ps ax | grep -i 'sp-app' | grep java | grep -v grep | awk '{print $1}'`
+if [ -z "$pid" ] ; then
+        echo "No sp-app Server running."
+        exit -1;
+fi
+
+kill -9 ${pid}
+
+echo "Send shutdown request to sp-app(${pid}) OK"

+ 39 - 0
java/sp-app/bin/src/main/resources/application-dev.properties

@@ -0,0 +1,39 @@
+# \u8BE5\u6587\u4EF6\u914D\u7F6E\u4F1A\u7EE7\u627Fbootstrap.xml\uFF0C\u53EA\u9700\u8981\u914D\u7F6E\u6570\u636E\u5E93\u7B49\u5DEE\u5F02\u914D\u7F6E
+spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.druid.url=jdbc:mysql://10.108.26.197:3306/aj_app_sp?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false
+spring.datasource.druid.username=root
+spring.datasource.druid.password=appuser@anji
+
+#redis
+#\u5355\u673A\u6A21\u5F0F
+#spring.redis.database=1
+spring.redis.host=10.108.26.197
+spring.redis.port=6379
+spring.redis.password=appuser@anji
+spring.redis.database=2
+
+
+# rabbitmq
+spring.rabbitmq.virtual-host=uat_appsp
+spring.rabbitmq.host=10.108.2.237
+spring.rabbitmq.port=5672
+spring.rabbitmq.username=uat_appsp
+spring.rabbitmq.password=DA%782ET
+#\u8BBE\u7F6E\u6D88\u8D39\u7AEF\u624B\u52A8 ack   none\u4E0D\u786E\u8BA4  auto\u81EA\u52A8\u786E\u8BA4  manual\u624B\u52A8\u786E\u8BA4
+spring.rabbitmq.listener.simple.acknowledge-mode=manual
+# \u5F00\u542F\u6D88\u8D39\u8005\u8FDB\u884C\u91CD\u8BD5
+spring.rabbitmq.listener.direct.retry.enabled=true
+# \u6700\u5927\u91CD\u8BD5\u6B21\u6570
+spring.rabbitmq.listener.direct.retry.max-attempts=5
+# \u91CD\u8BD5\u95F4\u9694 3000\u6BEB\u79D2
+spring.rabbitmq.listener.direct.retry.initial-interval=3000
+
+
+#\u670D\u52A1\u5668\u5730\u5740
+customer.environment.path=http://127.0.0.1:8081/sp
+#apk \u4E0B\u8F7D\u8DEF\u5F84\u524D\u7F00
+#file.apk.url=http://10.108.26.197:9096/sp/download/
+file.apk.url=http://127.0.0.1:8081/sp/download/
+
+# \u4E0A\u4F20\u4F60\u6587\u4EF6\u5730\u5740  upload.filename + /apk  \u67E5\u770B sp-version util FileProfileConfig\u3001FileNameEnum\u3001FileUploadUtils
+upload.filename=D:\\backup

+ 1 - 0
java/sp-app/bin/src/main/resources/application-prod.properties

@@ -0,0 +1 @@
+

+ 142 - 0
java/sp-app/bin/src/main/resources/application.properties

@@ -0,0 +1,142 @@
+spring.application.name=sp-service
+server.servlet.context-path=/sp
+server.port=8831
+#spring.profiles.active=uat
+
+#mysql数据库连接
+spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.druid.url=jdbc:mysql://114.55.230.80:3306/aj_app_sp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8
+spring.datasource.druid.username=root
+spring.datasource.druid.password=QopraffaQWPRPPR123
+spring.datasource.druid.initial-size=1
+spring.datasource.druid.max-active=100
+spring.datasource.druid.min-idle=1
+spring.datasource.druid.max-wait=30000
+spring.datasource.druid.keep-alive=true
+spring.datasource.druid.phy-timeout-millis=1200000
+spring.datasource.druid.validation-query="select 1"
+spring.datasource.druid.validation-query-timeout=10000
+spring.datasource.druid.test-on-borrow=false
+spring.datasource.druid.test-on-return=false
+spring.datasource.druid.test-while-idle=true
+spring.datasource.druid.time-between-eviction-runs-millis=10000
+spring.datasource.druid.web-stat-filter.enabled=false
+spring.datasource.druid.stat-view-servlet.enabled=false
+
+#redis
+#单机模式
+#spring.redis.database=1
+spring.redis.host=127.0.0.1
+spring.redis.port=6379
+spring.redis.password=
+
+# 集群模式
+#spring.redis.database=1
+#spring.redis.cluster.nodes=10.108.0.1:6379,10.108.0.2:6379
+#spring.redis.password=123456
+
+# 哨兵模式
+#spring.redis.database=1
+#spring.redis.sentinel.master=master01
+#spring.redis.sentinel.nodes=10.108.0.1:26379,10.108.0.2:2679,10.108.0.3:26379
+#spring.redis.password=123456
+
+spring.redis.timeout=10000
+spring.redis.lettuce.pool.min-idle=0
+spring.redis.lettuce.pool.max-idle=8
+spring.redis.lettuce.pool.max-active=8
+spring.redis.lettuce.pool.max-wait=-1ms
+
+mybatis-plus.mapper-locations=classpath*:mapper/*.xml
+mybatis-plus.type-aliases-package=com.anji.sp.model.po
+#token header key
+token.header=Authorization
+# token secret key
+token.secret=secret123456secret
+#token失效默认30分钟 60*24
+token.expireTime=30
+
+swagger.enabled=true
+swagger.pathMapping=/
+
+# 分页配置
+pagehelper.helperDialect=mysql
+pagehelper.reasonable=true
+pagehelper.supportMethodsArguments=true
+pagehelper.params=count=countSql
+
+
+#服务器地址
+customer.environment.path=https://openappsp.anji-plus.com
+#apk 下载路径前缀
+file.apk.url=http://192.168.0.105:8081/sp/download/
+# 上传你文件地址  upload.filename + /apk  查看 sp-version util FileProfileConfig、FileNameEnum、FileUploadUtils
+upload.filename=/app/file-sp
+#debuge mac file
+#upload.filename=/Users/
+#debuge windows file
+#upload.filename=D://
+spring.servlet.multipart.max-file-size=500MB
+spring.servlet.multipart.max-request-size=500MB
+#APP是否开启加密请求
+version.need.decrypt=true
+#默认毫秒数 7 天 7*24*60*60*1000=604800000
+version.timestamp.default=604800000
+#默认毫秒数 1 天 1*24*60*60*1000=86400000
+version.timestamp.one=86400000
+
+#vivo 推送mode  0 正式 1测试
+custom.push.vivo.mode=1
+
+# job任务单ip执行
+custom.app.jobId=127.0.0.1
+
+
+
+
+#缓存local/redis  https://gitee.com/anji-plus/captcha.git
+aj.captcha.cache-type=redis
+#local缓存的阈值,达到这个值,清除缓存
+#aj.captcha.cache-number=1000
+#local定时清除过期缓存(单位秒),设置为0代表不执行
+#aj.captcha.timing-clear=180
+aj.captcha.type=default
+#右下角水印文字(安吉加加)
+aj.captcha.water-mark=ANJI-PLUS
+
+#校验滑动拼图允许误差偏移量(默认10像素)
+aj.captcha.slip-offset=5
+#aes加密坐标开启或者禁用(true|false)
+aj.captcha.aes-status=true
+#滑动干扰项(0/1/2) 1.2.2版本新增
+aj.captcha.interference-options=1
+
+#actuator 默认关闭所有endpoint,只打开health。
+management.endpoints.enabled-by-default=false
+management.endpoint.health.enabled=true
+management.endpoint.health.show-details=always
+management.health.diskspace.enabled=true
+management.health.diskspace.threshold=10737418240
+management.health.db.enabled=true
+management.health.redis.enabled=true
+management.health.elasticsearch.enabled=true
+
+
+# rabbitmq
+spring.rabbitmq.virtual-host=/
+spring.rabbitmq.host=114.55.230.80
+spring.rabbitmq.port=5672
+spring.rabbitmq.username=admin
+spring.rabbitmq.password=admin
+#设置消费端手动 ack   none不确认  auto自动确认  manual手动确认
+spring.rabbitmq.listener.simple.acknowledge-mode=manual
+# 开启消费者进行重试
+spring.rabbitmq.listener.direct.retry.enabled=true
+# 最大重试次数
+spring.rabbitmq.listener.direct.retry.max-attempts=5
+# 重试间隔 3000毫秒
+spring.rabbitmq.listener.direct.retry.initial-interval=3000
+sp.minio.accesskey=minioadmin
+sp.minio.secretkey=minioadmin
+sp.minio.url=http://124.222.192.60:9000
+sp.minio.bucketName=mytest

+ 652 - 0
java/sp-app/bin/src/main/resources/db/aj_app_sp.sql

@@ -0,0 +1,652 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : 10.108.26.197gaea-dev
+ Source Server Type    : MySQL
+ Source Server Version : 50728
+ Source Host           : 10.108.26.197:3306
+ Source Schema         : aj_app_sp
+
+ Target Server Type    : MySQL
+ Target Server Version : 50728
+ File Encoding         : 65001
+
+ Date: 09/10/2021 16:08:06
+*/
+
+SET NAMES utf8mb4;
+SET
+FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for push_configures
+-- ----------------------------
+DROP TABLE IF EXISTS `push_configures`;
+CREATE TABLE `push_configures`
+(
+    `id`               bigint(20) NOT NULL AUTO_INCREMENT,
+    `app_id`           bigint(20) NOT NULL COMMENT '应用ID',
+    `app_key`          varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `secret_key`       varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '服务加密使用',
+    `jg_app_key`       varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '极光appkey',
+    `jg_master_secret` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '极光masterSecret',
+    `hw_app_id`        varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '华为appId',
+    `hw_app_secret`    varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '华为AppSecret',
+    `hw_default_title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '华为推送标题(默认建议应用名)',
+    `op_app_id`        varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'oppo appId',
+    `op_app_secret`    varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'oppo AppSecret',
+    `op_default_title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'oppo 推送标题(默认建议应用名)',
+    `op_app_key`       varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'oppo AppKey',
+    `op_master_secret` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'oppo Master Secret',
+    `vo_app_id`        varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'vivo appId',
+    `vo_app_secret`    varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'vivo AppSecret',
+    `vo_default_title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'vivo 推送标题(默认建议应用名)',
+    `vo_app_key`       varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'vivo AppKey',
+    `xm_app_id`        varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '小米appId',
+    `xm_app_secret`    varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '小米AppSecret',
+    `xm_default_title` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '小米推送标题(默认建议应用名)',
+    `xm_app_key`       varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '华为AppKey',
+    `package_name`     varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '包名',
+    `enable_flag`      int(11) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用  DIC_NAME=ENABLE_FLAG',
+    `delete_flag`      int(11) NOT NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG',
+    `create_by`        bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`      datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`        bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`      datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`          varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    `channel_enable`   int(11) NOT NULL DEFAULT 0 COMMENT '是否开启厂商通道 默认 0',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '推送配置项' ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for push_history
+-- ----------------------------
+DROP TABLE IF EXISTS `push_history`;
+CREATE TABLE `push_history`
+(
+    `id`               bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
+    `app_key`          varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `msg_id`           varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '消息唯一id',
+    `device_ids`       text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '设备唯一标识',
+    `registration_ids` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '极光唯一标识',
+    `target_type`      varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '1:华为,2:小米,3:oppo,4:vivo,5:极光iOS 6:极光Android ',
+    `target_num`       varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '目标(对应当次发送的条数)',
+    `success_num`      varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '成功条数(对应当次发送的条数)',
+    `title`            varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '标题',
+    `content`          varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '内容',
+    `extras`           text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '传递数据',
+    `ios_config`       text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'iOS配置项 json',
+    `android_config`   text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'android配置项 json {\"sound\": \"sound\"}',
+    `send_origin`      varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1' COMMENT '消息来源 0 web 1 api',
+    `push_type`        varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推送类型 1透传消息 0 普通消息',
+    `channel`          varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '渠道类型 华为厂商还是其他厂商',
+    `push_result`      varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接收结果是否成功 1成功 0不成功',
+    `send_time`        datetime(0) NOT NULL COMMENT '发送时间',
+    `enable_flag`      int(11) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用  DIC_NAME=ENABLE_FLAG',
+    `delete_flag`      int(11) NOT NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG',
+    `create_by`        bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`      datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`        bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`      datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`          text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4282 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '推送历史表' ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for push_message
+-- ----------------------------
+DROP TABLE IF EXISTS `push_message`;
+CREATE TABLE `push_message`
+(
+    `id`                bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
+    `app_key`           varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `msg_id`            varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '消息唯一id',
+    `oper_param`        text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '消息内容消息json',
+    `target_num`        varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '目标(对应消息推送总数)',
+    `success_num`       varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '0' COMMENT '成功条数(对应消息推送成功总数)',
+    `consumption_state` int(11) NOT NULL DEFAULT 0 COMMENT '消费状态 默认未消费 0: 未消费 1:已消费',
+    `enable_flag`       int(11) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用  DIC_NAME=ENABLE_FLAG',
+    `delete_flag`       int(11) NOT NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG',
+    `create_by`         bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`       datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`         bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`       datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`           text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '备注信息',
+    `send_origin`       varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1' COMMENT '消息来源 0 web 1 api',
+    `push_type`         varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推送类型 1透传消息 0 普通消息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1335 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '服务推送id记录' ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for push_user
+-- ----------------------------
+DROP TABLE IF EXISTS `push_user`;
+CREATE TABLE `push_user`
+(
+    `id`              bigint(20) NOT NULL AUTO_INCREMENT,
+    `app_key`         varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `device_id`       varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备唯一标识',
+    `manu_token`      varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '厂商通道的token或者regId',
+    `device_type`     varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '设备类型:0:其他手机,1:华为,2:小米,3:oppo,4:vivo,5:ios',
+    `alias`           varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '别名',
+    `registration_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '极光的用户id',
+    `brand`           varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备品牌(例如:小米6,iPhone 7plus)',
+    `os_version`      varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '系统版本例如:7.1.2  13.4.1',
+    `enable_flag`     int(11) NOT NULL DEFAULT 1 COMMENT '0--已禁用 1--已启用  DIC_NAME=ENABLE_FLAG',
+    `delete_flag`     int(11) NOT NULL DEFAULT 0 COMMENT ' 0--未删除 1--已删除 DIC_NAME=DEL_FLAG',
+    `create_by`       bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`     datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`       bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`     datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`         varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 92 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for sp_app_device
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_app_device`;
+CREATE TABLE `sp_app_device`
+(
+    `id`          bigint(20) NOT NULL AUTO_INCREMENT,
+    `app_key`     varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `device_id`   varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备唯一标识',
+    `platform`    varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '平台(iOS/Android)',
+    `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 244 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'app设备唯一标识表' ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for sp_app_log
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_app_log`;
+CREATE TABLE `sp_app_log`
+(
+    `id`                  bigint(20) NOT NULL AUTO_INCREMENT,
+    `app_key`             varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `device_id`           varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备唯一标识',
+    `ip`                  varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'ip地址',
+    `regional`            varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地域(中国|0|上海|上海市|电信)(0|0|0|内网IP|内网IP)',
+    `net_work_status`     varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '联网方式',
+    `platform`            varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '平台(iOS/Android)',
+    `screen_info`         varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '高*宽',
+    `brand`               varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备品牌(例如:小米6,iPhone 7plus)',
+    `version_name`        varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本名',
+    `version_code`        varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本号',
+    `sdk_version`         varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'sdk版本',
+    `os_version`          varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '系统版本例如:7.1.2  13.4.1',
+    `interface_type`      varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接口类型',
+    `interface_type_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '接口类型名',
+    `enable_flag`         int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag`         int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`           bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`         datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`           bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`         datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`             varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'app请求log' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_app_log
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for sp_app_release
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_app_release`;
+CREATE TABLE `sp_app_release`
+(
+    `id`           bigint(20) NOT NULL AUTO_INCREMENT,
+    `app_key`      varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `device_id`    varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设备唯一标识',
+    `version_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本名',
+    `enable_flag`  int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag`  int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`    bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`  datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`    bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`  datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`      varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'app灰度发布用户信息' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_app_release
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for sp_application
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_application`;
+CREATE TABLE `sp_application`
+(
+    `app_id`               bigint(20) NOT NULL AUTO_INCREMENT,
+    `app_key`              varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用唯一key',
+    `name`                 varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '应用名称',
+    `public_key`           varchar(2048) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '公钥',
+    `private_key`          varchar(2048) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '私钥',
+    `enable_flag`          int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag`          int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`            bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`          datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`            bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`          datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`              varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    `logo_url`             varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'logo Url',
+    `promote_version`      varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推广版本/环境信息',
+    `promote_name`         varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推广应用名',
+    `promote_desc`         varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推广语',
+    `promote_introduction` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '推广介绍',
+    PRIMARY KEY (`app_id`) USING BTREE,
+    UNIQUE INDEX `app_key_unique`(`app_key`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '应用' ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for sp_dict
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_dict`;
+CREATE TABLE `sp_dict`
+(
+    `id`          bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
+    `name`        varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '标签名',
+    `value`       varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '数据值',
+    `type`        varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '类型(Android版本、iOS版本、公告类型、展示类型)',
+    `description` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '描述(Android版本、iOS版本、公告类型、展示类型)',
+    `parent_id`   bigint(2) NULL DEFAULT 0 COMMENT '父级编号:0代表没有父级',
+    `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE,
+    INDEX         `sys_dict_value`(`value`) USING BTREE,
+    INDEX         `sys_dict_label`(`name`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8 COLLATE = utf8_bin COMMENT = '字典表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_dict
+-- ----------------------------
+INSERT INTO `sp_dict`
+VALUES (1, '6', 'Android6', 'ANDROID_VERSION', 'Android版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (2, '7', 'Android7', 'ANDROID_VERSION', 'Android版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (3, '8', 'Android8', 'ANDROID_VERSION', 'Android版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (4, '9', 'Android9', 'ANDROID_VERSION', 'Android版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (5, '10', 'Android10', 'ANDROID_VERSION', 'Android版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (6, '10', 'iOS10', 'IOS_VERSION', 'iOS版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-26 18:48:53', NULL);
+INSERT INTO `sp_dict`
+VALUES (7, '11', 'iOS11', 'IOS_VERSION', 'iOS版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-26 18:40:44', NULL);
+INSERT INTO `sp_dict`
+VALUES (8, '12', 'iOS12', 'IOS_VERSION', 'iOS版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (9, '13', 'iOS13', 'IOS_VERSION', 'iOS版本号', 0, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (10, '14', 'iOS14', 'IOS_VERSION', 'iOS版本号', 0, 1, 0, 2, '2020-10-23 14:08:09', 2, '2020-10-23 14:08:09', NULL);
+INSERT INTO `sp_dict`
+VALUES (11, 'horizontal_scroll', '水平滚动', 'TEMPLATE', '模板类型', 0, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (12, 'dialog', '弹框', 'TEMPLATE', '模板类型', 0, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_dict`
+VALUES (13, '11', 'Android11', 'ANDROID_VERSION', 'Android版本号', 0, 1, 0, 3, '2021-07-16 17:08:00', 3,
+        '2021-07-16 17:08:00', NULL);
+
+-- ----------------------------
+-- Table structure for sp_file
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_file`;
+CREATE TABLE `sp_file`
+(
+    `file_id`     varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci  NOT NULL COMMENT '文件性一id',
+    `file_path`   varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '文件在linux中的完整目录,比如/app/file-sp/file/${fileid}.xlsx',
+    `url_path`    varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '通过接口的下载完整http路径',
+    `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`file_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+
+
+-- ----------------------------
+-- Table structure for sp_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_menu`;
+CREATE TABLE `sp_menu`
+(
+    `menu_id`     bigint(20) NOT NULL AUTO_INCREMENT,
+    `parent_id`   bigint(20) NULL DEFAULT NULL COMMENT '父菜单ID,一级菜单为0',
+    `name`        varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单名称',
+    `url`         varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单URL',
+    `perms`       varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '授权(多个用逗号分隔,如:user:list,user:create)',
+    `type`        int(10) NULL DEFAULT NULL COMMENT '类型   0:目录   1:菜单   2:按钮',
+    `icon`        varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '菜单图标',
+    `order_num`   int(2) NULL DEFAULT NULL COMMENT '排序',
+    `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`menu_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '菜单' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_menu
+-- ----------------------------
+INSERT INTO `sp_menu`
+VALUES (1, 0, '账号管理', NULL, NULL, 0, NULL, 10, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_menu`
+VALUES (2, 1, '版本管理', NULL, 'system:user:version', 1, NULL, 100, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_menu`
+VALUES (3, 1, '公告管理', NULL, 'system:user:notice', 1, NULL, 101, 1, 0, 1, '2020-06-19 12:24:50', 1,
+        '2020-06-19 12:24:56', NULL);
+INSERT INTO `sp_menu`
+VALUES (4, 1, '推送管理', NULL, 'system:user:push', 1, NULL, 102, 1, 0, 1, '2020-06-19 12:24:50', 1, '2020-06-19 12:24:56',
+        NULL);
+INSERT INTO `sp_menu`
+VALUES (5, 0, '基础设置', NULL, NULL, 0, NULL, 11, 1, 0, 1, '2020-07-01 12:21:58', 1, '2020-07-01 12:22:04', NULL);
+INSERT INTO `sp_menu`
+VALUES (6, 1, '成员管理', NULL, 'system:user:members', 1, NULL, 103, 1, 0, 1, '2021-01-07 16:54:41', 1,
+        '2021-01-07 16:54:45', NULL);
+
+-- ----------------------------
+-- Table structure for sp_notice
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_notice`;
+CREATE TABLE `sp_notice`
+(
+    `id`                 bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
+    `app_id`             bigint(20) NOT NULL COMMENT '应用ID',
+    `name`               varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '公告名称',
+    `title`              varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '公告标题',
+    `details`            varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '公告内容',
+    `template_type`      varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '模板类型(来自字典表)',
+    `template_type_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '模板类型名',
+    `result_type`        int(10) NULL DEFAULT NULL COMMENT '效果类型(来自字典表)',
+    `result_type_name`   varchar(20) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '效果类型名',
+    `start_time`         datetime(0) NULL DEFAULT NULL COMMENT '开始时间',
+    `end_time`           datetime(0) NULL DEFAULT NULL COMMENT '结束时间',
+    `enable_flag`        int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag`        int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`          bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`        datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`          bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`        datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`            varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '公告管理' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_notice
+-- ----------------------------
+INSERT INTO `sp_notice`
+VALUES (1, 3, '测试公告', '公告标题', '公告内容', 'dialog', '弹框', NULL, NULL, '2021-03-02 12:22:12', '2021-03-31 00:00:00', 0, 0, 3,
+        '2020-12-15 11:24:06', 3, '2021-03-01 17:53:41', NULL);
+
+-- ----------------------------
+-- Table structure for sp_oper_log
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_oper_log`;
+CREATE TABLE `sp_oper_log`
+(
+    `oper_id`        bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
+    `title`          varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '模块标题',
+    `business_type`  int(2) NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)',
+    `method`         varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '方法名称',
+    `request_method` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求方式',
+    `oper_name`      varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作人员',
+    `app_id`         bigint(20) NULL DEFAULT NULL COMMENT '应用id',
+    `oper_url`       varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求URL',
+    `oper_ip`        varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '主机地址',
+    `oper_location`  varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作地点',
+    `oper_param`     text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '请求参数',
+    `json_result`    text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '返回参数',
+    `status`         int(1) NULL DEFAULT 0 COMMENT '操作状态(0正常 1异常)',
+    `error_msg`      varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '错误消息',
+    `oper_time`      datetime(0) NULL DEFAULT NULL COMMENT '操作时间',
+    `begin_time`     bigint(20) NULL DEFAULT NULL COMMENT '请求开始时间戳',
+    `end_time`       bigint(20) NULL DEFAULT NULL COMMENT '请求结束时间戳',
+    `time`           bigint(20) NULL DEFAULT NULL COMMENT '接口耗时-毫秒',
+    PRIMARY KEY (`oper_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 296 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic;
+
+
+-- ----------------------------
+-- Table structure for sp_role
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_role`;
+CREATE TABLE `sp_role`
+(
+    `role_id`     bigint(20) NOT NULL AUTO_INCREMENT,
+    `role_name`   varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名称',
+    `role_sign`   varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色标识',
+    `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`role_id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_role
+-- ----------------------------
+INSERT INTO `sp_role`
+VALUES (1, '产品经理', '1', 1, 0, 1, '2020-06-19 12:11:59', 2, '2021-03-17 18:12:16', '产品角色');
+INSERT INTO `sp_role`
+VALUES (2, '测试人员', '1', 1, 0, 1, '2020-06-19 12:11:59', 3, '2021-09-13 14:50:27', '测试角色');
+INSERT INTO `sp_role`
+VALUES (3, '移动开发', '1', 1, 0, 1, '2020-06-19 12:11:59', 3, '2021-08-18 15:55:57', '移动开发角色');
+INSERT INTO `sp_role`
+VALUES (4, '推送测试者', '1', 1, 0, 2, '2021-03-17 18:00:01', 2, '2021-03-17 18:12:08', NULL);
+
+-- ----------------------------
+-- Table structure for sp_role_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_role_menu`;
+CREATE TABLE `sp_role_menu`
+(
+    `id`      bigint(20) NOT NULL AUTO_INCREMENT,
+    `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
+    `menu_id` bigint(20) NULL DEFAULT NULL COMMENT '菜单ID',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 52 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色与菜单对应关系' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_role_menu
+-- ----------------------------
+INSERT INTO `sp_role_menu`
+VALUES (19, 4, 2);
+INSERT INTO `sp_role_menu`
+VALUES (20, 4, 3);
+INSERT INTO `sp_role_menu`
+VALUES (21, 4, 4);
+INSERT INTO `sp_role_menu`
+VALUES (25, 1, 2);
+INSERT INTO `sp_role_menu`
+VALUES (26, 1, 3);
+INSERT INTO `sp_role_menu`
+VALUES (27, 1, 4);
+INSERT INTO `sp_role_menu`
+VALUES (28, 1, 6);
+INSERT INTO `sp_role_menu`
+VALUES (45, 3, 2);
+INSERT INTO `sp_role_menu`
+VALUES (46, 3, 3);
+INSERT INTO `sp_role_menu`
+VALUES (47, 3, 4);
+INSERT INTO `sp_role_menu`
+VALUES (48, 2, 2);
+INSERT INTO `sp_role_menu`
+VALUES (49, 2, 3);
+INSERT INTO `sp_role_menu`
+VALUES (50, 2, 4);
+INSERT INTO `sp_role_menu`
+VALUES (51, 2, 6);
+
+-- ----------------------------
+-- Table structure for sp_user
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_user`;
+CREATE TABLE `sp_user`
+(
+    `user_id`     bigint(20) NOT NULL AUTO_INCREMENT,
+    `username`    varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '账号',
+    `name`        varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
+    `password`    varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '密码',
+    `email`       varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',
+    `mobile`      varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
+    `is_admin`    int(11) NOT NULL DEFAULT 0 COMMENT '0--不是admin 1--是admin',
+    `sex`         bigint(20) NULL DEFAULT NULL COMMENT '性别',
+    `pic_url`     bigint(20) NULL DEFAULT NULL,
+    `enable_flag` int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag` int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    PRIMARY KEY (`user_id`) USING BTREE,
+    UNIQUE INDEX `username_unique`(`username`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_user
+-- ----------------------------
+INSERT INTO `sp_user`
+VALUES (1, 'admin', '管理员', '$2a$10$nbGK7sLJI4wcG8n0gpRTd.7amOft4bAJPUrgAd5roGJTy.fQZSYeO', NULL, NULL, 1, 1, NULL, 1, 0,
+        1, '2020-06-19 12:08:59', 1, '2020-08-06 09:53:43', NULL);
+
+
+-- ----------------------------
+-- Table structure for sp_user_app_role
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_user_app_role`;
+CREATE TABLE `sp_user_app_role`
+(
+    `id`      bigint(20) NOT NULL AUTO_INCREMENT,
+    `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
+    `app_id`  bigint(20) NULL DEFAULT NULL COMMENT '应用ID',
+    `role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户与应用与角色对应关系' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of sp_user_app_role
+-- ----------------------------
+INSERT INTO `sp_user_app_role`
+VALUES (1, 5, 3, 1);
+INSERT INTO `sp_user_app_role`
+VALUES (4, 7, 4, 4);
+INSERT INTO `sp_user_app_role`
+VALUES (5, 8, 4, 2);
+INSERT INTO `sp_user_app_role`
+VALUES (7, 9, 8, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (8, 10, 8, 1);
+INSERT INTO `sp_user_app_role`
+VALUES (9, 11, 8, 2);
+INSERT INTO `sp_user_app_role`
+VALUES (10, 12, 9, 1);
+INSERT INTO `sp_user_app_role`
+VALUES (11, 13, 9, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (12, 9, 12, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (13, 13, 13, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (14, 14, 14, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (15, 13, 3, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (16, 13, 4, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (17, 15, 13, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (18, 16, 13, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (19, 17, 13, 2);
+INSERT INTO `sp_user_app_role`
+VALUES (20, 16, 15, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (21, 18, 13, 3);
+INSERT INTO `sp_user_app_role`
+VALUES (22, 18, 15, 3);
+
+-- ----------------------------
+-- Table structure for sp_version
+-- ----------------------------
+DROP TABLE IF EXISTS `sp_version`;
+CREATE TABLE `sp_version`
+(
+    `id`                          bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
+    `app_id`                      bigint(20) NOT NULL COMMENT '应用ID',
+    `platform`                    varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '平台名称',
+    `version_name`                varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '版本名称',
+    `version_number`              varchar(100) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '版本号',
+    `update_log`                  varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新日志',
+    `download_url`                varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '下载地址',
+    `internal_url`                varchar(500) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '内部下载url',
+    `external_url`                varchar(500) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '外部下载url',
+    `version_config`              varchar(500) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '版本配置(需要版本更新的版本号例如 10,11,12)',
+    `enable_edit`                 int(1) NOT NULL DEFAULT 1 COMMENT '是否可编辑',
+    `enable_flag`                 int(1) NOT NULL DEFAULT 1 COMMENT '启用状态',
+    `delete_flag`                 int(1) NOT NULL DEFAULT 0 COMMENT '删除状态',
+    `create_by`                   bigint(20) NULL DEFAULT NULL COMMENT '创建者',
+    `create_date`                 datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
+    `update_by`                   bigint(20) NULL DEFAULT NULL COMMENT '更新者',
+    `update_date`                 datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
+    `remarks`                     varchar(200) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '备注信息',
+    `need_update_versions`        longtext CHARACTER SET utf8 COLLATE utf8_bin NULL COMMENT '版本配置(需要版本更新的版本号例如: 1.1.1,1.1.2,1.1.3)',
+    `canary_release_stage`        varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '发布阶段(例如 2,10,30,40,50,100,100)',
+    `canary_release_enable`       int(1) NOT NULL DEFAULT 0 COMMENT '0--已禁用 1--已启用  是否灰度发布 默认禁用',
+    `canary_release_use_time`     bigint(20) NOT NULL DEFAULT 0 COMMENT '灰度发已用时间(毫秒)',
+    `old_canary_release_use_time` bigint(20) NOT NULL DEFAULT 0 COMMENT '已用时间(用于启用一段时间关闭的状态保存)',
+    `enable_time`                 datetime(0) NULL DEFAULT NULL COMMENT '启用时间',
+    `published`                   int(1) NOT NULL DEFAULT 0 COMMENT '发布状态',
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 62 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '版本管理' ROW_FORMAT = Dynamic;
+
+
+
+SET
+FOREIGN_KEY_CHECKS = 1;

BIN
java/sp-app/bin/src/main/resources/db/ip/ip2region.db


+ 29 - 0
java/sp-app/bin/src/main/resources/mapper/SpAppLogMapper.xml

@@ -0,0 +1,29 @@
+<?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.anji.sp.mapper.SpAppLogMapper">
+
+    <select id="getDeviceIdCount" parameterType="com.anji.sp.model.vo.SpAppLogVO"
+            resultType="java.lang.Long">
+    select COUNT(DISTINCT device_id) from sp_app_log where app_key=#{appKey} and platform=#{platform}
+    </select>
+
+    <update id="createTable" parameterType="string">
+        CREATE TABLE IF NOT EXISTS sp_app_log_${format} LIKE sp_app_log;
+    </update>
+
+    <update id="copyArchiveData" parameterType="string">
+    INSERT INTO `sp_app_log_${format}`
+    select
+        *
+    from
+        sp_app_log e
+    where
+        e.create_date &lt; #{timestamp}
+    </update>
+
+    <delete id="deleteArchiveData">
+    delete from sp_app_log where create_date &lt; #{timestamp}
+  </delete>
+
+</mapper>

+ 13 - 0
java/sp-app/bin/src/main/resources/mapper/SpApplicationMapper.xml

@@ -0,0 +1,13 @@
+<?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.anji.sp.mapper.SpApplicationMapper">
+
+<!--    <select id="selectMenuListByRoleId" parameterType="java.lang.Long"-->
+<!--            resultType="com.anji.sp.model.vo.SpRoleMenuVO">-->
+<!--    select rm.id, rm.role_id, rm.menu_id, r.role_name, m.`name` menu_name from sp_role_menu rm-->
+<!--	LEFT JOIN sp_role r on r.role_id=rm.role_id-->
+<!--	LEFT JOIN sp_menu m on m.menu_id=rm.menu_id-->
+<!--	WHERE rm.role_id =  #{roleId}-->
+<!--    </select>-->
+</mapper>

+ 42 - 0
java/sp-app/bin/src/main/resources/mapper/SpDictMapper.xml

@@ -0,0 +1,42 @@
+<?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.anji.sp.mapper.SpDictMapper">
+
+<!--    <resultMap id="BaseResultMap" type="com.anji.sp.model.po.SpDictPO" >-->
+<!--        <result column="id" property="id" />-->
+<!--        <result column="name" property="name" />-->
+<!--        <result column="value" property="value" />-->
+<!--        <result column="type" property="type" />-->
+<!--        <result column="description" property="description" />-->
+<!--        <result column="sort" property="sort" />-->
+<!--        <result column="parent_id" property="parentId" />-->
+<!--        <result column="enable_flag" property="enableFlag" />-->
+<!--        <result column="delete_flag" property="deleteFlag" />-->
+<!--        <result column="create_by" property="createBy" />-->
+<!--        <result column="create_date" property="createDate" />-->
+<!--        <result column="update_by" property="updateBy" />-->
+<!--        <result column="update_date" property="updateDate" />-->
+<!--        <result column="remarks" property="remarks" />-->
+<!--    </resultMap>-->
+
+<!--    <sql id="Base_Column_List">-->
+<!--                id,-->
+<!--                name,-->
+<!--                value,-->
+<!--                type,-->
+<!--                description,-->
+<!--                sort,-->
+<!--                parent_id,-->
+<!--                enable_flag,-->
+<!--                delete_flag,-->
+<!--                create_by,-->
+<!--                create_date,-->
+<!--                update_by,-->
+<!--                update_date,-->
+<!--                remarks-->
+<!--    </sql>-->
+
+
+
+</mapper>

+ 14 - 0
java/sp-app/bin/src/main/resources/mapper/SpRoleMenuMapper.xml

@@ -0,0 +1,14 @@
+<?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.anji.sp.mapper.SpRoleMenuMapper">
+
+    <select id="selectMenuListByRoleId" parameterType="java.lang.Long"
+            resultType="com.anji.sp.model.vo.SpRoleMenuVO">
+    select rm.id, rm.role_id, rm.menu_id, r.role_name, m.`name` menu_name from sp_role_menu rm
+	LEFT JOIN sp_role r on r.role_id=rm.role_id
+	LEFT JOIN sp_menu m on m.menu_id=rm.menu_id
+	WHERE rm.role_id =  #{roleId}
+    </select>
+
+</mapper>

+ 55 - 0
java/sp-app/bin/src/main/resources/mapper/SpUserAppRoleMapper.xml

@@ -0,0 +1,55 @@
+<?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.anji.sp.mapper.SpUserAppRoleMapper">
+
+    <select id="selectAppInfoByUserId" parameterType="com.anji.sp.model.vo.SpUserAppInfoVO"
+            resultType="com.anji.sp.model.vo.SpAppInfoVO">
+        select a.*, b.title operation_title,b.oper_name operation_name, b.oper_time operation_time FROM (select a.app_id, a.app_key, a.`name`,
+        ua.user_id user_id
+        from sp_user_app_role ua
+        LEFT JOIN sp_application a on ua.app_id=a.app_id
+        <where>
+            a.enable_flag = 1 and a.delete_flag = 0
+            <if test="userId !=null">
+                and user_id = #{userId, jdbcType=BIGINT}
+            </if>
+        </where>
+        ) a
+        LEFT JOIN
+        (select g.* FROM
+        (select s.app_id,MAX(s.oper_id) oper_id,MAX(s.oper_time) oper_time from sp_oper_log s GROUP BY s.app_id) log
+        LEFT JOIN sp_oper_log g on log.oper_id = g.oper_id) b
+        on a.app_id=b.app_id
+    </select>
+
+    <select id="selectAppInfoByAdmin" parameterType="com.anji.sp.model.vo.SpUserAppInfoVO"
+            resultType="com.anji.sp.model.vo.SpAppInfoVO">
+    select a.*, b.title operation_title, b.oper_name operation_name,b.oper_time operation_time FROM (
+	select 
+	 a.promote_name,a.promote_version,a.promote_desc,a.promote_introduction,
+	  a.app_id, a.app_key, a.`name` from  sp_application a where a.enable_flag = 1 and a.delete_flag = 0) a
+	LEFT JOIN (select g.*  FROM (select s.app_id,MAX(s.oper_id) oper_id,MAX(s.oper_time) oper_time from sp_oper_log s GROUP BY s.app_id) log
+	LEFT JOIN sp_oper_log g on log.oper_id = g.oper_id) b on a.app_id=b.app_id
+    </select>
+
+
+    <select id="selectMenuPermissionsByAppIDAndUserId" parameterType="com.anji.sp.model.vo.SpUserAppInfoVO"
+            resultType="com.anji.sp.model.vo.SpMenuVO">
+		select m.*  from sp_user_app_role uar
+		LEFT JOIN sp_role_menu  rm on rm.role_id = uar.role_id
+		LEFT JOIN sp_menu m on m.menu_id = rm.menu_id
+		where app_id = #{appId, jdbcType=BIGINT} and user_id = #{userId, jdbcType=BIGINT}
+	</select>
+
+
+    <select id="selectUserMenuPerms" parameterType="com.anji.sp.model.vo.SpUserMenuVO"
+            resultType="com.anji.sp.model.vo.SpUserMenuVO">
+		select uar.user_id, uar.app_id, uar.role_id, m.menu_id, m.`name` menu_name, m.perms from sp_user_app_role uar
+		LEFT JOIN sp_role_menu rm on rm.role_id = uar.role_id
+		LEFT JOIN sp_menu m on m.menu_id = rm.menu_id
+		where user_id = #{userId, jdbcType=BIGINT}
+	</select>
+
+
+</mapper>

+ 34 - 0
java/sp-app/bin/src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,34 @@
+<?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.anji.sp.mapper.UserMapper">
+
+    <!--    <select id="selectMenuListByRoleId" parameterType="java.lang.Long"-->
+    <!--            resultType="com.anji.sp.model.vo.SpRoleMenuVO">-->
+    <!--    select rm.id, rm.role_id, rm.menu_id, r.role_name, m.`name` menu_name from sp_role_menu rm-->
+    <!--	LEFT JOIN sp_role r on r.role_id=rm.role_id-->
+    <!--	LEFT JOIN sp_menu m on m.menu_id=rm.menu_id-->
+    <!--	WHERE rm.role_id =  #{roleId}-->
+    <!--    </select>-->
+
+    <select id="selectNoJoinApplicationByAppId" parameterType="com.anji.sp.model.vo.SpApplicationVO"
+            resultType="com.anji.sp.model.vo.SpUserVO">
+        select user_id, `name`, username from sp_user
+        where is_admin=0 and enable_flag=1 and delete_flag=0 and user_id
+        not in(select user_id from sp_user_app_role where app_id=#{appId})
+        <if test="name != null and name !=''">
+            and name like CONCAT('%',#{name,jdbcType=VARCHAR},'%')
+        </if>
+    </select>
+
+
+    <select id="selectUserAppRoleByAppId" parameterType="java.lang.Long"
+            resultType="com.anji.sp.model.vo.SpUserAppInfoVO">
+        select u.user_id user_id, uar.app_id app_id, uar.id user_app_role_id, u.username username, u.`name` `name`, r.role_id role_id,  r.role_name role_name  from sp_user u
+        LEFT JOIN sp_user_app_role uar on u.user_id=uar.user_id
+	    LEFT JOIN sp_role r on r.role_id=uar.role_id
+	    WHERE uar.app_id=#{appId}
+    </select>
+
+
+</mapper>

+ 9 - 0
java/sp-app/pom.xml

@@ -133,7 +133,16 @@
 					</execution>
 				</executions>
 			</plugin>
+			<!-- 跳过单元测试 -->
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-surefire-plugin</artifactId>
+				<configuration>
+					<skipTests>true</skipTests>
+				</configuration>
+			</plugin>
 		</plugins>
+
 	</build>
 
 </project>

+ 37 - 20
java/sp-app/src/main/java/com/anji/sp/controller/SpAppReqController.java

@@ -1,11 +1,14 @@
 package com.anji.sp.controller;
 
+import com.alibaba.fastjson.JSONObject;
 import com.anji.sp.model.ResponseModel;
+import com.anji.sp.model.vo.AppUpdateReqVo;
 import com.anji.sp.model.vo.SpAppReqDataVO;
 import com.anji.sp.service.SpAppReqService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -21,24 +24,38 @@ import javax.servlet.http.HttpServletRequest;
 @Api(tags = "手机端请求接口")
 public class SpAppReqController {
 
-    @Autowired
-    private SpAppReqService spAppReqService;
-
-    @ApiOperation(value = "初始化保存用户设备信息", httpMethod = "POST")
-    @PostMapping("/deviceInit")
-    public ResponseModel deviceInit(@RequestBody SpAppReqDataVO spAppReqDataVO, HttpServletRequest request) {
-        return spAppReqService.deviceInit(spAppReqDataVO, request);
-    }
-
-    @ApiOperation(value = "获取APP 版本 信息", httpMethod = "POST")
-    @PostMapping("/appVersion")
-    public ResponseModel getAppVersion(@RequestBody SpAppReqDataVO spAppReqDataVO, HttpServletRequest request) {
-        return spAppReqService.getAppVersion(spAppReqDataVO, request);
-    }
-
-    @ApiOperation(value = "获取APP 公告 信息", httpMethod = "POST")
-    @PostMapping("/appNotice")
-    public ResponseModel getAppNotice(@RequestBody SpAppReqDataVO spAppReqDataVO, HttpServletRequest request) {
-        return spAppReqService.getAppNotice(spAppReqDataVO, request);
-    }
+	@Autowired
+	private SpAppReqService spAppReqService;
+
+	@ApiOperation(value = "初始化保存用户设备信息", httpMethod = "POST")
+	@PostMapping("/deviceInit")
+	public ResponseModel deviceInit(@RequestBody SpAppReqDataVO spAppReqDataVO, HttpServletRequest request) {
+		return spAppReqService.deviceInit(spAppReqDataVO, request);
+	}
+
+	@ApiOperation(value = "获取APP 版本 信息", httpMethod = "POST")
+	@PostMapping("/appVersion")
+	public ResponseModel getAppVersion(@RequestBody SpAppReqDataVO spAppReqDataVO, HttpServletRequest request) {
+		return spAppReqService.getAppVersion(spAppReqDataVO, request);
+	}
+
+	@ApiOperation(value = "获取APP 公告 信息", httpMethod = "POST")
+	@PostMapping("/appNotice")
+	public ResponseModel getAppNotice(@RequestBody SpAppReqDataVO spAppReqDataVO, HttpServletRequest request) {
+		return spAppReqService.getAppNotice(spAppReqDataVO, request);
+	}
+
+	@ApiOperation(value = "下载app", httpMethod = "get")
+	@GetMapping("/download")
+	public JSONObject download(AppUpdateReqVo spAppReqDataVO) {
+		try {
+			return spAppReqService.download(spAppReqDataVO);
+		} catch (Exception e) {
+			JSONObject json = new JSONObject();
+			json.put("code", 70002);
+			json.put("msg", "版本更新失败!");
+			return json;
+		}
+
+	}
 }

+ 15 - 0
java/sp-app/src/main/java/com/anji/sp/model/vo/AppUpdateReqVo.java

@@ -0,0 +1,15 @@
+package com.anji.sp.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AppUpdateReqVo {
+	@ApiModelProperty(value = "平台(ios/android)", required = true)
+	private String platform = "Android";
+	private String appRegion;
+	private String versionCode;
+	private String versionName;
+}

+ 29 - 0
java/sp-app/src/main/java/com/anji/sp/model/vo/AppUpdateRespVo.java

@@ -0,0 +1,29 @@
+package com.anji.sp.model.vo;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AppUpdateRespVo {
+	private String code="0";
+	private String msg="";
+	private String updateStatus;
+	private String versionCode;
+	private String versionName;
+	private String modifyContent;
+	private String downloadUrl;
+	private String apkSize;
+	private String apkMd5;
+//	{
+//		  "Code": 0,
+//		  "Msg": "",
+//		  "UpdateStatus": 1,
+//		  "VersionCode": 3,
+//		  "VersionName": "1.0.2",
+//		  "ModifyContent": "1、优化api接口。\r\n2、添加使用demo演示。\r\n3、新增自定义更新服务API接口。\r\n4、优化更新提示界面。",
+//		  "DownloadUrl": "https://raw.githubusercontent.com/xuexiangjys/XUpdate/master/apk/xupdate_demo_1.0.2.apk",
+//		  "ApkSize": 2048,
+//		  "ApkMd5": ""
+//		}
+}

+ 4 - 3
java/sp-app/src/main/java/com/anji/sp/model/vo/SpAppReqDataVO.java

@@ -14,9 +14,10 @@ import java.io.Serializable;
 @Data
 @ApiModel("app请求VO")
 public class SpAppReqDataVO implements Serializable {
-    @ApiModelProperty(value = "应用唯一key", required = true)
+    @ApiModelProperty(value = "应用唯一key")
     private SpAppLogVO data;
-    @ApiModelProperty(value = "加密结果", required = true)
+    @ApiModelProperty(value = "加密结果")
     private String sign;
-
+    @ApiModelProperty(value = "app名称")
+    private String appRegion;
 }

+ 29 - 25
java/sp-app/src/main/java/com/anji/sp/service/SpAppReqService.java

@@ -1,41 +1,45 @@
 package com.anji.sp.service;
 
+import com.alibaba.fastjson.JSONObject;
 import com.anji.sp.model.ResponseModel;
+import com.anji.sp.model.vo.AppUpdateReqVo;
 import com.anji.sp.model.vo.SpAppReqDataVO;
 
 import javax.servlet.http.HttpServletRequest;
 
 /**
- * app  接口
+ * app 接口
  *
  * @author Kean
  * @date 2020/06/23
  */
 public interface SpAppReqService {
-    /**
-     * 初始化保存用户设备信息
-     *
-     * @param spAppReqDataVO
-     * @param request
-     * @return
-     */
-    ResponseModel deviceInit(SpAppReqDataVO spAppReqDataVO, HttpServletRequest request);
+	/**
+	 * 初始化保存用户设备信息
+	 *
+	 * @param spAppReqDataVO
+	 * @param request
+	 * @return
+	 */
+	ResponseModel deviceInit(SpAppReqDataVO spAppReqDataVO, HttpServletRequest request);
 
-    /**
-     * 获取APP 版本 信息
-     *
-     * @param spAppReqDataVO
-     * @param request
-     * @return
-     */
-    ResponseModel getAppVersion(SpAppReqDataVO spAppReqDataVO, HttpServletRequest request);
+	/**
+	 * 获取APP 版本 信息
+	 *
+	 * @param spAppReqDataVO
+	 * @param request
+	 * @return
+	 */
+	ResponseModel getAppVersion(SpAppReqDataVO spAppReqDataVO, HttpServletRequest request);
 
-    /**
-     * 获取APP 公告 信息
-     *
-     * @param spAppReqDataVO
-     * @param request
-     * @return
-     */
-    ResponseModel getAppNotice(SpAppReqDataVO spAppReqDataVO, HttpServletRequest request);
+	/**
+	 * 获取APP 公告 信息
+	 *
+	 * @param spAppReqDataVO
+	 * @param request
+	 * @return
+	 */
+	ResponseModel getAppNotice(SpAppReqDataVO spAppReqDataVO, HttpServletRequest request);
+
+	JSONObject download(AppUpdateReqVo spAppReqDataVO);
 }

Diferenças do arquivo suprimidas por serem muito extensas
+ 515 - 470
java/sp-app/src/main/java/com/anji/sp/service/impl/SpAppReqServiceImpl.java


+ 3 - 3
java/sp-app/src/main/resources/application.properties

@@ -1,13 +1,13 @@
 spring.application.name=sp-service
 server.servlet.context-path=/sp
-server.port=8081
+server.port=8831
 #spring.profiles.active=uat
 
 #mysql数据库连接
 spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
-spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/aj_app_sp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8
+spring.datasource.druid.url=jdbc:mysql://114.55.230.80:3306/aj_app_sp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8
 spring.datasource.druid.username=root
-spring.datasource.druid.password=admin
+spring.datasource.druid.password=QopraffaQWPRPPR123
 spring.datasource.druid.initial-size=1
 spring.datasource.druid.max-active=100
 spring.datasource.druid.min-idle=1

+ 33 - 0
java/sp-auth/bin/.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/

+ 40 - 0
java/sp-auth/bin/pom.xml

@@ -0,0 +1,40 @@
+<?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>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <parent>
+        <groupId>com.anji-plus.sp</groupId>
+        <artifactId>sp-parent</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <artifactId>sp-auth</artifactId>
+    <name>sp-auth</name>
+    <packaging>jar</packaging>
+    <description>Demo project for Spring Boot</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.anji-plus.sp</groupId>
+            <artifactId>sp-common</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+    </dependencies>
+
+
+</project>

+ 1 - 0
java/sp-auth/bin/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaCacheService

@@ -0,0 +1 @@
+com.anji.sp.service.impl.CaptchaCacheServiceRedisImpl

BIN
java/sp-auth/bin/src/main/resources/ip/ip2region.db


+ 47 - 0
java/sp-auth/bin/src/main/resources/logback.xml

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <property name="LOG_HOME" value="./logs"/>
+    <property name="LOG_NAME" value="sp"/>
+
+    <!--控制台-->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{MM-dd HH:mm:ss.SSS} | %thread |-%-5level %logger{36}:%L - %msg%n</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+
+    <!-- 日志文件 -->
+    <appender name="LOGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/${LOG_NAME}.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/${LOG_NAME}-%i.log</fileNamePattern>
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{MM-dd HH:mm:ss.SSS} |-%-5level %logger{36}:%L - %m%n</pattern>
+        </layout>
+    </appender>
+
+    <!-- sql文件 -->
+    <appender name="LOGSQL" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_HOME}/${LOG_NAME}-sql.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/${LOG_NAME}-sql-%i.log</fileNamePattern>
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{MM-dd HH:mm:ss.SSS} |-%-5level %logger{36}:%L - %m%n</pattern>
+        </layout>
+    </appender>
+
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT" />
+        <appender-ref ref="LOGFILE" />
+    </root>
+</configuration>

+ 1 - 0
java/sp-auth/src/main/java/com/anji/sp/config/SecurityConfig.java

@@ -97,6 +97,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                 // 对于登录login 验证码captcha 允许匿名访问
                 .antMatchers(
                   "/login/**",
+                  "/phone/**", 
                   "/download/**", 
                   "/upload/uploadMinio", 
                   "/captcha/**").anonymous()

+ 33 - 0
java/sp-common/bin/.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/

+ 26 - 0
java/sp-common/bin/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>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <parent>
+        <groupId>com.anji-plus.sp</groupId>
+        <artifactId>sp-parent</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <artifactId>sp-common</artifactId>
+    <name>sp-common</name>
+    <packaging>jar</packaging>
+    <description>common project</description>
+</project>

+ 33 - 0
java/sp-notice/bin/.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/

+ 33 - 0
java/sp-notice/bin/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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <parent>
+        <groupId>com.anji-plus.sp</groupId>
+        <artifactId>sp-parent</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <artifactId>sp-notice</artifactId>
+    <name>sp-notice</name>
+    <packaging>jar</packaging>
+    <description>Demo project for Spring Boot</description>
+    <dependencies>
+        <dependency>
+            <groupId>com.anji-plus.sp</groupId>
+            <artifactId>sp-auth</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+    </dependencies>
+</project>

+ 8 - 0
java/sp-notice/bin/src/main/resources/mapper/SpNoticeMapper.xml

@@ -0,0 +1,8 @@
+<?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.anji.sp.mapper.SpNoticeMapper">
+    <update id="setNoticeEnableInvalid">
+        update sp_notice set enable_flag = 0 where end_time <![CDATA[<]]> sysdate()
+    </update>
+</mapper>

+ 130 - 0
java/sp-push/bin/pom.xml

@@ -0,0 +1,130 @@
+<?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>
+    <parent>
+        <groupId>com.anji-plus.sp</groupId>
+        <artifactId>sp-parent</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <artifactId>sp-push</artifactId>
+    <name>sp-push</name>
+    <packaging>jar</packaging>
+    <description>app push module</description>
+    <dependencies>
+        <dependency>
+            <groupId>com.anji-plus.sp</groupId>
+            <artifactId>sp-auth</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+        <!--    本地加载    -->
+        <dependency>
+            <groupId>com.vivo.push.sdk</groupId>
+            <artifactId>vpush-server-sdk</artifactId>
+            <version>2.2</version>
+            <scope>system</scope>
+            <systemPath>${pom.basedir}/src/main/resources/libs/vpush-server-sdk-2.2.jar
+            </systemPath>
+        </dependency>
+        <dependency>
+            <groupId>com.oppo.push.sdk</groupId>
+            <artifactId>opush-server-sdk</artifactId>
+            <version>1.0.6</version>
+            <scope>system</scope>
+            <systemPath>${pom.basedir}/src/main/resources/libs/opush-server-sdk-1.0.6.jar
+            </systemPath>
+        </dependency>
+        <dependency>
+            <groupId>com.xiaomi.xmpush</groupId>
+            <artifactId>MiPush_SDK_Server_Http</artifactId>
+            <version>2_1.0.9</version>
+            <scope>system</scope>
+            <systemPath>${pom.basedir}/src/main/resources/libs/MiPush_SDK_Server_Http2_1.0.9.jar
+            </systemPath>
+        </dependency>
+
+        <!--commons-codec-->
+        <!--        <dependency>-->
+        <!--            <groupId>commons-codec</groupId>-->
+        <!--            <artifactId>commons-codec</artifactId>-->
+        <!--            <version>1.15</version>-->
+        <!--        </dependency>-->
+
+        <!--        <dependency>-->
+        <!--            <groupId>commons-logging</groupId>-->
+        <!--            <artifactId>commons-logging</artifactId>-->
+        <!--            <version>1.2</version>-->
+        <!--        </dependency>-->
+
+        <dependency>
+            <groupId>org.conscrypt</groupId>
+            <artifactId>conscrypt-openjdk-uber</artifactId>
+            <version>2.1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.12</version>
+        </dependency>
+
+        <!-- apache common封装好的HttpClient-->
+        <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+            <version>4.5.12</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.googlecode.json-simple</groupId>
+            <artifactId>json-simple</artifactId>
+            <version>1.1.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpcore</artifactId>
+            <version>4.4.13</version>
+        </dependency>
+
+        <!--        <dependency>-->
+        <!--            <groupId>com.squareup.okhttp3</groupId>-->
+        <!--            <artifactId>okhttp</artifactId>-->
+        <!--            <version>3.6.0</version>-->
+        <!--            <scope>provided</scope>-->
+        <!--        </dependency>-->
+        <!-- 极光推送开始-->
+        <dependency>
+            <groupId>cn.jpush.api</groupId>
+            <artifactId>jpush-client</artifactId>
+            <version>3.4.7</version>
+        </dependency>
+        <!-- 极光推送结束-->
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <!-- 项目打成jar的同时将本地jar包也引入进去-->
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 20 - 0
java/sp-push/bin/src/main/resources/AJPushUrl.properties

@@ -0,0 +1,20 @@
+# appKey
+#app_key=ssss
+# 华为
+#appid_hw=103436069
+#appsecret_hw=3cd49e4fea811cb20f66f215bf1c79c1cd5223da452599ced3e75b09cf1a5f19
+token_server_hw=https://oauth-login.cloud.huawei.com/oauth2/v2/token
+push_open_url_hw=https://push-api.cloud.huawei.com
+# 小米
+#package_name_xm=com.anji.plus.pushdemo
+#security_xm=9sv5rMFp26YwDtkviHNn7w==
+#oppo
+#mastersecret_op=040be856d0fd4727ad3edc54dc751707
+#appkey_op=c160669462604212962064ffa2df36af
+# vivo
+#secret_vo=6d3f83e7-aa55-45ab-8939-c549692eff44
+#appkey_vo=ecaa359c8bbe601d7bbc86d29f5cc58e
+#appid_vo=105303997
+# jg
+#appkey_jg=66c9266fc53b8025cb0dd919
+#mastersecret_jg=95fd6af12b0eaae5dab73215

+ 152 - 0
java/sp-push/bin/src/main/resources/mapper/PushConfiguresMapper.xml

@@ -0,0 +1,152 @@
+<?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.anji.sp.push.mapper.PushConfiguresMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.anji.sp.push.model.po.PushConfiguresPO">
+        <id column="id" property="id" />
+        <result column="app_id" property="appId" />
+        <result column="app_key" property="appKey" />
+        <result column="secret_key" property="secretKey" />
+        <result column="jg_app_key" property="jgAppKey" />
+        <result column="jg_master_secret" property="jgMasterSecret" />
+        <result column="hw_app_id" property="hwAppId" />
+        <result column="hw_app_secret" property="hwAppSecret" />
+        <result column="hw_default_title" property="hwDefaultTitle" />
+        <result column="op_app_id" property="opAppId" />
+        <result column="op_app_secret" property="opAppSecret" />
+        <result column="op_default_title" property="opDefaultTitle" />
+        <result column="op_app_key" property="opAppKey" />
+        <result column="op_master_secret" property="opMasterSecret" />
+        <result column="vo_app_id" property="voAppId" />
+        <result column="vo_app_secret" property="voAppSecret" />
+        <result column="vo_default_title" property="voDefaultTitle" />
+        <result column="vo_app_key" property="voAppKey" />
+        <result column="xm_app_id" property="xmAppId" />
+        <result column="xm_app_secret" property="xmAppSecret" />
+        <result column="xm_default_title" property="xmDefaultTitle" />
+        <result column="xm_app_key" property="xmAppKey" />
+        <result column="package_name" property="packageName" />
+        <result column="enable_flag" property="enableFlag" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="create_by" property="createBy" />
+        <result column="create_date" property="createDate" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_date" property="updateDate" />
+        <result column="remarks" property="remarks" />
+        <result column="channel_enable" property="channelEnable" />
+    </resultMap>
+
+    <!-- 自定义查询映射结果 -->
+    <resultMap id="ResultMapWithVO" type="com.anji.sp.push.model.vo.PushConfiguresVO" extends="BaseResultMap">
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, app_id, app_key, secret_key, jg_app_key, jg_master_secret, hw_app_id, hw_app_secret, hw_default_title, op_app_id, op_app_secret, op_default_title, op_app_key, op_master_secret, vo_app_id, vo_app_secret, vo_default_title, vo_app_key, xm_app_id, xm_app_secret, xm_default_title, xm_app_key, package_name, enable_flag, delete_flag, create_by, create_date, update_by, update_date, remarks, channel_enable
+    </sql>
+
+    <!-- 自定义分页查询 -->
+    <select id="queryByPage" resultMap="ResultMapWithVO" parameterType="com.anji.sp.push.model.vo.PushConfiguresVO">
+        select
+        <include refid="Base_Column_List" />
+        from push_configures
+        <where >
+            <!-- 模糊查询参考 columnName LIKE CONCAT('%',#{keyword,jdbcType=VARCHAR},'%') -->
+            <!-- 子查询参考 columnName IN <foreach collection="list" item="item" index="index" separator="," open="(" close=")">#{item}</foreach> -->
+            <if test="pushConfiguresVO.id != null " >
+                and id = #{pushConfiguresVO.id}
+            </if>
+            <if test="pushConfiguresVO.appId != null " >
+                and app_id = #{pushConfiguresVO.appId}
+            </if>
+            <if test="pushConfiguresVO.appKey != null " >
+                and app_key = #{pushConfiguresVO.appKey}
+            </if>
+            <if test="pushConfiguresVO.secretKey != null " >
+                and secret_key = #{pushConfiguresVO.secretKey}
+            </if>
+            <if test="pushConfiguresVO.jgAppKey != null " >
+                and jg_app_key = #{pushConfiguresVO.jgAppKey}
+            </if>
+            <if test="pushConfiguresVO.jgMasterSecret != null " >
+                and jg_master_secret = #{pushConfiguresVO.jgMasterSecret}
+            </if>
+            <if test="pushConfiguresVO.hwAppId != null " >
+                and hw_app_id = #{pushConfiguresVO.hwAppId}
+            </if>
+            <if test="pushConfiguresVO.hwAppSecret != null " >
+                and hw_app_secret = #{pushConfiguresVO.hwAppSecret}
+            </if>
+            <if test="pushConfiguresVO.hwDefaultTitle != null " >
+                and hw_default_title = #{pushConfiguresVO.hwDefaultTitle}
+            </if>
+            <if test="pushConfiguresVO.opAppId != null " >
+                and op_app_id = #{pushConfiguresVO.opAppId}
+            </if>
+            <if test="pushConfiguresVO.opAppSecret != null " >
+                and op_app_secret = #{pushConfiguresVO.opAppSecret}
+            </if>
+            <if test="pushConfiguresVO.opDefaultTitle != null " >
+                and op_default_title = #{pushConfiguresVO.opDefaultTitle}
+            </if>
+            <if test="pushConfiguresVO.opAppKey != null " >
+                and op_app_key = #{pushConfiguresVO.opAppKey}
+            </if>
+            <if test="pushConfiguresVO.opMasterSecret != null " >
+                and op_master_secret = #{pushConfiguresVO.opMasterSecret}
+            </if>
+            <if test="pushConfiguresVO.voAppId != null " >
+                and vo_app_id = #{pushConfiguresVO.voAppId}
+            </if>
+            <if test="pushConfiguresVO.voAppSecret != null " >
+                and vo_app_secret = #{pushConfiguresVO.voAppSecret}
+            </if>
+            <if test="pushConfiguresVO.voDefaultTitle != null " >
+                and vo_default_title = #{pushConfiguresVO.voDefaultTitle}
+            </if>
+            <if test="pushConfiguresVO.voAppKey != null " >
+                and vo_app_key = #{pushConfiguresVO.voAppKey}
+            </if>
+            <if test="pushConfiguresVO.xmAppId != null " >
+                and xm_app_id = #{pushConfiguresVO.xmAppId}
+            </if>
+            <if test="pushConfiguresVO.xmAppSecret != null " >
+                and xm_app_secret = #{pushConfiguresVO.xmAppSecret}
+            </if>
+            <if test="pushConfiguresVO.xmDefaultTitle != null " >
+                and xm_default_title = #{pushConfiguresVO.xmDefaultTitle}
+            </if>
+            <if test="pushConfiguresVO.xmAppKey != null " >
+                and xm_app_key = #{pushConfiguresVO.xmAppKey}
+            </if>
+            <if test="pushConfiguresVO.packageName != null " >
+                and package_name = #{pushConfiguresVO.packageName}
+            </if>
+            <if test="pushConfiguresVO.enableFlag != null " >
+                and enable_flag = #{pushConfiguresVO.enableFlag}
+            </if>
+            <if test="pushConfiguresVO.deleteFlag != null " >
+                and delete_flag = #{pushConfiguresVO.deleteFlag}
+            </if>
+            <if test="pushConfiguresVO.createBy != null " >
+                and create_by = #{pushConfiguresVO.createBy}
+            </if>
+            <if test="pushConfiguresVO.createDate != null " >
+                and create_date = #{pushConfiguresVO.createDate}
+            </if>
+            <if test="pushConfiguresVO.updateBy != null " >
+                and update_by = #{pushConfiguresVO.updateBy}
+            </if>
+            <if test="pushConfiguresVO.updateDate != null " >
+                and update_date = #{pushConfiguresVO.updateDate}
+            </if>
+            <if test="pushConfiguresVO.remarks != null " >
+                and remarks = #{pushConfiguresVO.remarks}
+            </if>
+            <if test="pushConfiguresVO.channelEnable != null " >
+                and channel_enable = #{pushConfiguresVO.channelEnable}
+            </if>
+        </where>
+    </select>
+</mapper>

+ 129 - 0
java/sp-push/bin/src/main/resources/mapper/PushHistoryMapper.xml

@@ -0,0 +1,129 @@
+<?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.anji.sp.push.mapper.PushHistoryMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.anji.sp.push.model.po.PushHistoryPO">
+        <id column="id" property="id" />
+        <result column="app_key" property="appKey" />
+        <result column="msg_id" property="msgId" />
+        <result column="device_ids" property="deviceIds" />
+        <result column="registration_ids" property="registrationIds" />
+        <result column="target_type" property="targetType" />
+        <result column="target_num" property="targetNum" />
+        <result column="success_num" property="successNum" />
+        <result column="title" property="title" />
+        <result column="content" property="content" />
+        <result column="extras" property="extras" />
+        <result column="ios_config" property="iosConfig" />
+        <result column="android_config" property="androidConfig" />
+        <result column="send_origin" property="sendOrigin" />
+        <result column="push_type" property="pushType" />
+        <result column="channel" property="channel" />
+        <result column="push_result" property="pushResult" />
+        <result column="send_time" property="sendTime" />
+        <result column="enable_flag" property="enableFlag" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="create_by" property="createBy" />
+        <result column="create_date" property="createDate" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_date" property="updateDate" />
+        <result column="remarks" property="remarks" />
+    </resultMap>
+
+    <!-- 自定义查询映射结果 -->
+    <resultMap id="ResultMapWithVO" type="com.anji.sp.push.model.vo.PushHistoryVO" extends="BaseResultMap">
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, app_key, msg_id, device_ids, registration_ids, target_type, target_num, success_num, title, content, extras, ios_config, android_config, send_origin, push_type, channel, push_result, send_time, enable_flag, delete_flag, create_by, create_date, update_by, update_date, remarks
+    </sql>
+
+    <!-- 自定义分页查询 -->
+    <select id="queryByPage" resultMap="ResultMapWithVO" parameterType="com.anji.sp.push.model.vo.PushHistoryVO">
+        select
+        <include refid="Base_Column_List" />
+        from push_history
+        <where >
+            <!-- 模糊查询参考 columnName LIKE CONCAT('%',#{keyword,jdbcType=VARCHAR},'%') -->
+            <!-- 子查询参考 columnName IN <foreach collection="list" item="item" index="index" separator="," open="(" close=")">#{item}</foreach> -->
+            <if test="pushHistoryVO.id != null " >
+                and id = #{pushHistoryVO.id}
+            </if>
+            <if test="pushHistoryVO.appKey != null " >
+                and app_key = #{pushHistoryVO.appKey}
+            </if>
+            <if test="pushHistoryVO.msgId != null " >
+                and msg_id = #{pushHistoryVO.msgId}
+            </if>
+            <if test="pushHistoryVO.deviceIds != null " >
+                and device_ids = #{pushHistoryVO.deviceIds}
+            </if>
+            <if test="pushHistoryVO.registrationIds != null " >
+                and registration_ids = #{pushHistoryVO.registrationIds}
+            </if>
+            <if test="pushHistoryVO.targetType != null " >
+                and target_type = #{pushHistoryVO.targetType}
+            </if>
+            <if test="pushHistoryVO.targetNum != null " >
+                and target_num = #{pushHistoryVO.targetNum}
+            </if>
+            <if test="pushHistoryVO.successNum != null " >
+                and success_num = #{pushHistoryVO.successNum}
+            </if>
+            <if test="pushHistoryVO.title != null " >
+                and title = #{pushHistoryVO.title}
+            </if>
+            <if test="pushHistoryVO.content != null " >
+                and content = #{pushHistoryVO.content}
+            </if>
+            <if test="pushHistoryVO.extras != null " >
+                and extras = #{pushHistoryVO.extras}
+            </if>
+            <if test="pushHistoryVO.iosConfig != null " >
+                and ios_config = #{pushHistoryVO.iosConfig}
+            </if>
+            <if test="pushHistoryVO.androidConfig != null " >
+                and android_config = #{pushHistoryVO.androidConfig}
+            </if>
+            <if test="pushHistoryVO.sendOrigin != null " >
+                and send_origin = #{pushHistoryVO.sendOrigin}
+            </if>
+            <if test="pushHistoryVO.pushType != null " >
+                and push_type = #{pushHistoryVO.pushType}
+            </if>
+            <if test="pushHistoryVO.channel != null " >
+                and channel = #{pushHistoryVO.channel}
+            </if>
+            <if test="pushHistoryVO.pushResult != null " >
+                and push_result = #{pushHistoryVO.pushResult}
+            </if>
+            <if test="pushHistoryVO.sendTime != null " >
+                and send_time = #{pushHistoryVO.sendTime}
+            </if>
+            <if test="pushHistoryVO.enableFlag != null " >
+                and enable_flag = #{pushHistoryVO.enableFlag}
+            </if>
+            <if test="pushHistoryVO.deleteFlag != null " >
+                and delete_flag = #{pushHistoryVO.deleteFlag}
+            </if>
+            <if test="pushHistoryVO.createBy != null " >
+                and create_by = #{pushHistoryVO.createBy}
+            </if>
+            <if test="pushHistoryVO.createDate != null " >
+                and create_date = #{pushHistoryVO.createDate}
+            </if>
+            <if test="pushHistoryVO.updateBy != null " >
+                and update_by = #{pushHistoryVO.updateBy}
+            </if>
+            <if test="pushHistoryVO.updateDate != null " >
+                and update_date = #{pushHistoryVO.updateDate}
+            </if>
+            <if test="pushHistoryVO.remarks != null " >
+                and remarks = #{pushHistoryVO.remarks}
+            </if>
+        </where>
+        ORDER BY update_date DESC
+    </select>
+</mapper>

+ 93 - 0
java/sp-push/bin/src/main/resources/mapper/PushMessageMapper.xml

@@ -0,0 +1,93 @@
+<?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.anji.sp.push.mapper.PushMessageMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.anji.sp.push.model.po.PushMessagePO">
+        <id column="id" property="id" />
+        <result column="app_key" property="appKey" />
+        <result column="msg_id" property="msgId" />
+        <result column="oper_param" property="operParam" />
+        <result column="target_num" property="targetNum" />
+        <result column="success_num" property="successNum" />
+        <result column="consumption_state" property="consumptionState" />
+        <result column="enable_flag" property="enableFlag" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="create_by" property="createBy" />
+        <result column="create_date" property="createDate" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_date" property="updateDate" />
+        <result column="remarks" property="remarks" />
+        <result column="send_origin" property="sendOrigin" />
+        <result column="push_type" property="pushType" />
+    </resultMap>
+
+    <!-- 自定义查询映射结果 -->
+    <resultMap id="ResultMapWithVO" type="com.anji.sp.push.model.vo.PushMessageVO" extends="BaseResultMap">
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, app_key, msg_id, oper_param, target_num, success_num, consumption_state, enable_flag, delete_flag, create_by, create_date, update_by, update_date, remarks, send_origin, push_type
+    </sql>
+
+    <!-- 自定义分页查询 -->
+    <select id="queryByPage" resultMap="ResultMapWithVO" parameterType="com.anji.sp.push.model.vo.PushMessageVO">
+        select
+        <include refid="Base_Column_List" />
+        from push_message
+        <where >
+            <!-- 模糊查询参考 columnName LIKE CONCAT('%',#{keyword,jdbcType=VARCHAR},'%') -->
+            <!-- 子查询参考 columnName IN <foreach collection="list" item="item" index="index" separator="," open="(" close=")">#{item}</foreach> -->
+            <if test="pushMessageVO.id != null " >
+                and id = #{pushMessageVO.id}
+            </if>
+            <if test="pushMessageVO.appKey != null and pushMessageVO.appKey != ''" >
+                and app_key = #{pushMessageVO.appKey}
+            </if>
+            <if test="pushMessageVO.msgId != null and pushMessageVO.msgId != ''" >
+                and msg_id = #{pushMessageVO.msgId}
+            </if>
+            <if test="pushMessageVO.operParam != null and pushMessageVO.operParam != ''" >
+                and oper_param = #{pushMessageVO.operParam}
+            </if>
+            <if test="pushMessageVO.targetNum != null " >
+                and target_num = #{pushMessageVO.targetNum}
+            </if>
+            <if test="pushMessageVO.successNum != null " >
+                and success_num = #{pushMessageVO.successNum}
+            </if>
+            <if test="pushMessageVO.consumptionState != null " >
+                and consumption_state = #{pushMessageVO.consumptionState}
+            </if>
+            <if test="pushMessageVO.enableFlag != null " >
+                and enable_flag = #{pushMessageVO.enableFlag}
+            </if>
+            <if test="pushMessageVO.deleteFlag != null " >
+                and delete_flag = #{pushMessageVO.deleteFlag}
+            </if>
+            <if test="pushMessageVO.createBy != null " >
+                and create_by = #{pushMessageVO.createBy}
+            </if>
+            <if test="pushMessageVO.createDate != null " >
+                and create_date = #{pushMessageVO.createDate}
+            </if>
+            <if test="pushMessageVO.updateBy != null " >
+                and update_by = #{pushMessageVO.updateBy}
+            </if>
+            <if test="pushMessageVO.remarks != null " >
+                and remarks = #{pushMessageVO.remarks}
+            </if>
+            <if test="pushMessageVO.sendOrigin != null and pushMessageVO.sendOrigin != '' " >
+                and send_origin = #{pushMessageVO.sendOrigin}
+            </if>
+            <if test="pushMessageVO.pushType != null and pushMessageVO.pushType != '' " >
+                and push_type = #{pushMessageVO.pushType}
+            </if>
+            <if test="pushMessageVO.startTime != null and pushMessageVO.startTime != '' and pushMessageVO.endTime != null and pushMessageVO.endTime != ''">
+                AND update_date between #{pushMessageVO.startTime} and #{pushMessageVO.endTime}
+            </if>
+        </where>
+        ORDER BY update_date DESC
+    </select>
+</mapper>

+ 92 - 0
java/sp-push/bin/src/main/resources/mapper/PushUserMapper.xml

@@ -0,0 +1,92 @@
+<?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.anji.sp.push.mapper.PushUserMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.anji.sp.push.model.po.PushUserPO">
+        <id column="id" property="id" />
+        <result column="app_key" property="appKey" />
+        <result column="device_id" property="deviceId" />
+        <result column="manu_token" property="manuToken" />
+        <result column="device_type" property="deviceType" />
+        <result column="alias" property="alias" />
+        <result column="registration_id" property="registrationId" />
+        <result column="brand" property="brand" />
+        <result column="os_version" property="osVersion" />
+        <result column="enable_flag" property="enableFlag" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="create_by" property="createBy" />
+        <result column="create_date" property="createDate" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_date" property="updateDate" />
+        <result column="remarks" property="remarks" />
+    </resultMap>
+
+    <!-- 自定义查询映射结果 -->
+    <resultMap id="ResultMapWithVO" type="com.anji.sp.push.model.vo.PushUserVO" extends="BaseResultMap">
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, app_key, device_id, manu_token, device_type, alias, registration_id, brand, os_version, enable_flag, delete_flag, create_by, create_date, update_by, update_date, remarks
+    </sql>
+
+    <!-- 自定义分页查询 -->
+    <select id="queryByPage" resultMap="ResultMapWithVO" parameterType="com.anji.sp.push.model.vo.PushUserVO">
+        select
+        <include refid="Base_Column_List" />
+        from push_user
+        <where >
+            <!-- 模糊查询参考 columnName LIKE CONCAT('%',#{keyword,jdbcType=VARCHAR},'%') -->
+            <!-- 子查询参考 columnName IN <foreach collection="list" item="item" index="index" separator="," open="(" close=")">#{item}</foreach> -->
+            <if test="pushUserVO.id != null " >
+                and id = #{pushUserVO.id}
+            </if>
+            <if test="pushUserVO.appKey != null " >
+                and app_key = #{pushUserVO.appKey}
+            </if>
+            <if test="pushUserVO.deviceId != null " >
+                and device_id = #{pushUserVO.deviceId}
+            </if>
+            <if test="pushUserVO.manuToken != null " >
+                and manu_token = #{pushUserVO.manuToken}
+            </if>
+            <if test="pushUserVO.deviceType != null " >
+                and device_type = #{pushUserVO.deviceType}
+            </if>
+            <if test="pushUserVO.alias != null " >
+                and alias = #{pushUserVO.alias}
+            </if>
+            <if test="pushUserVO.registrationId != null " >
+                and registration_id = #{pushUserVO.registrationId}
+            </if>
+            <if test="pushUserVO.brand != null " >
+                and brand = #{pushUserVO.brand}
+            </if>
+            <if test="pushUserVO.osVersion != null " >
+                and os_version = #{pushUserVO.osVersion}
+            </if>
+            <if test="pushUserVO.enableFlag != null " >
+                and enable_flag = #{pushUserVO.enableFlag}
+            </if>
+            <if test="pushUserVO.deleteFlag != null " >
+                and delete_flag = #{pushUserVO.deleteFlag}
+            </if>
+            <if test="pushUserVO.createBy != null " >
+                and create_by = #{pushUserVO.createBy}
+            </if>
+            <if test="pushUserVO.createDate != null " >
+                and create_date = #{pushUserVO.createDate}
+            </if>
+            <if test="pushUserVO.updateBy != null " >
+                and update_by = #{pushUserVO.updateBy}
+            </if>
+            <if test="pushUserVO.updateDate != null " >
+                and update_date = #{pushUserVO.updateDate}
+            </if>
+            <if test="pushUserVO.remarks != null " >
+                and remarks = #{pushUserVO.remarks}
+            </if>
+        </where>
+    </select>
+</mapper>

+ 33 - 0
java/sp-version/bin/.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/

+ 46 - 0
java/sp-version/bin/pom.xml

@@ -0,0 +1,46 @@
+<?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>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>8</source>
+					<target>8</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+	<parent>
+		<groupId>com.anji-plus.sp</groupId>
+		<artifactId>sp-parent</artifactId>
+		<version>1.0.0</version>
+	</parent>
+	<artifactId>sp-version</artifactId>
+	<name>sp-version</name>
+	<packaging>jar</packaging>
+	<description>Demo project for Spring Boot</description>
+
+	<dependencies>
+		<dependency>
+			<groupId>io.minio</groupId>
+			<artifactId>minio</artifactId>
+			<version>7.0.2</version>
+		</dependency>
+		<dependency>
+			<groupId>cn.hutool</groupId>
+			<artifactId>hutool-all</artifactId>
+			<version>5.8.10</version>
+		</dependency>
+		<dependency>
+			<groupId>com.anji-plus.sp</groupId>
+			<artifactId>sp-auth</artifactId>
+			<version>1.0.0</version>
+		</dependency>
+	</dependencies>
+
+</project>

+ 46 - 0
java/sp-version/bin/src/main/resources/mapper/SpVersionMapper.xml

@@ -0,0 +1,46 @@
+<?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.anji.sp.mapper.SpVersionMapper">
+
+    <resultMap id="BaseResultMap" type="com.anji.sp.model.po.SpVersionPO" >
+        <result column="id" property="id" />
+        <result column="app_id" property="appId" />
+        <result column="platform" property="platform" />
+        <result column="version_name" property="versionName" />
+        <result column="version_number" property="versionNumber" />
+        <result column="update_log" property="updateLog" />
+        <result column="internal_url" property="internalUrl" />
+        <result column="external_url" property="externalUrl" />
+        <result column="version_config" property="versionConfig" />
+        <result column="enable_flag" property="enableFlag" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="create_by" property="createBy" />
+        <result column="create_date" property="createDate" />
+        <result column="update_by" property="updateBy" />
+        <result column="update_date" property="updateDate" />
+        <result column="remarks" property="remarks" />
+    </resultMap>
+
+    <sql id="Base_Column_List">
+                id,
+                app_id,
+                platform,
+                version_name,
+                version_number,
+                update_log,
+                internal_url,
+                external_url,
+                version_config,
+                enable_flag,
+                delete_flag,
+                create_by,
+                create_date,
+                update_by,
+                update_date,
+                remarks
+    </sql>
+
+
+
+</mapper>

+ 4 - 0
java/sp-version/src/main/java/com/anji/sp/model/po/SpFilePO.java

@@ -31,4 +31,8 @@ public class SpFilePO extends BasePO {
     /** 通过接口的下载完整http路径 */
     @ApiModelProperty("通过接口的下载完整http路径")
     private String urlPath;
+    
+    private String apkMd5;   
+
+    private String apkSize;   
 }

+ 3 - 0
java/sp-version/src/main/java/com/anji/sp/model/vo/SpUploadFileVO.java

@@ -33,4 +33,7 @@ public class SpUploadFileVO implements Serializable {
     @ApiModelProperty("通过接口的下载完整http路径")
     private String urlPath;
 
+    private String apkMd5;   
+
+    private String apkSize;   
 }

+ 128 - 116
java/sp-version/src/main/java/com/anji/sp/service/impl/SpUploadServiceImpl.java

@@ -31,133 +31,145 @@ import java.net.URLEncoder;
 import java.util.Objects;
 
 /**
- * @author : kean_qi
- * create at:  2020/7/1  3:37 下午
+ * @author : kean_qi create at: 2020/7/1 3:37 下午
  * @description:
  */
 @Service
 @Slf4j
 public class SpUploadServiceImpl implements SpUploadService {
-    @Autowired
-    SpApplicationService spApplicationService;
-    @Autowired
-    SpFileService spFileService;
+	@Autowired
+	SpApplicationService spApplicationService;
+	@Autowired
+	SpFileService spFileService;
 
-    @Value("${customer.environment.path}")
-    private String environmentFlag;
-    @Value("${file.apk.url}")
-    private String fileApkUrl;
-    /**
-     * 上传文件
-     * @param spUploadVO
-     * @return
-     */
-    @Override
-    public ResponseModel uploadFile(SpUploadVO spUploadVO) {
-        ResponseModel r = getUploadVO(spUploadVO);
-        if (r.isError()){
-            return r;
-        }
-        spUploadVO = (SpUploadVO) r.getRepData();
-        try {
-            SpUploadFileVO spUploadFileVO = FileUploadUtils.uploadFile(spUploadVO.getFile(), spUploadVO.getAppKey(), UploadFileTypeEnum.APK);
-            SpVersionVO spVersionVO = new SpVersionVO();
-            spVersionVO.setVersionName(spUploadFileVO.getVersionName());
-            spVersionVO.setVersionNumber(spUploadFileVO.getVersionNumber());
-            //apk 还是原始url
-            spVersionVO.setDownloadUrl(spUploadFileVO.getUrlPath());
-            return ResponseModel.successData(spVersionVO);
-        } catch (FileException e) {
-            log.error("错误 : {}", e);
-            return ResponseModel.errorMsg(e.getArgs()[0] + "");
-        } catch (Exception e) {
-            return ResponseModel.errorMsg(e.getMessage());
-        }
-    }
+	@Value("${customer.environment.path}")
+	private String environmentFlag;
+	@Value("${file.apk.url}")
+	private String fileApkUrl;
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public ResponseModel uploadPictureFile(SpUploadVO spUploadVO) {
-        try {
-            SpUploadFileVO spUploadFileVO = FileUploadUtils.uploadFile(spUploadVO.getFile(), spUploadVO.getAppKey(), UploadFileTypeEnum.PICTURE);
-            SpFilePO filePO = new SpFilePO();
-            filePO.setFileId(spUploadFileVO.getFileId());
-            filePO.setFilePath(spUploadFileVO.getFilePath());
-            filePO.setUrlPath(environmentFlag+"/sp/file/download/"+spUploadFileVO.getUrlPath());
-            //插入到数据库
-            ResponseModel insertResponse = spFileService.insert(filePO);
-            if (insertResponse.isError()){
-                return insertResponse;
-            }
-            return ResponseModel.successData(insertResponse.getRepData());
-        } catch (FileException e) {
-            log.error("错误 : {}", e);
-            return ResponseModel.errorMsg(e.getArgs()[0] + "");
-        } catch (Exception e) {
-            return ResponseModel.errorMsg(e.getMessage());
-        }
-    }
+	/**
+	 * 上传文件
+	 * 
+	 * @param spUploadVO
+	 * @return
+	 */
+	@Override
+	public ResponseModel uploadFile(SpUploadVO spUploadVO) {
+		ResponseModel r = getUploadVO(spUploadVO);
+		if (r.isError()) {
+			return r;
+		}
+		spUploadVO = (SpUploadVO) r.getRepData();
+		try {
+			SpUploadFileVO spUploadFileVO = FileUploadUtils.uploadFile(spUploadVO.getFile(), spUploadVO.getAppKey(),
+					UploadFileTypeEnum.APK);
+			SpVersionVO spVersionVO = new SpVersionVO();
+			spVersionVO.setVersionName(spUploadFileVO.getVersionName());
+			spVersionVO.setVersionNumber(spUploadFileVO.getVersionNumber());
+			// apk 还是原始url
+			spVersionVO.setDownloadUrl(spUploadFileVO.getUrlPath());
+			
+			SpFilePO spFilePO = new SpFilePO();
+			spFilePO.setFileId(spUploadFileVO.getFileId());
+			spFilePO.setApkMd5(spUploadFileVO.getApkMd5());
+			spFilePO.setApkSize(spUploadFileVO.getApkSize());
+			spFilePO.setFilePath(spUploadFileVO.getFilePath());
+			spFilePO.setUrlPath(spUploadFileVO.getUrlPath());
+			 spFileService.insert(spFilePO);
+			return ResponseModel.successData(spVersionVO);
+		} catch (FileException e) {
+			log.error("错误 : {}", e);
+			return ResponseModel.errorMsg(e.getArgs()[0] + "");
+		} catch (Exception e) {
+			return ResponseModel.errorMsg(e.getMessage());
+		}
+	}
 
-    @Override
-    public ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, String fileId) {
+	@Override
+	@Transactional(rollbackFor = Exception.class)
+	public ResponseModel uploadPictureFile(SpUploadVO spUploadVO) {
+		try {
+			SpUploadFileVO spUploadFileVO = FileUploadUtils.uploadFile(spUploadVO.getFile(), spUploadVO.getAppKey(),
+					UploadFileTypeEnum.PICTURE);
+			SpFilePO filePO = new SpFilePO();
+			filePO.setFileId(spUploadFileVO.getFileId());
+			filePO.setFilePath(spUploadFileVO.getFilePath());
+			filePO.setUrlPath(environmentFlag + "/sp/file/download/" + spUploadFileVO.getUrlPath());
+			// 插入到数据库
+			ResponseModel insertResponse = spFileService.insert(filePO);
+			if (insertResponse.isError()) {
+				return insertResponse;
+			}
+			return ResponseModel.successData(insertResponse.getRepData());
+		} catch (FileException e) {
+			log.error("错误 : {}", e);
+			return ResponseModel.errorMsg(e.getArgs()[0] + "");
+		} catch (Exception e) {
+			return ResponseModel.errorMsg(e.getMessage());
+		}
+	}
 
-        try {
-            String userAgent = request.getHeader("User-Agent");
-            //IE 特殊处理
-            boolean isIEBrowser = userAgent.indexOf("MSIE") > 0;
+	@Override
+	public ResponseEntity<byte[]> download(HttpServletRequest request, HttpServletResponse response, String fileId) {
 
-            SpFilePO f = new SpFilePO();
-            f.setFileId(fileId);
-            ResponseModel re = spFileService.select(f);
-            if (re.isError()){
-                ResponseModel.errorMsg("文件不存在");
-            }
-            f = (SpFilePO) re.getRepData();
-            String filePath = f.getFilePath();
-            if (StringUtils.isBlank(f.getFilePath())) {
-                ResponseModel.errorMsg("文件路径不存在");
-            }
-            String filename = filePath.substring(filePath.lastIndexOf(File.separator));
-            if (StringUtils.isBlank(filename)) {
-                ResponseModel.errorMsg("文件名为空");
-            }
-            String fileSuffix = filename.substring(filename.lastIndexOf("."));
+		try {
+			String userAgent = request.getHeader("User-Agent");
+			// IE 特殊处理
+			boolean isIEBrowser = userAgent.indexOf("MSIE") > 0;
 
-            //根据文件后缀来判断,是显示图片\视频\音频,还是下载文件
-            File file = new File(filePath);
-            ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
-            //设置文件长度
-            builder.contentLength(file.length());
+			SpFilePO f = new SpFilePO();
+			f.setFileId(fileId);
+			ResponseModel re = spFileService.select(f);
+			if (re.isError()) {
+				ResponseModel.errorMsg("文件不存在");
+			}
+			f = (SpFilePO) re.getRepData();
+			String filePath = f.getFilePath();
+			if (StringUtils.isBlank(f.getFilePath())) {
+				ResponseModel.errorMsg("文件路径不存在");
+			}
+			String filename = filePath.substring(filePath.lastIndexOf(File.separator));
+			if (StringUtils.isBlank(filename)) {
+				ResponseModel.errorMsg("文件名为空");
+			}
+			String fileSuffix = filename.substring(filename.lastIndexOf("."));
 
-            //header 塞不一样的内容
-            if(StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.png|.jpg|.jpeg|.bmp|.gif|.icon)")){
-                builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG);
-            } else if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)")) {
-                builder.header("Content-Type", "video/mp4; charset=UTF-8");
-            }else {
-                //application/octet-stream 二进制数据流(最常见的文件下载)
-                builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
-                filename = URLEncoder.encode(filename, "UTF-8");
-                if (isIEBrowser) {
-                    builder.header("Content-Disposition", "attachment; filename=" + filename);
-                } else {
-                    builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + filename);
-                }
-            }
-            return builder.body(FileUtils.readFileToByteArray(file));
-        }catch (Exception e){
-            log.error("error: {}", e);
-            return null;
-        }
-    }
+			// 根据文件后缀来判断,是显示图片\视频\音频,还是下载文件
+			File file = new File(filePath);
+			ResponseEntity.BodyBuilder builder = ResponseEntity.ok();
+			// 设置文件长度
+			builder.contentLength(file.length());
 
-    private ResponseModel getUploadVO(SpUploadVO spUploadVO){
-        SpApplicationPO spApplicationPO = spApplicationService.selectByAppId(spUploadVO.getAppId());
-        if (Objects.isNull(spApplicationPO)) {
-            return ResponseModel.errorMsg("没有该应用,无法上传");
-        }
-        spUploadVO.setAppKey(spApplicationPO.getAppKey());
-        spUploadVO.setAppId(spApplicationPO.getAppId());
-        return ResponseModel.successData(spUploadVO);
-    }
+			// header 塞不一样的内容
+			if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix, "(.png|.jpg|.jpeg|.bmp|.gif|.icon)")) {
+				builder.cacheControl(CacheControl.noCache()).contentType(MediaType.IMAGE_PNG);
+			} else if (StringPatternUtil.StringMatchIgnoreCase(fileSuffix,
+					"(.flv|.swf|.mkv|.avi|.rm|.rmvb|.mpeg|.mpg|.ogg|.ogv|.mov|.wmv|.mp4|.webm|.wav|.mid|.mp3|.aac)")) {
+				builder.header("Content-Type", "video/mp4; charset=UTF-8");
+			} else {
+				// application/octet-stream 二进制数据流(最常见的文件下载)
+				builder.contentType(MediaType.APPLICATION_OCTET_STREAM);
+				filename = URLEncoder.encode(filename, "UTF-8");
+				if (isIEBrowser) {
+					builder.header("Content-Disposition", "attachment; filename=" + filename);
+				} else {
+					builder.header("Content-Disposition", "attacher; filename*=UTF-8''" + filename);
+				}
+			}
+			return builder.body(FileUtils.readFileToByteArray(file));
+		} catch (Exception e) {
+			log.error("error: {}", e);
+			return null;
+		}
+	}
+
+	private ResponseModel getUploadVO(SpUploadVO spUploadVO) {
+		SpApplicationPO spApplicationPO = spApplicationService.selectByAppId(spUploadVO.getAppId());
+		if (Objects.isNull(spApplicationPO)) {
+			return ResponseModel.errorMsg("没有该应用,无法上传");
+		}
+		spUploadVO.setAppKey(spApplicationPO.getAppKey());
+		spUploadVO.setAppId(spApplicationPO.getAppId());
+		return ResponseModel.successData(spUploadVO);
+	}
 }

+ 13 - 2
java/sp-version/src/main/java/com/anji/sp/util/file/FileUploadUtils.java

@@ -8,6 +8,7 @@ import com.anji.sp.util.file.exception.FileException;
 import com.anji.sp.util.file.exception.FileNameLengthLimitExceededException;
 import com.anji.sp.util.file.exception.FileSizeLimitExceededException;
 import com.anji.sp.util.file.exception.InvalidFileExceededException;
+import com.anji.sp.utils.Md5Utils;
 
 import cn.hutool.core.io.IoUtil;
 import lombok.extern.slf4j.Slf4j;
@@ -87,6 +88,8 @@ public class FileUploadUtils {
 		String profileName = "";
 		log.info("上传的后缀名为:" + suffixName);
 		try {
+
+	
 			// 文件大小校验
 			long size = multipartFile.getSize();
 			if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) {
@@ -113,12 +116,13 @@ public class FileUploadUtils {
 					spUploadFileVO.setVersionNumber(apkMeta.getVersionCode() + "");
 					profileName = apkMetaInfo.getProfileName();
 					fileName = FileProfileConfig.getAndroidAPKPath().concat(profileName);
+				
 				} else {
 					throw new InvalidFileExceededException("请上传正确的apk文件");
 				}
 			}
 
-			// 创建临时文件
+		// 创建临时文件
 			File desc = new File(fileName);
 			if (!desc.getParentFile().exists()) {
 				desc.getParentFile().mkdirs();
@@ -126,7 +130,6 @@ public class FileUploadUtils {
 			if (!desc.exists()) {
 				desc.createNewFile();
 			}
-
 			if (isWindows()) {
 				desc = new File(desc.getAbsolutePath().replaceAll("\\\\", "/"));
 			}
@@ -144,6 +147,14 @@ public class FileUploadUtils {
 				// xxxx 需要拼接成完整路径
 				spUploadFileVO.setUrlPath(profileName.substring(0, profileName.lastIndexOf(".")));
 			} else {
+				if (typeEnum.equals(UploadFileTypeEnum.APK)) {
+					String md5 = Md5Utils.getFileMD5(desc);
+					int apkSize = com.anji.sp.utils.FileUtils.getApkFileSize(desc);
+					spUploadFileVO.setFileId(desc.getName());
+					spUploadFileVO.setApkMd5(md5);
+					spUploadFileVO.setFilePath(desc.getAbsolutePath());
+					spUploadFileVO.setApkSize(String.valueOf(apkSize));
+				}
 				// 完整路径
 				spUploadFileVO.setUrlPath(FileProfileConfig.getApkUrl().concat(profileName));
 			}

+ 108 - 0
java/sp-version/src/main/java/com/anji/sp/utils/AspectJUtils.java

@@ -0,0 +1,108 @@
+package com.anji.sp.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * AspectJ 工具类
+ *
+ * @author xuexiang
+ * @since 2018/7/17 上午10:34
+ */
+public final class AspectJUtils {
+
+    private AspectJUtils() {
+        throw new UnsupportedOperationException("u can't instantiate me...");
+    }
+
+    /**
+     * 获取方法名
+     *
+     * @param joinPoint
+     * @return
+     */
+    public static String getMethodName(JoinPoint joinPoint) {
+        String methodName = joinPoint.getSignature().toShortString();
+        String shortMethodNameSuffix = "(..)";
+        if (methodName.endsWith(shortMethodNameSuffix)) {
+            methodName = methodName.substring(0, methodName.length() - shortMethodNameSuffix.length());
+        }
+        return methodName;
+    }
+
+    /**
+     * 获取需要记录日志方法的参数,敏感参数用*代替
+     *
+     * @param joinPoint 切点
+     * @return 去除敏感参数后的Json字符串
+     */
+    public static String getMethodParams(ProceedingJoinPoint joinPoint) {
+        Object[] arguments = joinPoint.getArgs();
+        StringBuilder sb = new StringBuilder();
+        if (arguments == null || arguments.length <= 0) {
+            return sb.toString();
+        }
+        for (Object arg : arguments) {
+            //移除敏感内容
+            String paramStr;
+            if (arg instanceof HttpServletResponse) {
+                paramStr = HttpServletResponse.class.getSimpleName();
+            } else if (arg instanceof HttpServletRequest) {
+                paramStr = HttpServletRequest.class.getSimpleName();
+            } else if (arg instanceof MultipartFile) {
+                long size = ((MultipartFile) arg).getSize();
+                paramStr = MultipartFile.class.getSimpleName() + " size:" + size;
+            } else {
+                paramStr = deleteSensitiveContent(arg);
+            }
+            sb.append(paramStr).append(",");
+        }
+        return sb.deleteCharAt(sb.length() - 1).toString();
+    }
+
+    /**
+     * 删除参数中的敏感内容
+     *
+     * @param obj 参数对象
+     * @return 去除敏感内容后的参数对象
+     */
+    public static String deleteSensitiveContent(Object obj) {
+        JSONObject jsonObject = new JSONObject();
+        if (obj == null || obj instanceof Exception) {
+            return jsonObject.toJSONString();
+        }
+        String param = JSON.toJSONString(obj);
+        try {
+            jsonObject = JSONObject.parseObject(param);
+        } catch (Exception e) {
+            return String.valueOf(obj);
+        }
+        List<String> sensitiveFieldList = getSensitiveFieldList();
+        for (String sensitiveField : sensitiveFieldList) {
+            if (jsonObject.containsKey(sensitiveField)) {
+                jsonObject.put(sensitiveField, "******");
+            }
+        }
+        return jsonObject.toJSONString();
+    }
+
+    /**
+     * 敏感字段列表(当然这里你可以更改为可配置的)
+     */
+    private static List<String> getSensitiveFieldList() {
+        List<String> sensitiveFieldList = Lists.newArrayList();
+        sensitiveFieldList.add("pwd");
+        sensitiveFieldList.add("password");
+        return sensitiveFieldList;
+    }
+}

+ 339 - 0
java/sp-version/src/main/java/com/anji/sp/utils/DateUtils.java

@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2018 nl-xx(xx@aecg.com.cn)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://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.
+ */
+
+package com.anji.sp.utils;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+import static org.apache.commons.lang3.StringUtils.EMPTY;
+
+/**
+ * 日期工具
+ *
+ * @author xuexiang
+ * @since 2018/7/26 下午4:07
+ */
+public final class DateUtils {
+
+    /**
+     * yyyy-MM-dd
+     */
+    public static final ThreadLocal<DateFormat> yyyyMMdd = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
+    /**
+     * yyyyMMdd
+     */
+    public static final ThreadLocal<DateFormat> yyyyMMddNoSep = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd"));
+    /**
+     * HH:mm:ss
+     */
+    public static final ThreadLocal<DateFormat> HHmmss = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss"));
+    /**
+     * HH:mm
+     */
+    public static final ThreadLocal<DateFormat> HHmm = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm"));
+    /**
+     * yyyy-MM-dd HH:mm:ss
+     */
+    public static final ThreadLocal<DateFormat> yyyyMMddHHmmss = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+    /**
+     * yyyyMMddHHmmss
+     */
+    public static final ThreadLocal<DateFormat> yyyyMMddHHmmssNoSep = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMddHHmmss"));
+    /**
+     * yyyy-MM-dd HH:mm
+     */
+    public static final ThreadLocal<DateFormat> yyyyMMddHHmm = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm"));
+    /**
+     * yyyy-MM-dd HH:mm:ss:SSS
+     */
+    public static final ThreadLocal<DateFormat> yyyyMMddHHmmssSSS = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS"));
+
+
+    //============================时间类型转化================================//
+
+    /**
+     * Don't let anyone instantiate this class.
+     */
+    private DateUtils() {
+        throw new UnsupportedOperationException("u can't instantiate me...");
+    }
+
+
+    /**
+     * 将时间戳转为时间字符串
+     * <p>格式为 format</p>
+     *
+     * @param millis 毫秒时间戳
+     * @param format 时间格式
+     * @return 时间字符串
+     */
+    public static String millis2String(final long millis, final DateFormat format) {
+        return date2String(new Date(millis), format);
+    }
+
+    /**
+     * 将 Date 类型转为时间字符串
+     * <p>格式为 format</p>
+     *
+     * @param date   Date 类型时间
+     * @param format 时间格式
+     * @return 时间字符串
+     */
+    public static String date2String(final Date date, final DateFormat format) {
+        if (format != null) {
+            return format.format(date);
+        } else {
+            return EMPTY;
+        }
+    }
+
+    /**
+     * 将时间字符串转为时间戳
+     * <p>time 格式为 format</p>
+     *
+     * @param time   时间字符串
+     * @param format 时间格式
+     * @return 毫秒时间戳
+     */
+    public static long string2Millis(final String time, final DateFormat format) {
+        try {
+            if (format != null) {
+                return format.parse(time).getTime();
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return -1;
+    }
+
+    /**
+     * 将时间字符串转为 Date 类型
+     * <p>time 格式为 format</p>
+     *
+     * @param time   时间字符串
+     * @param format 时间格式
+     * @return Date 类型
+     */
+    public static Date string2Date(final String time, final DateFormat format) {
+        try {
+            if (format != null) {
+                return format.parse(time);
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将 Date 类型转为时间戳
+     *
+     * @param date Date 类型时间
+     * @return 毫秒时间戳
+     */
+    public static long date2Millis(final Date date) {
+        return date != null ? date.getTime() : -1;
+    }
+
+    /**
+     * 将时间戳转为 Date 类型
+     *
+     * @param millis 毫秒时间戳
+     * @return Date 类型时间
+     */
+    public static Date millis2Date(final long millis) {
+        return new Date(millis);
+    }
+
+
+    /**
+     * 生日期获取年龄
+     *
+     * @param birthDay 出生日期字符串
+     * @param format   日期格式
+     * @return 计算出的年龄
+     * @throws IllegalArgumentException
+     */
+    public static int getAgeByBirthDay(final String birthDay, final DateFormat format) throws IllegalArgumentException {
+        return getAgeByBirthDay(DateUtils.string2Date(birthDay, format));
+    }
+
+    /**
+     * 根据出生日期获取年龄
+     *
+     * @param birthDay 出生日期
+     * @return 计算出的年龄
+     * @throws IllegalArgumentException
+     */
+    public static int getAgeByBirthDay(Date birthDay) throws IllegalArgumentException {
+        Calendar cal = Calendar.getInstance();
+
+        if (cal.before(birthDay)) {
+            throw new IllegalArgumentException("The birthDay is before Now.It's unbelievable!");
+        }
+        int yearNow = cal.get(Calendar.YEAR);
+        int monthNow = cal.get(Calendar.MONTH);
+        int dayNow = cal.get(Calendar.DAY_OF_MONTH);
+
+        cal.setTime(birthDay);
+        int yearBirth = cal.get(Calendar.YEAR);
+        int monthBirth = cal.get(Calendar.MONTH);
+        int dayBirth = cal.get(Calendar.DAY_OF_MONTH);
+
+        int age = yearNow - yearBirth;
+
+        if (monthNow <= monthBirth) {
+            if (monthNow == monthBirth) {
+                if (dayNow < dayBirth) {
+                    age--;
+                }
+            } else {
+                age--;
+            }
+        }
+        return age;
+    }
+
+    //==============================时间获取===============================//
+
+    /**
+     * 获取当前毫秒时间戳
+     *
+     * @return 毫秒时间戳
+     */
+    public static long getNowMills() {
+        return System.currentTimeMillis();
+    }
+
+    /**
+     * 获取当前时间字符串
+     * <p>格式为 format</p>
+     *
+     * @param format 时间格式
+     * @return 时间字符串
+     */
+    public static String getNowString(final DateFormat format) {
+        return millis2String(System.currentTimeMillis(), format);
+    }
+
+    /**
+     * 获取当前 Date
+     *
+     * @return Date 类型时间
+     */
+    public static Date getNowDate() {
+        return new Date();
+    }
+
+    /**
+     * 获取星期索引
+     * <p>注意:周日的 Index 才是 1,周六为 7</p>
+     * <p>time 格式为 format</p>
+     *
+     * @param time   时间字符串
+     * @param format 时间格式
+     * @return 1...7
+     * @see Calendar#SUNDAY
+     * @see Calendar#MONDAY
+     * @see Calendar#TUESDAY
+     * @see Calendar#WEDNESDAY
+     * @see Calendar#THURSDAY
+     * @see Calendar#FRIDAY
+     * @see Calendar#SATURDAY
+     */
+    public static int getWeekIndex(final String time, final DateFormat format) {
+        return getWeekIndex(string2Date(time, format));
+    }
+
+    /**
+     * 得到年
+     *
+     * @param date Date对象
+     * @return 年
+     */
+    public static int getYear(final Date date) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        return c.get(Calendar.YEAR);
+    }
+
+    /**
+     * 得到月
+     *
+     * @param date Date对象
+     * @return 月
+     */
+    public static int getMonth(final Date date) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        return c.get(Calendar.MONTH) + 1;
+    }
+
+    /**
+     * 得到日
+     *
+     * @param date Date对象
+     * @return 日
+     */
+    public static int getDay(final Date date) {
+        Calendar c = Calendar.getInstance();
+        c.setTime(date);
+        return c.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * 获取星期索引
+     * <p>注意:周日的 Index 才是 1,周六为 7</p>
+     *
+     * @param date Date 类型时间
+     * @return 1...7
+     * @see Calendar#SUNDAY
+     * @see Calendar#MONDAY
+     * @see Calendar#TUESDAY
+     * @see Calendar#WEDNESDAY
+     * @see Calendar#THURSDAY
+     * @see Calendar#FRIDAY
+     * @see Calendar#SATURDAY
+     */
+    public static int getWeekIndex(final Date date) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(date);
+        return cal.get(Calendar.DAY_OF_WEEK);
+    }
+
+    /**
+     * 获取星期索引
+     * <p>注意:周日的 Index 才是 1,周六为 7</p>
+     *
+     * @param millis 毫秒时间戳
+     * @return 1...7
+     * @see Calendar#SUNDAY
+     * @see Calendar#MONDAY
+     * @see Calendar#TUESDAY
+     * @see Calendar#WEDNESDAY
+     * @see Calendar#THURSDAY
+     * @see Calendar#FRIDAY
+     * @see Calendar#SATURDAY
+     */
+    public static int getWeekIndex(final long millis) {
+        return getWeekIndex(millis2Date(millis));
+    }
+
+}

+ 73 - 0
java/sp-version/src/main/java/com/anji/sp/utils/FileUtils.java

@@ -0,0 +1,73 @@
+package com.anji.sp.utils;
+
+import org.springframework.util.StringUtils;
+
+import java.io.File;
+
+/**
+ * @author xuexiang
+ * @since 2018/7/18 下午4:30
+ */
+public final class FileUtils {
+
+    private FileUtils() {
+        throw new UnsupportedOperationException("u can't instantiate me...");
+    }
+
+    /**
+     * 生成随机的文件名
+     *
+     * @return
+     */
+    public static String randomFileName(String filePath) {
+        String fileExtension = getFileExtension(filePath);
+        return RandomGUID.getRandomGUID() + "." + fileExtension;
+    }
+
+
+    /**
+     * 获取全路径中的文件拓展名
+     *
+     * @param filePath 文件路径
+     * @return 文件拓展名
+     */
+    public static String getFileExtension(final String filePath) {
+        if (StringUtils.isEmpty(filePath)) return filePath;
+        int lastPoi = filePath.lastIndexOf('.');
+        int lastSep = filePath.lastIndexOf(File.separator);
+        if (lastPoi == -1 || lastSep >= lastPoi) return "";
+        return filePath.substring(lastPoi + 1);
+    }
+
+    /**
+     * 获取apk的大小【单位:KB】
+     *
+     * @param file 文件
+     * @return 文件长度
+     */
+    public static int getApkFileSize(final File file) {
+        long fileLength = getFileLength(file);
+        return (int) (fileLength / 1024);
+    }
+
+    /**
+     * 获取文件长度
+     *
+     * @param file 文件
+     * @return 文件长度
+     */
+    private static long getFileLength(final File file) {
+        if (!isFile(file)) return -1;
+        return file.length();
+    }
+
+    /**
+     * 判断是否是文件
+     *
+     * @param file 文件
+     * @return {@code true}: 是<br>{@code false}: 否
+     */
+    private static boolean isFile(final File file) {
+        return file != null && file.exists() && file.isFile();
+    }
+}

+ 142 - 0
java/sp-version/src/main/java/com/anji/sp/utils/IpUtils.java

@@ -0,0 +1,142 @@
+package com.anji.sp.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * IP操作工具类
+ *
+ * @author xuexiang
+ * @since 2018/7/17 上午10:34
+ */
+public final class IpUtils {
+
+    private IpUtils() {
+        throw new UnsupportedOperationException("u can't instantiate me...");
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(IpUtils.class);
+
+    private static final String IP_PATTERN = "^(?:(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\.){3}(?:[01]?\\d{1,2}|2[0-4]\\d|25[0-5])\\b";
+
+    private static final String UNKNOWN = "unknown";
+
+    private static final String LOCAL_IP = "127.0.0.1";
+
+    /**
+     * 获取请求中的ip地址:过了多级反向代理,获取的ip不是唯一的,二是包含中间代理层ip
+     * @param request
+     * @return 可能有多个,例如:192.168.1.110, 192.168.1.120
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        String ip = LOCAL_IP;
+        if (request != null) {
+            ip = request.getHeader("x-forwarded-for");
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("Proxy-Client-IP");
+            }
+
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getHeader("WL-Proxy-Client-IP");
+            }
+
+            if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
+                ip = request.getRemoteAddr();
+            }
+        }
+        return ip;
+
+    }
+
+    /**
+     * 获取客户端请求中的真实的ip地址
+     *  获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的。
+     *  但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址。而且,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,
+     *  而是一串ip值,例如:192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100。其中第一个192.168.1.110才是用户真实的ip
+     * @param request
+     * @return
+     */
+    public static String getRealIp(HttpServletRequest request) {
+        String ip = LOCAL_IP;
+        if (request == null) {
+            return ip;
+        }
+        ip = request.getHeader("x-forwarded-for");
+        ip = getIp(request,ip);
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+            if (LOCAL_IP.equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
+                //根据网卡取本机配置的IP
+                InetAddress inet = null;
+                try {
+                    inet = InetAddress.getLocalHost();
+                    ip = inet.getHostAddress();
+                } catch (UnknownHostException e) {
+                    logger.error("getRealIp occurs error, caused by: ", e);
+                }
+            }
+        }
+        String ch = ",";
+        if (ip != null && ip.contains(ch)) {
+                ip = ip.substring(0, ip.indexOf(ch));
+        }
+        return ip;
+    }
+
+    /**
+     * 通过各种方式获取IP
+     * @param request
+     * @param ip
+     * @return
+     */
+    private static String getIp(HttpServletRequest request, String ip){
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_CLIENT_IP");
+        }
+        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+        }
+        return ip;
+    }
+
+    /**
+     * 获取服务器IP
+     */
+    public static String getServiceIp() {
+        Enumeration<NetworkInterface> netInterfaces = null;
+        String ipsStr = "";
+        try {
+            netInterfaces = NetworkInterface.getNetworkInterfaces();
+            while (netInterfaces.hasMoreElements()) {
+                NetworkInterface ni = netInterfaces.nextElement();
+                Enumeration<InetAddress> ips = ni.getInetAddresses();
+                Pattern pattern = Pattern.compile(IP_PATTERN);
+                while (ips.hasMoreElements()) {
+                    String ip = ips.nextElement().getHostAddress();
+                    Matcher matcher = pattern.matcher(ip);
+                    if (matcher.matches() && !LOCAL_IP.equals(ip)) {
+                        ipsStr = ip;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("getServiceIp occurs error, caused by: ", e);
+        }
+        return ipsStr;
+    }
+}

+ 93 - 0
java/sp-version/src/main/java/com/anji/sp/utils/Md5Utils.java

@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://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.
+ */
+
+package com.anji.sp.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * MD5加密工具类
+ *
+ * @author xuexiang
+ * @since 2018/7/2 下午3:14
+ */
+public final class Md5Utils {
+
+    private Md5Utils() {
+        throw new UnsupportedOperationException("cannot be instantiated");
+    }
+
+    public static String getFileMD5(File file) {
+        if (!file.exists()) {
+            return "";
+        }
+        FileInputStream in = null;
+        try {
+            in = new FileInputStream(file);
+            FileChannel channel = in.getChannel();
+            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            md.update(buffer);
+            return bytes2Hex(md.digest());
+        } catch (NoSuchAlgorithmException | IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ignored) {
+                }
+            }
+        }
+        return "";
+    }
+
+    /**
+     * 验证文件是否有效【通过MD5值比较】
+     *
+     * @param md5  如果md5值为空,则不进行校验,直接为true
+     * @param file 需要校验的文件
+     * @return 文件是否有效
+     */
+    public static boolean isFileValid(String md5, File file) {
+        return StringUtils.isEmpty(md5) || md5.equals(Md5Utils.getFileMD5(file));
+    }
+
+    /**
+     * 一个byte转为2个hex字符
+     *
+     * @param src byte数组
+     * @return 16进制大写字符串
+     */
+    private static String bytes2Hex(byte[] src) {
+        char[] res = new char[src.length << 1];
+        final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+        for (int i = 0, j = 0; i < src.length; i++) {
+            res[j++] = hexDigits[src[i] >>> 4 & 0x0f];
+            res[j++] = hexDigits[src[i] & 0x0f];
+        }
+        return new String(res);
+    }
+
+}

+ 119 - 0
java/sp-version/src/main/java/com/anji/sp/utils/RandomGUID.java

@@ -0,0 +1,119 @@
+package com.anji.sp.utils;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+
+/**
+ * 	生成唯一的GUID
+ *
+ * @author XUE
+ * @since 2019/4/22 13:30
+ */
+public final class RandomGUID {
+
+	public String valueBeforeMD5 = "";
+	public String valueAfterMD5 = "";
+	private static Random myRand;
+	private static SecureRandom mySecureRand;
+
+	private static String s_id;
+	private static final int PAD_BELOW = 0x10;
+	private static final int TWO_BYTES = 0xFF;
+
+	static {
+		mySecureRand = new SecureRandom();
+		long secureInitializer = mySecureRand.nextLong();
+		myRand = new Random(secureInitializer);
+		new Thread(new Runnable() {
+			public void run() {
+				try {
+					s_id = InetAddress.getLocalHost().toString();
+				} catch (UnknownHostException e) {
+					e.printStackTrace();
+				}
+			}
+		}).start();
+	}
+
+	/**
+	 * 获取随机生成的GUID
+	 * @return
+	 */
+	public static String getRandomGUID() {
+		return new RandomGUID().toString();
+	}
+
+	public RandomGUID() {
+		getRandomGUID(false);
+	}
+	public RandomGUID(boolean secure) {
+		getRandomGUID(secure);
+	}
+
+	/*
+	 * Method to generate the random GUID
+	 */
+	private void getRandomGUID(boolean secure) {
+		MessageDigest md5 = null;
+		StringBuffer sbValueBeforeMD5 = new StringBuffer(128);
+
+		try {
+			md5 = MessageDigest.getInstance("MD5");
+		} catch (NoSuchAlgorithmException e) {
+
+		}
+		try {
+			long time = System.currentTimeMillis();
+			long rand = 0;
+
+			if (secure) {
+				rand = mySecureRand.nextLong();
+			} else {
+				rand = myRand.nextLong();
+			}
+			sbValueBeforeMD5.append(s_id);
+			sbValueBeforeMD5.append(":");
+			sbValueBeforeMD5.append(time);
+			sbValueBeforeMD5.append(":");
+			sbValueBeforeMD5.append(rand);
+
+			valueBeforeMD5 = sbValueBeforeMD5.toString();
+			md5.update(valueBeforeMD5.getBytes());
+
+			byte[] array = md5.digest();
+			StringBuffer sb = new StringBuffer(32);
+			for (byte b1 : array) {
+				int b = b1 & TWO_BYTES;
+				if (b < PAD_BELOW)
+					sb.append('0');
+				sb.append(Integer.toHexString(b));
+			}
+
+			valueAfterMD5 = sb.toString();
+
+		} catch (Exception e) {
+
+		}
+	}
+
+	public String toString() {
+		String raw = valueAfterMD5.toUpperCase();
+		StringBuffer sb = new StringBuffer(64);
+		sb.append(raw, 0, 8);
+		sb.append("-");
+		sb.append(raw, 8, 12);
+		sb.append("-");
+		sb.append(raw, 12, 16);
+		sb.append("-");
+		sb.append(raw, 16, 20);
+		sb.append("-");
+		sb.append(raw.substring(20));
+
+		return sb.toString();
+	}
+
+}

+ 109 - 0
java/sp-version/src/main/java/com/anji/sp/utils/TokenUtils.java

@@ -0,0 +1,109 @@
+package com.anji.sp.utils;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import javax.xml.bind.DatatypeConverter;
+import java.security.Key;
+import java.util.Date;
+
+/**
+ * token生成工具
+ * @author xuexiang
+ * @since 2018/8/6 下午4:27
+ */
+public final class TokenUtils {
+
+    /**
+     * 签名秘钥
+     */
+    public static final String SECRET = "xuexiangjys";
+
+    /**
+     * 生成token
+     *
+     * @param id 一般传入userName
+     * @return
+     */
+    public static String createJwtToken(String id) {
+        String issuer = "www.github.com";
+        String subject = "xuexiangjys@163.com";
+        long ttlMillis = 60 * 60 * 1000; //有效期一小时
+        return createJwtToken(id, issuer, subject, ttlMillis);
+    }
+
+    /**
+     * 生成Token
+     *
+     * @param id        编号
+     * @param issuer    该JWT的签发者,是否使用是可选的
+     * @param subject   该JWT所面向的用户,是否使用是可选的;
+     * @param ttlMillis 签发时间 (有效时间,过期会报错)
+     * @return token String
+     */
+    public static String createJwtToken(String id, String issuer, String subject, long ttlMillis) {
+
+        // 签名算法 ,将对token进行签名
+        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
+
+        // 生成签发时间
+        long nowMillis = System.currentTimeMillis();
+        Date now = new Date(nowMillis);
+
+        // 通过秘钥签名JWT
+        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(SECRET);
+        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
+
+        // Let's set the JWT Claims
+        JwtBuilder builder = Jwts.builder().setId(id)
+                .setIssuedAt(now)
+                .setSubject(subject)
+                .setIssuer(issuer)
+                .signWith(signatureAlgorithm, signingKey);
+
+        // if it has been specified, let's add the expiration
+        if (ttlMillis >= 0) {
+            long expMillis = nowMillis + ttlMillis;
+            Date exp = new Date(expMillis);
+            builder.setExpiration(exp);
+        }
+
+        // Builds the JWT and serializes it to a compact, URL-safe string
+        return builder.compact();
+
+    }
+
+    // Sample method to validate and read the JWT
+    public static Claims parseJWT(String jwt) {
+        // This line will throw an exception if it is not a signed JWS (as expected)
+        Claims claims = Jwts.parser()
+                .setSigningKey(DatatypeConverter.parseBase64Binary(SECRET))
+                .parseClaimsJws(jwt).getBody();
+        return claims;
+    }
+
+
+    /**
+     * 从HttpServletRequest中解析出token
+     *
+     * @param request
+     * @return
+     */
+    public static String parseToken(HttpServletRequest request) {
+        String accessToken = request.getHeader("X-Token");
+        if (StringUtils.isEmpty(accessToken)) {
+            accessToken = request.getParameter("token");
+        }
+        return accessToken;
+    }
+
+    public static void main(String[] args) {
+        System.out.println(TokenUtils.createJwtToken("11111"));
+    }
+
+}