commit 6db74a39ffab83f6373b7b4c3d665a60fe0b2ba6 Author: xueyinfei <1207092115@qq.com> Date: Wed Jul 30 09:13:10 2025 +0800 blood-analysis init diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..549e00a --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..d58dfb7 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..19529dd --- /dev/null +++ b/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..249bdf3 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2937e2f --- /dev/null +++ b/pom.xml @@ -0,0 +1,206 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.7.8 + + + com.guozhi + blood-analysis + 0.0.1 + blood-analysis + blood-analysis + + + + + + + + + + + + + + + 1.8 + + + + io.springfox + springfox-swagger2 + 2.9.2 + + + + io.springfox + springfox-swagger-ui + 2.9.2 + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + + + org.springframework.boot + spring-boot-starter-logging + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-slf4j-impl + + + 3.0.0 + + + com.github.pagehelper + pagehelper-spring-boot-starter + 2.1.0 + + + mysql + mysql-connector-java + 8.0.25 + + + com.alibaba + druid-spring-boot-starter + 1.1.20 + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter-aop + + + org.apache.httpcomponents + httpclient + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-slf4j-impl + + + + + jakarta.validation + jakarta.validation-api + + + org.projectlombok + lombok + true + + + io.nats + jnats + 2.6.5 + + + com.alibaba + fastjson + 2.0.21 + + + org.apache.commons + commons-lang3 + 3.12.0 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.jupiter + junit-jupiter + test + + + org.apache.logging.log4j + log4j-api + 2.17.0 + + + org.apache.logging.log4j + log4j-core + 2.17.0 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.17.0 + + + com.guozhi + sqlparser + 1.0 + + + org.apache.poi + poi + 4.1.2 + + + org.apache.poi + poi-ooxml + 4.1.2 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.guozhi.bloodanalysis.BloodAnalysisApplication + + + + org.projectlombok + lombok + + + + + + + + + diff --git a/src/main/java/com/guozhi/bloodanalysis/BloodAnalysisApplication.java b/src/main/java/com/guozhi/bloodanalysis/BloodAnalysisApplication.java new file mode 100644 index 0000000..f77893e --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/BloodAnalysisApplication.java @@ -0,0 +1,15 @@ +package com.guozhi.bloodanalysis; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableAsync +public class BloodAnalysisApplication { + + public static void main(String[] args) { + SpringApplication.run(BloodAnalysisApplication.class, args); + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/config/BusinessAspect.java b/src/main/java/com/guozhi/bloodanalysis/config/BusinessAspect.java new file mode 100644 index 0000000..99d0575 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/BusinessAspect.java @@ -0,0 +1,106 @@ +//package com.guozhi.bloodanalysis.config; +// +//import com.guozhi.bloodanalysis.utils.RedisUtils; +//import lombok.extern.slf4j.Slf4j; +//import org.aspectj.lang.JoinPoint; +//import org.aspectj.lang.ProceedingJoinPoint; +//import org.aspectj.lang.annotation.AfterReturning; +//import org.aspectj.lang.annotation.Around; +//import org.aspectj.lang.annotation.Aspect; +//import org.aspectj.lang.annotation.Pointcut; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.stereotype.Component; +// +//import javax.servlet.http.HttpServletRequest; +// +///** +// * 切面处理层:使用@Pointcut定义你针对某些函数(一般来说是接口函数)的切点 +// * 使用@Around处理你定义的切点对应的处理逻辑、实例中给出了两种处理逻辑 +// * signFeild:前后台的验签逻辑、为了保证调用者的合法性和数据一致性 +// * oauthFeild: 获取用户信息的逻辑、优先从网关的头部参数中获取,如果没有取到, +// * 应用将会请求oauth,用请求参数或头部参数中的refresh_token获取用户信息,同时进行接口权限的判断。 +// */ +//@Slf4j +//@Component +//@Aspect +//public class BusinessAspect { +// +// @Autowired +// HttpServletRequest request; +// +// @Autowired +// private RedisUtils redisUtils; +// +//// @Autowired +//// UserRoleMapper userRoleMapper; +//// +//// @Autowired +//// PermissionMapper permissionMapper; +//// +//// @Autowired +//// MenuFunctionMapper menuFunctionMapper; +// +// +//// @Pointcut("execution(* com.guozhi.bloodanalysis.controller.SystemController.*(..))") +//// public void ApiController() {} +// +// +//// @Pointcut("within(@org.springframework.web.bind.annotation.RestController *) &&"+ +//// "!ApiController()") +//// public void OauthAround() {} +// +//// @Around("OauthAround()") +//// public Object OauthAround(ProceedingJoinPoint point) throws Throwable { +//// log.info("--------ApiController PointCut Start--------"); +//// Object[] objects = point.getArgs(); +//// String token = request.getHeader("token"); +//// if (StringUtils.isEmpty(token)){ +//// throw new BusinessException("tokenError","登录信息已过期,请重新登录"); +//// } +//// User user = (User)redisUtils.get(token); +//// if (user == null || StringUtils.isEmpty(user.getUserName())){ +//// throw new BusinessException("tokenError","登录信息已过期,请重新登录"); +//// } +//// redisUtils.expire(token,1800); +//// if (!user.isAdmin()){ +//// //todo 权限验证 +//// List userRoleList = userRoleMapper.getUserRoleByUserName(user.getUserName()); +//// if (CollectionUtils.isEmpty(userRoleList)){ +//// throw new BusinessException("hasNoAuth","无此功能权限,联系管理员"); +//// } +//// List roleCodes = userRoleList.stream().map(UserRole::getRoleCode).collect(Collectors.toList()); +//// List permissions = permissionMapper.getFunctionPermissionByRoleCodeList(roleCodes); +//// if (CollectionUtils.isEmpty(permissions)){ +//// throw new BusinessException("hasNoAuth","无此功能权限,联系管理员"); +//// } +//// boolean hasPermission = false; +//// List functionList = permissions.stream().map(Permission::getPermissionCode).collect(Collectors.toList()); +//// List menuFunctionList = menuFunctionMapper.getMenuFunctionByCodeList(functionList); +//// if (CollectionUtils.isEmpty(menuFunctionList)){ +//// throw new BusinessException("hasNoAuth","无此功能权限,联系管理员"); +//// } +//// for (MenuFunction menuFunction : menuFunctionList) { +//// if (new AntPathRequestMatcher(menuFunction.getUrl()).matches(request)){ +//// hasPermission = true; +//// break; +//// } +//// } +//// if (hasPermission){ +//// return point.proceed(objects); +//// }else{ +//// throw new BusinessException("hasNoAuth","无此功能权限,联系管理员"); +//// } +//// } +//// return point.proceed(objects); +//// } +// +// @AfterReturning(returning = "rvt", pointcut = "within(@org.springframework.web.bind.annotation.RestController *)"+ +// " || " + +// "within(@org.springframework.stereotype.Controller *) " + +// "execution(* *(..))") +// public Object afterExec(JoinPoint joinPoint, Object rvt) { +//// log.info("--------AfterReturningResult:"+ JSON.toJSONString(rvt)); +// return rvt; +// } +// +//} diff --git a/src/main/java/com/guozhi/bloodanalysis/config/CorsConfig.java b/src/main/java/com/guozhi/bloodanalysis/config/CorsConfig.java new file mode 100644 index 0000000..847d6da --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/CorsConfig.java @@ -0,0 +1,36 @@ +package com.guozhi.bloodanalysis.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +@Configuration // 一定不要忽略此注解 +//public class CorsConfig implements WebMvcConfigurer { +public class CorsConfig{ + private CorsConfiguration buildConfig() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用 + corsConfiguration.addAllowedHeader("*"); // 2允许任何头 + corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等) + corsConfiguration.setAllowCredentials(false);// 允许跨域带上cookies + return corsConfiguration; + } + + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", buildConfig()); // 4 + return new CorsFilter(source); + } +// @Override +// public void addCorsMappings(CorsRegistry registry) { +// registry.addMapping("/**") // 所有接口 +// .allowCredentials(true) // 是否发送 Cookie +// .allowedOriginPatterns("*") // 支持域 +// .allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法 +// .allowedHeaders("*") +// .exposedHeaders("*"); +// } +} \ No newline at end of file diff --git a/src/main/java/com/guozhi/bloodanalysis/config/DataSourceConfig.java b/src/main/java/com/guozhi/bloodanalysis/config/DataSourceConfig.java new file mode 100644 index 0000000..bd167b6 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/DataSourceConfig.java @@ -0,0 +1,40 @@ +package com.guozhi.bloodanalysis.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.support.http.StatViewServlet; +import com.alibaba.druid.support.http.WebStatFilter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +@Configuration +public class DataSourceConfig { + @Bean + public ServletRegistrationBean druidServlet() {// 主要实现web监控的配置处理 + ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");//表示进行druid监控的配置处理操作 +// servletRegistrationBean.addInitParameter("allow", "127.0.0.1,129.168.1.11");//白名单 +// servletRegistrationBean.addInitParameter("deny", "129.168.1.12");//黑名单 + servletRegistrationBean.addInitParameter("loginUsername", "admin");//用户名 + servletRegistrationBean.addInitParameter("loginPassword", "123456");//密码 + servletRegistrationBean.addInitParameter("resetEnable", "false");//是否可以重置数据源 + return servletRegistrationBean; + + } + @Bean //监控 + public FilterRegistrationBean filterRegistrationBean(){ + FilterRegistrationBean filterRegistrationBean=new FilterRegistrationBean(); + filterRegistrationBean.setFilter(new WebStatFilter()); + filterRegistrationBean.addUrlPatterns("/*");//所有请求进行监控处理 + filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");//排除 + return filterRegistrationBean; + } + @Bean + @ConfigurationProperties(prefix = "spring.datasource.druid") + public DataSource druidDataSource() { + return new DruidDataSource(); + } +} \ No newline at end of file diff --git a/src/main/java/com/guozhi/bloodanalysis/config/ExecutorConfig.java b/src/main/java/com/guozhi/bloodanalysis/config/ExecutorConfig.java new file mode 100644 index 0000000..9aefd19 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/ExecutorConfig.java @@ -0,0 +1,40 @@ +package com.guozhi.bloodanalysis.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +@Configuration +public class ExecutorConfig implements AsyncConfigurer { + + // ThredPoolTaskExcutor的处理流程 + // 当池子大小小于corePoolSize,就新建线程,并处理请求 + // 当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去workQueue中取任务并处理 + // 当workQueue放不下任务时,就新建线程入池,并处理请求, + // 如果池子大小撑到了maximumPoolSize,就用RejectedExecutionHandler来做拒绝处理 + // 当池子的线程数大于corePoolSize时,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁 + //getAsyncExecutor:自定义线程池,若不重写会使用默认的线程池。 + @Override + @Bean + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); + //设置核心线程数 + threadPool.setCorePoolSize(5); + //设置最大线程数 + threadPool.setMaxPoolSize(10); + //线程池所使用的缓冲队列 + threadPool.setQueueCapacity(10); + //等待任务在关机时完成--表明等待所有线程执行完 + threadPool.setWaitForTasksToCompleteOnShutdown(true); + // 等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止 + threadPool.setAwaitTerminationSeconds(60); + // 线程名称前缀 + threadPool.setThreadNamePrefix("ThreadPoolTaskExecutor-"); + // 初始化线程 + threadPool.initialize(); + return threadPool; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/config/GlobalRestExceptionHandler.java b/src/main/java/com/guozhi/bloodanalysis/config/GlobalRestExceptionHandler.java new file mode 100644 index 0000000..711e739 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/GlobalRestExceptionHandler.java @@ -0,0 +1,33 @@ +package com.guozhi.bloodanalysis.config; + +import com.guozhi.bloodanalysis.exception.BusinessException; +import com.guozhi.bloodanalysis.utils.ApiResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 全局的异常处理类 + */ +@ControllerAdvice(annotations = {RestController.class , Controller.class}) +@ResponseBody +@Slf4j +public class GlobalRestExceptionHandler { + + @ExceptionHandler(value = com.guozhi.bloodanalysis.exception.BusinessException.class) + public ApiResult easiBaseSysExceptionHandler(Exception e) { + log.error(((BusinessException) e).getCode(),e.getMessage()); + ApiResult result = ApiResult.error( 999 , e.getMessage()); + return result; + } + + @ExceptionHandler(value = Exception.class) + public ApiResult exceptionHandler(Exception e) { + e.printStackTrace(); + ApiResult result = ApiResult.error(999, e.getMessage()); + return result; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/config/MasterDataSourceConfig.java b/src/main/java/com/guozhi/bloodanalysis/config/MasterDataSourceConfig.java new file mode 100644 index 0000000..6427372 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/MasterDataSourceConfig.java @@ -0,0 +1,159 @@ +package com.guozhi.bloodanalysis.config; + +import com.alibaba.druid.pool.DruidDataSource; +import com.github.pagehelper.PageInterceptor; +import org.apache.ibatis.plugin.Interceptor; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; + +import javax.sql.DataSource; +import java.sql.SQLException; +import java.util.Properties; + +@Configuration +@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory") +public class MasterDataSourceConfig { + /** + * 配置多数据源 关键就在这里 这里配置了不同的mapper对应不同的数据源 + */ + static final String PACKAGE = "com.guozhi.bloodanalysis.mapper"; + static final String MAPPER_LOCATION = "classpath:mapper/*.xml"; + + /** + * 连接数据库信息 这个其实更好的是用配置中心完成 + */ + @Value("${master.datasource.url}") + private String url; + + @Value("${master.datasource.username}") + private String username; + + @Value("${master.datasource.password}") + private String password; + + @Value("${master.datasource.driverClassName}") + private String driverClassName; + + + /** + * 下面的配置信息可以读取配置文件,其实可以直接写死 如果是多数据源的话 还是考虑读取配置文件 + */ + @Value("${spring.datasource.initialSize}") + private int initialSize; + + @Value("${spring.datasource.minIdle}") + private int minIdle; + + @Value("${spring.datasource.maxActive}") + private int maxActive; + + @Value("${spring.datasource.maxWait}") + private int maxWait; + + @Value("${spring.datasource.timeBetweenEvictionRunsMillis}") + private int timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.minEvictableIdleTimeMillis}") + private int minEvictableIdleTimeMillis; + + @Value("${spring.datasource.validationQuery}") + private String validationQuery; + + @Value("${spring.datasource.testWhileIdle}") + private boolean testWhileIdle; + + @Value("${spring.datasource.testOnBorrow}") + private boolean testOnBorrow; + + @Value("${spring.datasource.testOnReturn}") + private boolean testOnReturn; + + @Value("${spring.datasource.poolPreparedStatements}") + private boolean poolPreparedStatements; + + @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}") + private int maxPoolPreparedStatementPerConnectionSize; + + @Value("${spring.datasource.filters}") + private String filters; + + @Value("{spring.datasource.connectionProperties}") + private String connectionProperties; + + + @Bean(name = "masterDataSource") + @Primary //标志这个 Bean 如果在多个同类 Bean 候选时,该 Bean 优先被考虑。 + public DataSource masterDataSource() { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setUrl(url); + dataSource.setUsername(username); + dataSource.setPassword(password); + dataSource.setDriverClassName(driverClassName); + + //具体配置 + dataSource.setInitialSize(initialSize); + dataSource.setMinIdle(minIdle); + dataSource.setMaxActive(maxActive); + dataSource.setMaxWait(maxWait); + dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + dataSource.setValidationQuery(validationQuery); + dataSource.setTestWhileIdle(testWhileIdle); + dataSource.setTestOnBorrow(testOnBorrow); + dataSource.setTestOnReturn(testOnReturn); + dataSource.setPoolPreparedStatements(poolPreparedStatements); + dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize); + + /** + * 这个是用来配置 druid 监控sql语句的 非常有用 如果你有两个数据源 这个配置哪个数据源就坚实哪个数据源的sql 同时配置那就都监控 + */ + try { + dataSource.setFilters(filters); + } catch (SQLException e) { + e.printStackTrace(); + } + dataSource.setConnectionProperties(connectionProperties); + return dataSource; + } + + @Bean(name = "masterTransactionManager") + @Primary + public DataSourceTransactionManager masterTransactionManager() { + return new DataSourceTransactionManager(masterDataSource()); + } + + @Bean(name = "masterSqlSessionFactory") + @Primary + public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource) + throws Exception { + final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); + sessionFactory.setDataSource(masterDataSource); + sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MasterDataSourceConfig.MAPPER_LOCATION)); + + //分页插件 + Interceptor interceptor = new PageInterceptor(); + Properties properties = new Properties(); + //数据库 + properties.setProperty("helperDialect", "mysql"); +// properties.setProperty("dialect", "mysql"); + //是否将参数offset作为PageNum使用 + properties.setProperty("offsetAsPageNum", "true"); + //是否进行count查询 + properties.setProperty("rowBoundsWithCount", "true"); + //是否分页合理化 + properties.setProperty("reasonable", "false"); + interceptor.setProperties(properties); + sessionFactory.setPlugins(new Interceptor[] {interceptor}); + + + return sessionFactory.getObject(); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/config/SwaggerConfig.java b/src/main/java/com/guozhi/bloodanalysis/config/SwaggerConfig.java new file mode 100644 index 0000000..a52b762 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/config/SwaggerConfig.java @@ -0,0 +1,43 @@ +package com.guozhi.bloodanalysis.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.Contact; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2// 开启Swagger2的自动配置 +public class SwaggerConfig extends WebMvcConfigurationSupport { + /** + * 解决高版本springboot无法访问http://localhost:8001/swagger-ui.html + * @param registry void + */ + @Override + protected void addResourceHandlers(ResourceHandlerRegistry registry) { + // 解决静态资源无法访问 + registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); + // 解决swagger无法访问 + registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); + // 解决swagger的js文件无法访问 + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + //配置文档信息 + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("接口文档") // 标题 + .description("各个controller以及接口,参数等展示页") //描述 + .version("v1.0") // 版本 + .contact(new Contact("薛寅飞", "http://192.168.8.138:8082/dispatch/swagger-ui.html", "qc_xueyinfei@xcmg.com")) + .build(); + } + @Bean + public Docket docket() { + return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/controller/BloodAnalysisController.java b/src/main/java/com/guozhi/bloodanalysis/controller/BloodAnalysisController.java new file mode 100644 index 0000000..c82bd09 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/controller/BloodAnalysisController.java @@ -0,0 +1,36 @@ +package com.guozhi.bloodanalysis.controller; + +import com.guozhi.bloodanalysis.parser.SqlParser; +import com.guozhi.bloodanalysis.service.BloodAnalysisService; +import com.guozhi.bloodanalysis.utils.ApiResult; +import com.guozhi.bloodanalysis.utils.RedisUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.io.FileNotFoundException; + +@RestController +public class BloodAnalysisController { + + @Autowired + BloodAnalysisService bloodAnalysisService; + + @Autowired + RedisUtils redisUtils; + + @PostMapping("/bloodAnalysis") + public ApiResult BloodAnalysis(HttpServletRequest request) { + String dashUserName = request.getHeader("dashUserName"); + String dashPassword = request.getHeader("dashPassword"); + Boolean startBloodAnalysis = (Boolean)redisUtils.get("startBloodAnalysis"); + if (startBloodAnalysis != null && startBloodAnalysis){ + return ApiResult.success("正在执行血缘解析任务,无需重复执行"); + }else { + bloodAnalysisService.analysis(dashUserName,dashPassword); + return ApiResult.success("启动任务成功,请稍后查看"); + } + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/entity/DataLineageInfo.java b/src/main/java/com/guozhi/bloodanalysis/entity/DataLineageInfo.java new file mode 100644 index 0000000..cd6be7d --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/entity/DataLineageInfo.java @@ -0,0 +1,17 @@ +package com.guozhi.bloodanalysis.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DataLineageInfo { + private Integer onum; + private String ssysCd; + private String mdlName; + private String procName; + private String procLine; + private String procText; +} diff --git a/src/main/java/com/guozhi/bloodanalysis/entity/MetaBloodAnalysis.java b/src/main/java/com/guozhi/bloodanalysis/entity/MetaBloodAnalysis.java new file mode 100644 index 0000000..43f4325 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/entity/MetaBloodAnalysis.java @@ -0,0 +1,28 @@ +package com.guozhi.bloodanalysis.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MetaBloodAnalysis { + private String id; + private Integer proId; + private String proName; + private String targetSysCd; + private String targetMdlName; + private String targetTableName; + private String targetTableCnName; + private String targetColName; + private String targetColCnName; + private String targetColType; + private String sourceSysCd; + private String sourceMdlName; + private String sourceTableName; + private String sourceTableCnName; + private String sourceColName; + private String sourceColCnName; + private String sourceColType; +} diff --git a/src/main/java/com/guozhi/bloodanalysis/entity/MetaColumn.java b/src/main/java/com/guozhi/bloodanalysis/entity/MetaColumn.java new file mode 100644 index 0000000..461ca1f --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/entity/MetaColumn.java @@ -0,0 +1,18 @@ +package com.guozhi.bloodanalysis.entity; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MetaColumn { + private int onum; + private String ssysCd; + private String mdlName; + private String tableEngName; + private String tableCnName; + private String fldEngName; + private String fldCnName; +} diff --git a/src/main/java/com/guozhi/bloodanalysis/exception/BusinessException.java b/src/main/java/com/guozhi/bloodanalysis/exception/BusinessException.java new file mode 100644 index 0000000..e391d03 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/exception/BusinessException.java @@ -0,0 +1,19 @@ +package com.guozhi.bloodanalysis.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = false) +@Data +public class BusinessException extends RuntimeException{ + private String code; + private String message; + public BusinessException(String message) { + super(message); + } + public BusinessException(String code, String message) { + super(message); + this.code = code; + this.message = message; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/mapper/DataLineageInfoMapper.java b/src/main/java/com/guozhi/bloodanalysis/mapper/DataLineageInfoMapper.java new file mode 100644 index 0000000..05da399 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/mapper/DataLineageInfoMapper.java @@ -0,0 +1,11 @@ +package com.guozhi.bloodanalysis.mapper; + +import com.guozhi.bloodanalysis.entity.DataLineageInfo; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface DataLineageInfoMapper { + List search(); +} diff --git a/src/main/java/com/guozhi/bloodanalysis/mapper/MetaBloodAnalysisMapper.java b/src/main/java/com/guozhi/bloodanalysis/mapper/MetaBloodAnalysisMapper.java new file mode 100644 index 0000000..3c74e92 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/mapper/MetaBloodAnalysisMapper.java @@ -0,0 +1,25 @@ +package com.guozhi.bloodanalysis.mapper; + +import com.guozhi.bloodanalysis.entity.MetaBloodAnalysis; +import com.guozhi.bloodanalysis.entity.MetaColumn; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +@Mapper +public interface MetaBloodAnalysisMapper { + + void insert(@Param("blood") MetaBloodAnalysis metaBloodAnalysis); + + MetaColumn isColExis(@Param("db") String db, @Param("schema") String schema, @Param("tableCode") String tableCode, @Param("columnName") String columnName); + + List> getColumnsByTabId(@Param("tableId") String tabId,@Param("colCode") String colCode); + + List> getSystem(@Param("schema") String schema, @Param("tableCode") String tableCode); + + List> getColumnsByTable(@Param("tableName") String tableName, @Param("ssysCd") String defaultDb, @Param("mdlName") String defaultSchema); + + void deleteAllBloodData(); +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/SqlParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/SqlParser.java new file mode 100644 index 0000000..b6ba48e --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/SqlParser.java @@ -0,0 +1,302 @@ +package com.guozhi.bloodanalysis.parser; + +import com.guozhi.bloodanalysis.entity.DataLineageInfo; +import com.guozhi.bloodanalysis.exception.BusinessException; +import com.guozhi.bloodanalysis.parser.clean.GenericLogNormalizer; +import com.guozhi.bloodanalysis.parser.common.*; +import com.guozhi.bloodanalysis.parser.utils.ExportParseResultUtil; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import gudusoft.gsqlparser.EDbVendor; +import gudusoft.gsqlparser.TCustomSqlStatement; +import gudusoft.gsqlparser.TGSqlParser; +import gudusoft.gsqlparser.TStatementList; +import gudusoft.gsqlparser.stmt.TAlterTableStatement; +import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement; +import gudusoft.gsqlparser.stmt.TDeleteSqlStatement; +import gudusoft.gsqlparser.stmt.TInsertSqlStatement; +import gudusoft.gsqlparser.stmt.TSelectSqlStatement; +import gudusoft.gsqlparser.stmt.TUpdateSqlStatement; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.guozhi.bloodanalysis.parser.utils.DatabaseType.Oracle; + + +@Slf4j +@Component +@Data +@NoArgsConstructor +@Scope("prototype") +public class SqlParser { + //解析器对象 + private TGSqlParser sqlParser = null; + //sql解析器上下文 + private ParserContext parserContext = new ParserContext(); + + @Autowired + ExportParseResultUtil exportParseResultUtil; + + @Autowired + ApplicationContext applicationContext; + + public void parse(DataLineageInfo dataLineageInfo, List> databaseList) throws Exception { + String sqlText = ""; + try { + List targetSqlList = new ArrayList<>(); + String dbType = "MYSQL"; + if (databaseList !=null && databaseList.size()>0){ + for (Map map : databaseList) { + String type = map.get(dataLineageInfo.getSsysCd()); + if (type != null) { + dbType = type; + } + } + } + String sql = new GenericLogNormalizer().normalizer(dataLineageInfo.getProcText(),dbType); + sql = optDeclare(sql,dataLineageInfo.getProcName()); + sql = optDeclare2(sql); + if(sql.trim().equals("")){ + throw new BusinessException("errorSQLparse:"+dataLineageInfo.getProcName()); + } + targetSqlList.add(sql); + String defaultSchema = dataLineageInfo.getMdlName(); + String defaultSystem = dataLineageInfo.getSsysCd(); + this.parserContext.setDefaultDb(defaultSystem); + this.parserContext.setDefaultSchema(defaultSchema); + int length = targetSqlList.size(); + for (String s : targetSqlList) { + sqlText = s; + if ("ORACLE".equals(dbType)) { + if (Objects.equals(dbType, Oracle.toString())) { + if (sqlText != null) { + sqlText = sqlText.toUpperCase(); + } + } + sqlParser = new TGSqlParser(EDbVendor.dbvoracle); + } + if ("MYSQL".equals(dbType)) { + sqlParser = new TGSqlParser(EDbVendor.dbvmysql); + } + if ("SQLSERVER".equals(dbType)) { + sqlParser = new TGSqlParser(EDbVendor.dbvmssql); + } + if ("TERADATA".equals(dbType)) { + sqlParser = new TGSqlParser(EDbVendor.dbvteradata); + } + if ("POSTGRESQL".equals(dbType)) { + sqlParser = new TGSqlParser(EDbVendor.dbvpostgresql); + } + if ("DB2".equals(dbType)) { + sqlParser = new TGSqlParser(EDbVendor.dbvdb2); + } + sqlParser.sqltext = sqlText; + int ret = sqlParser.parse(); + List result = new ArrayList<>(); + if (ret == 0) { + TStatementList statementList = sqlParser.getSqlstatements(); + while (statementList.hasNext()) { + TCustomSqlStatement stmt = statementList.next(); + parserContext.getTableInCurrentStatement().clear(); + switch (stmt.sqlstatementtype) { + case sstselect: + result = parseSelect(stmt); + break; + case sstdelete: + result = parseDelete(stmt); + break; + case sstupdate: + result = parseUpdate(stmt); + break; + case sstinsert: + result = parseInsert(stmt); + break; + case sstcreatetable: + result = parseCreateTable(stmt); + break; + case sstcreateview: + break; + case sstoraclealtertablespace: + // parseAlterTable(stmt); + break; + case sstdroptable: + // parseDropTable(stmt); + break; + case sstmerge: + log.error("sstmerge[" + + stmt.sqlstatementtype + + "][unknow sql type]sqltext:" + ); + default: + log.error("[" + stmt.sqlstatementtype + + "][unknow sql type]sqltext:" + ); + break; + } + } + } else { + log.error(sqlParser.sqltext + sqlParser.getErrormessage()); + } + if (result.size() > 0) { + exportParseResultUtil.expResult(result, dataLineageInfo); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private String optDeclare(String sql,String procName) { + String returnSql=sql; + if(StringUtils.isNotEmpty(sql)){ + //储存过程名称 + String[] sqls = sql.split(";"); + for(String sql2:sqls){ + sql2 = sql2.trim(); + //去掉set和 truncate和delete语句 还有引用其他存储过程的语句 + if(sql2.startsWith("SET")||sql2.startsWith("TRUNCATE")||sql2.startsWith("DELETE")||sql2.startsWith("PERFORM")){ + sql = sql.replace(sql2+";", ""); + } + +// String dd = sql2.replaceAll(" ", ""); +// int startIndex = dd.toUpperCase().lastIndexOf("PROCEDURE"); +// if(startIndex >= 0){ +// startIndex += "PROCEDURE".length(); +// int endIndex = dd.indexOf("("); +// if(endIndex >= 0){ +// procName = dd.substring(startIndex, endIndex); +// } +// } + /* + Pattern pat = Pattern.compile("(DECLARE)(\\s*)"); + Matcher mat = pat.matcher(sql2); + if (mat.find()) { + sql2 = mat.replaceAll(""); + String sub = sql2.substring(0,sql2.indexOf(" ")).trim(); + if(sql.contains(sub)){ + sql = sql.replaceAll(sub, "'88888888'"); + } + }*/ + } + Pattern pat = Pattern.compile("(DECLARE)(\\s).*"); + Matcher mat = pat.matcher(sql); + while (mat.find()) { + sql = mat.replaceAll(""); + } + + //找出脚本结束的位置 + Pattern lastPattern = Pattern.compile("(END)(\\s)+"+("".equals(procName)?";":procName)); + Matcher lastMatcher = lastPattern.matcher(sql); + if(lastMatcher.find()){ + int lastIndex = lastMatcher.start(); + if(sql.contains("BEGIN")){ + returnSql = sql.substring(sql.indexOf("BEGIN")+5, lastIndex); + }else{ + returnSql = sql.substring(0, lastIndex); + } + }else{ + Pattern tempPattern = Pattern.compile("(END)(\\s)*;"); + Matcher tempMatcher = tempPattern.matcher(sql); + Pattern tempPatternBegin = Pattern.compile("(\\s)(BEGIN)(\\s)"); + Matcher tempMatcherBegin = tempPatternBegin.matcher(sql); + + if(tempMatcher.find()){ + int tempIndex = tempMatcher.start(); + int tempIndexBegin = 0; + if(tempMatcherBegin.find()){ + tempIndexBegin = tempMatcherBegin.start(); + } + returnSql = sql.substring(tempIndexBegin+6, tempIndex); + } + } + + } + return returnSql; + } + + private String optDeclare2(String sql) { + StringBuilder returnVal = new StringBuilder(); + if(StringUtils.isNotEmpty(sql)){ + + String[] sqls = sql.split(";"); + for(String sql2:sqls){ + sql2 = sql2.trim(); + //去掉set和 truncate和delete语句 还有引用其他存储过程的语句 + if(sql2.toUpperCase().trim().startsWith("INSERT")){ + returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("INSERT"))).append(";\r\n"); + + }else if(sql2.toUpperCase().trim().startsWith("UPDATE")){ + returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("UPDATE"))).append(";\r\n"); + + }else if(sql2.toUpperCase().trim().startsWith("MERGE")){ + //TODO wxl merge语句的解析暂时不支持,导致报错 +// returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("MERGE"))+";\r\n"); + + }else if(sql2.toUpperCase().trim().startsWith("CREATE")){ + returnVal.append(sql2.substring(sql2.toUpperCase().indexOf("CREATE"))).append(";\r\n"); + + } + } + } + return returnVal.toString(); + } + + + private List parseAlterTable(TCustomSqlStatement stmt) { + TAlterTableStatement alterTableStatement=(TAlterTableStatement)stmt; + AlterParser parser=new AlterParser(alterTableStatement,parserContext); + parser.parse(); + return parser.getParseResult(); + } + + private List parseUpdate(TCustomSqlStatement stmt) { + TUpdateSqlStatement dStmt=(TUpdateSqlStatement)stmt; + UpdateParser parser=new UpdateParser(dStmt,parserContext); + parser.parse(); + return parser.getParseResult(); + } + + private List parseDelete(TCustomSqlStatement stmt) { + TDeleteSqlStatement dStmt=(TDeleteSqlStatement)stmt; + DeleteParser parser=new DeleteParser(dStmt,parserContext); + parser.parse(); + return parser.getParseResult(); + } + + private List parseInsert(TCustomSqlStatement stmt) { + InsertParser parser = applicationContext.getBean(InsertParser.class); + parser.setMInsertSql((TInsertSqlStatement)stmt); + parser.setMParserContext(this.parserContext); + parser.parse(); + return parser.getParseResult(); + } + +// private void parseDropTable(TCustomSqlStatement stmt) { +// DropParser dp=new DropParser(stmt,parserContext); +// dp.parse(); +// } + + public List parseCreateTable(TCustomSqlStatement stmt) { + TCreateTableSqlStatement ctSql=(TCreateTableSqlStatement)stmt; + CreateParser parser=new CreateParser(ctSql,parserContext); + parser.parse(); + return parser.getParseResult(); + } + + public List parseSelect(TCustomSqlStatement stmt) { + TSelectSqlStatement selectSqlStatement = (TSelectSqlStatement) stmt; + SelectParser parser=new SelectParser(selectSqlStatement,parserContext); + parser.parse(); + return parser.getParseResult(); + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizer.java b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizer.java new file mode 100644 index 0000000..f474a54 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizer.java @@ -0,0 +1,145 @@ +package com.guozhi.bloodanalysis.parser.clean; + +import lombok.extern.slf4j.Slf4j; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Slf4j +public class GenericLogNormalizer{ + + public String normalizer(String logstr,String dbType) { + String retVal=logstr.toUpperCase(); + if(retVal.length()>0){//说明存在有效内容 +// retVal = this.replaceYinhao(retVal); + retVal = this.replaceFenhao(retVal); + retVal = this.replaceUnuseful(retVal); + retVal = this.dropUnuseful(retVal); + retVal = this.dropTableFix(retVal); + //替换出现在非查询结束状态中的升降序关键字ROW_NUMBER()OVER(PARTITION BY WORKDATE,AGENTSERIALNO DESC) AS NUM; + retVal = this.replaceASC(retVal); + retVal = this.changeAlter(retVal); + if("GreenPlum".equals(dbType)){ + //GP类数据库清洗器 + retVal = new GenericLogNormalizerGP(retVal).parser(); + }else if("Oracle".equals(dbType)){ + //oracle类数据库清洗器 + retVal = new GenericLogNormalizerOra(retVal).parser(); + }else if("Teradata".equals(dbType)){ + //teradata类数据库清洗器 + retVal = new GenericLogNormalizerTrd(retVal).parser(); + }else if("DB2".equals(dbType)){ + //DB2类数据库清洗器 + //TODO 未实现 + retVal = new GenericLogNormalizerGP(retVal).parser(); + } + } + return retVal.trim(); + } + + private String replaceUnuseful(String retVal) { + + Pattern pat = Pattern.compile("--'\\s*\\|\\|"); + Matcher mat = pat.matcher(retVal); + while (mat.find()) { + String s = mat.group(); + String _s = s.replaceAll("--", ""); + retVal = retVal.replace(s, _s); + } + + pat = Pattern.compile("FORMAT\\s*'--.*?'"); + mat = pat.matcher(retVal); + while (mat.find()) { + String s = mat.group(); + String _s = s.replaceAll("--", ""); + retVal = retVal.replace(s, _s); + } + return retVal; + } + + private String replaceFenhao(String str) { + Pattern pat = Pattern.compile("'(\\s|\\d|;|\\||%)*(;)+(\\s|\\d|;|\\||%)*'"); + Matcher mat = pat.matcher(str); + while (mat.find()) { + str = mat.replaceAll("\\'fenhao\\'"); + } + return str ; + } + + private String dropUnuseful(String retVal) { + Pattern p = Pattern.compile("(?ms)(--.*?$)|(/\\*.*?\\*/)"); + retVal = p.matcher(retVal).replaceAll(""); //去掉/*...*/的多行注释,和以 -- 开始的单行注释 + log.info("去除/*...*/和以 -- 开始的单行注释,取出BEGIN,END等多余字符 , 成功"); + return retVal; + } + + private String dropTableFix(String str) { + Pattern pat = Pattern.compile("(((_1_PRT_P)|(_1_PRT_SDB))_PARTITION_(\\$)(\\w)*(\\s))"); + Matcher mat = pat.matcher(str); + while (mat.find()) { + str = mat.replaceAll(" "); + } + pat = Pattern.compile("(((_1_PRT_P)|(_1_PRT_SDB))_PARTITION_(\\$\\{)(\\s)*(\\w)*(\\s)*(\\})(\\s))"); + mat = pat.matcher(str); + while (mat.find()) { + str = mat.replaceAll(" "); + } + pat = Pattern.compile("(((_1_PRT_P)|(_1_PRT_SDB))_PARTITION_(\\d)+(\\s))"); + mat = pat.matcher(str); + while (mat.find()) { + str = mat.replaceAll(" "); + } + + return str; + } + + private String replaceASC(String str) { + Pattern pat = Pattern.compile("(\\bASC\\b)|(\\bDESC\\b)"); + Matcher mat = pat.matcher(str); + while (mat.find()) { + str = mat.replaceAll(""); + } + return str; + } + + private String changeAlter(String str){ + //String str_change =str; + Pattern pat = Pattern.compile("(?ms)(ALTER)(\\s)+(TABLE)(\\s)+(\\w)+(\\.)*(\\w)*(\\s)*" + + "(EXCHANGE)(\\s)*(PARTITION)(\\s)+(\\w)+(\\s)+(WITH)(\\s)+" + + "(TABLE)(\\s)+(\\w)+(\\.)*(\\w)*(\\s)*;"); + Matcher mat = pat.matcher(str); + String dest_table =""; + String source_table =""; + while(mat.find()){ + String sen = mat.group(); + dest_table = sen.substring(sen.indexOf("ALTER")+"ALTER".length(),sen.indexOf("EXCHANGE")).trim(); + dest_table = dest_table.substring("table".length()).trim(); + source_table = sen.substring(sen.indexOf("WITH")+"WITH".length(),sen.indexOf(";")).trim(); + source_table = source_table.substring("table".length()).trim(); + str=str.replace(sen,"ALTER TABLE "+source_table+" RENAME TO "+ dest_table+" ;"); + } + return str; + } + + public static void main(String[] args) { + //------------------------------------------------TRIM(COALESCE(t2.brch_no),'') +// String sql = "COALESCE(TRIM(A.COD_ACCT_NO_BENEF)||TRIM(CAST(A.CTR_SWP_INST_NO AS INTEGER)),'')"; + String sql = "TRIM(COALESCE(t2.brch_no),'')"; + Pattern p = Pattern.compile("(\\s*)(TRIM)(\\s*)\\((\\w+)\\(((\\w|\\.)+)\\)(\\s*)(,(\\s*)'')(\\s*)\\)"); +// sql = p.matcher(sql).replaceAll(" "); +// System.out.println(sql.trim()); + Matcher mat = p.matcher(sql); + while(mat.find()){ + System.out.println(mat.group()); + System.out.println("1="+mat.group(1)); + System.out.println("2="+mat.group(2)); + System.out.println("3="+mat.group(3)); + System.out.println("4="+mat.group(4)); + System.out.println("5="+mat.group(5)); + System.out.println("6="+mat.group(6)); + System.out.println("7="+mat.group(7)); + System.out.println("8="+mat.group(8)); + System.out.println("9="+mat.group(9)); + } + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerGP.java b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerGP.java new file mode 100644 index 0000000..8902a75 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerGP.java @@ -0,0 +1,95 @@ +package com.guozhi.bloodanalysis.parser.clean; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GenericLogNormalizerGP { + private String retVal; + + public GenericLogNormalizerGP (String retVal){ + this.retVal = retVal; + } + + public String parser(){ + dropgangt(); + dropInvSql(); + replaceSpecial(); + setSpecialFun();//替换 DATE ''; + return retVal; + } + + + private void dropInvSql(){ + /** + * 去除DISTRIBUTED 原来: (GROUP|DISTRIBUTED)(\\s)+(BY)*(.*?)\\) + */ + Pattern pat = Pattern.compile("(?ms)(GROUP|DISTRIBUTED)(\\s)+(BY)(\\s)*\\((.*?)\\)"); + retVal = pat.matcher(retVal.toUpperCase()).replaceAll(""); + pat = Pattern.compile("\\bROW\\b"); + Matcher mat = pat.matcher(retVal); + while (mat.find()) { + retVal = mat.replaceAll("ROW_SYMBOLYANG1111"); + } + } + + private void dropgangt() { + Pattern pat = Pattern.compile("(?ms)\\\\\\\\[a-zA-Z]+([a-zA-Z]|\\s|\\\\\\\\)*?$"); + Matcher mat = pat.matcher(retVal); + while(mat.find()){ + retVal = mat.replaceAll("\n"); + } + } + + + private void replaceSpecial() { + /** + * 将剩下的 ${}替换掉 + */ + Pattern pat = Pattern.compile("\\$\\{[\\w]*\\}"); + + Matcher mat = pat.matcher(retVal); + + while(mat.find()){ + retVal = retVal.replace(mat.group(),"defaultMODEL_"+mat.group().substring(2,mat.group().length() - 1 )); + } + /** + * 将剩下的 $替换掉 + */ + retVal = retVal.replace("$", "defaultMODEL_"); + /** + * 去除%等特殊符号 + */ + retVal=retVal.replace("%", "/"); + retVal=retVal.replace("?", " "); + } + + private void setSpecialFun(){ + //(date(... --- (date( ... + retVal = retVal.replaceAll("(\\()(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*\\(", "(datetime("); + //(date'...' ---(date '...' + retVal = retVal.replaceAll("(\\()(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*'", "(datetime'"); + /** + * 运算符号要包括 + */ + //,date(... --- ,(date (... + retVal = retVal.replaceAll(",(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*\\(", ",datetime("); + //,date'... --- ,date '... + retVal = retVal.replaceAll(",(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*'", ",datetime'"); + + retVal = retVal.replaceAll("=(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*\\(", "=datetime("); + retVal = retVal.replaceAll("=(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*'", "=datetime'"); + + retVal = retVal.replaceAll("-(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*\\(", "-datetime("); + retVal = retVal.replaceAll("-(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*'", "-datetime'"); + + retVal = retVal.replaceAll("(>|<|>=|<=)(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*\\(", ">datetime("); + retVal = retVal.replaceAll("(>|<|>=|<=)(\\s)*(d|D)(a|A)(t|T)(e|E)(\\s)*'", ">datetime'"); + + // date ... --- + //retVal = retVal.replaceAll("(\\s)+(d|D)(a|A)(t|T)(e|E)(\\s)+", " datetime "); + // date'... --- date '... + retVal = retVal.replaceAll("(\\s)+(d|D)(a|A)(t|T)(e|E)(\\s)*'", " datetime'"); + // date(... --- date (... + retVal = retVal.replaceAll("(\\s)+(d|D)(a|A)(t|T)(e|E)(\\s)*\\(", " datetime("); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerOra.java b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerOra.java new file mode 100644 index 0000000..a5b8953 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerOra.java @@ -0,0 +1,74 @@ +package com.guozhi.bloodanalysis.parser.clean; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GenericLogNormalizerOra { + private String retVal; + + public GenericLogNormalizerOra (String retVal){ + this.retVal = retVal; + } + + public String parser(){ + dropInvSql(); + replaceSpecial(); + return retVal; + } + + private void replaceSpecial() { + /** + * 将剩下的 ${}替换掉 + */ + Pattern pat = Pattern.compile("\\$\\{[\\w]*\\}"); + + Matcher mat = pat.matcher(retVal); + + while(mat.find()){ + retVal = retVal.replace(mat.group(),"defaultMODEL_"+mat.group().substring(2,mat.group().length() - 1 )); + } + /** + * 将剩下的 $替换掉 + */ + retVal=retVal.replace("$", "defaultMODEL_"); + /** + * 去除%等特殊符号 + */ + retVal=retVal.replace("%", "/"); + } + + + private void dropInvSql(){ + /* + Pattern p = Pattern.compile("((\\s)+(SET).*(\\s)+)"); + retVal = p.matcher(retVal).replaceAll(""); + */ + /** + * 去除DISTRIBUTED + */ + Pattern p = Pattern.compile("(?ms)(GROUP|DISTRIBUTED)(\\s)+(BY)(\\s)*\\((.*?)\\)"); + retVal = p.matcher(retVal.toUpperCase()).replaceAll(""); + + p = Pattern.compile("((WHENEVER(\\s*)SQLERROR)(\\s)*.*)"); + retVal = p.matcher(retVal).replaceAll(""); + + p = Pattern.compile("((SPOOL)(\\s)*.*)"); + retVal = p.matcher(retVal).replaceAll(""); + + p = Pattern.compile("((COMMIT)(\\s)*;)"); + retVal = p.matcher(retVal).replaceAll(""); + + p = Pattern.compile("CALL(\\s)+(.*?)\\);"); + retVal = p.matcher(retVal.toUpperCase()).replaceAll(""); + + p = Pattern.compile("((EXIT)(\\s)*;)"); + retVal = p.matcher(retVal.toUpperCase()).replaceAll(" "); + + p = Pattern.compile("(\\s*)(CONNECT)(\\s*)(.*?)(/|\\\\)(.*?)(/|\\\\)(@)(.*?);"); + retVal = p.matcher(retVal.toUpperCase()).replaceAll(" "); + + if(retVal.lastIndexOf("EOF")!=-1){ + retVal = retVal.substring(0,retVal.lastIndexOf("EOF")).trim(); + } + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerTrd.java b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerTrd.java new file mode 100644 index 0000000..98af4b5 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/clean/GenericLogNormalizerTrd.java @@ -0,0 +1,115 @@ +package com.guozhi.bloodanalysis.parser.clean; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GenericLogNormalizerTrd { + private String retVal; + + public GenericLogNormalizerTrd (String retVal){ + this.retVal = retVal; + } + + public String parser(){ + dropgangt(); + replaceSpecial(); + dropNoStdSql(); + return retVal; + } + + + private void dropgangt() { + Pattern pat = Pattern.compile("(?ms)\\\\\\\\[a-zA-Z]+([a-zA-Z]|\\s|\\\\\\\\)*?$"); + Matcher mat = pat.matcher(retVal); + while(mat.find()){ + retVal = mat.replaceAll("\n"); + } + } + + + private void replaceSpecial() { + /** + * 将剩下的'${}'替换掉 + */ + Pattern pat = Pattern.compile("\\$\\{[\\w]*\\}\\s*(>|=|<|LIKE|>=|=>|<=|=<|<>)\\s*\\$\\{[\\w]*\\}"); + + Matcher mat = pat.matcher(retVal); + + while(mat.find()){ + retVal = retVal.replace(mat.group(), "'1' = '1'"); + } + + /** + * 先替换一次带有''${}的特殊变量 + */ + pat = Pattern.compile("(>|=|<|LIKE|>=|=>|<=|=<|<>)\\s*\\$\\{[\\w]*\\}"); + mat = pat.matcher(retVal); + + while(mat.find()){ + retVal = retVal.replace(mat.group()," = '1'"); + } + + /** + * 将剩下的${}替换掉 + */ + pat = Pattern.compile("\\$\\{[\\w]*\\}"); + + mat = pat.matcher(retVal); + + while(mat.find()){ + retVal = retVal.replace(mat.group(),""); + } + + /** + * 将剩下的';'替换掉 + */ + pat = Pattern.compile("'(.*?);(.*?)'"); + mat = pat.matcher(retVal); + while (mat.find()) { + String s = mat.group(); + String _s = s.replace(";", ";"); + retVal = retVal.replace(s, _s); + } + + /** + * 去除%等特殊符号 + */ + retVal=retVal.replace("%", "/"); + retVal=retVal.replace("?", " "); + } + + private void dropNoStdSql(){ + String pattern = "^CREATE.*|^SELECT.*|^INSERT.*|^ALTER.*"; + Pattern pat = Pattern.compile(pattern); + String retVals [] = retVal.split(";"); + retVal = ""; + for (String _retVal : retVals) { + _retVal = _retVal.toUpperCase().trim(); + _retVal = dorpLockingSql(_retVal); + Matcher mat = pat.matcher(_retVal); + while(mat.find()){ + retVal +=_retVal+";"; + } + } + } + + /** + * 广农商的存在这个句型20170216 + * 去除LOCKING TABLE 。。。FOR ACCESS句型 + * @param val + */ + private String dorpLockingSql(String val){ + String res = null; + String startPattern = "^(LOCKING)\\s*(TABLE)\\s.*(FOR\\s*ACCESS)\\s+[\\s\\S]*"; + if(val.matches(startPattern)) { + String keyPat = "FOR\\s*ACCESS?"; + Matcher m = Pattern.compile(keyPat).matcher(val); + int keyEnd = 0; + if(m.find()) { + keyEnd=m.end(); + res = val.substring(keyEnd); + } + } + return res == null ? val : res.trim(); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/AlterParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/AlterParser.java new file mode 100644 index 0000000..86ee368 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/AlterParser.java @@ -0,0 +1,62 @@ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.List; + +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import gudusoft.gsqlparser.nodes.TAlterTableOptionList; +import gudusoft.gsqlparser.nodes.TObjectName; +import gudusoft.gsqlparser.stmt.TAlterTableStatement; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +/** + * Created by Walk.Lai on 2015/8/29. + */ +public class AlterParser { + private TAlterTableStatement mStmt;//table, view + private List mColumns; + + private VTable mTable; + private ParserContext mParserContext; + + public AlterParser(TAlterTableStatement alterSql,ParserContext context){ + mStmt =alterSql; + this.mParserContext=context; + } + + public void parse() { + //alter table exchange partition with table +// --将新数据以交换分区方式插入目标表 +// ALTER TABLE IML_DB.EV_EVENT_PROD_RELA EXCHANGE SUBPARTITION P_1008_1111 WITH TABLE IML_DB.VT_NEW_1008; + /* + 例如 ALTER TABLE $PDM_SCH.PD_BCC_3F_TRAN_INFO RENAME TO PD_BCC_3F_TRAN_INFO_EXCHANGE2; + ALTER TABLE $PDM_SCH.PD_BCC_3F_TRAN_INFO_EXCHANGE RENAME TO PD_BCC_3F_TRAN_INFO; + tempTable -- $PDM_SCH.PD_BCC_3F_TRAN_INFO_EXCHANGE + targetTable -- PD_BCC_3F_TRAN_INFO + */ + String tempTableName = null; + String targetTableName = null; + TObjectName obj = mStmt.getTableName(); + if (obj!=null) { + tempTableName = obj.toString(); + } + TAlterTableOptionList oplist = mStmt.getAlterTableOptionList(); + if (oplist!=null) { + for (int i = 0; i < oplist.size(); i++) { + String option = oplist.getAlterTableOption(i).toString(); + if (option.contains("RENAME")&&option.contains(" TO ")) { + targetTableName = option.substring(option.indexOf(" TO ")+" TO ".length()).trim(); + targetTableName = targetTableName.replace("SYMBOLALTERPOINT", "."); + // targetTableName = this.addAlterSchema(tempTableName,targetTableName); + break; + } + } + } + +} + public List getParseResult() { + return null; + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/AsTableParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/AsTableParser.java new file mode 100644 index 0000000..6a138ee --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/AsTableParser.java @@ -0,0 +1,128 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; +import com.guozhi.bloodanalysis.parser.utils.KColumnProvider; +import com.guozhi.bloodanalysis.parser.utils.KDatabaseProvider; +import com.guozhi.bloodanalysis.parser.utils.SpUtils; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import gudusoft.gsqlparser.nodes.TTable; +import gudusoft.gsqlparser.stmt.TSelectSqlStatement; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +@NoArgsConstructor +public class AsTableParser extends BaseParser{ + private TTable tTable; + private boolean mKeepConstant=false;//是否保留常量值 + private ParserContext mParserContext; + private VTable vTable;//将整个查询语句当成一个表进行处理 + + @Autowired + ApplicationContext applicationContext; + + @Autowired + KDatabaseProvider kDatabaseProvider; + + public AsTableParser(TTable tTable,ParserContext context) { + this.tTable = tTable; + vTable = new VTable(SpUtils.generateId(tTable.toString(),"")); + this.mParserContext=context; + } + + public void parse() { + //TODO 将CTE转化为表关系 + mParserContext.setCurrentTable(vTable); + VTable sVTable = analyseTable(tTable); + sVTable.addColumns(new KColumnProvider().getColumns(sVTable, null, mParserContext)); + vTable.addTable(sVTable); + mParserContext.setCurrentTable(vTable); + vTable.addColumns(sVTable.getColumns()); + mParserContext.addVTable( vTable); + } + + + private VTable analyseTable(TTable table){ + String fullName=table.getFullName(); + String tableAlias=table.getAliasName(); + VTable vTable=null; + if(StringUtils.isBlank(fullName)){//子查询,fullName为空 + vTable=new VTable(SpUtils.generateId(table.toString(),tableAlias)); + }else{//普通表名//StringUtils.isNotBlank(fullName) + String[] nameInfo=SpUtils.analyseTableName(fullName); + vTable=new VTable(nameInfo[2],nameInfo[2]); + vTable.db=mParserContext.getDefaultDb(); + vTable.schema=mParserContext.getDefaultSchema(); + } + if(StringUtils.isNotBlank(tableAlias)){ + vTable.setAlias(tableAlias); + } + + //已知的表 + VTable createdTable = mParserContext.findExistedTable(vTable.getFullName(),true); + if(createdTable!=null) { + createdTable.setAlias(vTable.alias); + return createdTable; + } + + switch (table.getTableType()) { + case objectname: + //真实数据库中的表,查找表对应系统,可能存在多个情况 + kDatabaseProvider.getDatabase(vTable, mParserContext); + break; + case subquery: + TSelectSqlStatement subQuery = table.getSubquery(); +// VTable currentTable=mParserContext.getCurrentTable(); + SelectParser sp = applicationContext.getBean(SelectParser.class); + sp.initWithTable(subQuery,mParserContext,vTable,mKeepConstant); + sp.parse(); +// mParserContext.setCurrentTable(vTable); + //创建依赖关系 重复了。。。。。。。。。。 +// vTable.addColumns(sp.getParseResult()); +// vTable.getFromTables().addAll(sp.vTable.getFromTables()); + break; //subquery + + case function: +// table.getFuncCall(); + break; + case tableExpr:break; + case rowList:break; + //SQL Server only + case containsTable:break; + case freetextTable:break; + + default:break; + } + mParserContext.addVTable(vTable); + return vTable; + } + + public List getParseResult() { + List ret=new ArrayList<>(); + for(KColumn column: vTable.getColumns()){ + if(column==null){ + ret.add(column); + }else { + if (column.isStar) { + ret.addAll(column.getRefColumns()); + } else { + ret.add(column); + } + } + } + return ret; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/BaseParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/BaseParser.java new file mode 100644 index 0000000..5b598bb --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/BaseParser.java @@ -0,0 +1,202 @@ +package com.guozhi.bloodanalysis.parser.common; + +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class BaseParser { + + public void getResultParser(ParserContext mParserContext, VTable tTable, List mColumns){ + VTable currTable = mParserContext.getCurrentTable(); + if(currTable==null){ + return; + } + Map tables = new HashMap(); + if(mColumns!=null){ + //先清理一遍空表字段对象,并从目标找到最终源字段 + cleanNullTabCol(mParserContext, tTable, mColumns); + //开始验证当前SQL中的源表是否都存在结果对象中,如果不存在则需要创建一个默认字段,做到目标-源表的关系 + List sTables = currTable.getFromTables(); + for (VTable sTable : sTables) { + childTable(mParserContext, tTable, sTable, mColumns, tables); + } + } + } + + + /*** + * 清空目标表,并从找到源字段 + * @param mParserContext + * @param tTable + * @param mColumns + */ + private void cleanNullTabCol(ParserContext mParserContext,VTable tTable,List mColumns){ + //记录需要删除的目标列对象 + List delTCols = new ArrayList(); + for (int i = 0; i < mColumns.size(); i++) { + KColumn tCol = mColumns.get(i); + List sCols = tCol.getRefColumns(); + //删除对象集合 + List delSCols = new ArrayList(); + //调整级别的对象 + List addSCols = new ArrayList(); + Map sMap = new HashMap(); + //开始迭代子级判断获得最终的列对象 + childColumn(sCols, delSCols,addSCols,sMap,false); + //有调整列级别的 + if(addSCols.size()>0){ + for (KColumn kColumn : addSCols) { + sCols.add(kColumn); + } + } + //删除空白记录 + for (int j = 0; j < delSCols.size(); j++) { + sCols.remove(delSCols.get(j)); + } + + if(sCols.size()<=0){ + delTCols.add(tCol); + } + } + //删除没有源的目标记录 + if(delTCols.size()>0){ + for (int i = 0; i < delTCols.size(); i++) { + mColumns.remove(delTCols.get(i)); + } + } + } + + private void childColumn(List sCols,List delSCols,List addSCols,Map sMap,boolean isChild){ + for (KColumn sCol : sCols) { + //有表别名,但没有表名称,是一个子查询(select t.col from (select col from table) t ) + List _sCols = sCol.getRefColumns(); + //还有来源,继续往下走,一直走到最后一层级获取源头字段是谁 + if(_sCols.size()>0){ + isChild = true; + delSCols.add(sCol); + childColumn(sCol.getRefColumns(), delSCols, addSCols,sMap,isChild); + }else{ + if(sCol.tableName!=null){ + if(isChild){ + String colKey = sCol.db+"."+sCol.schema+"."+sCol.tableName+"."+sCol.columnName; + if(sMap.containsKey(colKey)){ + delSCols.add(sCol); + }else{ + String pattern = "(^'.*'$)|(^\\d+$)"; + Pattern pat = Pattern.compile(pattern); + Matcher mat = pat.matcher(sCol.columnName.toUpperCase().trim()); + if(mat.find()){ + delSCols.add(sCol); + }else{ + sMap.put(colKey, sCol); + addSCols.add(sCol); + } + } + } + }else{ + delSCols.add(sCol); + } + } + } + } + + private void childTable(ParserContext mParserContext,VTable tTable,VTable sTable,List mColumns,Map tables){ + if(sTable.isRealTable()){ + //判断源表是否存在 + isSourceTableExis(tables, sTable, tTable, mParserContext, mColumns); + }else{ + List sTbles = sTable.getFromTables(); + for (VTable sCTable : sTbles) { + //判断源表是否都存在 + childTable(mParserContext, tTable, sCTable, mColumns, tables); + } + } + } + + /** + * 源表是否存在 + * @param tables 源表Map集合 + * @param sTable 源表 + * @param tTable 目标表 + * @param mParserContext sql上下文 + * @param mColumns 目标表字段 + */ + private void isSourceTableExis(Map tables,VTable sTable,VTable tTable,ParserContext mParserContext,List mColumns){ + //源表主键KEY + String tabKey = sTable.db+"."+sTable.schema+"."+sTable.name; + boolean isTableExis = false; + //如果已经进行过验证,则退出 + if(tables.containsKey(tabKey)){ + return; + } + //开始迭代判断当前源表是否已经写入结果 + for (int i = 0; i < mColumns.size(); i++) { + KColumn tCol = mColumns.get(i); + List sCols = tCol.getRefColumns(); + //开始迭代查找 + isTableExis = childColumn(sCols, tabKey); + if(isTableExis){ + break; + } + } + if(sTable.isCreated()){ + //判断源表是否都存在,如果不存在,则建立源表与目标表的关系,字段建立一个默认字段 + if(!isTableExis){ + //目标 + KColumn tCol = new KColumn(); + //TODO wxl 对列名进行分析?解析不到字段级别,最终结果需要保留到表级 + tCol.columnName = "default_col"; + tCol.alias = "默认字段"; + + tCol.columnPrefix = tTable.getName(); + tCol.db=tTable.db; + tCol.schema=tTable.schema; + //表的状态是临时表还是实体表 + tCol.isEvTable = tTable.isCreated(); + tCol.tableName=tTable.getName(); + tCol.export=true; + + //源 + KColumn sCol = new KColumn(); + //TODO wxl 对列名进行分析?解析不到字段级别,最终结果需要保留到表级 + sCol.columnName = "default_col"; + sCol.alias = "默认字段"; + + sCol.columnPrefix = sTable.getName(); + sCol.db=sTable.db; + sCol.schema=sTable.schema; + sCol.tableName=sTable.getName(); + sCol.export=true; + //表的状态是临时表还是实体表 + sCol.isEvTable = sTable.isCreated(); + tCol.addRefColumn(sCol); + mColumns.add(tCol); + tables.put(tabKey, sTable); + } + } + } + + private boolean childColumn(List sCols,String tabKey){ + for (KColumn sCol : sCols) { + //源字段表主键KEY + String tabColKey = sCol.db+"."+sCol.schema+"."+sCol.tableName; + if(tabColKey.toUpperCase().equals(tabKey.toUpperCase())){ + return true; + }else{ + //如果当前表不存在此层级,判断是否还有下一级继续找 + if(sCol.getRefColumns().size()>0){ + childColumn(sCol.getRefColumns() ,tabKey); + } + } + + } + return false; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/CreateParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/CreateParser.java new file mode 100644 index 0000000..3f6d37c --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/CreateParser.java @@ -0,0 +1,194 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.guozhi.bloodanalysis.parser.utils.SpUtils; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import gudusoft.gsqlparser.TCustomSqlStatement; +import gudusoft.gsqlparser.nodes.TColumnDefinition; +import gudusoft.gsqlparser.nodes.TColumnDefinitionList; +import gudusoft.gsqlparser.nodes.TTable; +import gudusoft.gsqlparser.stmt.TCreateTableSqlStatement; +import gudusoft.gsqlparser.stmt.TCreateViewSqlStatement; +import gudusoft.gsqlparser.stmt.TSelectSqlStatement; + +public class CreateParser extends BaseParser { + private TCustomSqlStatement mCreateSql;//table, view + private List mColumns; + + /**当前目标表*/ + private VTable mTable; + private ParserContext mParserContext; + public CreateParser(TCustomSqlStatement createSql,ParserContext context){ + mCreateSql=createSql; + this.mParserContext=context; + } + + public void parse() { + if(mCreateSql instanceof TCreateTableSqlStatement){ + TCreateTableSqlStatement ctSql=(TCreateTableSqlStatement)mCreateSql; + String tableName=ctSql.getTableName().toString(); + //分析表名,如:db.schema.table或schema.table + String[] nameInfo= SpUtils.analyseTableName(tableName); + //用表名和别名初始化一个表 + mTable=new VTable(nameInfo[2],nameInfo[2]); + mTable.db=mParserContext.getDefaultDb(); + mTable.schema=mParserContext.getDefaultSchema(); + //设置并判断是否临时表,如:CREATE MULTISET|VOLATILE的为临时表 + mTable.setCreated(isEvTable(mCreateSql.toString())); + TColumnDefinitionList cdList = ctSql.getColumnList(); + List definedColumns=new ArrayList();//定义的列 + for(int i=0;i selectColumns=null;//subQuery中的结果列 + if(subQuery!=null){ + SelectParser sp=new SelectParser(subQuery,mParserContext); + sp.parse(); + selectColumns=sp.getParseResult(); + }else{ + TTable tTable = ctSql.getAsTable(); + if(tTable!=null){ + System.out.println("此处可能为AsTable,暂未考虑如何获取:"+ctSql.getAsTable()); +// System.out.println("sql:"+ctSql); + AsTableParser asTable = new AsTableParser( tTable, mParserContext); + //设置上下文当前表,解析源表和目标表 + asTable.parse(); + selectColumns = asTable.getParseResult(); + } + } + if(selectColumns!=null&&selectColumns.size()>0) { + List sourceColumns=new ArrayList(); + for(KColumn c: selectColumns){ + if(c!=null&&c.isStar&&c.getRefColumns().size()>0){ + sourceColumns.addAll(c.getRefColumns()); + }else{ + sourceColumns.add(c); + } + } + if(definedColumns.size()>0) { + if(definedColumns.size()!=sourceColumns.size()){ + //列个数不对称,SQL出错 + }else{ + for(int i=0;i0){ + dc.addRefColumnList(sc.getRefColumns()); + }else { + dc.addRefColumn(sc); + } + } + } + }else{ + //类似这样的语句没有列名定义时:create table t as select a,b from c; + for (KColumn refCol : sourceColumns) { + if(refCol==null){ + definedColumns.add(null); + continue; + } + +// String tcName = refCol.columnName; +// if (refCol.alias != null) +// tcName = refCol.alias; + Map map = getColNameAndAlias(refCol); + + KColumn col = new KColumn(); + //TODO 对列名进行分析? +// col.columnName = "default_col"; +// col.alias = "默认字段"; + col.columnName=map.get("colName"); + col.alias=map.get("alias"); + col.columnPrefix = tableName; + col.db=mTable.db; + col.schema=mTable.schema; + col.tableName=mTable.getName(); + //表的状态是临时表还是实体表 + col.isEvTable = mTable.isCreated(); + col.addRefColumn(refCol); + definedColumns.add(col); + } + } + }else{ + //TODO 没有列的数据,出错了 + } + mColumns=definedColumns; +// mTable.addColumns(definedColumns); + mTable.setRealTable(false); + //把字段存在创建的表里面 + mTable.addColumns(getParseResult()); + mParserContext.addCreatedTable(mTable.getFullName(), mTable); + }else if(mCreateSql instanceof TCreateViewSqlStatement){ + //视图 + } + } + + private Map getColNameAndAlias(KColumn refCol){ + Map map = new HashMap(); + if(refCol.vColumn){ + if(refCol.columnName!=refCol.alias&&refCol.alias!=null&&refCol.columnName!=null){ + map.put("colName", refCol.alias); + map.put("alias", refCol.alias); + }else{ + if(refCol.getRefColumns().size()>1){ + map.put("colName", "default_col"); + map.put("alias", "默认字段"); + }else{ + KColumn c = new KColumn(); + if(refCol.getRefColumns().size()>0){ + c = refCol.getRefColumns().get(0); + } + map.put("colName", c.columnName == null ? "default_col" : c.columnName); + map.put("alias", c.alias == null ? "默认字段" : c.alias); + } + } + }else{ + map.put("colName", refCol.columnName == null ? "default_col" : refCol.columnName); + map.put("alias", refCol.alias == null ? "默认字段" : refCol.alias); + } + return map; + } + + /** + * 验证是否为实体表 + * @param retVal + * @return + */ + private boolean isEvTable(String retVal){ + boolean isEvTable = true; + String pattern = "^\\s*CREATE\\s*(VOLATILE|MULTISET)\\s*(VOLATILE|MULTISET)"; + Pattern pat = Pattern.compile(pattern); + Matcher mat = pat.matcher(retVal.toUpperCase().trim()); + while(mat.find()){ + isEvTable = false; + break; + } + return isEvTable; + } + + public List getParseResult() { + super.getResultParser(mParserContext, mTable, mColumns); + return mColumns; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/DeleteParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/DeleteParser.java new file mode 100644 index 0000000..b0e6f59 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/DeleteParser.java @@ -0,0 +1,41 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.ArrayList; +import java.util.List; + +import com.guozhi.bloodanalysis.parser.utils.ExprToColumn; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import gudusoft.gsqlparser.nodes.TExpression; +import gudusoft.gsqlparser.nodes.TWhereClause; +import gudusoft.gsqlparser.stmt.TDeleteSqlStatement; + +public class DeleteParser{ +private TDeleteSqlStatement mDeleteStmt; +private List mColumns; +private ParserContext mParserContext; + +public DeleteParser(TDeleteSqlStatement deleteSqlStatement,ParserContext context){ + mDeleteStmt=deleteSqlStatement; + mColumns=new ArrayList(); + this.mParserContext=context; +} + +public void parse() { + String tableName=mDeleteStmt.getTargetTable().toString(); + TWhereClause whereClause=mDeleteStmt.getWhereClause(); + if(whereClause!=null) { + TExpression expr = whereClause.getCondition(); + new ExprToColumn(mDeleteStmt, mParserContext, false).exprVisit(expr); + } + + //TODO +} +public List getParseResult() { + return mColumns; +} + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/DropParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/DropParser.java new file mode 100644 index 0000000..5bab467 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/DropParser.java @@ -0,0 +1,50 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.List; + +import com.guozhi.bloodanalysis.parser.utils.SpUtils; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import lombok.extern.slf4j.Slf4j; +import gudusoft.gsqlparser.TCustomSqlStatement; +import gudusoft.gsqlparser.stmt.TDropTableSqlStatement; +import gudusoft.gsqlparser.stmt.TDropViewSqlStatement; + +@Slf4j +public class DropParser{ +private TCustomSqlStatement mDropStmt; +private ParserContext mParserContext; + +public DropParser(TCustomSqlStatement stmt,ParserContext context){ + this.mDropStmt=stmt; + this.mParserContext=context; +} + +public void parse() { + if(mDropStmt instanceof TDropTableSqlStatement){ + TDropTableSqlStatement dropTableStmt=(TDropTableSqlStatement)mDropStmt; + + String fullname=dropTableStmt.getTableName().toString(); + String tableName= SpUtils.removeQuote(fullname); + + VTable t=mParserContext.findExistedTable(tableName,true); + if(t==null){ + + } + mParserContext.dropExistTable(tableName); + //TODO 应该不用理这个表了, + + }else if( mDropStmt instanceof TDropViewSqlStatement){ + + } +} +public List getParseResult() { + return null; +} + + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/InsertParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/InsertParser.java new file mode 100644 index 0000000..b678869 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/InsertParser.java @@ -0,0 +1,211 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.ArrayList; +import java.util.List; + +import com.guozhi.bloodanalysis.parser.utils.ExprToColumn; +import com.guozhi.bloodanalysis.parser.utils.KColumnProvider; +import com.guozhi.bloodanalysis.parser.utils.SpUtils; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import gudusoft.gsqlparser.nodes.TExpression; +import gudusoft.gsqlparser.nodes.TMultiTarget; +import gudusoft.gsqlparser.nodes.TMultiTargetList; +import gudusoft.gsqlparser.nodes.TObjectNameList; +import gudusoft.gsqlparser.nodes.TResultColumn; +import gudusoft.gsqlparser.nodes.TResultColumnList; +import gudusoft.gsqlparser.stmt.TInsertSqlStatement; +import gudusoft.gsqlparser.stmt.TSelectSqlStatement; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Component +@NoArgsConstructor +@Data +public class InsertParser extends BaseParser{ + private List mColumns; + private TInsertSqlStatement mInsertSql; + private ParserContext mParserContext; + private VTable tTable = null; + + @Autowired + private ApplicationContext applicationContext; + + public InsertParser(TInsertSqlStatement insertSqlStatement,ParserContext context) { + mInsertSql = insertSqlStatement; + this.mParserContext=context; + } + + + + public void parse() { + //INSERT INTO 表名称 VALUES (值1, 值2,....) + //INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....) + //insert into table_name select from.... + // + String targetTableName = mInsertSql.getTargetTable().getFullName(); +// System.out.println(mInsertSql.toString()); + String[] nameInfo= SpUtils.analyseTableName(targetTableName); + tTable=new VTable(nameInfo[2],nameInfo[2]); + tTable.db=mParserContext.getDefaultDb(); + tTable.schema=mParserContext.getDefaultSchema(); + boolean exportColumn=false; + VTable createdTable=mParserContext.findExistedTable(tTable.getFullName(),false); + //在解析的时候前面已经创建了临时表,这里再次使用就直接使用临时表 + //,但是一开始解析的临时表是没有字段的,这次解析insert语句是有字段的,如果直接使用导致临时表字段缺失 + if(createdTable==null){ + exportColumn=true; + }else{ + tTable = createdTable; + } + + //目标表字段 + TObjectNameList objectNameList = mInsertSql.getColumnList(); + + mColumns=new ArrayList(); + if (objectNameList != null) { + for (int i = 0; i < objectNameList.size(); i++) { + KColumn col = new KColumn(); + //TODO 对列名进行分析? + col.columnName = objectNameList.getObjectName(i).toString(); + col.alias = col.columnName; + col.columnPrefix = targetTableName; + col.db=tTable.db; + col.schema=tTable.schema; + col.tableName=tTable.getName(); + col.isEvTable = exportColumn ? true : createdTable.isCreated();//是否真实表 + col.export=exportColumn; + //grc 记录级标记 + col.etlFlag="12"; + mColumns.add(col); + } + }else{ + //这种形式只会按列顺序来计算,不会按列的名称匹配,所以列的顺序很重要 + KColumnProvider kColumnProvider = applicationContext.getBean(KColumnProvider.class); + List columns=kColumnProvider.getColumns(null,targetTableName, mParserContext); + if(columns!=null) { + mColumns.addAll(columns); + } + } + + List sourceColumns=new ArrayList(); + switch (mInsertSql.getValueType()) { + case 1: + TMultiTargetList valueList = mInsertSql.getValues(); + for (int i = 0; i < valueList.size(); i++) { + TMultiTarget value = valueList.getMultiTarget(i); + //TODO 对不同类型进行不同的处理 + TResultColumnList resultColumnList=value.getColumnList(); + for (int j = 0; j < resultColumnList.size(); j++) { + TResultColumn column = resultColumnList.getResultColumn(j); + TExpression expr = column.getExpr(); + //TODO currentTable可能会有些影响? + sourceColumns.add(new ExprToColumn(mInsertSql, mParserContext, false).exprVisit(expr)); + } + } + break; + case 2://SubQuery + TSelectSqlStatement subQuery = mInsertSql.getSubQuery(); + SelectParser sp = applicationContext.getBean(SelectParser.class); + sp.init(subQuery,mParserContext,true); + //这里解析表依赖关系》????当源表和目标表?? + sp.parse(); + //源字段,解析出的字段为null.null.null.AGMT_ID as AGMT_ID??? + List subQueryColumns = sp.getParseResult(); + + for(KColumn c: subQueryColumns){ + if(c!=null&&c.isStar&&c.getRefColumns().size()>0){ + sourceColumns.addAll(c.getRefColumns()); + }else{ + sourceColumns.add(c); + } + } + break; //case 2: subQuery + case 3:break; + case 4:break; + case 6:break; + case 5: + mInsertSql.getFunctionCall(); + break; + case 7: + mInsertSql.getSetColumnValues(); + break; + case 8: + mInsertSql.getRecordName(); + default: + break; + } + + if(mColumns.size()>sourceColumns.size()){ + System.out.println(mColumns.size()+"--"+sourceColumns.size()); + log.error("目标列与源列数量不一致"); + return; + } + + if(mColumns.size()==0){ + log.info("目标表:"+targetTableName+",没有定义字段,设置默认字段,总数:"+sourceColumns.size()); + //如果没有指定字段,则默认一个字段,如有其他必须要字段,可以通过元数据管理系统获取,但需要重新开发。 + for (int i = 0; i < sourceColumns.size(); i++) { + KColumn col = new KColumn(); + //TODO 对列名进行分析? + col.columnName = "default_col"; + col.alias = "默认字段"; + col.columnPrefix = targetTableName; + col.db=tTable.db; + col.schema=tTable.schema; + col.tableName=tTable.getName(); + col.isEvTable = exportColumn || createdTable.isCreated(); + col.export=exportColumn; + mColumns.add(col); + } + } + + + //假设列之间关系完全是可以上的 + int length=mColumns.size(); + //从源字段中获取到etlSrcTabName==== + if(mParserContext.getEtlSrcTabName() == null) { + for(int i = 0;i < length;i++){ + KColumn column=mColumns.get(i); + KColumn refCol=sourceColumns.get(i); + if(column.columnName.equals(KColumn.etlSrcTabName)) { + String etlSrcColName = refCol.columnName; + etlSrcColName = etlSrcColName.replaceAll("'", ""); + mParserContext.setEtlSrcTabName(etlSrcColName); + break; + } + } + } + for (int i=0;i0){ + column.getRefColumns().addAll(refCol.getRefColumns()); + }else { + column.addRefColumn(refCol); + } + } + } + tTable.addColumns(mColumns); + } + + public List getParseResult() { + //在父类中先清理一次结果 + super.getResultParser(mParserContext, tTable, mColumns); + return mColumns; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/ParserContext.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/ParserContext.java new file mode 100644 index 0000000..9e6300f --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/ParserContext.java @@ -0,0 +1,141 @@ +package com.guozhi.bloodanalysis.parser.common; + +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * Created by Walk.Lai on 2015/8/1. + */ +public class ParserContext { + // 使用create语句创建的表 + private Map mCreatedTables = new HashMap(); + /** 只保存当前语句中出现的表,包括虚表 */ + private List mTableInCurrentStatement = new ArrayList(); + // 当前语句所构成的虚表 + private VTable mCurrentTable; + + //wxl TODO 对于存储过程可以知道归属库和schema,但对于perl、python、shell、sql脚本,就获取不到了。 + private String mDefaultDb;//TODO db or sys? + private String mDefaultSchema; + + /** + * grc etl源表名称 + */ + private String etlSrcTabName; + + public VTable findExistedTable(String tableName, boolean isCopy) { + if (isCopy) { + return copyTable(mCreatedTables.get(tableName)); + } else { + return mCreatedTables.get(tableName); + } + } + + private VTable copyTable(VTable s) { + if (s == null) { + return null; + } + VTable t = new VTable(s.getName()); + t.alias = s.alias; + t.db = s.db; + t.name = s.name; + t.schema = s.schema; + t.setCreated(s.isCreated()); + t.setRealTable(s.isRealTable()); + for (int i = 0; i < s.getColumns().size(); i++) { + KColumn _col = s.getColumns().get(i); + KColumn col = new KColumn(); + // TODO 对列名进行分析? + col.columnName = _col.columnName; + col.alias = _col.alias; + col.columnPrefix = _col.columnPrefix; + col.db = _col.db; + col.schema = _col.schema; + col.tableName = _col.tableName; + col.isEvTable = _col.isEvTable; + col.export = _col.export; + t.addColumn(col); + } + return t; + } + + public void dropExistTable(String tableName) { + mCreatedTables.remove(tableName); + } + + public void addVTable(VTable table) { + this.mTableInCurrentStatement.add(table); + } + + /** + * 当前解析语句中保存的表 + * + * @return + */ + public List getTableInCurrentStatement() { + return mTableInCurrentStatement; + } + + public VTable getCurrentTable() { + return mCurrentTable; + } + + public void setCurrentTable(VTable currentTable) { + this.mCurrentTable = currentTable; + } + + public String getDefaultDb() { + return mDefaultDb; + } + + public void setDefaultDb(String defaultDb) { + this.mDefaultDb = defaultDb; + } + + public String getDefaultSchema() { + return mDefaultSchema; + } + + public void setDefaultSchema(String defaultSchema) { + this.mDefaultSchema = defaultSchema; + } + + public Map getCreatedTables() { + return mCreatedTables; + } + + + public VTable findTableInCurrentStatement(String tableName) { + for (VTable t : mTableInCurrentStatement) { + if (t.getName().equals(tableName)) + return t; + if (t.getAlias() != null) { + if (t.getAlias().equals(tableName)) + return t; + } + } + return null; + } + + public boolean addCreatedTable(String tableName, VTable table) { + if (mCreatedTables.get(tableName) == null) { + mCreatedTables.put(tableName, table); + } + return false; + } + + public String getEtlSrcTabName() { + return etlSrcTabName; + } + + public void setEtlSrcTabName(String etlSrcTabName) { + this.etlSrcTabName = etlSrcTabName; + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/SelectParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/SelectParser.java new file mode 100644 index 0000000..9174338 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/SelectParser.java @@ -0,0 +1,294 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.ArrayList; +import java.util.List; + +import com.guozhi.bloodanalysis.parser.utils.ExprToColumn; +import com.guozhi.bloodanalysis.parser.utils.KDatabaseProvider; +import com.guozhi.bloodanalysis.parser.utils.SpUtils; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import gudusoft.gsqlparser.nodes.TExpression; +import gudusoft.gsqlparser.nodes.TExpressionList; +import gudusoft.gsqlparser.nodes.TIntoClause; +import gudusoft.gsqlparser.nodes.TJoin; +import gudusoft.gsqlparser.nodes.TJoinItem; +import gudusoft.gsqlparser.nodes.TJoinItemList; +import gudusoft.gsqlparser.nodes.TJoinList; +import gudusoft.gsqlparser.nodes.TResultColumn; +import gudusoft.gsqlparser.nodes.TResultColumnList; +import gudusoft.gsqlparser.nodes.TTable; +import gudusoft.gsqlparser.nodes.TWhereClause; +import gudusoft.gsqlparser.stmt.TSelectSqlStatement; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Component +@NoArgsConstructor +@Scope("prototype") +@Data +public class SelectParser extends BaseParser { + private List mSourceColumn = new ArrayList(); + private TSelectSqlStatement mSelect; + private boolean mKeepConstant=false;//是否保留常量值 + private ParserContext mParserContext; + private VTable vTable;//将整个查询语句当成一个表进行处理 + + @Autowired + ApplicationContext applicationContext; + + + public SelectParser(TSelectSqlStatement statement,ParserContext context) { + mSelect = statement; + vTable=new VTable(SpUtils.generateId(statement.toString(),"")); + this.mParserContext=context; + } + public SelectParser(TSelectSqlStatement statement,ParserContext context,boolean keepConstant) { + mSelect = statement; + mKeepConstant=keepConstant; + vTable=new VTable(SpUtils.generateId(statement.toString(),"")); + this.mParserContext=context; + } + + public void init(TSelectSqlStatement statement, ParserContext context, boolean keepConstant) { + mSelect = statement; + mKeepConstant=keepConstant; + vTable=new VTable(SpUtils.generateId(statement.toString(),"")); + this.mParserContext=context; + } + + public void initWithTable(TSelectSqlStatement statement,ParserContext context,VTable vTable,boolean keepConstant) { + mSelect = statement; + mKeepConstant=keepConstant; + this.vTable=vTable; + this.mParserContext=context; + } + +// public SelectParser(TSelectSqlStatement statement,ParserContext context,VTable vTable,boolean keepConstant) { +// mSelect = statement; +// mKeepConstant=keepConstant; +// this.vTable=vTable; +// this.mParserContext=context; +// } + public void parse() { + //当前表的关系已存在,则直接取消解析 + if(isTableExisted(vTable)){ + return ; + } + + //where 部分 + TWhereClause where = mSelect.getWhereClause(); + if(where != null) { +// System.out.println(where); + } + //TODO 将CTE转化为表关系 + + mParserContext.setCurrentTable(vTable); + //Join items from后边部分都属于join + TJoinList joinList = mSelect.joins; + if (joinList != null) { + for (int i = 0; i < joinList.size(); i++) { + TJoin join = joinList.getJoin(i); + TTable table=join.getTable(); + + vTable.addTable(analyseTable(table)); + + TJoinItemList joinItemList = join.getJoinItems(); + if (joinItemList != null) { + for (int j = 0; j < joinItemList.size(); j++) { + TJoinItem joinItem = joinItemList.getJoinItem(j); + TTable joinTable = joinItem.getTable(); + vTable.addTable(analyseTable(joinTable)); + //TExpression expr = joinItem.getOnCondition(); + //TODO 对On的列进行分析,如果不是这个表的列,则是会影响这个列的 + } + } + + } + } else { + log.error("找不到From对应的表"); + return; + } + mParserContext.setCurrentTable(vTable); +// mSelect.getSetOperatorType() + //对 union, unionall, except等进行处理 + if(mSelect.getSetOperator()!=TSelectSqlStatement.setOperator_none){ + + VTable currentTable = mParserContext.getCurrentTable();//暂存 + + SelectParser sp1 = new SelectParser(mSelect.getLeftStmt(), mParserContext); + sp1.parse(); + + SelectParser sp2 = new SelectParser(mSelect.getRightStmt(), mParserContext); + sp2.parse(); + currentTable.addTable(sp1.vTable); + currentTable.addTable(sp2.vTable); + mParserContext.setCurrentTable(currentTable);//还原 + currentTable.addColumns(sp1.getParseResult()); + currentTable.addColumns(sp2.getParseResult()); + }else { + TResultColumnList resultColumnList = mSelect.getResultColumnList(); + for (int i = 0; i < resultColumnList.size(); i++) { + TResultColumn column = resultColumnList.getResultColumn(i); + TExpression expr = column.getExpr(); + ExprToColumn etc = applicationContext.getBean(ExprToColumn.class); + etc.setMStmt(mSelect); + etc.setMParserContext(mParserContext); + KColumn rc = etc.exprVisit(expr); +// KColumn rc = new ExprToColumn(mSelect, mParserContext, mKeepConstant).exprVisit(expr); + ///$$$$$$$$$$$$$$$$$$$$$$$grc 记录级标志 +// rc.setEtlFlag("12"); + mSourceColumn.add(rc); + } + + } + + //into table, 对应表的字段依赖于结果字段中的别名,根据上边结果创建依赖关系 + /* + SELECT * + INTO new_table_name [IN externaldatabase] + FROM old_tablename + */ + //TODO select into相当于创建一个新表 + TIntoClause intoClause = mSelect.getIntoClause(); + if (intoClause != null) { + + TExpressionList exprList = intoClause.getExprList(); + List newColumns = new ArrayList(mSourceColumn.size()); + for (int i = 0; i < exprList.size(); i++) { + TExpression expr = exprList.getExpression(i); + String tableName = null; + switch (expr.getExpressionType()) { + case in_t: + tableName = SpUtils.removeQuote(expr.getLeftOperand().toString()); + //对表名进行处理,可能含有数据库 + break; + case simple_object_name_t: + //select语句的关联关系 + List fromTables=vTable.getFromTables(); + String[] nameInfo= SpUtils.analyseTableName(expr.toString()); + vTable=new VTable(nameInfo[2],nameInfo[2]); + vTable.db=mParserContext.getDefaultDb(); + vTable.schema=mParserContext.getDefaultSchema(); + vTable.getFromTables().addAll(fromTables); + break; + } + + for (KColumn col : mSourceColumn) { + if(col==null)continue; + KColumn nc = new KColumn(); + nc.columnPrefix = tableName; + nc.columnName = col.alias == null ? col.columnName : col.alias; + nc.alias = null; + if(col.vColumn){ + nc.getRefColumns().addAll(col.getRefColumns()); + }else { + nc.addRefColumn(col); + } + newColumns.add(nc); + } + + } + //TODO 返回结果转化为该表的,暂时这样处理,是不是这样处理得再考虑考虑 + this.mSourceColumn=newColumns; + } + vTable.addColumns(mSourceColumn); + mParserContext.addVTable( vTable); + } + + private boolean isTableExisted(VTable vTable) { + return false; + } + + private VTable analyseTable(TTable table){ + String fullName=table.getFullName(); + String tableAlias=table.getAliasName(); + VTable vTable=null; + if(StringUtils.isBlank(fullName)){//子查询,fullName为空 + vTable=new VTable(SpUtils.generateId(table.toString(),tableAlias)); + }else{//普通表名//StringUtils.isNotBlank(fullName) + String[] nameInfo=SpUtils.analyseTableName(fullName); + vTable=new VTable(nameInfo[2],nameInfo[2]); + vTable.db=mParserContext.getDefaultDb(); + vTable.schema=mParserContext.getDefaultSchema(); + } + + if(StringUtils.isNotBlank(tableAlias)){ + vTable.setAlias(tableAlias); + } + + //已知的表 + VTable createdTable = mParserContext.findExistedTable(vTable.getFullName(),true); + if(createdTable!=null) { + createdTable.setAlias(vTable.alias); + return createdTable; + } + + switch (table.getTableType()) { + case objectname: + //真实数据库中的表,查找表对应系统,可能存在多个情况 + KDatabaseProvider kDatabaseProvider = applicationContext.getBean(KDatabaseProvider.class); + kDatabaseProvider.getDatabase(vTable, mParserContext); + break; + case subquery: + TSelectSqlStatement subQuery = table.getSubquery(); +// VTable currentTable=mParserContext.getCurrentTable(); + SelectParser sp = applicationContext.getBean(SelectParser.class); + sp.initWithTable(subQuery,mParserContext,vTable,mKeepConstant); + sp.parse(); +// mParserContext.setCurrentTable(vTable); + //创建依赖关系 重复了。。。。。。。。。。 +// vTable.addColumns(sp.getParseResult()); +// vTable.getFromTables().addAll(sp.vTable.getFromTables()); + break; //subquery + + case function: +// table.getFuncCall(); + break; + case tableExpr:break; + case rowList:break; + //SQL Server only + case containsTable:break; + case freetextTable:break; + + default:break; + } + mParserContext.addVTable(vTable); + return vTable; + } + + public List getParseResult() { + List ret=new ArrayList(); + for(KColumn column: vTable.getColumns()){ + if(column==null){ + ret.add(column); + }else { + if (column.isStar) { + ret.addAll(column.getRefColumns()); + } else { + ret.add(column); + } + } + } + return ret; + } + + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/common/UpdateParser.java b/src/main/java/com/guozhi/bloodanalysis/parser/common/UpdateParser.java new file mode 100644 index 0000000..9d03f86 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/common/UpdateParser.java @@ -0,0 +1,179 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.common; + +import java.util.ArrayList; +import java.util.List; + +import com.guozhi.bloodanalysis.parser.utils.ExprToColumn; +import com.guozhi.bloodanalysis.parser.utils.KColumnProvider; +import com.guozhi.bloodanalysis.parser.utils.SpUtils; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import gudusoft.gsqlparser.nodes.TExpression; +import gudusoft.gsqlparser.nodes.TJoinList; +import gudusoft.gsqlparser.nodes.TResultColumn; +import gudusoft.gsqlparser.nodes.TResultColumnList; +import gudusoft.gsqlparser.nodes.TTable; +import gudusoft.gsqlparser.nodes.TTableList; +import gudusoft.gsqlparser.nodes.TWhereClause; +import gudusoft.gsqlparser.stmt.TSelectSqlStatement; +import gudusoft.gsqlparser.stmt.TUpdateSqlStatement; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +@Component +@NoArgsConstructor +public class UpdateParser{ + private TUpdateSqlStatement mUpdateStmt; + private List mColumns; + private ParserContext mParserContext; + + @Autowired + ApplicationContext applicationContext; + + public UpdateParser(TUpdateSqlStatement stmt, ParserContext context) { + mUpdateStmt = stmt; + mColumns = new ArrayList(); + this.mParserContext = context; + } + + public void parse() { + TTable targetTable = mUpdateStmt.getTargetTable(); + VTable updateTable = new VTable(targetTable.getName(), targetTable.getName()); + updateTable.db = mParserContext.getDefaultDb(); + updateTable.schema = mParserContext.getDefaultSchema(); + boolean exportColumn = false; + VTable createdTable = mParserContext.findExistedTable(updateTable.getFullName(),true); + if (createdTable == null) { + exportColumn = true; + } + + mParserContext.setCurrentTable(updateTable); + TTableList tableList = mUpdateStmt.tables; + if (tableList != null) { + for (int i = 0; i < tableList.size(); i++) { + TTable fromTable = tableList.getTable(i); + VTable table=analyseTable(fromTable); + if(table.getFullName().equals(updateTable.getFullName()))continue; + + mParserContext.getTableInCurrentStatement().add(table); + + + } + } + TJoinList joinList=mUpdateStmt.getReferenceJoins(); + if(joinList!=null){ + for(int i=0;i conditionColumns = new ArrayList(); + // conditionColumns.add(new ExprToColumn(mUpdateStmt, mParserContext, false).exprVisit(conditionExpr)); + TResultColumnList rcList = mUpdateStmt.getResultColumnList(); + + + for (int i = 0; i < rcList.size(); i++) { + TResultColumn rc = rcList.getResultColumn(i); + TExpression expr = rc.getExpr(); + KColumn dest= new KColumn(); + dest.db=updateTable.db; + dest.schema=updateTable.schema; + dest.tableName=updateTable.getName(); + dest.columnName=expr.getLeftOperand().toString(); + //表的状态是临时表还是实体表 + dest.isEvTable = updateTable.isCreated(); + dest.export=exportColumn; + KColumn src= new ExprToColumn(mUpdateStmt, mParserContext, false).exprVisit(expr.getRightOperand()) ; + dest.addRefColumn(src); + mColumns.add(dest); + } + //依赖关系只计算不同表之间的 + /* for (KColumn column : conditionColumns) { + //TODO 列所属表是否相同的判断需要加强 + System.out.println(column.tableName); + if (column != null && !column.tableName.equals(targetTable.getName())) { + for (KColumn mColumn : mColumns) { + + mColumn.addRefColumn(column); + + } + } + + }*/ + + } + + public List getParseResult() { + return mColumns; + } + + private VTable analyseTable(TTable table) { + String fullName = table.getFullName(); + String tableAlias = table.getAliasName(); + VTable vTable = null; + if (StringUtils.isBlank(fullName)) {//子查询 + vTable = new VTable(SpUtils.generateId(table.toString(), tableAlias)); + } else if (StringUtils.isNotBlank(fullName)) {//普通表名 + String[] nameInfo = SpUtils.analyseTableName(fullName); + vTable = new VTable(nameInfo[2], nameInfo[2]); + vTable.db = mParserContext.getDefaultDb(); + vTable.schema = mParserContext.getDefaultSchema(); + } + + if (StringUtils.isNotBlank(tableAlias)) { + vTable.setAlias(tableAlias); + } + //已知的表 + VTable createdTable = mParserContext.findExistedTable(vTable.getFullName(),true); + if (createdTable != null) { + createdTable.setAlias(vTable.alias); + return createdTable; + } + switch (table.getTableType()) { + case objectname: + vTable.setRealTable(true); + //真实数据库中的表,查找表对应关系 + vTable.addColumns(new KColumnProvider().getColumns(null,table.getFullName(), mParserContext)); + break; + case subquery: + TSelectSqlStatement subQuery = table.getSubquery(); + VTable currentTable = mParserContext.getCurrentTable(); + SelectParser sp = applicationContext.getBean(SelectParser.class); + sp.initWithTable(subQuery, mParserContext, vTable, true); + sp.parse(); + mParserContext.setCurrentTable(currentTable); + //创建依赖关系 + vTable.addColumns(sp.getParseResult()); + break; //subquery + + case function: + //table.getFuncCall(); + break; + case tableExpr: + break; + case rowList: + break; + //SQL Server only + case containsTable: + break; + case freetextTable: + break; + + default: + break; + } + mParserContext.addVTable(vTable); + return vTable; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/ColumnRefFinder.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ColumnRefFinder.java new file mode 100644 index 0000000..00aaa33 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ColumnRefFinder.java @@ -0,0 +1,189 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import com.guozhi.bloodanalysis.entity.MetaColumn; +import com.guozhi.bloodanalysis.mapper.MetaBloodAnalysisMapper; +import com.guozhi.bloodanalysis.parser.common.ParserContext; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Created by Walk.Lai on 2015/8/8. + */ +@Slf4j +@Component +@Scope("prototype") +public class ColumnRefFinder { + + @Autowired + MetaBloodAnalysisMapper metaBloodAnalysisMapper; + + public void find(KColumn column, ParserContext parserContext) { + + VTable currentTable = parserContext.getCurrentTable(); + if(currentTable==null){ + return; + } + List fromTables = currentTable.getFromTables(); + + VTable foundTable = findRelatedTable(column, fromTables,parserContext); + + if (foundTable == null) {// 实在找不到 + foundTable = findRelatedTable(column,parserContext.getTableInCurrentStatement(),parserContext); + if (foundTable == null) { + log.error("找不到列对应的表:" + column.toString()); + return; + } + } + + if (foundTable.isRealTable()) { + column.db = foundTable.db; + column.schema = foundTable.schema; + column.tableName = foundTable.getName(); + column.columnPrefix = foundTable.getFullName(); + // 找到这个表,看是不是创建的临时表 + VTable table = parserContext.getCreatedTables().get(foundTable.getFullName()); + if (table == null) { + column.export = true; + // 已经是实表了,直接关联上表就行了 + if (column.isStar) { + // TODO 通过接口查找数据库获得表对应的列信息 + if (foundTable.getColumns().size() > 0) { + column.addRefColumnList(foundTable.getColumns()); + } else { + column.addRefColumnList(new KColumnProvider().getColumns(foundTable,null,parserContext)); + } + + } + } else { + column.columnPrefix = foundTable.getFullName(); + if (column.isStar) { + column.addRefColumnList(table.getColumns()); + } else { + for (KColumn c : foundTable.getColumns()) { + if (c == null) { + continue; + } + String name = (c.alias == null ? c.columnName : c.alias); + if (name.equals(column.columnName)) { + column = c; + break; + } + } + } + } + return; + } + if (column.isStar) { + if (foundTable.getColumns().size() > 0) { + column.addRefColumnList(foundTable.getColumns()); + } else { + // TODO 找到表的定义和对应列数据 + List columns = new KColumnProvider().getColumns(null,column.columnPrefix, parserContext); + column.addRefColumnList(columns); + } + } else { + for (KColumn s : foundTable.getColumns()) { + if (s == null) { + continue; + } + String name = s.alias == null ? s.columnName : s.alias; + if (name != null && name.equals(column.columnName)) { + addRefCol(s, column); + } + } + // iterFromTableColumn(column, foundTable); + } + } + + private void addRefCol(KColumn s, KColumn column) { + KColumn t = new KColumn(); + if (s.vColumn) { + List list = s.getRefColumns(); + for (KColumn _s : list) { + addRefCol(_s, column); + } + } else { + if (s.db == null || s.tableName == null || s.schema == null) { + List list = s.getRefColumns(); + for (KColumn _s : list) { + addRefCol(_s, column); + } + } else { + t.alias = s.alias; + t.columnName = s.columnName; + t.columnPrefix = s.columnPrefix; + t.db = s.db; + t.export = s.export; + t.isEvTable = s.isEvTable; + t.isStar = s.isStar; + t.schema = s.schema; + t.tableName = s.tableName; + t.vColumn = s.vColumn; + + // 在Union等情况下,一个列会关联多个表的同名列 + column.addRefColumn(t); + } + } + } + + private VTable findRelatedTable(KColumn column, List fromTables, ParserContext parserContext) { + if (fromTables.size() == 1) { + return fromTables.get(0); + } + + if (column.columnPrefix != null) {// 明确知道属于哪个表,必须找到这个表 + // TODO 如何判断列的前缀是哪个表? + for (VTable t : fromTables) { + // 一般列名的前缀也就是表名或别名,不会包含数据库等 + if (column.columnPrefix.equals(t.getAlias()) + || column.columnPrefix.equals(t.getName()) + || column.columnPrefix.equals(t.getFullName())) { + return t; + } + } + } else { + VTable t = new VTable("V" + System.currentTimeMillis()); + // 没有前缀,无法确认是哪个表的字段,需要查找数据确认字段 + for (VTable vt : fromTables) { + if(vt.isRealTable()){ + MetaColumn col = metaBloodAnalysisMapper.isColExis(vt.db,vt.schema, vt.name, column.columnName); + if(col != null){ + t = vt; + break; + } + }else{ + if(getRealTable(vt, column.columnName)){ + t = vt; + break; + } + } + } + return t; + } + return null; + } + + private boolean getRealTable(VTable t,String colName){ + boolean isExis = false; + List list = t.getFromTables(); + for (VTable vt : list) { + if(vt.isRealTable()){ + MetaColumn metaColumn = metaBloodAnalysisMapper.isColExis(vt.db,vt.schema, vt.name, colName); + if (metaColumn != null) { + isExis = true; + break; + } + }else{ + getRealTable(vt,colName); + } + } + return isExis; + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/Constants.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/Constants.java new file mode 100644 index 0000000..0126784 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/Constants.java @@ -0,0 +1,29 @@ +package com.guozhi.bloodanalysis.parser.utils; + +public class Constants { + public static String kvsImplClass = "com.pactera.edg.am.etlmapping.perlparser.perlclean.common.GenericKeyVarSimulator"; + public static String sfpImplClass = "com.pactera.edg.am.etlmapping.perlparser.perlclean.common.GenericSqlFragmentParser"; + public static String lgsImplClass = "com.pactera.edg.am.etlmapping.perlparser.perlclean.common.GenericLogGenSimulator"; + public static String lnImplClass = "com.pactera.edg.am.etlmapping.perlparser.perlclean.common.GenericLogNormalizer"; + public static String dcfppImplClass = "com.pactera.edg.am.etlmapping.perlparser.perlclean.common.GenericDbCfgFilePathParser"; + /** + * GP类脚本执行体常量定义 + */ + public static String GP_RUN_COMMAND_STR = "SUB RUN_PSQL_COMMAND"; + /** + * ORACLE类脚本执行体常量定义 + */ + public static String ORA_RUN_COMMAND_STR = "SUB RUN_SQLPLUS_COMMAND"; + /** + * TD类脚本执行体常量定义 + */ + public static String TRD_RUN_COMMAND_STR = "SUB RUN_BTEQ_COMMAND"; + + // 定义需解析文件类型 + public final static String FILE_SUFFIX = ".SQL";//PL + + //脚本状态枚举,有效、不标准、故障、不是perl脚本,无效 + public static enum fileSts { + VALID,NOTSTANDARD,FAULT,NOTPERL,INVALID + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/CryptUtils.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/CryptUtils.java new file mode 100644 index 0000000..148b054 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/CryptUtils.java @@ -0,0 +1,133 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import java.io.ByteArrayOutputStream; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESKeySpec; + +import sun.misc.BASE64Decoder; +import sun.misc.BASE64Encoder; + +public class CryptUtils { + + /** + * @param args + */ + public static void main(String[] args) { + String value = "hello12315677中国"; + String ss = getInstance().encrypt(value); + String end = getInstance().decrypt(ss); + System.out.println("加密后:" + ss); + System.out.println("解密后:" + end); + } + + private final static BASE64Encoder base64encoder = new BASE64Encoder(); + private final static BASE64Decoder base64decoder = new BASE64Decoder(); + private final static String encoding = "UTF-8"; + static byte[] keyData = { 1, 9, 8, 2, 0, 8, 2, 1 }; + + static CryptUtils utils = null; + public static CryptUtils getInstance(){ + if(utils == null){ + utils = new CryptUtils(); + } + return utils; + } + + /** + * 加密 + */ + public String encrypt(String str) { + String result = str; + if (str != null && str.length() > 0) { + try { + byte[] encodeByte = symmetricEncrypto(str.getBytes(encoding)); + result = base64encoder.encode(encodeByte); + } catch (Exception e) { + e.printStackTrace(); + } + } + return result; + } + + /** + * 解密 + */ + public String decrypt(String str) { + String result = str; + if (str != null && str.length() > 0) { + try { + byte[] encodeByte = base64decoder.decodeBuffer(str); + byte[] decoder = symmetricDecrypto(encodeByte); + result = new String(decoder, encoding); + } catch (Exception e) { + return str; +// e.printStackTrace(); + } + } + return result; + } + + /** + * 对称加密方法 + * + * @param byteSource + * 需要加密的数据 + * @return 经过加密的数据 + * @throws Exception + */ + private byte[] symmetricEncrypto(byte[] byteSource) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + int mode = Cipher.ENCRYPT_MODE; + Key key = createDESSecretKey(); + Cipher cipher = Cipher.getInstance("DES"); + cipher.init(mode, key); + byte[] result = cipher.doFinal(byteSource); + return result; + } catch (Exception e) { + throw e; + } finally { + baos.close(); + } + } + + /** + * 对称解密方法 + * + * @param byteSource + * 需要解密的数据 + * @return 经过解密的数据 + * @throws Exception + */ + private byte[] symmetricDecrypto(byte[] byteSource) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + int mode = Cipher.DECRYPT_MODE; + Key key = createDESSecretKey(); + Cipher cipher = Cipher.getInstance("DES"); + cipher.init(mode, key); + byte[] result = cipher.doFinal(byteSource); + return result; + } catch (Exception e) { + throw e; + } finally { + baos.close(); + } + } + + SecretKey createDESSecretKey() + throws NoSuchAlgorithmException, InvalidKeyException, + InvalidKeySpecException { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); + DESKeySpec keySpec = new DESKeySpec(keyData); + SecretKey key = keyFactory.generateSecret(keySpec); + return key; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/DatabaseType.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/DatabaseType.java new file mode 100644 index 0000000..c872dd3 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/DatabaseType.java @@ -0,0 +1,5 @@ +package com.guozhi.bloodanalysis.parser.utils; + +public enum DatabaseType { + Oracle, Mysql, Teradata, SqlServer, GreenPlum, DB2, TDH, HIVE +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/ErrorRecorder.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ErrorRecorder.java new file mode 100644 index 0000000..1570e06 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ErrorRecorder.java @@ -0,0 +1,14 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.utils; + +import lombok.extern.slf4j.Slf4j; +@Slf4j +public class ErrorRecorder { + +public static void logError(String error){ + log.error(error); +} +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/ExportParseResultUtil.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ExportParseResultUtil.java new file mode 100644 index 0000000..8f67f2f --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ExportParseResultUtil.java @@ -0,0 +1,125 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import java.util.*; + +import com.guozhi.bloodanalysis.entity.DataLineageInfo; +import com.guozhi.bloodanalysis.entity.MetaBloodAnalysis; +import com.guozhi.bloodanalysis.mapper.MetaBloodAnalysisMapper; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class ExportParseResultUtil { + @Autowired + private MetaBloodAnalysisMapper metaBloodAnalysisMapper; + + /** + * 从内存对象中导出数据 + * @throws Exception + */ + public void expResult(List kColumns, DataLineageInfo dataLineageInfo) throws Exception{ + log.info("正在导出解析结果"); + List result = new ArrayList<>(); + for (KColumn tCol : kColumns) { + getOutList(kColumns, tCol, tCol.getRefColumns(), result); + } + outTable(result,dataLineageInfo); + log.info("解析结果导出完成"); + } + + private void outTable(List result, DataLineageInfo dataLineageInfo){ + for (String line : result) { + String lines [] = line.split(","); + MetaBloodAnalysis metaBloodAnalysis = new MetaBloodAnalysis(); + metaBloodAnalysis.setId(UUID.randomUUID().toString().replace("-","")); + metaBloodAnalysis.setProId(dataLineageInfo.getOnum()); + metaBloodAnalysis.setProName(dataLineageInfo.getProcName()); + metaBloodAnalysis.setSourceSysCd(lines[0]); + metaBloodAnalysis.setSourceMdlName(lines[1]); + metaBloodAnalysis.setSourceTableName(lines[2]); + metaBloodAnalysis.setSourceColName(lines[3]); + metaBloodAnalysis.setTargetSysCd(lines[4]); + metaBloodAnalysis.setTargetMdlName(lines[5]); + String[] arr = lines[6].split("\\."); + String targetTableName = arr[arr.length-1]; + metaBloodAnalysis.setTargetTableName(targetTableName); + metaBloodAnalysis.setTargetColName(lines[7]); + metaBloodAnalysisMapper.insert(metaBloodAnalysis); + } + } + + private void getOutList(List kColumns,KColumn tCol,List sCols,List list){ + if(tCol.vColumn){ + for (KColumn sCol : sCols) { + getOutList(kColumns, sCol, sCol.getRefColumns(),list); + } + }else{ + for (KColumn sCol : sCols) { + if(sCol.vColumn){ + getOutList(kColumns,tCol, sCol.getRefColumns(),list); + continue; + } + //只取源表是实体表 字段信息 + if(sCol.isEvTable){ + //目标表为实体表 + if(tCol.isEvTable){ + addLineStr(tCol, sCol, list); + }else{ + String tKey = tCol.db+"."+tCol.schema+"."+tCol.tableName+"."+tCol.columnName+"."+tCol.isEvTable; + findTargetTab(kColumns, tKey, sCol, list); + } + } + + if(sCol.getRefColumns()!=null&&sCol.getRefColumns().size()>0){ + getOutList(kColumns,sCol,sCol.getRefColumns(), list); + } + } + } + } + + private void findTargetTab(List kColumns,String tKey,KColumn sCol,List list){ + for (KColumn tCol : kColumns) { + List sCols = tCol.getRefColumns(); + for (KColumn t_sCol : sCols) { + String sKey = t_sCol.db+"."+t_sCol.schema+"."+t_sCol.tableName+"."+t_sCol.columnName+"."+t_sCol.isEvTable; + //如果在源中找到则看当前目标是否为真实表 + if(tKey.equals(sKey)){ + if(tCol.isEvTable){ + addLineStr(tCol, sCol, list); + }else{ + String t_tKey = tCol.db+"."+tCol.schema+"."+tCol.tableName+"."+tCol.columnName+"."+tCol.isEvTable; + if(!t_tKey.equals(tKey)){ + findTargetTab(kColumns, t_tKey, sCol, list); + } + } + } + } + } + } + + private void addLineStr(KColumn tCol,KColumn sCol,List list){ + StringBuffer sb = new StringBuffer(); + sb.append(StringUtils.defaultString(sCol.db,"")); + sb.append(","); + sb.append(StringUtils.defaultString(sCol.schema,"")); + sb.append(","); + sb.append(StringUtils.defaultString(sCol.tableName,"")); + sb.append(","); + sb.append(StringUtils.defaultString(sCol.columnName,"")); + sb.append(","); + sb.append(StringUtils.defaultString(tCol.db,"")); + sb.append(","); + sb.append(StringUtils.defaultString(tCol.schema,"")); + sb.append(","); + sb.append(StringUtils.defaultString(tCol.tableName,"")); + sb.append(","); + sb.append(StringUtils.defaultString(tCol.columnName,"")); +// sb.append(System.getProperty("line.separator"));//jdk1.7以下 +// sb.append(System.lineSeparator()); + list.add(sb.toString()); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/ExprToColumn.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ExprToColumn.java new file mode 100644 index 0000000..aa63a0e --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/ExprToColumn.java @@ -0,0 +1,421 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import java.awt.Point; + +import com.guozhi.bloodanalysis.parser.common.ParserContext; +import com.guozhi.bloodanalysis.parser.common.SelectParser; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import gudusoft.gsqlparser.TCustomSqlStatement; +import gudusoft.gsqlparser.nodes.TAnalyticFunction; +import gudusoft.gsqlparser.nodes.TCaseExpression; +import gudusoft.gsqlparser.nodes.TExpression; +import gudusoft.gsqlparser.nodes.TExpressionList; +import gudusoft.gsqlparser.nodes.TFunctionCall; +import gudusoft.gsqlparser.nodes.TOrderByItem; +import gudusoft.gsqlparser.nodes.TOrderByItemList; +import gudusoft.gsqlparser.nodes.TParseTreeNode; +import gudusoft.gsqlparser.nodes.TParseTreeNodeList; +import gudusoft.gsqlparser.nodes.TResultColumn; +import gudusoft.gsqlparser.nodes.TWhenClauseItem; +import gudusoft.gsqlparser.nodes.TWhenClauseItemList; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * Created by Walk.Lai on 2015/7/25. + */ +@Slf4j +@Component +@NoArgsConstructor +@Data +public class ExprToColumn { + + + private TCustomSqlStatement mStmt; + private ParserContext mParserContext; + + @Autowired + ApplicationContext applicationContext; + + +public ExprToColumn(TCustomSqlStatement stmt, ParserContext context, boolean keepConst) { + mStmt = stmt; + mParserContext = context; +} + +/** + * 取得列的别名 + * @param attr + * @return + */ +private String getColumnAlias(TExpression attr){ + TParseTreeNodeList tokens = attr.getStartToken() + .getNodesStartFromThisToken(); + if (tokens != null) { + for (int i = 0; i < tokens.size(); i++) { + TParseTreeNode node = tokens.getElement(i); + if (node instanceof TResultColumn) { + TResultColumn field = (TResultColumn) node; + if (field.getAliasClause() != null) { + return field.getAliasClause().toString(); + } + } + } + } + return null; +} +/** + * 把表达式转换成列信息 + * 一般来说一个表达式只能生成一列,但如果是*的话,就可能对应多列 + * + * @param attr + * @param stmt + * @return + */ +private KColumn attrToColumn(TExpression attr, TCustomSqlStatement stmt ) { + + KColumn column = new KColumn(); + //getEndToken()取出来就是没带前缀的表名 t.a as aa =a, t.b bb =b + column.columnName = SpUtils.removeQuote(attr.getEndToken().toString()); + if(column.columnName.indexOf("*")!=-1){ + column.vColumn=true; + column.isStar=true; + } + //TODO 这一段为什么这样处理 + //getExprAlias取出来的不是别名,别名要像下边这样取 + String alias=getColumnAlias(attr); + if(alias!=null){ + column.alias=alias; + }else{ + column.alias=column.columnName; + } + + if (attr.toString().indexOf(".") > 0) { //有前缀 + column.columnPrefix = SpUtils.removeQuote(attr.toString().substring(0, + attr.toString().lastIndexOf("."))); + }else{ + + } + new ColumnRefFinder().find(column,mParserContext); + + return column; +} +public KColumn exprVisit(TParseTreeNode pNode){ + return exprVisit(pNode,true); +} +public KColumn exprVisit(TParseTreeNode pNode,boolean keepConstant) { + if(pNode==null){ + return null; + } + TExpression expr = (TExpression) pNode; + KColumn toColumn=new KColumn(); + switch (expr.getExpressionType()) { + case simple_object_name_t: //select * 也算这一种情况 + return attrToColumn(expr, mStmt); + case simple_constant_t: + //TODO 根据配置判断常量值是否要当作一列 + toColumn.columnName=expr.toString(); + toColumn.vColumn=true; + toColumn.export=keepConstant; + ColumnRefFinder columnRefFinder = applicationContext.getBean(ColumnRefFinder.class); + columnRefFinder.find(toColumn,mParserContext); + return toColumn; + case subquery_t: + VTable currentTable=mParserContext.getCurrentTable();//暂存 + SelectParser sp = applicationContext.getBean(SelectParser.class); + sp.setMSelect(expr.getSubQuery()); + sp.setVTable(new VTable(SpUtils.generateId(expr.getSubQuery().toString(),""))); + sp.setMParserContext(mParserContext); + sp.parse(); + mParserContext.setCurrentTable(currentTable);//还原 + //TODO 别名? + String alias=getColumnAlias(expr); + if(alias!=null){ + toColumn.alias=alias; + toColumn.columnName=toColumn.alias; + }else{ + Point location = new Point((int) expr.getEndToken().lineNo, + (int) expr.getEndToken().columnNo); + String columnName=SpUtils.generateId(mStmt.toString(), location.toString()); + toColumn.alias=columnName; + toColumn.columnName=toColumn.alias; + } + toColumn.addRefColumnList(sp.getParseResult()); + return toColumn; + case case_t: + return caseSide(expr); + case logical_and_t: + return analyseBothSide(expr); + case logical_or_t: + return analyseBothSide(expr); + case concatenate_t: //a||b + return analyseBothSide(expr); + case logical_not_t: + return analyseLogical_not_tSide(expr); + case null_t: + return analyseNull_TSide(expr); + case simple_comparison_t: // where a=1 中的 a=1; + return analyseBothSide(expr); + case in_t: + return analyseBothSide(expr); + case arithmetic_plus_t: + return analyseBothSide(expr); + case arithmetic_minus_t: + return analyseBothSide(expr); + case arithmetic_times_t: + return analyseBothSide(expr); + case arithmetic_divide_t: + return analyseBothSide(expr); + case typecast_t: + break; + case unknown_t: + break; + case pattern_matching_t: + break; + case unary_minus_t: + break; + case parenthesis_t: + return analyseNull_TSide(expr); + case function_t: + return functionAnalyse(expr); + case assignment_t://set a=1 中的 a=1 + return analyseBothSide(expr); + case simple_source_token_t: // select null + return null; + case arithmetic_modulo_t: + return modSide(expr); + case list_t: + return listSide(expr); + case between_t: + return betweenSide(expr); + default: + log.info("##【留】【意】--没有检测到当前类型 : "+expr.getExpressionType()); + return null; + } + return null; +} + +private KColumn betweenSide(TExpression expr){ + KColumn column = new KColumn(); + String alias = getColumnAlias(expr); + column.vColumn = true; + column.columnName = SpUtils.generateId(expr.toString(),""); + if (alias!= null) { + column.alias = alias; + }else{ + column.alias = column.columnName; + } + column.addRefColumn(exprVisit(expr.getLeftOperand())); + column.addRefColumn(exprVisit(expr.getRightOperand())); + return column; +} + +private KColumn listSide(TExpression expr){ + KColumn column = new KColumn(); + String alias = getColumnAlias(expr); + column.vColumn = true; + column.columnName = SpUtils.generateId(expr.toString(),""); + if (alias!= null) { + column.alias = alias; + }else{ + column.alias = column.columnName; + } + TExpressionList expList = expr.getExprList(); + for (int i = 0; i < expList.size(); i++) { + TExpression exp = expList.getExpression(i); + column.addRefColumn(this.exprVisit(exp)); + } + return column; +} + +private KColumn modSide(TExpression expr){ + KColumn column = new KColumn(); + String alias = getColumnAlias(expr); + column.vColumn = true; + column.columnName = SpUtils.generateId(expr.toString(),""); + if (alias!= null) { + column.alias = alias; + }else{ + column.alias = column.columnName; + } + column.addRefColumn(analyseLeft(expr)); + return column; +} + +private KColumn caseSide(TExpression expr){ + KColumn column = new KColumn(); + column.vColumn = true; + column.columnName = SpUtils.generateId(expr.toString(),""); + String alias=getColumnAlias(expr); + if (alias!= null) { + column.alias = alias; + } + TCaseExpression caseExp = expr.getCaseExpression(); +// column.columnName = caseExp.toString().replaceAll("\r\n", ""); + //情况太复杂了,暂时不考虑case when的具体取值,如需要后期优化 + TWhenClauseItemList whenList = caseExp.getWhenClauseItemList(); + for (int i = 0; i < whenList.size(); i++) { + TWhenClauseItem item = whenList.getWhenClauseItem(i); + TExpression tExpr = item.getReturn_expr(); + TExpression sExpr = item.getComparison_expr(); + KColumn tCol = this.exprVisit(tExpr); + column.addRefColumn(tCol); + column.addRefColumn(analyseRight(sExpr)); + column.addRefColumn(analyseLeft(sExpr)); + } + column.addRefColumn(exprVisit(caseExp.getElse_expr())); + ColumnRefFinder crf = applicationContext.getBean(ColumnRefFinder.class); + crf.find(column,mParserContext); + return column; +} + +private KColumn analyseNull_TSide(TExpression expr) { + KColumn column = new KColumn(); + column.vColumn = true; + Point location = new Point((int) expr.getEndToken().lineNo, + (int) expr.getEndToken().columnNo); + column.columnName = SpUtils.generateId(mStmt.toString(), location.toString()); + + String alias=getColumnAlias(expr); + if (alias!= null) { + column.alias = alias; + }else{ + column.alias=column.columnName; + } + column.addRefColumn(exprVisit(expr.getLeftOperand())); + return column; +} + +private KColumn analyseLogical_not_tSide(TExpression expr) { + KColumn column = new KColumn(); + column.vColumn = true; + Point location = new Point((int) expr.getEndToken().lineNo, + (int) expr.getEndToken().columnNo); + column.columnName = SpUtils.generateId(mStmt.toString(), location.toString()); + + String alias=getColumnAlias(expr); + if (alias!= null) { + column.alias = alias; + }else{ + column.alias=column.columnName; + } + column.addRefColumn(exprVisit(expr.getRightOperand())); + return column; +} + +private KColumn analyseBothSide(TExpression expr) { + KColumn column = new KColumn(); + column.vColumn = true; + Point location = new Point((int) expr.getEndToken().lineNo, + (int) expr.getEndToken().columnNo); + column.columnName = SpUtils.generateId(mStmt.toString(), location.toString()); + + String alias=getColumnAlias(expr); + if (alias!= null) { + column.alias = alias; + }else{ + column.alias=column.columnName; + } + + column.addRefColumn(exprVisit(expr.getLeftOperand())); + column.addRefColumn(exprVisit(expr.getRightOperand())); + + return column; +} + +private KColumn analyseRight(TExpression expr) { + return exprVisit(expr.getRightOperand()); +} + + +private KColumn analyseLeft(TExpression expr) { + return exprVisit(expr.getLeftOperand()); +} + + +private KColumn functionAnalyse(TExpression expr){ + KColumn column=new KColumn(); + column.vColumn=true; + Point location = new Point((int) expr.getEndToken().lineNo, + (int) expr.getEndToken().columnNo); + String columnName=SpUtils.generateId(mStmt.toString(), location.toString()); + column.columnName=columnName; + String alias=getColumnAlias(expr); + if(alias!=null){ + column.alias=alias; + }else { + column.alias = columnName; + } + TFunctionCall func = expr.getFunctionCall(); + //System.out.println(func.getFunctionName()); + switch ((func.getFunctionType())){ + case extract_t: + case cast_t: + column.addRefColumn(this.exprVisit(func.getExpr1())); + break; + case trim_t: + column.addRefColumn(this.exprVisit(func.getTrimArgument().getStringExpression())); + break; + case unknown_t: + if (func.getArgs() != null){ + for ( int k = 0; k < func.getArgs( ).size( ); k++ ){ + TExpression argExpr=func.getArgs( ).getExpression(k); + column.addRefColumn(this.exprVisit(argExpr,false)); + } + }else if("DENSE_RANK".equals(func.getFunctionName()+"")||"ROW_NUMBER".equals(func.getFunctionName()+"")){ + TAnalyticFunction afun = func.getAnalyticFunction(); + //TODO wxl PARTITION BY.. 语句报错 +// TExpressionList expressionList = afun.getPartitionBy_ExprList(); +// if(expressionList!=null){ +// for ( int k = 0; k < expressionList.size( ); k++ ){ +// TExpression exp = expressionList.getExpression(k); +// column.addRefColumn(this.exprVisit(exp,false)); + column.addRefColumn(null); +// } +// } + } + break; + case rank_t: + TAnalyticFunction analy = func.getAnalyticFunction(); + if(analy!=null){ + TExpressionList expList = analy.getPartitionBy_ExprList(); + if(expList!=null){ + for (int i = 0; i < expList.size(); i++) { + TExpression exp = expList.getExpression(i); + column.addRefColumn(this.exprVisit(exp,false)); + } + } + }else{ + TOrderByItemList odrList = func.getOrderByList(); + if(odrList!=null){ + for (int i = 0; i < odrList.size(); i++) { + TOrderByItem item = odrList.getOrderByItem(i); + column.addRefColumn(this.exprVisit(item.getSortKey(),false)); + } + } + } + break; + case csum_t: + TOrderByItemList odrList = func.getOrderByList(); + if(odrList!=null){ + for (int i = 0; i < odrList.size(); i++) { + TOrderByItem item = odrList.getOrderByItem(i); + column.addRefColumn(this.exprVisit(item.getSortKey(),false)); + } + } + break; + case substring_t: + column.addRefColumn(this.exprVisit(func.getExpr1())); + break; + default: + log.info("##【留】【意】--没有检测到当前函数类型 : "+func); + break; + } + return column; +} +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/KColumnProvider.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/KColumnProvider.java new file mode 100644 index 0000000..43aa32a --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/KColumnProvider.java @@ -0,0 +1,76 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import com.guozhi.bloodanalysis.mapper.MetaBloodAnalysisMapper; +import com.guozhi.bloodanalysis.parser.common.ParserContext; +import com.guozhi.bloodanalysis.parser.vo.KColumn; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * User: Administrator + * Date: 2015/7/28 + * Time: 22:11 + */ +@Component +@Scope("prototype") +public class KColumnProvider { + + @Autowired + MetaBloodAnalysisMapper metaBloodAnalysisMapper; + + public List getColumns(VTable vt , String tableName, ParserContext context) { + if (context != null&&tableName!=null) { + VTable table = context.findTableInCurrentStatement(tableName); + if (table == null) { + table = context.findExistedTable(tableName,false); + } + if (table != null && table.getColumns().size() > 0) { + return table.getColumns(); + }else { + String[] arr = tableName.split("\\."); + List> colList = metaBloodAnalysisMapper.getColumnsByTable(arr[arr.length-1], context.getDefaultDb(),context.getDefaultSchema()); + if(colList.size()>0){ + List cols = new ArrayList(); + for (Map colMap : colList) { + KColumn col = new KColumn(); +// col.columnPrefix = vt.alias; + col.columnName = colMap.get("colCode"); + col.alias = col.columnName; + col.db = context.getDefaultDb(); + col.schema = context.getDefaultSchema(); + col.tableName = tableName; + col.isEvTable = true; + cols.add(col); + } + return cols; + } + } + } + if(vt!=null&&vt.tabId!=null){ + List> colList = metaBloodAnalysisMapper.getColumnsByTabId(vt.tabId, null); + if(colList.size()>0){ + List cols = new ArrayList(); + for (Map colMap : colList) { + KColumn col = new KColumn(); + col.columnPrefix = vt.alias; + col.columnName = colMap.get("colCode"); + col.alias = col.columnName; + col.db = vt.db; + col.schema = vt.schema; + col.tableName = vt.name; + col.isEvTable = true; + cols.add(col); + } + return cols; + } + } + return null; + } + +} \ No newline at end of file diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/KDatabaseProvider.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/KDatabaseProvider.java new file mode 100644 index 0000000..f170f25 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/KDatabaseProvider.java @@ -0,0 +1,81 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import com.guozhi.bloodanalysis.mapper.MetaBloodAnalysisMapper; +import com.guozhi.bloodanalysis.parser.common.ParserContext; +import com.guozhi.bloodanalysis.parser.vo.VTable; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + + +/** + * User: Administrator + * Date: 2015/7/28 + * Time: 22:11 + */ +@Component +@Scope("prototype") +public class KDatabaseProvider { + + @Autowired + MetaBloodAnalysisMapper bloodAnalysisMapper; + + @Autowired + ApplicationContext applicationContext; + + public void getDatabase(VTable vTable, ParserContext context) { + boolean realTable = true; + List schemas = new ArrayList<>(); + schemas.add(vTable.schema); + if(schemas.size()>1){ + for (String schema : schemas) { + List> sysList = bloodAnalysisMapper.getSystem(schema, vTable.name); + if(sysList.size()>0){ + addRealTables(vTable, sysList, schema, context); + realTable = false; + } + } + }else{ + List> sysList = bloodAnalysisMapper.getSystem(schemas.get(0), vTable.name); + if(sysList.size()>1){ + addRealTables(vTable, sysList, schemas.get(0), context); + }else if(sysList.size()>0){ + Map sysMap = sysList.get(0); + vTable.db = (String) sysMap.get("SYS_CODE"); + vTable.tabId = (String) sysMap.get("TAB_ID"); + KColumnProvider kColumnProvider = applicationContext.getBean(KColumnProvider.class); + vTable.addColumns(kColumnProvider.getColumns(vTable, null, context)); + } + } + //如果是多个,无法准确的明确出来 + vTable.setRealTable(realTable); + } + + private void addRealTables(VTable vTable , List> sysList,String schema, ParserContext context){ + int i = 1; + for (Map map : sysList) { + String sysCode = (String)map.get("SYS_CODE"); + String schCode = (String)map.get("SCH_CODE"); + String tabCode = (String)map.get("TAB_CODE"); + VTable vt = new VTable(tabCode); + vt.db = sysCode; + vt.schema = schCode; + vt.alias = "T_"+schema+"_"+(i++); + Integer tabId = (Integer) map.get("TAB_ID"); + vt.tabId = String.valueOf(tabId); + vt.setRealTable(true); + KColumnProvider kColumnProvider = applicationContext.getBean(KColumnProvider.class); + vt.addColumns(kColumnProvider.getColumns(vt, null, context)); + vTable.addTable(vt); + vTable.addColumns(vt.getColumns()); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/PartitionTool.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/PartitionTool.java new file mode 100644 index 0000000..020d9a9 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/PartitionTool.java @@ -0,0 +1,49 @@ +package com.guozhi.bloodanalysis.parser.utils; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class PartitionTool { + + private static Log logger = LogFactory.getLog(PartitionTool.class); + + public void truncatePartitionIfExistOrAddPartition(Connection con,Map param){ + truncatePartitionIfExist(con,param); + addPartitionIfNoExist(con,param); + } + + public boolean truncatePartitionIfExist(Connection con,Map map) { + String produceSql = "{call droppartition(?,?,?) }"; + boolean bool = execute(con,produceSql,map); + return bool; + } + + public boolean addPartitionIfNoExist(Connection con,Map map) { + String produceSql = "{call addpartition(?,?,?) }"; + boolean bool = execute(con,produceSql,map); + return bool; + } + + private boolean execute(Connection con,String produceSql,Map map){ + + String scheName = map.get("scheName"); + String tableName = map.get("tarTable"); + String partitionName = map.get("partitionName"); + logger.info("调用"+partitionName+"存储过程,参数为"+"["+scheName+","+tableName+","+partitionName+"]"); + try { + CallableStatement call = con.prepareCall(produceSql); + call.setString(1, scheName); + call.setString(2, tableName); + call.setString(3, partitionName); + return call.execute(); + } catch (SQLException e) { + logger.error("调用"+partitionName+"存储过程失败,参数为"+"["+scheName+","+tableName+","+partitionName+"]",e); + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/utils/SpUtils.java b/src/main/java/com/guozhi/bloodanalysis/parser/utils/SpUtils.java new file mode 100644 index 0000000..9f4b872 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/utils/SpUtils.java @@ -0,0 +1,123 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.utils; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; + +import lombok.extern.slf4j.Slf4j; + +import sun.misc.BASE64Encoder; + +@Slf4j +public class SpUtils { + +public static String removeQuote(String string) { + if (string != null && string.indexOf('.') != -1) { + String[] splits = string.split("\\."); + StringBuffer result = new StringBuffer(); + for (int i = 0; i < splits.length; i++) { + result.append(removeQuote(splits[i])); + if (i < splits.length - 1) { + result.append("."); + } + } + return result.toString(); + } + if (string != null && string.startsWith("\"") && string.endsWith("\"")) + return string.substring(1, string.length() - 1); + return string; +} + +public static String generateId(String wholeSQL, String idStr) { + //确定计算方法 + StringBuilder sb = new StringBuilder(wholeSQL).append(idStr); + try { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + BASE64Encoder base64en = new BASE64Encoder(); + + //加密后的字符串 + + return base64en.encode(md5.digest(sb.toString().getBytes("utf-8"))); + }catch ( NoSuchAlgorithmException e){ + log.error(e.getMessage()); + }catch (UnsupportedEncodingException e){ + log.error(e.getMessage()); + } + return sb.toString(); +} + +public static String[] analyseTableName(String name){ + name=removeQuote(name); + String[] arr=name.split("\\.",3); + String[] ret=new String[]{null,null,null,null}; //db.schema.table.column + + if(arr.length==1){ //只有表名 + ret[2]=arr[0]; + }else if(arr.length==2){//schema.table + ret[0]=arr[0]; + ret[1]=arr[0]; + ret[2]=arr[1]; + }else if(arr.length==3) {//db.schema.table + ret[0]=arr[0]; + ret[1]=arr[1]; + ret[2]=arr[2]; + } + return ret; + +} + +public static void deleteDir(String filePath){ + /*try { + // 创建多层目录 + if(file.isDirectory()){ + String[] children = file.list(); + //递归删除目录中的子目录下 + for (int i=0; i titles; + /* + * excel数据 + */ + //private List datas; + private List> datas; + + public ExcelSheet(String sheetName, boolean merged, Map titles, List> datas) { + super(); + this.sheetName = sheetName; + this.merged = merged; + this.titles = titles; + this.datas = datas; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public boolean isMerged() { + return merged; + } + + public void setMerged(boolean merged) { + this.merged = merged; + } + + public Map getTitles() { + return titles; + } + + public void setTitles(Map titles) { + this.titles = titles; + } + + public List> getDatas() { + return datas; + } + + public void setDatas(List> datas) { + this.datas = datas; + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/vo/KColumn.java b/src/main/java/com/guozhi/bloodanalysis/parser/vo/KColumn.java new file mode 100644 index 0000000..1b54454 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/vo/KColumn.java @@ -0,0 +1,146 @@ +/* + Copyright 2015 Dell Inc. + ALL RIGHTS RESERVED. +*/ +package com.guozhi.bloodanalysis.parser.vo; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class KColumn { + /** + * 数据库标识 + */ + public String db; + /** + * 模式Schema + */ + public String schema; + /** + * 表名称 + */ + public String tableName; + /** + * 字段前缀 + */ + public String columnPrefix; + /** + * 字段名称--业务主键 + */ + public String columnName; + /** + * 字段别名 + */ + public String alias;//只在同一个语句中起作用,上下文中该字段没意义 + + public boolean isEvTable = true; + + public boolean vColumn = false; + public boolean isStar=false; + public boolean export=false; + + private List refColumns = new ArrayList(); //必须使用列表以确保顺序 + private Set whereColumns=new HashSet(); + + /** + * etl标志。记录源标志。 + */ + public String etlFlag; + + /** + * grc etl标志字段名称 + */ + public final static String etlSrcTabName="ETL_SRC_TBL_NAME"; + public KColumn() { + + } + + public void addRefColumn(KColumn column) { + if(column!=null){ + for(KColumn col: refColumns){ + if(StringUtils.equals(col.db,column.db)&&StringUtils.equals(col.schema,column.schema) + &&StringUtils.equals(col.tableName,column.tableName) + &&StringUtils.equals(col.columnName,column.columnName) + && StringUtils.equals(col.columnPrefix,column.columnPrefix)){ + //已存在,不再次加入 + return; + } + } + this.refColumns.add(column); + } + } + + public void addRefColumnList(Collection columns) { + if(columns!=null) + this.refColumns.addAll(columns); + } + + public void setRefColumnList(List columns) { + if(columns!=null) + this.refColumns = columns; + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(db+"."+schema+"."+tableName + "." + columnName ); + if(alias!=null){ + sb.append(" as "+alias); + } + if (refColumns.size() > 0) { + sb.append(" <-- "+ refColumns.toString()); + } + return sb.toString(); + } + + public String toCypherString(){ + StringBuilder sb=new StringBuilder(); + sb.append("{name:\""); + sb.append(columnName); + sb.append("\",db:\""); + sb.append(db); + sb.append("\",schema:\""); + sb.append(schema); + sb.append("\",tableName:\""); + sb.append(tableName); + // sb.append("\",vColumn:\""); + // sb.append(vColumn); + // sb.append("\",isStar:\""); + // sb.append(isStar); + sb.append("\",export:\""); + sb.append(export); + sb.append("\"}"); + return sb.toString(); + } + + public String queryDependsString(){ + StringBuilder sb=new StringBuilder(); + sb.append("Match (c:Column {name:\""); + sb.append(columnName); + sb.append("\",db:\""); + sb.append(db); + sb.append("\",schema:\""); + sb.append(schema); + sb.append("\",tableName:\""); + sb.append(tableName); + sb.append("\",export:'true'}),\n (c)-[:DEPENDS*1..10]->(c1 {export:'true'}) return c1"); + return sb.toString(); + } + + public List getRefColumns() { + return refColumns; + } + + public String getEtlFlag() { + return etlFlag; + } + + public void setEtlFlag(String etlFlag) { + this.etlFlag = etlFlag; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/parser/vo/VTable.java b/src/main/java/com/guozhi/bloodanalysis/parser/vo/VTable.java new file mode 100644 index 0000000..9482a75 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/parser/vo/VTable.java @@ -0,0 +1,141 @@ +package com.guozhi.bloodanalysis.parser.vo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Walk.Lai on 2015/8/2. + */ +public class VTable { + + /** + * 数据库中的表instId + */ + public String tabId; + /** + * 数据库标识 + */ + public String db; + /** + * 数据库Schema + */ + public String schema; + /** + * 数据库表名 + */ + public String name; + /** + * 表别名 + */ + public String alias;// 只在同一个语句中起作用,上下文中该字段没意义 + /** + * 是否被依赖的表 + */ + private boolean realTable = false; + /** + * 是否实体表,相对于临时表来讲 false临时表,true实体表 + */ + private boolean created = true; + /** + * 表字段集合 + */ + private List columns = new ArrayList<>(); + /** + * 来源表集合 + */ + private List fromTables = new ArrayList<>(); + /** + * grc 记录级解析标志 + */ + public String etlFlag; + + public VTable(String name) { + this.name = name; + } + + public VTable(String name, String alias) { + this.name = name; + this.alias = alias; + } + + public String getName() { + return name; + } + + public String getFullName() { + StringBuilder sb = new StringBuilder(); + sb.append(db); + sb.append("."); + if (schema != null) { + sb.append(schema); + sb.append("."); + } + sb.append(name); + return sb.toString(); + } + + public List getColumns() { + return columns; + } + + public List getFromTables() { + return fromTables; + } + + public void addColumn(KColumn column) { + columns.add(column); + } + + public void addColumns(List column) { + if (column != null) { + columns.addAll(column); + } + } + public void emptyColumns() { + columns.clear(); + } + + public void addTable(VTable table) { + fromTables.add(table); + } + + public boolean isRealTable() { + return realTable; + } + + public void setRealTable(boolean realTable) { + this.realTable = realTable; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + public boolean isCreated() { + return created; + } + + public void setCreated(boolean created) { + this.created = created; + } + + public String toCypherString() { + StringBuilder sb = new StringBuilder(); + sb.append("{db:\""); + sb.append(db); + sb.append("\",schema:\""); + sb.append(schema); + sb.append("\",name:\""); + sb.append(name); + sb.append("\",realTable:\""); + sb.append(realTable); + sb.append("\",created:\""); + sb.append(created); + sb.append("\"}"); + return sb.toString(); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/service/BloodAnalysisService.java b/src/main/java/com/guozhi/bloodanalysis/service/BloodAnalysisService.java new file mode 100644 index 0000000..1823b1a --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/service/BloodAnalysisService.java @@ -0,0 +1,110 @@ +package com.guozhi.bloodanalysis.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageHelper; +import com.guozhi.bloodanalysis.entity.DataLineageInfo; +import com.guozhi.bloodanalysis.mapper.DataLineageInfoMapper; +import com.guozhi.bloodanalysis.mapper.MetaBloodAnalysisMapper; +import com.guozhi.bloodanalysis.parser.SqlParser; +import com.guozhi.bloodanalysis.utils.RedisUtils; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class BloodAnalysisService { + + @Autowired + DataLineageInfoMapper dataLineageInfoMapper; + + @Autowired + ApplicationContext applicationContext; + + @Value("${blood-analysis.pageNum}") + Integer pageNum; + + @Value("${blood-analysis.pageSize}") + Integer pageSize; + + @Value("${databaseUrl}") + String databaseUrl; + + @Autowired + MetaBloodAnalysisMapper mapper; + + @Autowired + RedisUtils redisUtils; +// @Autowired +// HttpServletRequest request; + + @Async + public void analysis(String dashUserName,String dashPassword) { + redisUtils.set("startBloodAnalysis",true); + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + // 1. 创建 POST 请求 + HttpGet get = new HttpGet(databaseUrl); + // 2. 设置请求头(可选) + get.setHeader("Content-Type", "application/json"); + get.setHeader("dashUserName",dashUserName); + get.setHeader("dashPassword",dashPassword); + // 4. 执行请求 + try (CloseableHttpResponse response = httpClient.execute(get)) { + // 5. 获取响应 + HttpEntity entity = response.getEntity(); + if (entity != null) { + String responseStr = EntityUtils.toString(entity); + JSONObject obj = JSON.parseObject(responseStr); + JSONObject data = obj.getJSONObject("data"); + JSONArray totalList = data.getJSONArray("totalList"); + List> list = new ArrayList<>(); + if (totalList !=null && totalList.size()>0){ + for (int i = 0; i < totalList.size(); i++) { + JSONObject database = totalList.getJSONObject(i); + Map map = new HashMap<>(); + map.put(database.getString("name"),database.getString("type")); + list.add(map); + } + mapper.deleteAllBloodData(); + parse(pageNum,pageSize,list); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + redisUtils.set("startBloodAnalysis",false); + } + } + + public void parse(Integer pageNum, Integer pageSize, List> databaseList) throws Exception { + PageHelper.startPage(pageNum,pageSize); + List list = dataLineageInfoMapper.search(); + if (list != null && list.size()>0){ + //访问dolphinscheduler接口,获取数据库名称以及对应的类型列表 + for (DataLineageInfo dataLineageInfo : list) { + SqlParser sqlParser = applicationContext.getBean(SqlParser.class); + sqlParser.parse(dataLineageInfo,databaseList); + } + } + if (list != null && list.size() == pageSize){ + parse(pageNum+1,pageSize,databaseList); + } + } + +} diff --git a/src/main/java/com/guozhi/bloodanalysis/utils/ApiResult.java b/src/main/java/com/guozhi/bloodanalysis/utils/ApiResult.java new file mode 100644 index 0000000..f757aec --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/utils/ApiResult.java @@ -0,0 +1,81 @@ +package com.guozhi.bloodanalysis.utils; + +public class ApiResult { + private Integer code; // 状态码 + private String msg; // 返回的信息 + private T data; // 返回的数据 + + /** + * 成功时候的调用(有数据) + * @param data + * @param + * @return + */ + public static ApiResult success(T data){ + return new ApiResult(data); + } + + /** + * 成功时候的调用(无数据) + * @param + * @return + */ + public static ApiResult success(){ + return new ApiResult(); + } + + /** + * 异常时候的调用(有msg参数) + * @param msg + * @param + * @return + */ + public static ApiResult error(Integer code,String msg){ + return new ApiResult(code,msg); + } + + public static ApiResult error(String msg){ + return new ApiResult(msg); + } + + /** + * 异常时候的调用(无msg参数) + * @param + * @return + */ + public static ApiResult error(){ + return new ApiResult("error"); + } + + private ApiResult(T data) { + this.code = 200; + this.msg = "success"; + this.data = data; + } + + private ApiResult() { + this.code = 200; + this.msg = "success"; + } + + private ApiResult(String msg) { + this.code = 400; + this.msg = msg; + } + private ApiResult(Integer code,String msg) { + this.code = code; + this.msg = msg; + } + + public Integer getCode() { + return code; + } + + public String getMsg() { + return msg; + } + + public T getData() { + return data; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/utils/DateUtils.java b/src/main/java/com/guozhi/bloodanalysis/utils/DateUtils.java new file mode 100644 index 0000000..2031874 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/utils/DateUtils.java @@ -0,0 +1,15 @@ +package com.guozhi.bloodanalysis.utils; + +import org.springframework.stereotype.Component; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +@Component +public class DateUtils { + public String getFormateByDate(Date date){ + DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return sdf.format(date); + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/utils/EncryptUtils.java b/src/main/java/com/guozhi/bloodanalysis/utils/EncryptUtils.java new file mode 100644 index 0000000..406a84e --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/utils/EncryptUtils.java @@ -0,0 +1,31 @@ +package com.guozhi.bloodanalysis.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class EncryptUtils { + + public static String encryptSHA256(String str){ + return sha("SHA-256",str); + } + private static String sha(String type,String str){ + String result = null; + try { + MessageDigest md = MessageDigest.getInstance(type); + md.update(str.getBytes()); + byte[] byteBuffer = md.digest(); + StringBuilder strHexString = new StringBuilder(); + for (byte b : byteBuffer) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + strHexString.append('0'); + } + strHexString.append(hex); + } + result = strHexString.toString(); + }catch (NoSuchAlgorithmException e){ + e.printStackTrace(); + } + return result; + } +} diff --git a/src/main/java/com/guozhi/bloodanalysis/utils/RedisUtils.java b/src/main/java/com/guozhi/bloodanalysis/utils/RedisUtils.java new file mode 100644 index 0000000..e142374 --- /dev/null +++ b/src/main/java/com/guozhi/bloodanalysis/utils/RedisUtils.java @@ -0,0 +1,588 @@ +package com.guozhi.bloodanalysis.utils; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@Component +public final class RedisUtils { + + @Resource + private RedisTemplate redisTemplate; + + // =============================common============================ + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete((Collection) CollectionUtils.arrayToList(key)); + } + } + } + + + // ============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public Object get(String key) { + return key == null ? null : redisTemplate.opsForValue().get(key); + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + + public boolean set(String key, Object value) { + try { + redisTemplate.opsForValue().set(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + + public boolean set(String key, Object value, long time) { + try { + if (time > 0) { + redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 递增 + * + * @param key 键 + * @param delta 要增加几(大于0) + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, delta); + } + + + /** + * 递减 + * + * @param key 键 + * @param delta 要减少几(小于0) + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisTemplate.opsForValue().increment(key, -delta); + } + + + // ================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + */ + public Object hget(String key, String item) { + return redisTemplate.opsForHash().get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + */ + public boolean hmset(String key, Map map) { + try { + redisTemplate.opsForHash().putAll(key, map); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisTemplate.opsForHash().putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisTemplate.opsForHash().put(key, item, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisTemplate.opsForHash().put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisTemplate.opsForHash().delete(key, item); + } + + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisTemplate.opsForHash().hasKey(key, item); + } + + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + */ + public double hincr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, by); + } + + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + */ + public double hdecr(String key, String item, double by) { + return redisTemplate.opsForHash().increment(key, item, -by); + } + + + // ============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + */ + public Set sGet(String key) { + try { + return redisTemplate.opsForSet().members(key); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisTemplate.opsForSet().isMember(key, value); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisTemplate.opsForSet().add(key, values); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisTemplate.opsForSet().add(key, values); + if (time > 0) + expire(key, time); + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + + /** + * 获取set缓存的长度 + * + * @param key 键 + */ + public long sGetSetSize(String key) { + try { + return redisTemplate.opsForSet().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + + public long setRemove(String key, Object... values) { + try { + Long count = redisTemplate.opsForSet().remove(key, values); + return count; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + // ===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + */ + public List lGet(String key, long start, long end) { + try { + return redisTemplate.opsForList().range(key, start, end); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * 获取list缓存的长度 + * + * @param key 键 + */ + public long lGetListSize(String key) { + try { + return redisTemplate.opsForList().size(key); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + */ + public Object lGetIndex(String key, long index) { + try { + return redisTemplate.opsForList().index(key, index); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + */ + public boolean lSet(String key, Object value) { + try { + redisTemplate.opsForList().rightPush(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + */ + public boolean lSet(String key, Object value, long time) { + try { + redisTemplate.opsForList().rightPush(key, value); + if (time > 0) + expire(key, time); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + } + + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List value) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + + } + + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisTemplate.opsForList().rightPushAll(key, value); + if (time > 0) + expire(key, time); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisTemplate.opsForList().set(key, index, value); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + + public long lRemove(String key, long count, Object value) { + try { + Long remove = redisTemplate.opsForList().remove(key, count, value); + return remove; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..eb04a80 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,74 @@ +server: + port: 8082 + servlet: + context-path: /bloodAnalysis +spring: + main: + allow-circular-references: true + application: + name: blood-analysis + data: + redis: + repositories: + enabled: false + datasource: + type: com.alibaba.druid.pool.DruidDataSource + initialSize: 10 + minIdle: 10 + maxActive: 200 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 30000 + validationQuery: select 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + # 打开PSCache,并且指定每个连接上PSCache的大小 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + # 配置监控统计拦截的filters + filters: stat,wall,slf4j + # 通过connectProperties属性来打开mergeSql功能;慢SQL记录 + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + redis: + host: 192.168.0.3 +# host: 127.0.0.1 + port: 6379 +master: + datasource: +# url: jdbc:mysql://192.168.0.3:3306/TrunkSystem?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true +# username: admin +# password: 123456 + url: jdbc:mysql://47.113.147.166:3306/vfa_test_0115?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: dbf + password: 1q2w3e4r + driverClassName: com.mysql.cj.jdbc.Driver + + +mybatis: + mapper-locations: classpath:mapper/*.xml + type-aliases-package: com.xgqc.dispatch.entity + configuration: +# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + log-impl: org.apache.ibatis.logging.log4j2.Log4j2Impl + type-handlers-package: com.xgqc.dispatch.typeHandler +pagehelper: +# helper-dialect: mysql + params: count=countSql + reasonable: true + support-methods-arguments: true + auto-runtime-dialect: true + auto-dialect: true +logging: + config: classpath:log4j2-dev.xml + level: + com.xgqc.dispatch.mapper: DEBUG + +blood-analysis: + pageNum: 1 + pageSize: 1000 + +databaseUrl: http://47.121.207.11:12345/dolphinscheduler/datasources/withpwdlist?pageNo=1&pageSize=100 diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..7191684 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,25 @@ +develop by yfxue +//////////////////////////////////////////////////////////////////// +// _ooOoo_ // +// o8888888o // +// 88" . "88 // +// (| ^_^ |) // +// O\ = /O // +// ____/`---'\____ // +// .' \\| |// `. // +// / \\||| : |||// \ // +// / _||||| -:- |||||- \ // +// | | \\\ - /// | | // +// | \_| ''\---/'' | | // +// \ .-\__ `-` ___/-. / // +// ___`. .' /--.--\ `. . ___ // +// ."" '< `.___\_<|>_/___.' >'"". // +// | | : `- \`.;`\ _ /`;.`/ - ` : | | // +// \ \ `-. \_ __\ /__ _/ .-` / / // +// ========`-.____`-.___\_____/___.-`____.-'======== // +// `=---=' // +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// 佛祖保佑 永不宕机 永无BUG // +//////////////////////////////////////////////////////////////////// +${AnsiColor.BRIGHT_BLUE} +::: Project (version:${application.version}) ::: \(^O^)/ Spring-Boot ${spring-boot.version} \ No newline at end of file diff --git a/src/main/resources/log4j2-dev.xml b/src/main/resources/log4j2-dev.xml new file mode 100644 index 0000000..85be066 --- /dev/null +++ b/src/main/resources/log4j2-dev.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/DataLineageInfoMapper.xml b/src/main/resources/mapper/DataLineageInfoMapper.xml new file mode 100644 index 0000000..8619d35 --- /dev/null +++ b/src/main/resources/mapper/DataLineageInfoMapper.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/MetaBloodAnalysisMapper.xml b/src/main/resources/mapper/MetaBloodAnalysisMapper.xml new file mode 100644 index 0000000..ededbf0 --- /dev/null +++ b/src/main/resources/mapper/MetaBloodAnalysisMapper.xml @@ -0,0 +1,55 @@ + + + + + insert into meta_blood_analysis (id,proId,proName, + targetSysCd,targetMdlName,targetTableName,targetTableCnName,targetColName,targetColCnName,targetColType, + sourceSysCd,sourceMdlName,sourceTableName,sourceTableCnName,sourceColName,sourceColCnName,sourceColType) + values( + #{blood.id,jdbcType=VARCHAR}, + #{blood.proId,jdbcType=INTEGER}, + #{blood.proName,jdbcType=VARCHAR}, + #{blood.targetSysCd,jdbcType=VARCHAR}, + #{blood.targetMdlName,jdbcType=BOOLEAN}, + #{blood.targetTableName,jdbcType=VARCHAR}, + #{blood.targetTableCnName,jdbcType=VARCHAR}, + #{blood.targetColName,jdbcType=VARCHAR}, + #{blood.targetColCnName,jdbcType=VARCHAR}, + #{blood.targetColType,jdbcType=VARCHAR}, + #{blood.sourceSysCd,jdbcType=VARCHAR}, + #{blood.sourceMdlName,jdbcType=BOOLEAN}, + #{blood.sourceTableName,jdbcType=VARCHAR}, + #{blood.sourceTableCnName,jdbcType=VARCHAR}, + #{blood.sourceColName,jdbcType=VARCHAR}, + #{blood.sourceColCnName,jdbcType=VARCHAR}, + #{blood.sourceColType,jdbcType=VARCHAR} + ) + + + + + + + delete from meta_blood_analysis + + \ No newline at end of file diff --git a/src/test/java/com/guozhi/bloodanalysis/BloodAnalysisApplicationTests.java b/src/test/java/com/guozhi/bloodanalysis/BloodAnalysisApplicationTests.java new file mode 100644 index 0000000..d5af5c7 --- /dev/null +++ b/src/test/java/com/guozhi/bloodanalysis/BloodAnalysisApplicationTests.java @@ -0,0 +1,13 @@ +package com.guozhi.bloodanalysis; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class BloodAnalysisApplicationTests { + + @Test + void contextLoads() { + } + +}