Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07136a6679 | ||
|
|
c3edb50e80 | ||
|
|
aee1861630 | ||
|
|
4196b2531d | ||
|
|
dfaeacae92 | ||
|
|
b304c48dd1 | ||
|
|
d045534be6 | ||
|
|
56b923f5db | ||
|
|
f3e8231814 | ||
|
|
2ca04e654f | ||
|
|
149f4ab061 | ||
|
|
a22c08738a | ||
|
|
d28f3250e3 | ||
|
|
bf3b88b43b | ||
|
|
0a98e81109 | ||
|
|
e3c051d443 | ||
|
|
282a46458a | ||
|
|
637a9d1ace | ||
|
|
959eff62df | ||
|
|
fdbdf79383 | ||
|
|
800c53c6fd | ||
|
|
c3f4f91a37 | ||
|
|
31f6babb97 | ||
|
|
668e7069f7 | ||
|
|
5cd4994624 | ||
|
|
941bd0f65e | ||
|
|
5cf6e1f8d4 | ||
|
|
def1b4e06a | ||
|
|
f5b8e989b7 | ||
|
|
1918dfbaa0 | ||
|
|
7fcc407514 | ||
|
|
b79895aa56 | ||
|
|
4700d4e061 | ||
|
|
a8be751e65 | ||
|
|
1b1073eab1 | ||
|
|
56e2a66bdf | ||
|
|
c5654474b0 | ||
|
|
a125c6f907 | ||
|
|
a314351fc9 | ||
|
|
23493afb2f | ||
|
|
e8369320ab | ||
|
|
a19fa65166 | ||
|
|
ea12290f03 | ||
|
|
c6662407a7 | ||
|
|
29e45fff7f | ||
|
|
e7089d9cc5 | ||
|
|
f0493cea77 | ||
|
|
8854225934 | ||
|
|
5ad35cefda | ||
|
|
1921efa27b | ||
|
|
2e9de7ee64 | ||
|
|
e352927396 | ||
|
|
51b26c077d | ||
|
|
2c5f55a876 | ||
|
|
c52f7f5c77 | ||
|
|
7f46d2d371 | ||
|
|
34d8201641 | ||
|
|
92e1c1d9ef | ||
|
|
ee3748c361 | ||
|
|
439947caad | ||
|
|
17706e8065 | ||
|
|
8853e3170d | ||
|
|
222f37afc1 | ||
|
|
f8bc11d456 | ||
|
|
1ea7fa968b | ||
|
|
c892fec45b | ||
|
|
7e94ea54a8 | ||
|
|
d006788c90 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -4,4 +4,5 @@ rebel.xml
|
||||
/.idea/
|
||||
*.iml
|
||||
/static/
|
||||
/ipdb/
|
||||
/config/
|
||||
/runtime/
|
||||
|
||||
@@ -16,4 +16,3 @@ deploy-jar:
|
||||
- git add .
|
||||
- git commit -m "deploy $CI_PROJECT_NAME $CI_COMMIT_TAG"
|
||||
- git push origin master
|
||||
|
||||
|
||||
12
CHANGELOG.md
Normal file
12
CHANGELOG.md
Normal file
@@ -0,0 +1,12 @@
|
||||
## 0.7.3
|
||||
|
||||
### 增加
|
||||
|
||||
> 1,TsTokenConfig增加新的属性**ignorePaths**,用于通过路径忽略token;
|
||||
> 2,PasswordUtils增加密码复杂度校验方法;
|
||||
> 3,PasswordUtils.verifyPassword增加登录次数限制:10分钟内不能错误6次;
|
||||
>
|
||||
|
||||
### 调整
|
||||
|
||||
> 1,TsTokenConfig中的**ignores**属性调整为**testMap**;
|
||||
4
README.md
Normal file
4
README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
## 杭州铁晟科技有限公司基础项目
|
||||
|
||||
更新日志可点击查看[changelog](./CHANGELOG.md ':include')
|
||||
|
||||
66
pom.xml
66
pom.xml
@@ -4,9 +4,9 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>springboot-parent</name>
|
||||
<description>杭州铁晟科技有限公司基础依赖</description>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<modules>
|
||||
<module>springboot-ademo</module>
|
||||
<module>springboot-db-migration</module>
|
||||
<module>springboot-database</module>
|
||||
<module>springboot-login</module>
|
||||
<module>springboot-web</module>
|
||||
<module>springboot-util</module>
|
||||
@@ -55,57 +55,57 @@
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<artifactId>springboot-db-migration</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-database</artifactId>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-login</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-web</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-message</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-encrypt</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-poi</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -123,9 +123,30 @@
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>kepai-repo-plugin</id>
|
||||
<url>http://git.kepai365.com/zeng_wenhao/kepai-repo/raw/master</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.tiesheng.springboot-plugin</groupId>
|
||||
<artifactId>tiesheng-maven-plugin</artifactId>
|
||||
<version>0.0.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>initStartScript</goal>
|
||||
<goal>mysqlComparison</goal>
|
||||
<goal>mysqlDoc</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
@@ -134,6 +155,7 @@
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
<!-- 打包后的jar可直接执行 -->
|
||||
<executable>true</executable>
|
||||
<embeddedLaunchScript>${basedir}/target/launchScript</embeddedLaunchScript>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# . ____ _ __ _ _
|
||||
# /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
# ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
# \\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
# ' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
# =========|_|==============|___/=/_/_/_/
|
||||
# :: Spring Boot Startup Script ::
|
||||
#
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: {{initInfoProvides:spring-boot-application}}
|
||||
# Required-Start: {{initInfoRequiredStart:$remote_fs $syslog $network}}
|
||||
# Required-Stop: {{initInfoRequiredStop:$remote_fs $syslog $network}}
|
||||
# Default-Start: {{initInfoDefaultStart:2 3 4 5}}
|
||||
# Default-Stop: {{initInfoDefaultStop:0 1 6}}
|
||||
# Short-Description: {{initInfoShortDescription:Spring Boot Application}}
|
||||
# Description: {{initInfoDescription:Spring Boot Application}}
|
||||
# chkconfig: {{initInfoChkconfig:2345 99 01}}
|
||||
### END INIT INFO
|
||||
|
||||
[[ -n "$DEBUG" ]] && set -x
|
||||
|
||||
# Initialize variables that cannot be provided by a .conf file
|
||||
WORKING_DIR="$(pwd)"
|
||||
# shellcheck disable=SC2153
|
||||
[[ -n "$JARFILE" ]] && jarfile="$JARFILE"
|
||||
[[ -n "$APP_NAME" ]] && identity="$APP_NAME"
|
||||
|
||||
# Follow symlinks to find the real jar and detect init.d script
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
[[ -z "$jarfile" ]] && jarfile=$(pwd)/$(basename "$0")
|
||||
while [[ -L "$jarfile" ]]; do
|
||||
[[ "$jarfile" =~ init\.d ]] && init_script=$(basename "$jarfile")
|
||||
jarfile=$(readlink "$jarfile")
|
||||
cd "$(dirname "$jarfile")" || exit 1
|
||||
jarfile=$(pwd)/$(basename "$jarfile")
|
||||
done
|
||||
jarfolder="$( (cd "$(dirname "$jarfile")" && pwd -P) )"
|
||||
cd "$WORKING_DIR" || exit 1
|
||||
|
||||
# Source any config file
|
||||
configfile="$(basename "${jarfile%.*}.conf")"
|
||||
|
||||
# Initialize CONF_FOLDER location defaulting to jarfolder
|
||||
[[ -z "$CONF_FOLDER" ]] && CONF_FOLDER="{{confFolder:${jarfolder}}}"
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
[[ -r "${CONF_FOLDER}/${configfile}" ]] && source "${CONF_FOLDER}/${configfile}"
|
||||
|
||||
# Initialize PID/LOG locations if they weren't provided by the config file
|
||||
[[ -z "$PID_FOLDER" ]] && PID_FOLDER="{{pidFolder:/var/run}}"
|
||||
[[ -z "$LOG_FOLDER" ]] && LOG_FOLDER="{{logFolder:/var/log}}"
|
||||
! [[ "$PID_FOLDER" == /* ]] && PID_FOLDER="$(dirname "$jarfile")"/"$PID_FOLDER"
|
||||
! [[ "$LOG_FOLDER" == /* ]] && LOG_FOLDER="$(dirname "$jarfile")"/"$LOG_FOLDER"
|
||||
! [[ -x "$PID_FOLDER" ]] && PID_FOLDER="/tmp"
|
||||
! [[ -x "$LOG_FOLDER" ]] && LOG_FOLDER="/tmp"
|
||||
|
||||
# Set up defaults
|
||||
[[ -z "$MODE" ]] && MODE="{{mode:auto}}" # modes are "auto", "service" or "run"
|
||||
[[ -z "$USE_START_STOP_DAEMON" ]] && USE_START_STOP_DAEMON="{{useStartStopDaemon:true}}"
|
||||
|
||||
# Create an identity for log/pid files
|
||||
if [[ -z "$identity" ]]; then
|
||||
if [[ -n "$init_script" ]]; then
|
||||
identity="${init_script}"
|
||||
else
|
||||
identity=$(basename "${jarfile%.*}")_${jarfolder//\//}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Initialize log file name if not provided by the config file
|
||||
[[ -z "$LOG_FILENAME" ]] && LOG_FILENAME="{{logFilename:${identity}.log}}"
|
||||
|
||||
# Initialize stop wait time if not provided by the config file
|
||||
[[ -z "$STOP_WAIT_TIME" ]] && STOP_WAIT_TIME="{{stopWaitTime:60}}"
|
||||
|
||||
# ANSI Colors
|
||||
echoRed() { echo $'\e[0;31m'"$1"$'\e[0m'; }
|
||||
echoGreen() { echo $'\e[0;32m'"$1"$'\e[0m'; }
|
||||
echoYellow() { echo $'\e[0;33m'"$1"$'\e[0m'; }
|
||||
|
||||
# Utility functions
|
||||
checkPermissions() {
|
||||
touch "$pid_file" &> /dev/null || { echoRed "Operation not permitted (cannot access pid file)"; return 4; }
|
||||
touch "$log_file" &> /dev/null || { echoRed "Operation not permitted (cannot access log file)"; return 4; }
|
||||
}
|
||||
|
||||
isRunning() {
|
||||
ps -p "$1" | grep -v "PID" &> /dev/null
|
||||
}
|
||||
|
||||
await_file() {
|
||||
end=$(date +%s)
|
||||
let "end+=10"
|
||||
while [[ ! -s "$1" ]]
|
||||
do
|
||||
now=$(date +%s)
|
||||
if [[ $now -ge $end ]]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
# Determine the script mode
|
||||
action="run"
|
||||
if [[ "$MODE" == "auto" && -n "$init_script" ]] || [[ "$MODE" == "service" ]]; then
|
||||
action="$1"
|
||||
shift
|
||||
fi
|
||||
|
||||
# Build the pid and log filenames
|
||||
PID_FOLDER="$PID_FOLDER/${identity}"
|
||||
pid_file="$PID_FOLDER/{{pidFilename:${identity}.pid}}"
|
||||
log_file="$LOG_FOLDER/$LOG_FILENAME"
|
||||
|
||||
# Determine the user to run as if we are root
|
||||
# shellcheck disable=SC2012
|
||||
[[ $(id -u) == "0" ]] && run_user=$(ls -ld "$jarfile" | awk '{print $3}')
|
||||
|
||||
# Find Java
|
||||
if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then
|
||||
javaexe="$JAVA_HOME/bin/java"
|
||||
elif type -p java > /dev/null 2>&1; then
|
||||
javaexe=$(type -p java)
|
||||
elif [[ -x "/usr/bin/java" ]]; then
|
||||
javaexe="/usr/bin/java"
|
||||
else
|
||||
echo "Unable to find Java"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
arguments=(-Dsun.misc.URLClassPath.disableJarChecking=true $JAVA_OPTS -jar "$jarfile" $RUN_ARGS "$@")
|
||||
|
||||
# Action functions
|
||||
start() {
|
||||
if [[ -f "$pid_file" ]]; then
|
||||
pid=$(cat "$pid_file")
|
||||
isRunning "$pid" && { echoYellow "Already running [$pid]"; return 0; }
|
||||
fi
|
||||
do_start "$@"
|
||||
}
|
||||
|
||||
do_start() {
|
||||
working_dir=$(dirname "$jarfile")
|
||||
pushd "$working_dir" > /dev/null
|
||||
mkdir -p "$PID_FOLDER" &> /dev/null
|
||||
if [[ -n "$run_user" ]]; then
|
||||
checkPermissions || return $?
|
||||
chown "$run_user" "$PID_FOLDER"
|
||||
chown "$run_user" "$pid_file"
|
||||
chown "$run_user" "$log_file"
|
||||
if [ $USE_START_STOP_DAEMON = true ] && type start-stop-daemon > /dev/null 2>&1; then
|
||||
start-stop-daemon --start --quiet \
|
||||
--chuid "$run_user" \
|
||||
--name "$identity" \
|
||||
--make-pidfile --pidfile "$pid_file" \
|
||||
--background --no-close \
|
||||
--startas "$javaexe" \
|
||||
--chdir "$working_dir" \
|
||||
-- "${arguments[@]}" \
|
||||
>> "$log_file" 2>&1
|
||||
await_file "$pid_file"
|
||||
else
|
||||
su -s /bin/sh -c "$javaexe $(printf "\"%s\" " "${arguments[@]}") >> \"$log_file\" 2>&1 & echo \$!" "$run_user" > "$pid_file"
|
||||
fi
|
||||
pid=$(cat "$pid_file")
|
||||
else
|
||||
checkPermissions || return $?
|
||||
"$javaexe" "${arguments[@]}" >> "$log_file" 2>&1 &
|
||||
pid=$!
|
||||
disown $pid
|
||||
echo "$pid" > "$pid_file"
|
||||
fi
|
||||
[[ -z $pid ]] && { echoRed "Failed to start"; return 1; }
|
||||
echoGreen "Started [$pid]"
|
||||
}
|
||||
|
||||
stop() {
|
||||
working_dir=$(dirname "$jarfile")
|
||||
pushd "$working_dir" > /dev/null
|
||||
[[ -f $pid_file ]] || { echoYellow "Not running (pidfile not found)"; return 0; }
|
||||
pid=$(cat "$pid_file")
|
||||
isRunning "$pid" || { echoYellow "Not running (process ${pid}). Removing stale pid file."; rm -f "$pid_file"; return 0; }
|
||||
do_stop "$pid" "$pid_file"
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
kill "$1" &> /dev/null || { echoRed "Unable to kill process $1"; return 1; }
|
||||
for i in $(seq 1 $STOP_WAIT_TIME); do
|
||||
isRunning "$1" || { echoGreen "Stopped [$1]"; rm -f "$2"; return 0; }
|
||||
[[ $i -eq STOP_WAIT_TIME/2 ]] && kill "$1" &> /dev/null
|
||||
sleep 1
|
||||
done
|
||||
echoRed "Unable to kill process $1";
|
||||
return 1;
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop && start
|
||||
}
|
||||
|
||||
status() {
|
||||
working_dir=$(dirname "$jarfile")
|
||||
pushd "$working_dir" > /dev/null
|
||||
[[ -f "$pid_file" ]] || { echoRed "Not running"; return 3; }
|
||||
pid=$(cat "$pid_file")
|
||||
isRunning "$pid" || { echoRed "Not running (process ${pid} not found)"; return 1; }
|
||||
echoGreen "Running [$pid]"
|
||||
return 0
|
||||
}
|
||||
|
||||
run() {
|
||||
pushd "$(dirname "$jarfile")" > /dev/null
|
||||
"$javaexe" "${arguments[@]}"
|
||||
result=$?
|
||||
popd > /dev/null
|
||||
return "$result"
|
||||
}
|
||||
|
||||
# Call the appropriate action function
|
||||
case "$action" in
|
||||
start)
|
||||
start "$@"; exit $?;;
|
||||
stop)
|
||||
stop "$@"; exit $?;;
|
||||
restart)
|
||||
restart "$@"; exit $?;;
|
||||
status)
|
||||
status "$@"; exit $?;;
|
||||
run)
|
||||
run "$@"; exit $?;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|status|run}"; exit 1;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-ademo</artifactId>
|
||||
@@ -16,11 +16,13 @@
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- 该模块不发布到maven仓库 -->
|
||||
<maven.deploy.skip>true</maven.deploy.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -29,20 +31,18 @@
|
||||
<repository>
|
||||
<id>kepai-repo</id>
|
||||
<url>http://git.kepai365.com/zeng_wenhao/kepai-repo/raw/master</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.tiesheng.springboot-plugin</groupId>
|
||||
<artifactId>tiesheng-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<embeddedLaunchScript>../script/launchScript</embeddedLaunchScript>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tiesheng.demo.config;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.tiesheng.core.pojos.CurrentWebUser;
|
||||
import com.tiesheng.core.pojos.RequestUserInfo;
|
||||
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
|
||||
import com.tiesheng.core.service.TieshengWebConfigurer;
|
||||
import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
@@ -19,8 +19,11 @@ public class DemoWebConfigurer implements TieshengWebConfigurer {
|
||||
GlobalConfig globalConfig;
|
||||
|
||||
@Override
|
||||
public CurrentWebUser getCurrentUserName(String userId) {
|
||||
return null;
|
||||
public RequestUserInfo getCurrentUserName(TokenBean tokenBean) {
|
||||
RequestUserInfo info = new RequestUserInfo();
|
||||
info.setId("1");
|
||||
info.setName("test");
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package com.tiesheng.demo.controller;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.annotation.token.TokenIgnore;
|
||||
import com.tiesheng.demo.pojos.TestFile;
|
||||
import com.tiesheng.login.config.token.TsTokenConfig;
|
||||
import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
import com.tiesheng.message.config.aliyun.AliyunSmsConfig;
|
||||
import com.tiesheng.message.pojos.MessageReqResp;
|
||||
import com.tiesheng.util.config.GlobalConfig;
|
||||
import com.tiesheng.util.config.Ip2regionConfig;
|
||||
import com.tiesheng.util.pojos.ApiResp;
|
||||
import com.tiesheng.util.pojos.FileUploadPath;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -12,6 +18,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
@@ -24,22 +31,30 @@ public class TestController {
|
||||
GlobalConfig globalConfig;
|
||||
@Autowired
|
||||
AliyunSmsConfig aliyunSmsConfig;
|
||||
@Autowired
|
||||
TsTokenConfig tsTokenConfig;
|
||||
@Autowired
|
||||
Ip2regionConfig ip2regionConfig;
|
||||
|
||||
|
||||
@RequestMapping("/index")
|
||||
@TokenIgnore
|
||||
public ApiResp<String> index() {
|
||||
|
||||
TokenBean tokenBean = new TokenBean("11", "", "fdfd");
|
||||
LogFactory.get().info(tokenBean.toToken());
|
||||
|
||||
return ApiResp.respOK("hello world");
|
||||
}
|
||||
|
||||
@RequestMapping("/redirect")
|
||||
@TokenIgnore
|
||||
public void redirect(HttpServletResponse response) {
|
||||
globalConfig.redirect("mobile", "/test", response);
|
||||
// tsTokenConfig.validToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NzYwMDY4NzUsImlkIjoiMSIsImVudmlyb25tZW50VHlwZSI6Im1vYmlsZSIsInNlcnZpY2UiOiJjb250ZXN0LXJlc2VydmUiLCJleHRyYSI6IiJ9.nsfxEFpCNHC7eNCS5DJXdu1VDdnHrTjSfgrozND70Lc", true);
|
||||
// globalConfig.redirect("mobile", "/test", response);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("/send")
|
||||
@TokenIgnore
|
||||
public ApiResp<MessageReqResp> sendMessage() {
|
||||
MessageReqResp reqResp = aliyunSmsConfig.sendSms("13567116463", "SMS_154950909",
|
||||
JSONUtil.createObj().putOpt("code", "123456"));
|
||||
@@ -66,8 +81,25 @@ public class TestController {
|
||||
@RequestMapping("/uploadPath")
|
||||
@TokenIgnore
|
||||
public ApiResp<String> uploadPath() {
|
||||
FileUploadPath uploadPath = FileUploadPath.get("http://scv6.tmp.kepai365.ltd/upload/2023-01/2b4b6b7b-70d0-4683-859a-f799adc4f04c.xls");
|
||||
FileUploadPath uploadPath = FileUploadPath.file("http://scv6.tmp.kepai365.ltd/upload/2023-01/2b4b6b7b-70d0-4683-859a-f799adc4f04c.xls");
|
||||
return ApiResp.respOK(uploadPath.getAbsolutePath());
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("searchIP")
|
||||
@TokenIgnore
|
||||
public ApiResp<String> searchIp() {
|
||||
String search = ip2regionConfig.search("127.0.0.1");
|
||||
return ApiResp.respOK(search);
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("desensitize")
|
||||
@TokenIgnore
|
||||
public ApiResp<List<TestFile>> desensitize() {
|
||||
TestFile file = new TestFile("11111");
|
||||
TestFile file1 = new TestFile("22222");
|
||||
return ApiResp.respOK(CollUtil.newArrayList(file, file1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
//package com.tiesheng.demo.pojos;
|
||||
//
|
||||
//import com.alibaba.excel.annotation.ExcelProperty;
|
||||
//import com.tiesheng.poi.pojos.PoiWriteBase;
|
||||
//
|
||||
//public class TestFile implements PoiWriteBase {
|
||||
//
|
||||
//
|
||||
// @ExcelProperty("测试")
|
||||
// private String test;
|
||||
//
|
||||
// public TestFile(String test) {
|
||||
// this.test = test;
|
||||
// }
|
||||
//
|
||||
// ///////////////////////////////////////////////////////////////////////////
|
||||
// // setter、getter
|
||||
// ///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// public String getTest() {
|
||||
// return test;
|
||||
// }
|
||||
//
|
||||
// public void setTest(String test) {
|
||||
// this.test = test;
|
||||
// }
|
||||
//}
|
||||
package com.tiesheng.demo.pojos;
|
||||
|
||||
import com.tiesheng.annotation.desensitize.Desensitize;
|
||||
import com.tiesheng.poi.pojos.PoiWriteBase;
|
||||
|
||||
public class TestFile implements PoiWriteBase {
|
||||
|
||||
|
||||
@Desensitize()
|
||||
private String test;
|
||||
|
||||
public TestFile(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter、getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getTest() {
|
||||
return test;
|
||||
}
|
||||
|
||||
public void setTest(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
}
|
||||
|
||||
28
springboot-ademo/src/main/resources/application-test.yml
Normal file
28
springboot-ademo/src/main/resources/application-test.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
## Spring配置
|
||||
spring:
|
||||
|
||||
## 数据库配置
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://47.96.30.85:3306/com_tiesheng_web?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&queryTimeout=5400&allowMultiQueries=true&serverTimezone=GMT%2B8
|
||||
username: com_tiesheng_web
|
||||
password: 4Xo$XheGFc
|
||||
|
||||
platform:
|
||||
wxmp:
|
||||
global:
|
||||
app-id: wxa0343fe519824651
|
||||
app-secret: 776f089ba70bcd66455a7c7893f810b9
|
||||
|
||||
tiesheng:
|
||||
token:
|
||||
test-map:
|
||||
"1111":
|
||||
id: "1111"
|
||||
global:
|
||||
version: 2
|
||||
host: http://localhost:8080
|
||||
aliyun:
|
||||
access-key-id: LTAI5tJtbgBCnTY5eS4SmrTf
|
||||
access-key-secret: JIHqpRUFffCHhXaJEVvWN31WcexWqG
|
||||
sign-name: 阿里云短信测试
|
||||
@@ -1,28 +1,22 @@
|
||||
server:
|
||||
compression:
|
||||
enabled: true
|
||||
port: 8100
|
||||
|
||||
## Spring配置
|
||||
spring:
|
||||
|
||||
## 数据库配置
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://47.96.30.85:3306/com_tiesheng_web?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&queryTimeout=5400&allowMultiQueries=true&serverTimezone=GMT%2B8
|
||||
username: com_tiesheng_web
|
||||
password: 4Xo$XheGFc
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 20MB
|
||||
web:
|
||||
resources:
|
||||
static-locations: classpath:/static/,file:static/
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
|
||||
platform:
|
||||
wxmp:
|
||||
global:
|
||||
app-id: wxa0343fe519824651
|
||||
app-secret: 776f089ba70bcd66455a7c7893f810b9
|
||||
|
||||
tiesheng:
|
||||
token:
|
||||
ignores:
|
||||
"1111":
|
||||
id: "1111"
|
||||
global:
|
||||
version: 2
|
||||
host: http://localhost:8080
|
||||
aliyun:
|
||||
access-key-id: LTAI5tJtbgBCnTY5eS4SmrTf
|
||||
access-key-secret: JIHqpRUFffCHhXaJEVvWN31WcexWqG
|
||||
sign-name: 阿里云短信测试
|
||||
## 日志
|
||||
logging:
|
||||
file:
|
||||
name: runtime/logs/tiesheng.log
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.tiesheng.annotation.desensitize;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Desensitize {
|
||||
|
||||
int prefix() default 1;
|
||||
|
||||
int suffix() default 1;
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import java.lang.annotation.*;
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Target({ElementType.METHOD,ElementType.TYPE})
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TokenIgnore {
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-db-migration</artifactId>
|
||||
<artifactId>springboot-database</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.tiesheng.database;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@ComponentScan({
|
||||
"com.tiesheng.database.**.*"
|
||||
})
|
||||
public class DatabaseAutoConfigurer {
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.tiesheng.database.config;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.RuntimeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.database.utls.TieshengDbUtil;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "tiesheng.db-backup")
|
||||
public class DbBackupConfig {
|
||||
|
||||
/**
|
||||
* 数据库备份的路径
|
||||
*/
|
||||
private String path = "/root/backup/";
|
||||
|
||||
/**
|
||||
* 备份文件的时间格式
|
||||
*/
|
||||
private String format = "yyyyMMdd";
|
||||
|
||||
|
||||
public void dbBackup() {
|
||||
String url = SpringUtil.getProperty("spring.datasource.url");
|
||||
String username = SpringUtil.getProperty("spring.datasource.username");
|
||||
String password = SpringUtil.getProperty("spring.datasource.password");
|
||||
String dbName = TieshengDbUtil.getTableSchema(url);
|
||||
|
||||
try {
|
||||
String saveFile = StrUtil.format("{}{}/{}.sql", getPath(), dbName, DateUtil.format(new Date(), format));
|
||||
FileUtil.mkParentDirs(saveFile);
|
||||
String cmd = StrUtil.format("mysqldump -u{} -p {} > {}", username, dbName, saveFile);
|
||||
LogFactory.get().info("cmd: " + cmd);
|
||||
String forStr = RuntimeUtil.execForStr(cmd);
|
||||
LogFactory.get().info("dbBackup: " + forStr);
|
||||
forStr = RuntimeUtil.execForStr(password);
|
||||
LogFactory.get().info("dbBackup: " + forStr);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tiesheng.migration.config;
|
||||
package com.tiesheng.database.config;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
@@ -21,7 +21,7 @@ public class DbMigrationConfig {
|
||||
|
||||
private String table = "core_config_db";
|
||||
private List<String> locations = CollUtil.newArrayList("classpath*:db/migration/*.sql");
|
||||
private String ignoreSqls = "drop,delete";
|
||||
private String ignoreSqls = "drop table,delete from";
|
||||
|
||||
/**
|
||||
* 检查数据库是否存在
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.tiesheng.database.service;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Component
|
||||
public interface DbDataInitializer {
|
||||
|
||||
/**
|
||||
* 初始化数据
|
||||
*/
|
||||
void init();
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.tiesheng.migration.service;
|
||||
package com.tiesheng.database.service;
|
||||
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
@@ -9,7 +9,7 @@ import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.db.Db;
|
||||
import cn.hutool.db.Entity;
|
||||
import com.tiesheng.migration.config.DbMigrationConfig;
|
||||
import com.tiesheng.database.config.DbMigrationConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.web.servlet.ServletContextInitializer;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -35,12 +35,17 @@ public class DbMigrationInitializer implements ServletContextInitializer {
|
||||
DataSource dataSource;
|
||||
@Autowired
|
||||
DbMigrationConfig dbMigrationConfig;
|
||||
@Autowired(required = false)
|
||||
List<DbDataInitializer> dbDataInitializerList;
|
||||
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext servletContext) {
|
||||
try {
|
||||
startDeal();
|
||||
if (dbDataInitializerList != null) {
|
||||
dbDataInitializerList.forEach(DbDataInitializer::init);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
@@ -91,7 +96,7 @@ public class DbMigrationInitializer implements ServletContextInitializer {
|
||||
if (StrUtil.isEmpty(sql)) {
|
||||
continue;
|
||||
}
|
||||
if (StrUtil.startWithAnyIgnoreCase(sql, StrUtil.splitToArray(dbMigrationConfig.getIgnoreSqls(), ","))) {
|
||||
if (StrUtil.containsAnyIgnoreCase(sql, StrUtil.splitToArray(dbMigrationConfig.getIgnoreSqls(), ","))) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.tiesheng.database.utls;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
public class TieshengDbUtil {
|
||||
|
||||
/**
|
||||
* 通过url获取table_schema
|
||||
*
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static String getTableSchema(String url) {
|
||||
return StrUtil.sub(url, url.lastIndexOf('/') + 1, StrUtil.indexOf(url, '?'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.tiesheng.migration;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@ComponentScan({
|
||||
"com.tiesheng.migration.**.*"
|
||||
})
|
||||
public class MigrationAutoConfigurer {
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-encrypt</artifactId>
|
||||
@@ -31,12 +31,12 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-login</artifactId>
|
||||
@@ -27,12 +27,12 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.tiesheng.login.config.token;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.tiesheng.annotation.token.TokenIgnore;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
@@ -46,7 +48,18 @@ public class TsTokenAspect {
|
||||
@Before("methodArgs()")
|
||||
public void before(JoinPoint joinPoint) {
|
||||
|
||||
// 过滤不要需要验证的接口
|
||||
// 过滤不要需要验证的接口(path)
|
||||
String requestURI = ServletKit.getRequest().getRequestURI();
|
||||
if (StrUtil.startWithAnyIgnoreCase(requestURI, tsTokenConfig.getIgnorePaths())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 过滤不要需要验证的接口(注解)
|
||||
Object aThis = joinPoint.getTarget();
|
||||
TokenIgnore annotation = aThis.getClass().getAnnotation(TokenIgnore.class);
|
||||
if (annotation != null) {
|
||||
return;
|
||||
}
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
TokenIgnore apiTokenIgnore = method.getAnnotation(TokenIgnore.class);
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTValidator;
|
||||
import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
@@ -22,9 +23,10 @@ import java.util.Map;
|
||||
@ConfigurationProperties("tiesheng.token")
|
||||
public class TsTokenConfig {
|
||||
|
||||
private Map<String, TokenBean> ignores = MapUtil.newHashMap();
|
||||
private Map<String, TokenBean> testMap = MapUtil.newHashMap();
|
||||
private String encryptKey = "%kIp9frQCu";
|
||||
private Integer expireHours = 48;
|
||||
private String[] ignorePaths;
|
||||
|
||||
|
||||
/**
|
||||
@@ -55,11 +57,23 @@ public class TsTokenConfig {
|
||||
* @param token
|
||||
* @return
|
||||
*/
|
||||
public TokenBean isIgnored(String token) {
|
||||
if (ignores == null) {
|
||||
public TokenBean isTestToken(String token) {
|
||||
if (testMap == null) {
|
||||
return null;
|
||||
}
|
||||
return ignores.get(token);
|
||||
return testMap.get(token);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证token
|
||||
*
|
||||
* @param thrExp
|
||||
* @return
|
||||
*/
|
||||
public TokenBean validToken(boolean thrExp) {
|
||||
String token = ServletUtil.getHeader(ServletKit.getRequest(), "token", "utf-8");
|
||||
return validToken(token, thrExp);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,31 +82,27 @@ public class TsTokenConfig {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public TokenBean validToken(boolean thrExp) {
|
||||
String token = ServletUtil.getHeader(ServletKit.getRequest(), "token", "utf-8");
|
||||
TokenBean tokenBean = isIgnored(token);
|
||||
public TokenBean validToken(String token, boolean thrExp) {
|
||||
TokenBean tokenBean = isTestToken(token);
|
||||
if (tokenBean != null) {
|
||||
return tokenBean;
|
||||
}
|
||||
|
||||
try {
|
||||
JWT decode = JWT.of(token);
|
||||
JWTValidator.of(decode).validateDate();
|
||||
String id = decode.getPayload("id").toString();
|
||||
String environmentType = decode.getPayload("environmentType").toString();
|
||||
String service = decode.getPayload("service").toString();
|
||||
String extra = decode.getPayload("extra").toString();
|
||||
Long expireTime = decode.getPayloads().getLong("time");
|
||||
if (expireTime != null && expireTime < System.currentTimeMillis()) {
|
||||
throw new ApiException("登录过期,请重新登陆");
|
||||
}
|
||||
|
||||
tokenBean = new TokenBean(id, environmentType, service);
|
||||
tokenBean.setExtra(extra);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
if (tokenBean == null && thrExp) {
|
||||
throw new ApiException(StrUtil.isEmpty(token) ? "请先登录" : "登录过期,请重新登陆");
|
||||
throw new ApiException(StrUtil.isEmpty(token) ? 110 : 112,
|
||||
StrUtil.isEmpty(token) ? "请先登录" : "登录过期,请重新登陆");
|
||||
}
|
||||
|
||||
if (tokenBean == null) {
|
||||
@@ -107,12 +117,12 @@ public class TsTokenConfig {
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Map<String, TokenBean> getIgnores() {
|
||||
return ignores;
|
||||
public Map<String, TokenBean> getTestMap() {
|
||||
return testMap;
|
||||
}
|
||||
|
||||
public void setIgnores(Map<String, TokenBean> ignores) {
|
||||
this.ignores = ignores;
|
||||
public void setTestMap(Map<String, TokenBean> testMap) {
|
||||
this.testMap = testMap;
|
||||
}
|
||||
|
||||
public String getEncryptKey() {
|
||||
@@ -130,4 +140,12 @@ public class TsTokenConfig {
|
||||
public void setExpireHours(Integer expireHours) {
|
||||
this.expireHours = expireHours;
|
||||
}
|
||||
|
||||
public String[] getIgnorePaths() {
|
||||
return ignorePaths;
|
||||
}
|
||||
|
||||
public void setIgnorePaths(String[] ignorePaths) {
|
||||
this.ignorePaths = ignorePaths;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tiesheng.login.config.token.bean;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import com.tiesheng.login.config.token.TsTokenConfig;
|
||||
@@ -31,11 +32,11 @@ public class TokenBean {
|
||||
public String toToken() {
|
||||
TsTokenConfig tsTokenConfig = SpringUtil.getBean(TsTokenConfig.class);
|
||||
return JWT.create()
|
||||
.setExpiresAt(DateUtil.offsetHour(DateUtil.date(), tsTokenConfig.getExpireHours()))
|
||||
.setPayload("id", getId())
|
||||
.setPayload("environmentType", getEnvironmentType())
|
||||
.setPayload("service", getService())
|
||||
.setPayload("extra", getExtra())
|
||||
.setPayload("time", System.currentTimeMillis() + tsTokenConfig.getExpireHours() * 1000 * 60 * 60)
|
||||
.setKey(tsTokenConfig.getEncryptKey().getBytes())
|
||||
.sign();
|
||||
}
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package com.tiesheng.login.config.zust;
|
||||
|
||||
public class CasLoginDTO {
|
||||
|
||||
private String data;
|
||||
|
||||
/**
|
||||
* 工号
|
||||
*/
|
||||
private String casUser;
|
||||
|
||||
/**
|
||||
* 用户容器
|
||||
*/
|
||||
private String casUserContainerId;
|
||||
|
||||
/**
|
||||
* 用户姓名
|
||||
*/
|
||||
private String casUserCn;
|
||||
|
||||
/**
|
||||
* 用户别名
|
||||
*/
|
||||
private String casUserAlias;
|
||||
/**
|
||||
* 用户所在组
|
||||
*/
|
||||
private String casUserMemberOf;
|
||||
/**
|
||||
* 用户性别
|
||||
*/
|
||||
private String casUserGender;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public String getCasUser() {
|
||||
return casUser;
|
||||
}
|
||||
|
||||
public void setCasUser(String casUser) {
|
||||
this.casUser = casUser;
|
||||
}
|
||||
|
||||
public String getCasUserContainerId() {
|
||||
return casUserContainerId;
|
||||
}
|
||||
|
||||
public void setCasUserContainerId(String casUserContainerId) {
|
||||
this.casUserContainerId = casUserContainerId;
|
||||
}
|
||||
|
||||
public String getCasUserCn() {
|
||||
return casUserCn;
|
||||
}
|
||||
|
||||
public void setCasUserCn(String casUserCn) {
|
||||
this.casUserCn = casUserCn;
|
||||
}
|
||||
|
||||
public String getCasUserAlias() {
|
||||
return casUserAlias;
|
||||
}
|
||||
|
||||
public void setCasUserAlias(String casUserAlias) {
|
||||
this.casUserAlias = casUserAlias;
|
||||
}
|
||||
|
||||
public String getCasUserMemberOf() {
|
||||
return casUserMemberOf;
|
||||
}
|
||||
|
||||
public void setCasUserMemberOf(String casUserMemberOf) {
|
||||
this.casUserMemberOf = casUserMemberOf;
|
||||
}
|
||||
|
||||
public String getCasUserGender() {
|
||||
return casUserGender;
|
||||
}
|
||||
|
||||
public void setCasUserGender(String casUserGender) {
|
||||
this.casUserGender = casUserGender;
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,14 @@ import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
import com.tiesheng.login.pojos.CodeExtraDTO;
|
||||
import com.tiesheng.login.pojos.DoLoginInfo;
|
||||
import com.tiesheng.login.pojos.UniqueIndexDTO;
|
||||
import com.tiesheng.login.pojos.WxminiLoginVo;
|
||||
import com.tiesheng.login.service.TieshengLoginConfigurer;
|
||||
import com.tiesheng.platform.config.ding.PlatformDingConfig;
|
||||
import com.tiesheng.platform.config.ding.bean.DingJsapiSignature;
|
||||
import com.tiesheng.platform.config.ding.bean.DingUserInfo;
|
||||
import com.tiesheng.platform.config.wxmini.PlatformWxminiConfig;
|
||||
import com.tiesheng.platform.config.wxmp.PlatformWxmpConfig;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxJsapiSignature;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxUserInfo;
|
||||
import com.tiesheng.util.config.GlobalConfig;
|
||||
@@ -32,6 +35,7 @@ import java.util.Map;
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/login")
|
||||
@TokenIgnore
|
||||
public class LoginController {
|
||||
|
||||
|
||||
@@ -40,6 +44,8 @@ public class LoginController {
|
||||
@Autowired
|
||||
PlatformDingConfig platformDingConfig;
|
||||
@Autowired
|
||||
PlatformWxminiConfig platformWxminiConfig;
|
||||
@Autowired
|
||||
TieshengLoginConfigurer tieshengLoginConfigurer;
|
||||
@Autowired
|
||||
GlobalConfig globalConfig;
|
||||
@@ -51,7 +57,6 @@ public class LoginController {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/unique/redirect")
|
||||
@TokenIgnore
|
||||
public void uniqueIndex(UniqueIndexDTO dto, HttpServletResponse response) {
|
||||
TokenBean tokenBean = tieshengLoginConfigurer.doLogin(new DoLoginInfo("unique_index_web",
|
||||
dto.getNo(), "web", dto.getTo(), dto.getInfo()));
|
||||
@@ -66,7 +71,6 @@ public class LoginController {
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/unique/index")
|
||||
@TokenIgnore
|
||||
public ApiResp<String> uniqueIndex(@RequestBody UniqueIndexDTO dto) {
|
||||
TokenBean tokenBean = tieshengLoginConfigurer.doLogin(new DoLoginInfo("unique_index_web",
|
||||
dto.getNo(), "web", dto.getTo(), dto.getInfo()));
|
||||
@@ -89,7 +93,6 @@ public class LoginController {
|
||||
* @param response
|
||||
*/
|
||||
@GetMapping("/ding/index/{service}")
|
||||
@TokenIgnore
|
||||
public void dingIndex(@PathVariable String service, String extra, HttpServletResponse response) {
|
||||
if (StrUtil.isEmpty(extra)) {
|
||||
extra = "";
|
||||
@@ -113,7 +116,6 @@ public class LoginController {
|
||||
* @param service
|
||||
*/
|
||||
@RequestMapping("/ding/oauth2/{service}")
|
||||
@TokenIgnore
|
||||
public void dingOauth2(@PathVariable String service, CodeExtraDTO dto, HttpServletResponse response) {
|
||||
String ddUserId = platformDingConfig.getUserIdByCode(service, dto.getCode());
|
||||
DingUserInfo dingUserInfo = platformDingConfig.topapiV2UserGet(service, ddUserId);
|
||||
@@ -131,7 +133,6 @@ public class LoginController {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/ding/jssdk/{service}")
|
||||
@TokenIgnore
|
||||
public ApiResp<DingJsapiSignature> dingJssdk(@PathVariable String service, String url) {
|
||||
DingJsapiSignature jsapiSignature = platformDingConfig.createJsapiSignature(service, url);
|
||||
return ApiResp.respOK(jsapiSignature);
|
||||
@@ -149,7 +150,6 @@ public class LoginController {
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/wxmp/index/{service}")
|
||||
@TokenIgnore
|
||||
public void wxmpIndex(@PathVariable String service, String extra, HttpServletResponse response) throws IOException {
|
||||
if (StrUtil.isEmpty(extra)) {
|
||||
extra = "";
|
||||
@@ -164,7 +164,6 @@ public class LoginController {
|
||||
* 微信授权回调
|
||||
*/
|
||||
@RequestMapping("/wxmp/oauth2/{service}")
|
||||
@TokenIgnore
|
||||
public void wxmpOauth2(@PathVariable String service, CodeExtraDTO dto, HttpServletResponse response) {
|
||||
WxUserInfo wxUserInfo = platformWxmpConfig.getOAuth2AccessToken(service, dto.getCode());
|
||||
TokenBean tokenBean = tieshengLoginConfigurer.doLogin(new DoLoginInfo(wxUserInfo.getAppId(),
|
||||
@@ -180,11 +179,34 @@ public class LoginController {
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/wxmp/jssdk/{service}")
|
||||
@TokenIgnore
|
||||
public ApiResp<WxJsapiSignature> wxmpJssdk(@PathVariable String service, String url) {
|
||||
WxJsapiSignature jsapiSignature = platformWxmpConfig.createJsapiSignature(service, url);
|
||||
return ApiResp.respOK(jsapiSignature);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 小程序相关
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 微信小程序登录
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping("/wxmini/index/{service}")
|
||||
public ApiResp<WxminiLoginVo> wxminiIndex(@PathVariable String service, String code) {
|
||||
String openid = platformWxminiConfig.jscode2session(service, code);
|
||||
WxConfigBean configBean = platformWxminiConfig.getConfigBean(service);
|
||||
TokenBean tokenBean = tieshengLoginConfigurer.doLogin(new DoLoginInfo(configBean.getAppId(),
|
||||
openid, "wxmini", "mini", "{}"));
|
||||
|
||||
WxminiLoginVo loginVo = new WxminiLoginVo();
|
||||
loginVo.setOpenid(openid);
|
||||
if (tokenBean != null) {
|
||||
loginVo.setToken(tokenBean.toToken());
|
||||
}
|
||||
return ApiResp.respOK(loginVo);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.tiesheng.login.pojos;
|
||||
|
||||
public class WxminiLoginVo {
|
||||
|
||||
private String openid;
|
||||
private String token;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public String getOpenid() {
|
||||
return openid;
|
||||
}
|
||||
|
||||
public void setOpenid(String openid) {
|
||||
this.openid = openid;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-message</artifactId>
|
||||
@@ -20,7 +20,7 @@
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-platform</artifactId>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.tiesheng.platform.config.wxmini;
|
||||
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
|
||||
import com.tiesheng.util.exception.ApiException;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "platform.wxmini")
|
||||
public class PlatformWxminiConfig {
|
||||
|
||||
private WxConfigBean global;
|
||||
private Map<String, WxConfigBean> configs = MapUtil.newHashMap();
|
||||
|
||||
/**
|
||||
* 获取一个DingConfigBean
|
||||
*
|
||||
* @param service
|
||||
* @return
|
||||
*/
|
||||
public WxConfigBean getConfigBean(String service) {
|
||||
WxConfigBean bean = configs.get(service);
|
||||
if (bean == null) {
|
||||
bean = global;
|
||||
}
|
||||
if (bean == null) {
|
||||
throw new ApiException("该服务未配置微信小程序授权");
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 业务逻辑
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* 通过code获取openid
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String jscode2session(String service, String code) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
String body = HttpRequest.get("https://api.weixin.qq.com/sns/jscode2session"
|
||||
+ "?appid=" + configBean.getAppId()
|
||||
+ "&secret=" + configBean.getAppSecret()
|
||||
+ "&js_code=" + code + "&grant_type=authorization_code").execute().body();
|
||||
JSONObject object = JSONUtil.parseObj(body);
|
||||
return object.getStr("openid");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getAccessToken(String service) {
|
||||
WxConfigBean configBean = getConfigBean(service);
|
||||
String body = HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token"
|
||||
+ "?grant_type=client_credential&appid=" + configBean.getAppId()
|
||||
+ "&secret=" + configBean.getAppSecret()).execute().body();
|
||||
JSONObject object = JSONUtil.parseObj(body);
|
||||
return object.getStr("access_token");
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// setter\getter
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Map<String, WxConfigBean> getConfigs() {
|
||||
return configs;
|
||||
}
|
||||
|
||||
public void setConfigs(Map<String, WxConfigBean> configs) {
|
||||
this.configs = configs;
|
||||
}
|
||||
|
||||
public WxConfigBean getGlobal() {
|
||||
return global;
|
||||
}
|
||||
|
||||
public void setGlobal(WxConfigBean global) {
|
||||
this.global = global;
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-poi</artifactId>
|
||||
@@ -25,7 +25,7 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-util</artifactId>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.tiesheng.util;
|
||||
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
@@ -21,6 +22,17 @@ public class PasswordUtils {
|
||||
return prefix + SecureUtil.sha1(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 密码复杂度校验
|
||||
*
|
||||
* @param userPassword
|
||||
* @return
|
||||
*/
|
||||
public static boolean verifyComplexity(String userPassword) {
|
||||
String password = "^(?![A-Za-z0-9]+$)(?![a-z0-9\\W]+$)(?![A-Za-z\\W]+$)(?![A-Z0-9\\W]+$)[a-zA-Z0-9\\W]{8,}$";
|
||||
return userPassword.matches(password);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证密码
|
||||
@@ -30,12 +42,18 @@ public class PasswordUtils {
|
||||
* @return
|
||||
*/
|
||||
public static void verifyPassword(String userInput, String encrypted) {
|
||||
String clientIp = ServletKit.getClientIP();
|
||||
String userEncrypted = buildPassword(userInput);
|
||||
|
||||
userEncrypted = StrUtil.subSuf(userEncrypted, PREFIX_SIZE);
|
||||
encrypted = StrUtil.subSuf(encrypted, PREFIX_SIZE);
|
||||
|
||||
if (!StrUtil.equals(userEncrypted, encrypted)) {
|
||||
int num = NumberUtil.parseInt(TimedCacheHelper.getTimedCache().get(clientIp, false));
|
||||
if (num > 5) {
|
||||
throw new ApiException("登录失败已达6次,请10分钟后再试");
|
||||
}
|
||||
TimedCacheHelper.getTimedCache().put(clientIp, String.valueOf(num + 1), 10 * 60 * 1000);
|
||||
throw new ApiException("账号或密码错误");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,5 +20,14 @@ public class ServletKit extends ServletUtil {
|
||||
return attributes.getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getClientIP() {
|
||||
return getClientIP(getRequest());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,11 @@ package com.tiesheng.util.config;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.util.ip2region.Searcher;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
@@ -17,8 +16,8 @@ import java.io.RandomAccessFile;
|
||||
@ConfigurationProperties(prefix = "tiesheng.ip2region")
|
||||
public class Ip2regionConfig {
|
||||
|
||||
private String dbUrl = "http://git.kepai365.com/zeng_wenhao/kepai-repo/raw/master/ipdb/ip2region.db";
|
||||
private String dbPath = System.getProperty("user.dir") + "/ipdb/ip2region.db";
|
||||
private String dbUrl = "http://git.kepai365.com/zeng_wenhao/kepai-repo/raw/master/ipdb/ip2region.xdb";
|
||||
private String dbPath = System.getProperty("user.dir") + "/runtime/ip2region/ip2region.xdb";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 逻辑方法
|
||||
@@ -35,15 +34,20 @@ public class Ip2regionConfig {
|
||||
|
||||
|
||||
/**
|
||||
* 获取db文件
|
||||
* 搜索ip
|
||||
*
|
||||
* @param ip
|
||||
* @return
|
||||
*/
|
||||
public RandomAccessFile getDbAccessFile() throws FileNotFoundException {
|
||||
if (!FileUtil.exist(dbPath)) {
|
||||
downloadDbFile();
|
||||
public String search(String ip) {
|
||||
String region = "";
|
||||
try {
|
||||
Searcher searcher = Searcher.newWithFileOnly(dbPath);
|
||||
region = searcher.search(ip);
|
||||
searcher.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return new RandomAccessFile(dbPath, "r");
|
||||
return region;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
/**
|
||||
* data block class
|
||||
*
|
||||
* @author chenxin<chenxin619315 @ gmail.com>
|
||||
*/
|
||||
public class DataBlock {
|
||||
/**
|
||||
* city id
|
||||
*/
|
||||
private int cityId;
|
||||
|
||||
/**
|
||||
* region address
|
||||
*/
|
||||
private String region;
|
||||
|
||||
/**
|
||||
* region ptr in the db file
|
||||
*/
|
||||
private int dataPtr;
|
||||
|
||||
/**
|
||||
* construct method
|
||||
*
|
||||
* @param cityId
|
||||
* @param region region string
|
||||
* @param dataPtr data ptr
|
||||
*/
|
||||
public DataBlock(int cityId, String region, int dataPtr) {
|
||||
this.cityId = cityId;
|
||||
this.region = region;
|
||||
this.dataPtr = dataPtr;
|
||||
}
|
||||
|
||||
public DataBlock(int cityId, String region) {
|
||||
this(cityId, region, 0);
|
||||
}
|
||||
|
||||
public int getCityId() {
|
||||
return cityId;
|
||||
}
|
||||
|
||||
public DataBlock setCityId(int cityId) {
|
||||
this.cityId = cityId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public DataBlock setRegion(String region) {
|
||||
this.region = region;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDataPtr() {
|
||||
return dataPtr;
|
||||
}
|
||||
|
||||
public DataBlock setDataPtr(int dataPtr) {
|
||||
this.dataPtr = dataPtr;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(cityId).append('|').append(region).append('|').append(dataPtr);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
/**
|
||||
* database configuration class
|
||||
*
|
||||
* @author chenxin<chenxin619315 @ gmail.com>
|
||||
*/
|
||||
public class DbConfig {
|
||||
/**
|
||||
* total header data block size
|
||||
*/
|
||||
private int totalHeaderSize;
|
||||
|
||||
/**
|
||||
* max index data block size
|
||||
* u should always choice the fastest read block size
|
||||
*/
|
||||
private int indexBlockSize;
|
||||
|
||||
/**
|
||||
* construct method
|
||||
*
|
||||
* @param totalHeaderSize
|
||||
*/
|
||||
public DbConfig(int totalHeaderSize) {
|
||||
this.totalHeaderSize = totalHeaderSize;
|
||||
this.indexBlockSize = 8192;
|
||||
}
|
||||
|
||||
public DbConfig() {
|
||||
this(8 * 2048);
|
||||
}
|
||||
|
||||
public int getTotalHeaderSize() {
|
||||
return totalHeaderSize;
|
||||
}
|
||||
|
||||
public DbConfig setTotalHeaderSize(int totalHeaderSize) {
|
||||
this.totalHeaderSize = totalHeaderSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getIndexBlockSize() {
|
||||
return indexBlockSize;
|
||||
}
|
||||
|
||||
public DbConfig setIndexBlockSize(int dataBlockSize) {
|
||||
this.indexBlockSize = dataBlockSize;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
*/
|
||||
public class Header {
|
||||
public final int version;
|
||||
public final int indexPolicy;
|
||||
public final int createdAt;
|
||||
public final int startIndexPtr;
|
||||
public final int endIndexPtr;
|
||||
public final byte[] buffer;
|
||||
|
||||
public Header(byte[] buff) {
|
||||
assert buff.length >= 16;
|
||||
version = Searcher.getInt2(buff, 0);
|
||||
indexPolicy = Searcher.getInt2(buff, 2);
|
||||
createdAt = Searcher.getInt(buff, 4);
|
||||
startIndexPtr = Searcher.getInt(buff, 8);
|
||||
endIndexPtr = Searcher.getInt(buff, 12);
|
||||
buffer = buff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{" +
|
||||
"Version: " + version + ',' +
|
||||
"IndexPolicy: " + indexPolicy + ',' +
|
||||
"CreatedAt: " + createdAt + ',' +
|
||||
"StartIndexPtr: " + startIndexPtr + ',' +
|
||||
"EndIndexPtr: " + endIndexPtr +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
/**
|
||||
* item index class
|
||||
*
|
||||
* @author chenxin<chenxin619315 @ gmail.com>
|
||||
*/
|
||||
public class IndexBlock {
|
||||
|
||||
private static int LENGTH = 12;
|
||||
|
||||
/**
|
||||
* start ip address
|
||||
*/
|
||||
private long startIp;
|
||||
|
||||
/**
|
||||
* end ip address
|
||||
*/
|
||||
private long endIp;
|
||||
|
||||
/**
|
||||
* data ptr and data length
|
||||
*/
|
||||
private int dataPtr;
|
||||
|
||||
/**
|
||||
* data length
|
||||
*/
|
||||
private int dataLen;
|
||||
|
||||
public IndexBlock(long startIp, long endIp, int dataPtr, int dataLen) {
|
||||
this.startIp = startIp;
|
||||
this.endIp = endIp;
|
||||
this.dataPtr = dataPtr;
|
||||
this.dataLen = dataLen;
|
||||
}
|
||||
|
||||
public static int getIndexBlockLength() {
|
||||
return LENGTH;
|
||||
}
|
||||
|
||||
public long getStartIp() {
|
||||
return startIp;
|
||||
}
|
||||
|
||||
public IndexBlock setStartIp(long startIp) {
|
||||
this.startIp = startIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getEndIp() {
|
||||
return endIp;
|
||||
}
|
||||
|
||||
public IndexBlock setEndIp(long endIp) {
|
||||
this.endIp = endIp;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDataPtr() {
|
||||
return dataPtr;
|
||||
}
|
||||
|
||||
public IndexBlock setDataPtr(int dataPtr) {
|
||||
this.dataPtr = dataPtr;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getDataLen() {
|
||||
return dataLen;
|
||||
}
|
||||
|
||||
public IndexBlock setDataLen(int dataLen) {
|
||||
this.dataLen = dataLen;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the bytes for storage
|
||||
*
|
||||
* @return byte[]
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
/*
|
||||
* +------------+-----------+-----------+
|
||||
* | 4bytes | 4bytes | 4bytes |
|
||||
* +------------+-----------+-----------+
|
||||
* start ip end ip data ptr + len
|
||||
*/
|
||||
byte[] b = new byte[12];
|
||||
|
||||
IpUtil.writeIntLong(b, 0, startIp); //start ip
|
||||
IpUtil.writeIntLong(b, 4, endIp); //end ip
|
||||
|
||||
//write the data ptr and the length
|
||||
long mix = dataPtr | ((dataLen << 24) & 0xFF000000L);
|
||||
IpUtil.writeIntLong(b, 8, mix);
|
||||
|
||||
return b;
|
||||
}
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.tiesheng.util.config.Ip2regionConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* ip db searcher class (Not thread safe)
|
||||
*
|
||||
* @author chenxin<chenxin619315 @ gmail.com>
|
||||
*/
|
||||
public class Ip2Region {
|
||||
|
||||
|
||||
private static Ip2Region ip2Region;
|
||||
/**
|
||||
* db config
|
||||
*/
|
||||
private final DbConfig dbConfig;
|
||||
/**
|
||||
* db file access handler
|
||||
*/
|
||||
private RandomAccessFile raf = null;
|
||||
/**
|
||||
* header blocks buffer
|
||||
*/
|
||||
private long[] headerSip = null;
|
||||
private int[] headerPtr = null;
|
||||
private int headerLength;
|
||||
/**
|
||||
* super blocks info
|
||||
*/
|
||||
private long firstIndexPtr = 0;
|
||||
private long lastIndexPtr = 0;
|
||||
private int totalIndexBlocks = 0;
|
||||
/**
|
||||
* for memory mode
|
||||
* the original db binary string
|
||||
*/
|
||||
private byte[] dbBinStr = null;
|
||||
|
||||
/**
|
||||
* construct class
|
||||
*/
|
||||
public Ip2Region() {
|
||||
this.dbConfig = new DbConfig();
|
||||
try {
|
||||
Ip2regionConfig ip2regionConfig = SpringUtil.getBean(Ip2regionConfig.class);
|
||||
raf = ip2regionConfig.getDbAccessFile();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单例
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Ip2Region getInstance() {
|
||||
if (ip2Region == null) {
|
||||
synchronized (Ip2Region.class) {
|
||||
if (ip2Region == null) {
|
||||
ip2Region = new Ip2Region();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ip2Region;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region with an int ip address with memory binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock memorySearch(long ip) throws IOException {
|
||||
int blen = IndexBlock.getIndexBlockLength();
|
||||
if (dbBinStr == null) {
|
||||
dbBinStr = new byte[(int) raf.length()];
|
||||
raf.seek(0L);
|
||||
raf.readFully(dbBinStr, 0, dbBinStr.length);
|
||||
|
||||
//initialize the global vars
|
||||
firstIndexPtr = IpUtil.getIntLong(dbBinStr, 0);
|
||||
lastIndexPtr = IpUtil.getIntLong(dbBinStr, 4);
|
||||
totalIndexBlocks = (int) ((lastIndexPtr - firstIndexPtr) / blen) + 1;
|
||||
}
|
||||
|
||||
//search the index blocks to define the data
|
||||
int l = 0, h = totalIndexBlocks;
|
||||
long sip, eip, dataptr = 0;
|
||||
while (l <= h) {
|
||||
int m = (l + h) >> 1;
|
||||
int p = (int) (firstIndexPtr + m * blen);
|
||||
|
||||
sip = IpUtil.getIntLong(dbBinStr, p);
|
||||
if (ip < sip) {
|
||||
h = m - 1;
|
||||
} else {
|
||||
eip = IpUtil.getIntLong(dbBinStr, p + 4);
|
||||
if (ip > eip) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
dataptr = IpUtil.getIntLong(dbBinStr, p + 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not matched
|
||||
if (dataptr == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//get the data
|
||||
int dataLen = (int) ((dataptr >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
|
||||
int cityId = (int) IpUtil.getIntLong(dbBinStr, dataPtr);
|
||||
String region = new String(dbBinStr, dataPtr + 4, dataLen - 4, StandardCharsets.UTF_8);
|
||||
|
||||
return new DataBlock(cityId, region, dataPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region throught the ip address with memory binary search algorithm
|
||||
*
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock memorySearch() throws IOException {
|
||||
return memorySearch(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region throught the ip address with memory binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock memorySearch(String ip) throws IOException {
|
||||
return memorySearch(IpUtil.ip2long(ip));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get by index ptr
|
||||
*
|
||||
* @param ptr
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock getByIndexPtr(long ptr) throws IOException {
|
||||
raf.seek(ptr);
|
||||
byte[] buffer = new byte[12];
|
||||
raf.readFully(buffer, 0, buffer.length);
|
||||
long extra = IpUtil.getIntLong(buffer, 8);
|
||||
|
||||
int dataLen = (int) ((extra >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((extra & 0x00FFFFFF));
|
||||
|
||||
raf.seek(dataPtr);
|
||||
byte[] data = new byte[dataLen];
|
||||
raf.readFully(data, 0, data.length);
|
||||
|
||||
int cityId = (int) IpUtil.getIntLong(data, 0);
|
||||
String region = new String(data, 4, data.length - 4, StandardCharsets.UTF_8);
|
||||
|
||||
return new DataBlock(cityId, region, dataPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region with an int ip address with b-tree algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock btreeSearch(long ip) throws IOException {
|
||||
//check and load the header
|
||||
if (headerSip == null) {
|
||||
raf.seek(8L);
|
||||
byte[] b = new byte[dbConfig.getTotalHeaderSize()];
|
||||
raf.readFully(b, 0, b.length);
|
||||
|
||||
//fill the header
|
||||
int len = b.length >> 3, idx = 0;
|
||||
headerSip = new long[len];
|
||||
headerPtr = new int[len];
|
||||
long startIp, dataPtr;
|
||||
for (int i = 0; i < b.length; i += 8) {
|
||||
startIp = IpUtil.getIntLong(b, i);
|
||||
dataPtr = IpUtil.getIntLong(b, i + 4);
|
||||
if (dataPtr == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
headerSip[idx] = startIp;
|
||||
headerPtr[idx] = (int) dataPtr;
|
||||
idx++;
|
||||
}
|
||||
|
||||
headerLength = idx;
|
||||
}
|
||||
|
||||
//1. define the index block with the binary search
|
||||
if (ip == headerSip[0]) {
|
||||
return getByIndexPtr(headerPtr[0]);
|
||||
} else if (ip == headerSip[headerLength - 1]) {
|
||||
return getByIndexPtr(headerPtr[headerLength - 1]);
|
||||
}
|
||||
|
||||
int l = 0, h = headerLength, sptr = 0, eptr = 0;
|
||||
while (l <= h) {
|
||||
int m = (l + h) >> 1;
|
||||
|
||||
//perfetc matched, just return it
|
||||
if (ip == headerSip[m]) {
|
||||
if (m > 0) {
|
||||
sptr = headerPtr[m - 1];
|
||||
eptr = headerPtr[m];
|
||||
} else {
|
||||
sptr = headerPtr[m];
|
||||
eptr = headerPtr[m + 1];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//less then the middle value
|
||||
if (ip < headerSip[m]) {
|
||||
if (m == 0) {
|
||||
sptr = headerPtr[m];
|
||||
eptr = headerPtr[m + 1];
|
||||
break;
|
||||
} else if (ip > headerSip[m - 1]) {
|
||||
sptr = headerPtr[m - 1];
|
||||
eptr = headerPtr[m];
|
||||
break;
|
||||
}
|
||||
h = m - 1;
|
||||
} else {
|
||||
if (m == headerLength - 1) {
|
||||
sptr = headerPtr[m - 1];
|
||||
eptr = headerPtr[m];
|
||||
break;
|
||||
} else if (ip <= headerSip[m + 1]) {
|
||||
sptr = headerPtr[m];
|
||||
eptr = headerPtr[m + 1];
|
||||
break;
|
||||
}
|
||||
l = m + 1;
|
||||
}
|
||||
}
|
||||
|
||||
//match nothing just stop it
|
||||
if (sptr == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//2. search the index blocks to define the data
|
||||
int blockLen = eptr - sptr, blen = IndexBlock.getIndexBlockLength();
|
||||
//include the right border block
|
||||
byte[] iBuffer = new byte[blockLen + blen];
|
||||
raf.seek(sptr);
|
||||
raf.readFully(iBuffer, 0, iBuffer.length);
|
||||
|
||||
l = 0;
|
||||
h = blockLen / blen;
|
||||
long sip, eip, dataptr = 0;
|
||||
while (l <= h) {
|
||||
int m = (l + h) >> 1;
|
||||
int p = m * blen;
|
||||
sip = IpUtil.getIntLong(iBuffer, p);
|
||||
if (ip < sip) {
|
||||
h = m - 1;
|
||||
} else {
|
||||
eip = IpUtil.getIntLong(iBuffer, p + 4);
|
||||
if (ip > eip) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
dataptr = IpUtil.getIntLong(iBuffer, p + 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not matched
|
||||
if (dataptr == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//3. get the data
|
||||
int dataLen = (int) ((dataptr >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
|
||||
|
||||
raf.seek(dataPtr);
|
||||
byte[] data = new byte[dataLen];
|
||||
raf.readFully(data, 0, data.length);
|
||||
|
||||
int cityId = (int) IpUtil.getIntLong(data, 0);
|
||||
String region = new String(data, 4, data.length - 4, StandardCharsets.UTF_8);
|
||||
|
||||
return new DataBlock(cityId, region, dataPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region throught the ip address with b-tree search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock btreeSearch(String ip) {
|
||||
try {
|
||||
return btreeSearch(IpUtil.ip2long(ip));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return new DataBlock(0, "未知IP");
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region with a int ip address with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock binarySearch(long ip) throws IOException {
|
||||
int blen = IndexBlock.getIndexBlockLength();
|
||||
if (totalIndexBlocks == 0) {
|
||||
raf.seek(0L);
|
||||
byte[] superBytes = new byte[8];
|
||||
raf.readFully(superBytes, 0, superBytes.length);
|
||||
//initialize the global vars
|
||||
firstIndexPtr = IpUtil.getIntLong(superBytes, 0);
|
||||
lastIndexPtr = IpUtil.getIntLong(superBytes, 4);
|
||||
totalIndexBlocks = (int) ((lastIndexPtr - firstIndexPtr) / blen) + 1;
|
||||
}
|
||||
|
||||
//search the index blocks to define the data
|
||||
int l = 0, h = totalIndexBlocks;
|
||||
byte[] buffer = new byte[blen];
|
||||
long sip, eip, dataptr = 0;
|
||||
while (l <= h) {
|
||||
int m = (l + h) >> 1;
|
||||
raf.seek(firstIndexPtr + m * blen);
|
||||
raf.readFully(buffer, 0, buffer.length);
|
||||
sip = IpUtil.getIntLong(buffer, 0);
|
||||
if (ip < sip) {
|
||||
h = m - 1;
|
||||
} else {
|
||||
eip = IpUtil.getIntLong(buffer, 4);
|
||||
if (ip > eip) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
dataptr = IpUtil.getIntLong(buffer, 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//not matched
|
||||
if (dataptr == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//get the data
|
||||
int dataLen = (int) ((dataptr >> 24) & 0xFF);
|
||||
int dataPtr = (int) ((dataptr & 0x00FFFFFF));
|
||||
|
||||
raf.seek(dataPtr);
|
||||
byte[] data = new byte[dataLen];
|
||||
raf.readFully(data, 0, data.length);
|
||||
|
||||
int cityId = (int) IpUtil.getIntLong(data, 0);
|
||||
String region = new String(data, 4, data.length - 4, StandardCharsets.UTF_8);
|
||||
|
||||
return new DataBlock(cityId, region, dataPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the region throught the ip address with binary search algorithm
|
||||
*
|
||||
* @param ip
|
||||
* @return DataBlock
|
||||
* @throws IOException
|
||||
*/
|
||||
public DataBlock binarySearch(String ip) throws IOException {
|
||||
return binarySearch(IpUtil.ip2long(ip));
|
||||
}
|
||||
|
||||
/**
|
||||
* get the db config
|
||||
*
|
||||
* @return DbConfig
|
||||
*/
|
||||
public DbConfig getDbConfig() {
|
||||
return dbConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* close the db
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
headerSip = null;
|
||||
headerPtr = null;
|
||||
dbBinStr = null;
|
||||
if (raf != null) {
|
||||
raf.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
/**
|
||||
* util class
|
||||
*
|
||||
* @author chenxin<chenxin619315 @ gmail.com>
|
||||
*/
|
||||
public class IpUtil {
|
||||
/**
|
||||
* write specfield bytes to a byte array start from offset
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
* @param v
|
||||
* @param bytes
|
||||
*/
|
||||
public static void write(byte[] b, int offset, long v, int bytes) {
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
b[offset++] = (byte) ((v >>> (8 * i)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* write a int to a byte array
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
* @param v
|
||||
*/
|
||||
public static void writeIntLong(byte[] b, int offset, long v) {
|
||||
b[offset++] = (byte) ((v >> 0) & 0xFF);
|
||||
b[offset++] = (byte) ((v >> 8) & 0xFF);
|
||||
b[offset++] = (byte) ((v >> 16) & 0xFF);
|
||||
b[offset] = (byte) ((v >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a int from a byte array start from the specifiled offset
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
*/
|
||||
public static long getIntLong(byte[] b, int offset) {
|
||||
return (
|
||||
((b[offset++] & 0x000000FFL)) |
|
||||
((b[offset++] << 8) & 0x0000FF00L) |
|
||||
((b[offset++] << 16) & 0x00FF0000L) |
|
||||
((b[offset] << 24) & 0xFF000000L)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get a int from a byte array start from the specifield offset
|
||||
*
|
||||
* @param b
|
||||
* @param offset
|
||||
*/
|
||||
public static int getInt3(byte[] b, int offset) {
|
||||
return (
|
||||
(b[offset++] & 0x000000FF) |
|
||||
(b[offset++] & 0x0000FF00) |
|
||||
(b[offset] & 0x00FF0000)
|
||||
);
|
||||
}
|
||||
|
||||
public static int getInt2(byte[] b, int offset) {
|
||||
return (
|
||||
(b[offset++] & 0x000000FF) |
|
||||
(b[offset] & 0x0000FF00)
|
||||
);
|
||||
}
|
||||
|
||||
public static int getInt1(byte[] b, int offset) {
|
||||
return (
|
||||
(b[offset] & 0x000000FF)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* string ip to long ip
|
||||
*
|
||||
* @param ip
|
||||
* @return long
|
||||
*/
|
||||
public static long ip2long(String ip) {
|
||||
String[] p = ip.split("\\.");
|
||||
if (p.length != 4) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int p1 = ((Integer.valueOf(p[0]) << 24) & 0xFF000000);
|
||||
int p2 = ((Integer.valueOf(p[1]) << 16) & 0x00FF0000);
|
||||
int p3 = ((Integer.valueOf(p[2]) << 8) & 0x0000FF00);
|
||||
int p4 = ((Integer.valueOf(p[3]) << 0) & 0x000000FF);
|
||||
|
||||
return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
* int to ip string
|
||||
*
|
||||
* @param ip
|
||||
* @return string
|
||||
*/
|
||||
public static String long2ip(long ip) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb
|
||||
.append((ip >> 24) & 0xFF).append('.')
|
||||
.append((ip >> 16) & 0xFF).append('.')
|
||||
.append((ip >> 8) & 0xFF).append('.')
|
||||
.append((ip >> 0) & 0xFF);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
package com.tiesheng.util.ip2region;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class Searcher {
|
||||
// constant defined copied from the xdb maker
|
||||
public static final int HeaderInfoLength = 256;
|
||||
public static final int VectorIndexRows = 256;
|
||||
public static final int VectorIndexCols = 256;
|
||||
public static final int VectorIndexSize = 8;
|
||||
public static final int SegmentIndexSize = 14;
|
||||
public static final byte[] shiftIndex = {24, 16, 8, 0};
|
||||
// random access file handle for file based search
|
||||
private final RandomAccessFile handle;
|
||||
// vector index.
|
||||
// use the byte[] instead of VectorIndex entry array to keep
|
||||
// the minimal memory allocation.
|
||||
private final byte[] vectorIndex;
|
||||
|
||||
// xdb content buffer, used for in-memory search
|
||||
private final byte[] contentBuff;
|
||||
|
||||
// --- static method to create searchers
|
||||
private int ioCount = 0;
|
||||
|
||||
public Searcher(String dbFile, byte[] vectorIndex, byte[] cBuff) throws IOException {
|
||||
if (cBuff != null) {
|
||||
this.handle = null;
|
||||
this.vectorIndex = null;
|
||||
this.contentBuff = cBuff;
|
||||
} else {
|
||||
this.handle = new RandomAccessFile(dbFile, "r");
|
||||
this.vectorIndex = vectorIndex;
|
||||
this.contentBuff = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Searcher newWithFileOnly(String dbPath) throws IOException {
|
||||
return new Searcher(dbPath, null, null);
|
||||
}
|
||||
|
||||
// --- End of creator
|
||||
|
||||
public static Searcher newWithVectorIndex(String dbPath, byte[] vectorIndex) throws IOException {
|
||||
return new Searcher(dbPath, vectorIndex, null);
|
||||
}
|
||||
|
||||
public static Searcher newWithBuffer(byte[] cBuff) throws IOException {
|
||||
return new Searcher(null, null, cBuff);
|
||||
}
|
||||
|
||||
public static Header loadHeader(RandomAccessFile handle) throws IOException {
|
||||
handle.seek(0);
|
||||
final byte[] buff = new byte[HeaderInfoLength];
|
||||
handle.read(buff);
|
||||
return new Header(buff);
|
||||
}
|
||||
|
||||
public static Header loadHeaderFromFile(String dbPath) throws IOException {
|
||||
final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
|
||||
final Header header = loadHeader(handle);
|
||||
handle.close();
|
||||
return header;
|
||||
}
|
||||
|
||||
public static byte[] loadVectorIndex(RandomAccessFile handle) throws IOException {
|
||||
handle.seek(HeaderInfoLength);
|
||||
int len = VectorIndexRows * VectorIndexCols * VectorIndexSize;
|
||||
final byte[] buff = new byte[len];
|
||||
int rLen = handle.read(buff);
|
||||
if (rLen != len) {
|
||||
throw new IOException("incomplete read: read bytes should be " + len);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
public static byte[] loadVectorIndexFromFile(String dbPath) throws IOException {
|
||||
final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
|
||||
final byte[] vIndex = loadVectorIndex(handle);
|
||||
handle.close();
|
||||
return vIndex;
|
||||
}
|
||||
|
||||
// --- static cache util function
|
||||
|
||||
public static byte[] loadContent(RandomAccessFile handle) throws IOException {
|
||||
handle.seek(0);
|
||||
final byte[] buff = new byte[(int) handle.length()];
|
||||
int rLen = handle.read(buff);
|
||||
if (rLen != buff.length) {
|
||||
throw new IOException("incomplete read: read bytes should be " + buff.length);
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
public static byte[] loadContentFromFile(String dbPath) throws IOException {
|
||||
final RandomAccessFile handle = new RandomAccessFile(dbPath, "r");
|
||||
final byte[] content = loadContent(handle);
|
||||
handle.close();
|
||||
return content;
|
||||
}
|
||||
|
||||
/* get an int from a byte array start from the specified offset */
|
||||
public static long getIntLong(byte[] b, int offset) {
|
||||
return (
|
||||
((b[offset++] & 0x000000FFL)) |
|
||||
((b[offset++] << 8) & 0x0000FF00L) |
|
||||
((b[offset++] << 16) & 0x00FF0000L) |
|
||||
((b[offset] << 24) & 0xFF000000L)
|
||||
);
|
||||
}
|
||||
|
||||
public static int getInt(byte[] b, int offset) {
|
||||
return (
|
||||
((b[offset++] & 0x000000FF)) |
|
||||
((b[offset++] << 8) & 0x0000FF00) |
|
||||
((b[offset++] << 16) & 0x00FF0000) |
|
||||
((b[offset] << 24) & 0xFF000000)
|
||||
);
|
||||
}
|
||||
|
||||
public static int getInt2(byte[] b, int offset) {
|
||||
return (
|
||||
((b[offset++] & 0x000000FF)) |
|
||||
((b[offset] << 8) & 0x0000FF00)
|
||||
);
|
||||
}
|
||||
|
||||
/* long int to ip string */
|
||||
public static String long2ip(long ip) {
|
||||
return String.valueOf((ip >> 24) & 0xFF) + '.' +
|
||||
((ip >> 16) & 0xFF) + '.' + ((ip >> 8) & 0xFF) + '.' + ((ip) & 0xFF);
|
||||
}
|
||||
|
||||
// --- End cache load util function
|
||||
|
||||
// --- static util method
|
||||
|
||||
/* check the specified ip address */
|
||||
public static long checkIP(String ip) throws Exception {
|
||||
String[] ps = ip.split("\\.");
|
||||
if (ps.length != 4) {
|
||||
throw new Exception("invalid ip address `" + ip + "`");
|
||||
}
|
||||
|
||||
long ipDst = 0;
|
||||
for (int i = 0; i < ps.length; i++) {
|
||||
int val = Integer.parseInt(ps[i]);
|
||||
if (val > 255) {
|
||||
throw new Exception("ip part `" + ps[i] + "` should be less then 256");
|
||||
}
|
||||
|
||||
ipDst |= ((long) val << shiftIndex[i]);
|
||||
}
|
||||
|
||||
return ipDst & 0xFFFFFFFFL;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (this.handle != null) {
|
||||
this.handle.close();
|
||||
}
|
||||
}
|
||||
|
||||
public int getIOCount() {
|
||||
return ioCount;
|
||||
}
|
||||
|
||||
public String search(String ipStr) throws Exception {
|
||||
long ip = checkIP(ipStr);
|
||||
return search(ip);
|
||||
}
|
||||
|
||||
public String search(long ip) throws IOException {
|
||||
// reset the global counter
|
||||
this.ioCount = 0;
|
||||
|
||||
// locate the segment index block based on the vector index
|
||||
int sPtr = 0, ePtr = 0;
|
||||
int il0 = (int) ((ip >> 24) & 0xFF);
|
||||
int il1 = (int) ((ip >> 16) & 0xFF);
|
||||
int idx = il0 * VectorIndexCols * VectorIndexSize + il1 * VectorIndexSize;
|
||||
// System.out.printf("il0: %d, il1: %d, idx: %d\n", il0, il1, idx);
|
||||
if (vectorIndex != null) {
|
||||
sPtr = getInt(vectorIndex, idx);
|
||||
ePtr = getInt(vectorIndex, idx + 4);
|
||||
} else if (contentBuff != null) {
|
||||
sPtr = getInt(contentBuff, HeaderInfoLength + idx);
|
||||
ePtr = getInt(contentBuff, HeaderInfoLength + idx + 4);
|
||||
} else {
|
||||
final byte[] buff = new byte[VectorIndexSize];
|
||||
read(HeaderInfoLength + idx, buff);
|
||||
sPtr = getInt(buff, 0);
|
||||
ePtr = getInt(buff, 4);
|
||||
}
|
||||
|
||||
// System.out.printf("sPtr: %d, ePtr: %d\n", sPtr, ePtr);
|
||||
|
||||
// binary search the segment index block to get the region info
|
||||
final byte[] buff = new byte[SegmentIndexSize];
|
||||
int dataLen = -1, dataPtr = -1;
|
||||
int l = 0, h = (ePtr - sPtr) / SegmentIndexSize;
|
||||
while (l <= h) {
|
||||
int m = (l + h) >> 1;
|
||||
int p = sPtr + m * SegmentIndexSize;
|
||||
|
||||
// read the segment index
|
||||
read(p, buff);
|
||||
long sip = getIntLong(buff, 0);
|
||||
if (ip < sip) {
|
||||
h = m - 1;
|
||||
} else {
|
||||
long eip = getIntLong(buff, 4);
|
||||
if (ip > eip) {
|
||||
l = m + 1;
|
||||
} else {
|
||||
dataLen = getInt2(buff, 8);
|
||||
dataPtr = getInt(buff, 10);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// empty match interception
|
||||
// System.out.printf("dataLen: %d, dataPtr: %d\n", dataLen, dataPtr);
|
||||
if (dataPtr < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// load and return the region data
|
||||
final byte[] regionBuff = new byte[dataLen];
|
||||
read(dataPtr, regionBuff);
|
||||
return new String(regionBuff, "utf-8");
|
||||
}
|
||||
|
||||
protected void read(int offset, byte[] buffer) throws IOException {
|
||||
// check the in-memory buffer first
|
||||
if (contentBuff != null) {
|
||||
// @TODO: reduce data copying, directly decode the data ?
|
||||
System.arraycopy(contentBuff, offset, buffer, 0, buffer.length);
|
||||
return;
|
||||
}
|
||||
|
||||
// read from the file handle
|
||||
assert handle != null;
|
||||
handle.seek(offset);
|
||||
|
||||
this.ioCount++;
|
||||
int rLen = handle.read(buffer);
|
||||
if (rLen != buffer.length) {
|
||||
throw new IOException("incomplete read: read bytes should be " + buffer.length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.tiesheng.util.pojos;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
@@ -29,19 +30,26 @@ public class FileUploadPath {
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
public static FileUploadPath get(String fileName) {
|
||||
public static FileUploadPath file(String fileName) {
|
||||
|
||||
// 下载文件
|
||||
fileName = downloadFile(fileName);
|
||||
fileName = fileDownload(fileName);
|
||||
|
||||
FileUploadPath pathBean = new FileUploadPath();
|
||||
|
||||
String tempPath = fileName;
|
||||
if (!StrUtil.startWith(tempPath, CharUtil.SLASH)) {
|
||||
tempPath = CharUtil.SLASH + tempPath;
|
||||
}
|
||||
if (!StrUtil.startWith(tempPath, UPLOAD_FOLDER)) {
|
||||
tempPath = UPLOAD_FOLDER + DateUtil.format(DateUtil.date(), "yyyy-MM") + "/" + fileName;
|
||||
tempPath = UPLOAD_FOLDER + DateUtil.format(DateUtil.date(), "yyyy-MM") + CharUtil.SLASH + fileName;
|
||||
}
|
||||
pathBean.setHttpPath(tempPath);
|
||||
pathBean.setAbsolutePath(String.format("%s/static%s", System.getProperty("user.dir"), tempPath));
|
||||
|
||||
String tempAbs = String.format("%s/static%s", System.getProperty("user.dir"), tempPath);
|
||||
tempAbs = FileUtil.normalize(tempAbs);
|
||||
pathBean.setAbsolutePath(tempAbs);
|
||||
|
||||
FileUtil.mkParentDirs(pathBean.getAbsolutePath());
|
||||
|
||||
return pathBean;
|
||||
@@ -51,40 +59,33 @@ public class FileUploadPath {
|
||||
/**
|
||||
* 下载http文件
|
||||
*
|
||||
* @param fileName
|
||||
* @param httpUrl
|
||||
* @return
|
||||
*/
|
||||
public static String downloadFile(String fileName) {
|
||||
if (!StrUtil.startWith(fileName, "http")) {
|
||||
return fileName;
|
||||
public static String fileDownload(String httpUrl) {
|
||||
if (!StrUtil.startWith(httpUrl, "http")) {
|
||||
return httpUrl;
|
||||
}
|
||||
String newFileName = UPLOAD_FOLDER + StrUtil.subAfter(fileName, UPLOAD_FOLDER, true);
|
||||
FileUploadPath uploadPath = get(newFileName);
|
||||
String newFileName = UPLOAD_FOLDER + StrUtil.subAfter(httpUrl, UPLOAD_FOLDER, true);
|
||||
FileUploadPath uploadPath = file(newFileName);
|
||||
if (!FileUtil.exist(uploadPath.getAbsolutePath())) {
|
||||
HttpUtil.downloadFile(fileName, uploadPath.getAbsolutePath());
|
||||
HttpUtil.downloadFile(httpUrl, uploadPath.getAbsolutePath());
|
||||
}
|
||||
|
||||
return uploadPath.getHttpPath();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机生成一个文件路径
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static FileUploadPath random() {
|
||||
return get(IdUtil.simpleUUID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机生成一个文件路径
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static FileUploadPath random(String fileExt) {
|
||||
return get(IdUtil.simpleUUID() + "." + fileExt);
|
||||
String fileName = IdUtil.simpleUUID();
|
||||
if (!StrUtil.isEmpty(fileExt)) {
|
||||
fileName = fileName + "." + fileExt;
|
||||
}
|
||||
return file(fileName);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,20 +96,9 @@ public class FileUploadPath {
|
||||
* @return
|
||||
*/
|
||||
public static FileUploadPath folder(String folder) {
|
||||
FileUploadPath pathBean = new FileUploadPath();
|
||||
|
||||
String tempFolder = folder;
|
||||
if (!StrUtil.startWith(tempFolder, UPLOAD_FOLDER)) {
|
||||
tempFolder = UPLOAD_FOLDER + tempFolder;
|
||||
}
|
||||
if (!StrUtil.endWith(folder, "/")) {
|
||||
tempFolder = tempFolder + "/";
|
||||
}
|
||||
pathBean.setHttpPath(tempFolder);
|
||||
pathBean.setAbsolutePath(String.format("%s/static%s", System.getProperty("user.dir"), tempFolder));
|
||||
FileUtil.mkParentDirs(pathBean.getAbsolutePath());
|
||||
|
||||
return pathBean;
|
||||
FileUploadPath file = file(folder);
|
||||
FileUtil.mkdir(file.getAbsolutePath());
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
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.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-parent</artifactId>
|
||||
<version>0.1.8</version>
|
||||
<version>0.7.4</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>springboot-web</artifactId>
|
||||
@@ -58,32 +58,32 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-util</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<artifactId>springboot-db-migration</artifactId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-database</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-poi</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-annotation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-login</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.tiesheng</groupId>
|
||||
<groupId>com.tiesheng.springboot-parent</groupId>
|
||||
<artifactId>springboot-message</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.tiesheng.core;
|
||||
|
||||
import com.tiesheng.core.service.TieshengWebConfigurer;
|
||||
import com.tiesheng.database.DatabaseAutoConfigurer;
|
||||
import com.tiesheng.login.LoginAutoConfigurer;
|
||||
import com.tiesheng.message.MessageAutoConfigurer;
|
||||
import com.tiesheng.migration.MigrationAutoConfigurer;
|
||||
import com.tiesheng.util.UtilAutoConfigurer;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.lang.annotation.*;
|
||||
MessageAutoConfigurer.class,
|
||||
CoreAutoConfigurer.class,
|
||||
LoginAutoConfigurer.class,
|
||||
MigrationAutoConfigurer.class
|
||||
DatabaseAutoConfigurer.class
|
||||
})
|
||||
public @interface EnableTieshengWeb {
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.tiesheng.core.config.desensitize;
|
||||
|
||||
import cn.hutool.core.util.ClassUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.serializer.ValueFilter;
|
||||
import com.tiesheng.annotation.desensitize.Desensitize;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* 脱敏过滤类
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
public class DesensitizeValueFilter implements ValueFilter {
|
||||
|
||||
@Override
|
||||
public Object process(Object object, String name, Object value) {
|
||||
if (ObjectUtil.isEmpty(value) || !(value instanceof String)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
Field field = ClassUtil.getDeclaredField(object.getClass(), name);
|
||||
if (ObjectUtil.isEmpty(field)) {
|
||||
return value;
|
||||
}
|
||||
Desensitize desensitize = field.getAnnotation(Desensitize.class);
|
||||
if (String.class != field.getType() || ObjectUtil.isEmpty(desensitize)) {
|
||||
return value;
|
||||
}
|
||||
String originVal = String.valueOf(value);
|
||||
return StrUtil.hide(originVal, desensitize.prefix(),
|
||||
StrUtil.length(originVal) - desensitize.suffix());
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.tiesheng.core.config.json;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.tiesheng.core.config.desensitize.DesensitizeValueFilter;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -30,6 +31,7 @@ public class FastJsonMessageConverter {
|
||||
SerializerFeature.WriteNullStringAsEmpty,
|
||||
SerializerFeature.WriteEnumUsingName);
|
||||
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
config.setSerializeFilters(new DesensitizeValueFilter());
|
||||
|
||||
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
|
||||
fastConverter.setFastJsonConfig(config);
|
||||
|
||||
@@ -5,6 +5,7 @@ import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.tiesheng.annotation.operation.OperationLog;
|
||||
import com.tiesheng.core.service.CoreLogService;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
@@ -13,6 +14,7 @@ import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -35,7 +37,7 @@ public class OperationAspect {
|
||||
CoreLogService coreLogService;
|
||||
|
||||
|
||||
@Pointcut("@annotation(com.tiesheng.annotation.operation.OperationLog)")
|
||||
@Pointcut("execution(* com..controller..*.*(..))")
|
||||
public void methodArgs() {
|
||||
|
||||
}
|
||||
@@ -48,11 +50,24 @@ public class OperationAspect {
|
||||
*/
|
||||
@Around("methodArgs()")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
|
||||
// GET请求不处理
|
||||
HttpServletRequest request = ServletKit.getRequest();
|
||||
if (StrUtil.equalsIgnoreCase(request.getMethod(), "GET")) {
|
||||
return joinPoint.proceed(joinPoint.getArgs());
|
||||
}
|
||||
|
||||
String title = "", subject = "";
|
||||
String insertKey = "";
|
||||
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
OperationLog operationLog = method.getAnnotation(OperationLog.class);
|
||||
String subject = operationLog.subject();
|
||||
String insertKey = operationLog.insertKey();
|
||||
if (operationLog != null) {
|
||||
title = operationLog.title();
|
||||
subject = operationLog.subject();
|
||||
insertKey = operationLog.insertKey();
|
||||
}
|
||||
|
||||
Object reqObj = null;
|
||||
Map<String, Object> allParams = new HashMap<>(16);
|
||||
@@ -65,7 +80,6 @@ public class OperationAspect {
|
||||
allParams.putAll(BeanUtil.beanToMap(response));
|
||||
|
||||
if (!StrUtil.isEmpty(subject)) {
|
||||
|
||||
// 添加、编辑关键字处理
|
||||
if (!StrUtil.isEmpty(insertKey)) {
|
||||
String insertVal = MapUtil.getStr(allParams, insertKey);
|
||||
@@ -74,9 +88,12 @@ public class OperationAspect {
|
||||
|
||||
// 占位符处理
|
||||
subject = StrUtil.format(subject, allParams);
|
||||
} else {
|
||||
title = method.getName();
|
||||
subject = ServletKit.getRequest().getRequestURI();
|
||||
}
|
||||
|
||||
coreLogService.addOperationLog(operationLog.title(), subject, reqObj);
|
||||
coreLogService.addOperationLog(title, subject, reqObj);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package com.tiesheng.core.pojos;
|
||||
|
||||
public class CurrentWebUser {
|
||||
/**
|
||||
* 当前token的数据
|
||||
*
|
||||
* @author hao
|
||||
*/
|
||||
public class RequestUserInfo {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
@@ -1,22 +1,23 @@
|
||||
package com.tiesheng.core.service;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.tiesheng.core.mapper.CoreLogLoginMapper;
|
||||
import com.tiesheng.core.mapper.CoreLogMessageMapper;
|
||||
import com.tiesheng.core.mapper.CoreLogOperationMapper;
|
||||
import com.tiesheng.core.pojos.CurrentWebUser;
|
||||
import com.tiesheng.core.pojos.RequestUserInfo;
|
||||
import com.tiesheng.core.pojos.dao.CoreLogLogin;
|
||||
import com.tiesheng.core.pojos.dao.CoreLogMessage;
|
||||
import com.tiesheng.core.pojos.dao.CoreLogOperation;
|
||||
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
|
||||
import com.tiesheng.login.config.token.TsTokenConfig;
|
||||
import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
import com.tiesheng.message.pojos.MessageReqResp;
|
||||
import com.tiesheng.message.service.TieshengMessageConfigurer;
|
||||
import com.tiesheng.util.ServletKit;
|
||||
import com.tiesheng.util.ip2region.DataBlock;
|
||||
import com.tiesheng.util.ip2region.Ip2Region;
|
||||
import com.tiesheng.util.config.Ip2regionConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -34,6 +35,8 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
CoreLogLoginMapper coreLogLoginMapper;
|
||||
@Autowired
|
||||
CoreLogMessageMapper coreLogMessageMapper;
|
||||
@Autowired
|
||||
Ip2regionConfig ip2regionConfig;
|
||||
|
||||
public CoreLogLoginMapper getLogLoginMapper() {
|
||||
return coreLogLoginMapper;
|
||||
@@ -52,10 +55,15 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
* 添加操作日志
|
||||
*/
|
||||
public void addOperationLog(String title, String subject, Object params) {
|
||||
TokenBean tokenBean = TsTokenConfig.getWithoutThr();
|
||||
if (tokenBean == null || StrUtil.isEmpty(tokenBean.getId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RequestUserInfo requestUserInfo = tieshengWebConfigurer.getCurrentUserName(tokenBean);
|
||||
CoreLogOperation operation = new CoreLogOperation();
|
||||
CurrentWebUser currentWebUser = tieshengWebConfigurer.getCurrentUserName(TsTokenConfig.get().getId());
|
||||
operation.setUserId(currentWebUser.getId());
|
||||
operation.setUserName(currentWebUser.getName());
|
||||
operation.setUserId(requestUserInfo.getId());
|
||||
operation.setUserName(requestUserInfo.getName());
|
||||
operation.setTitle(title);
|
||||
operation.setSubject(subject);
|
||||
if (params != null) {
|
||||
@@ -72,22 +80,22 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
|
||||
* 添加登录日志
|
||||
*
|
||||
* @param platformUnique
|
||||
* @param tokenBean
|
||||
*/
|
||||
public void addLoginLog(CorePlatformUnique platformUnique) {
|
||||
public void addLoginLog(CorePlatformUnique platformUnique, TokenBean tokenBean) {
|
||||
|
||||
HttpServletRequest request = ServletKit.getRequest();
|
||||
String ip = ServletUtil.getClientIP(request);
|
||||
|
||||
CoreLogLogin login = new CoreLogLogin();
|
||||
login.setUserId(platformUnique.getUserId());
|
||||
login.setUserId(tokenBean.getId());
|
||||
login.setPlatform(platformUnique.getPlatform());
|
||||
|
||||
CurrentWebUser currentWebUser = tieshengWebConfigurer.getCurrentUserName(platformUnique.getUserId());
|
||||
login.setUserName(currentWebUser.getName());
|
||||
RequestUserInfo requestUserInfo = tieshengWebConfigurer.getCurrentUserName(tokenBean);
|
||||
login.setUserName(requestUserInfo.getName());
|
||||
|
||||
login.setIp(ip);
|
||||
DataBlock dataBlock = Ip2Region.getInstance().btreeSearch(ip);
|
||||
login.setAddress(dataBlock.getRegion());
|
||||
login.setAddress(ip2regionConfig.search(login.getIp()));
|
||||
coreLogLoginMapper.insert(login);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.tiesheng.core.service;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.tiesheng.core.mapper.CorePlatformUniqueMapper;
|
||||
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
|
||||
import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
@@ -11,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author hao
|
||||
@@ -35,15 +33,12 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
|
||||
platformUnique.setUniqueId(loginInfo.getUnique());
|
||||
}
|
||||
platformUnique.setInfo(loginInfo.getInfo());
|
||||
saveOrUpdate(platformUnique);
|
||||
|
||||
TokenBean tokenBean = tieshengWebConfigurer.loginConfigurer().doLogin(platformUnique, loginInfo.getTo());
|
||||
if (tokenBean != null) {
|
||||
platformUnique.setUserId(tokenBean.getId());
|
||||
platformUnique.setIsDeleted(0);
|
||||
saveOrUpdate(platformUnique);
|
||||
|
||||
// 添加登录日志
|
||||
coreLogService.addLoginLog(platformUnique);
|
||||
coreLogService.addLoginLog(platformUnique, tokenBean);
|
||||
}
|
||||
return tokenBean;
|
||||
}
|
||||
@@ -55,22 +50,18 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
|
||||
|
||||
|
||||
/**
|
||||
* 通过平台和用户id查询
|
||||
* 更新用户id
|
||||
*
|
||||
* @param platform
|
||||
* @param userIds
|
||||
* @param uniqueId
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
private List<CorePlatformUnique> getByPlatformAndUser(String platform, List<String> userIds) {
|
||||
if (CollUtil.isEmpty(userIds)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
|
||||
QueryWrapper<CorePlatformUnique> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.in("user_id", userIds);
|
||||
queryWrapper.eq("platform", platform);
|
||||
queryWrapper.last("limit 1");
|
||||
return list(queryWrapper);
|
||||
public boolean updateUserId(String uniqueId, String userId) {
|
||||
return update(new UpdateWrapper<CorePlatformUnique>().eq("unique_id", uniqueId)
|
||||
.set("user_id", userId)
|
||||
.set("is_deleted", 0)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.tiesheng.core.service;
|
||||
|
||||
import cn.hutool.log.LogFactory;
|
||||
import com.tiesheng.core.pojos.CurrentWebUser;
|
||||
import com.tiesheng.core.pojos.RequestUserInfo;
|
||||
import com.tiesheng.core.pojos.dao.CorePlatformUnique;
|
||||
import com.tiesheng.login.config.token.bean.TokenBean;
|
||||
import com.tiesheng.util.exception.ApiRespEnum;
|
||||
@@ -22,7 +22,7 @@ public interface TieshengWebConfigurer {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
CurrentWebUser getCurrentUserName(String userId);
|
||||
RequestUserInfo getCurrentUserName(TokenBean userId);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
server:
|
||||
compression:
|
||||
enabled: true
|
||||
|
||||
## Spring配置
|
||||
spring:
|
||||
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 20MB
|
||||
web:
|
||||
resources:
|
||||
static-locations: classpath:/static/,file:static/
|
||||
mvc:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
|
||||
## 日志
|
||||
logging:
|
||||
file:
|
||||
name: logs/tiesheng.log
|
||||
Reference in New Issue
Block a user