1

parents
Pipeline #298 failed with stages
/mvnw text eol=lf
*.cmd text eol=crlf
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/
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
#!/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.4
#
# 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:]'
}
scriptDir="$(dirname "$0")"
scriptName="$(basename "$0")"
# 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 <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.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${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -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
# Find the actual extracted directory name (handles snapshots where filename != directory name)
actualDistributionDir=""
# First try the expected directory name (for regular distributions)
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
actualDistributionDir="$distributionUrlNameMain"
fi
fi
# If not found, search for any directory with the Maven executable (for snapshots)
if [ -z "$actualDistributionDir" ]; then
# enable globbing to iterate over items
set +f
for dir in "$TMP_DOWNLOAD_DIR"/*; do
if [ -d "$dir" ]; then
if [ -f "$dir/bin/$MVN_CMD" ]; then
actualDistributionDir="$(basename "$dir")"
break
fi
fi
done
set -f
fi
if [ -z "$actualDistributionDir" ]; then
verbose "Contents of $TMP_DOWNLOAD_DIR:"
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
die "Could not find Maven distribution directory in extracted archive"
fi
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"
<# : 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.4
@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-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/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_M2_PATH = "$HOME/.m2"
if ($env:MAVEN_USER_HOME) {
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
}
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
}
$MAVEN_WRAPPER_DISTS = $null
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
} else {
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
}
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::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
# Find the actual extracted directory name (handles snapshots where filename != directory name)
$actualDistributionDir = ""
# First try the expected directory name (for regular distributions)
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
$actualDistributionDir = $distributionUrlNameMain
}
# If not found, search for any directory with the Maven executable (for snapshots)
if (!$actualDistributionDir) {
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
if (Test-Path -Path $testPath -PathType Leaf) {
$actualDistributionDir = $_.Name
}
}
}
if (!$actualDistributionDir) {
Write-Error "Could not find Maven distribution directory in extracted archive"
}
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -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"
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>java-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo2</name>
<description>demo2</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<mybatis-plus.version>3.5.6</mybatis-plus.version>
<dynamic-datasource.version>3.6.1</dynamic-datasource.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus 核心(必须添加) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- 动态数据源 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>${dynamic-datasource.version}</version>
</dependency>
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.5.0.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>10.2.1.jre8</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot Maven Plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<!-- Maven Compiler Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>9</source>
<target>9</target>
<encoding>${project.build.sourceEncoding}</encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package com.example;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
@Component
public class DatabaseTester implements CommandLineRunner {
private final DataSource dataSource;
public DatabaseTester(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void run(String... args) throws Exception {
try (Connection conn = dataSource.getConnection()) {
System.out.println("数据库连接成功!");
System.out.println("数据库: " + conn.getMetaData().getDatabaseProductName());
} catch (Exception e) {
System.out.println("数据库连接失败: " + e.getMessage());
}
}
}
\ No newline at end of file
package com.example;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mapper") // 扫描Mapper接口
public class Demo1Application {
public static void main(String[] args) {
SpringApplication.run(Demo1Application.class, args);
}
}
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.controller")) // 修改为您的包名
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Demo2 API 文档")
.description("多数据库项目接口文档")
.version("1.0.0")
.build();
}
}
\ No newline at end of file
package com.example.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author MyBatis-Plus
* @since 2025-09-25
*/
@RestController
@RequestMapping("/department")
public class DepartmentController {
}
package com.example.controller;
import com.example.entity.MaterialInfo;
import com.example.service.MaterialInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 物料主数据表 前端控制器
* </p>
*
* @author yourName
* @since 2025-09-25
*/
@RestController
@RequestMapping("/materialInfo")
@Api(tags = "测试接口")
public class MaterialInfoController {
@Autowired
MaterialInfoService materialInfoService;
@ApiOperation(value = "获取物料列表", notes = "返回所有用物料据", httpMethod = "GET")
@RequestMapping("/test")
public MaterialInfo test(){
List<MaterialInfo> list = materialInfoService.list();
return list.get(0);
}
}
package com.example.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/test")
@Api(tags = "测试接口")
public class TestController {
@GetMapping("/hello")
@ApiOperation("Hello World 测试接口")
public String hello() {
return "Hello, Swagger!";
}
@GetMapping("/info")
@ApiOperation("获取应用信息")
public String info() {
return "Demo2 Application - Multi Database Project";
}
}
\ No newline at end of file
package com.example.controller.codeGeneratorController;
import com.example.entity.codeGeneratorEntity.DatabaseConfig;
import com.example.entity.codeGeneratorEntity.GenerateRequest;
import com.example.service.codeGeneratorService.CodeGeneratorService;
import com.example.service.codeGeneratorService.DatabaseConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/code-generator")
@Api(tags = "代码生成器")
public class CodeGeneratorController {
@Autowired
private CodeGeneratorService codeGeneratorService;
@Autowired
private DatabaseConfigService databaseConfigService;
@GetMapping("/config")
@ApiOperation("获取当前主数据源配置")
public DatabaseConfig getDatabaseConfig() {
DatabaseConfig config = databaseConfigService.getPrimaryDatabaseConfig();
if (config == null) {
throw new RuntimeException("无法获取数据库配置,请检查application.yml配置");
}
return config;
}
@GetMapping("/config/{dataSourceName}")
@ApiOperation("获取指定数据源配置")
public DatabaseConfig getDatabaseConfig(@PathVariable String dataSourceName) {
DatabaseConfig config = databaseConfigService.getDatabaseConfig(dataSourceName);
if (config == null) {
throw new RuntimeException("数据源 " + dataSourceName + " 配置不存在或配置错误");
}
return config;
}
@GetMapping("/tables/{dataSourceName}")
@ApiOperation("获取指定数据源的表列表")
public List<String> getTables(@PathVariable String dataSourceName) {
DatabaseConfig config = databaseConfigService.getDatabaseConfig(dataSourceName);
if (config == null || config.getUrl() == null) {
throw new RuntimeException("数据源 " + dataSourceName + " 配置错误,无法获取表列表");
}
return codeGeneratorService.getTableList(config);
}
@GetMapping("/test-connection/{dataSourceName}")
@ApiOperation("测试指定数据源连接")
public String testConnection(@PathVariable String dataSourceName) {
DatabaseConfig config = databaseConfigService.getDatabaseConfig(dataSourceName);
if (config == null) {
return dataSourceName + " 数据源配置不存在";
}
boolean isConnected = databaseConfigService.testConnection(config);
return isConnected ? dataSourceName + " 数据库连接成功!" : dataSourceName + " 数据库连接失败!";
}
@PostMapping("/generate/{dataSourceName}")
@ApiOperation("使用指定数据源生成代码")
public String generateCode(@PathVariable String dataSourceName,
@RequestBody GenerateRequest request) {
try {
DatabaseConfig dbConfig = databaseConfigService.getDatabaseConfig(dataSourceName);
if (dbConfig == null || dbConfig.getUrl() == null) {
return "数据源 " + dataSourceName + " 配置错误,请检查application.yml";
}
codeGeneratorService.generateCode(dbConfig, request.getTables(),
request.getPackageName(), request.getAuthor());
return "代码生成成功!(数据源: " + dataSourceName + ")";
} catch (Exception e) {
return "代码生成失败: " + e.getMessage();
}
}
}
\ No newline at end of file
package com.example.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import java.time.LocalDate;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
*
* </p>
*
* @author MyBatis-Plus
* @since 2025-09-25
*/
@Getter
@Setter
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
private Integer organizationId;
private Integer parentId;
private Short status;
private Long creatoruserid;
private LocalDate creationtime;
private Long lastmodifieruserid;
private LocalDate lastmodificationtime;
private Long deleteruserid;
private LocalDate deletiontime;
private Short isdeleted;
private String levelDesc;
private Short isProduction;
private String code;
private String location;
private String property;
private String note;
private Long sysDeptId;
private String measureUnitName;
private String currencyTypeName;
private String capacityTypeName;
private Integer measureUnit;
private Integer currencyType;
private Integer capacityType;
private Long productType;
private String belongCode;
}
package com.example.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 物料主数据表
* </p>
*
* @author yourName
* @since 2025-09-25
*/
@Getter
@Setter
@TableName("material_info")
public class MaterialInfo implements Serializable {
private static final long serialVersionUID = 1L;
@TableId("id")
private String id;
@TableField("creationtime")
private LocalDateTime creationtime;
@TableField("creatoruserid")
private Long creatoruserid;
@TableField("lastmodificationtime")
private LocalDateTime lastmodificationtime;
@TableField("lastmodifieruserid")
private Long lastmodifieruserid;
@TableField("isdeleted")
private Long isdeleted;
@TableField("deletiontime")
private LocalDateTime deletiontime;
@TableField("deleteruserid")
private Long deleteruserid;
/**
* 名称
*/
@TableField("name")
private String name;
@TableField("brand")
private String brand;
/**
* 规格
*/
@TableField("specifications")
private String specifications;
@TableField("batch")
private String batch;
@TableField("unit_price")
private BigDecimal unitPrice;
@TableField("min_num")
private BigDecimal minNum;
@TableField("tempcode")
private String tempcode;
/**
* 编码
*/
@TableField("code")
private String code;
@TableField("material_type_name")
private String materialTypeName;
@TableField("inspect_duration")
private Long inspectDuration;
@TableField("purchase_duration")
private Long purchaseDuration;
@TableField("first_lot")
private String firstLot;
@TableField("tail_lot")
private BigDecimal tailLot;
@TableField("standard_log")
private BigDecimal standardLog;
@TableField("safe_stock_day")
private Long safeStockDay;
@TableField("safe_stock_quantity")
private BigDecimal safeStockQuantity;
/**
* 类别名称
*/
@TableField("category_name")
private String categoryName;
/**
* 类别编码
*/
@TableField("category_code")
private String categoryCode;
/**
* 类别ID
*/
@TableField("category_id")
private Long categoryId;
@TableField("material_property")
private Long materialProperty;
@TableField("root_category_id")
private Long rootCategoryId;
@TableField("code_rule_id")
private Long codeRuleId;
@TableField("code_rule_type")
private Long codeRuleType;
/**
* 编码
*/
@TableField("drawing")
private String drawing;
@TableField("material_type")
private Long materialType;
/**
* 单位
*/
@TableField("measure_unit")
private Long measureUnit;
/**
* 单位名称
*/
@TableField("measure_unit_name")
private String measureUnitName;
/**
* 版本
*/
@TableField("version")
private String version;
/**
* 产品类型
*/
@TableField("product_type")
private String productType;
@TableField("status")
private Long status;
@TableField("latest")
private Long latest;
/**
* 是否创建原材料供应供应
*/
@TableField("iscreatesupplyrouting")
private Long iscreatesupplyrouting;
/**
* 是否创建原材料检验供应
*/
@TableField("iscreatecheckrouting")
private Long iscreatecheckrouting;
@TableField("description")
private String description;
/**
* 物料类型
*/
@TableField("quintiq_ortems")
private Long quintiqOrtems;
@TableField("isync")
private Long isync;
@TableField("issend")
private Long issend;
/**
* 辅助计量单位
*/
@TableField("measure_unit2")
private Long measureUnit2;
@TableField("measure_unit_name2")
private String measureUnitName2;
@TableField("linkmaterialid")
private String linkmaterialid;
/**
* 辅助计量单位2
*/
@TableField("measure_unit3")
private Long measureUnit3;
@TableField("measure_unit_name3")
private String measureUnitName3;
@TableField("zjltofjl1")
private BigDecimal zjltofjl1;
/**
* 供应商ID
*/
@TableField("supply_id")
private String supplyId;
/**
* 供应商名称
*/
@TableField("supply_name")
private String supplyName;
/**
* 供应商编码
*/
@TableField("supply_code")
private String supplyCode;
@TableField("istrade")
private Long istrade;
@TableField("ser")
private String ser;
/**
* 是否共用料
*/
@TableField("iscommon")
private Long iscommon;
/**
* 是否创建汇总供应
*/
@TableField("iscreatepoolrouting")
private Long iscreatepoolrouting;
/**
* 特殊产品,普通产品
*/
@TableField("variety")
private String variety;
/**
* 规格
*/
@TableField("spec")
private String spec;
/**
* MP类别
*/
@TableField("category_id2")
private Long categoryId2;
@TableField("utility_material")
private Long utilityMaterial;
/**
* 特殊产品
*/
@TableField("special_product")
private Long specialProduct;
/**
* 瓶型
*/
@TableField("bottle_type")
private Long bottleType;
@TableField("bottle_type_str")
private String bottleTypeStr;
/**
* 最大库存目标
*/
@TableField("max_inventory_day")
private BigDecimal maxInventoryDay;
/**
* 最大库存目标
*/
@TableField("max_inventory_quantity")
private BigDecimal maxInventoryQuantity;
/**
* 最小库存目标
*/
@TableField("min_inventory_day")
private BigDecimal minInventoryDay;
/**
* 最小库存目标
*/
@TableField("min_inventory_quantity")
private BigDecimal minInventoryQuantity;
/**
* 最小供应量
*/
@TableField("minimum_supply")
private BigDecimal minimumSupply;
/**
* 开始时间
*/
@TableField("start_time")
private LocalDateTime startTime;
/**
* 结束时间
*/
@TableField("end_time")
private LocalDateTime endTime;
/**
* 产线设备
*/
@TableField("equip_id")
private Long equipId;
/**
* 大宗产品 1==是
*/
@TableField("bigpro")
private Long bigpro;
/**
* 小宗产品 1==是
*/
@TableField("smallpro")
private Long smallpro;
/**
* 周三后排产
*/
@TableField("isthree")
private Long isthree;
/**
* 是否负库存
*/
@TableField("is_minus")
private Long isMinus;
@TableField("remark")
private String remark;
/**
* 搭配大宗产品
*/
@TableField("match_bigpro_id")
private String matchBigproId;
/**
* 搭配大宗产品
*/
@TableField("match_bigpro_code")
private String matchBigproCode;
/**
* 搭配小宗产品
*/
@TableField("match_smallpro_id")
private String matchSmallproId;
/**
* 搭配小宗产品
*/
@TableField("match_smallpro_code")
private String matchSmallproCode;
/**
* 全称
*/
@TableField("full_name")
private String fullName;
/**
* 是否包含库存,默认1,1是,0否
*/
@TableField("is_include_store")
private Long isIncludeStore;
/**
* 是否平分到未来四周,默认0,0否,1是
*/
@TableField("is_average_four_week")
private Long isAverageFourWeek;
/**
* 库存同步时间
*/
@TableField("stocksynctime")
private LocalDateTime stocksynctime;
@TableField("inventory_host_cost")
private Long inventoryHostCost;
/**
* 拆分前计划ID
*/
@TableField("beforeplanid")
private String beforeplanid;
/**
* 计划顺序号
*/
@TableField("plannum")
private Long plannum;
/**
* 计划总数
*/
@TableField("plancount")
private Long plancount;
/**
* 集成过来的主键;
*/
@TableField("new_long_id")
private Long newLongId;
/**
* 集成过来的旧物料编码
*/
@TableField("new_oldnumber")
private String newOldnumber;
/**
* 集成过来的最小起订量
*/
@TableField("min_quantity")
private BigDecimal minQuantity;
/**
* 0 其他1 外贸 2 研发 3 试料 4西南 5追加
*/
@TableField("material_plan_type")
private Long materialPlanType;
/**
* 最小生产量
*/
@TableField("min_production")
private BigDecimal minProduction;
/**
* 最大生产量
*/
@TableField("max_production")
private BigDecimal maxProduction;
/**
* 不可见性(外贸删除的物料)
*/
@TableField("invisable")
private Long invisable;
}
package com.example.entity.codeGeneratorEntity;
public class DatabaseConfig {
private String url;
private String username;
private String password;
private String driverClassName;
private String dbType; // mysql, oracle, sqlserver
// 构造方法、getter、setter
public DatabaseConfig() {}
public DatabaseConfig(String url, String username, String password, String driverClassName) {
this.url = url;
this.username = username;
this.password = password;
this.driverClassName = driverClassName;
}
// getter 和 setter 方法
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getDriverClassName() { return driverClassName; }
public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; }
public String getDbType() { return dbType; }
public void setDbType(String dbType) { this.dbType = dbType; }
}
\ No newline at end of file
package com.example.entity.codeGeneratorEntity;
import java.util.List;
public class GenerateRequest {
private DatabaseConfig dbConfig;
private List<String> tables;
private String packageName;
private String author;
private boolean overwrite;
// 构造方法、getter、setter
public GenerateRequest() {}
public DatabaseConfig getDbConfig() { return dbConfig; }
public void setDbConfig(DatabaseConfig dbConfig) { this.dbConfig = dbConfig; }
public List<String> getTables() { return tables; }
public void setTables(List<String> tables) { this.tables = tables; }
public String getPackageName() { return packageName; }
public void setPackageName(String packageName) { this.packageName = packageName; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public boolean isOverwrite() { return overwrite; }
public void setOverwrite(boolean overwrite) { this.overwrite = overwrite; }
}
\ No newline at end of file
package com.example.generator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
// 1. 配置数据库连接(这里以MySQL为例,生成的代码通用)
FastAutoGenerator.create(
"jdbc:mysql://192.168.0.181:3310/mes?useSSL=false&serverTimezone=UTC",
"root",
"root_mes@123456~"
)
// 2. 全局配置
.globalConfig(builder -> {
builder.author("yourName") // 作者名
.outputDir(System.getProperty("user.dir") + "/src/main/java") // 代码输出目录
.disableOpenDir(); // 生成后不打开文件夹
})
// 3. 包配置(指定代码存放的包路径)
.packageConfig(builder -> {
builder.parent("com.example") // 父包名
.entity("entity") // 实体类包
.mapper("mapper") // Mapper接口包
.service("service") // Service接口包
.serviceImpl("service.impl") // Service实现包
.controller("controller") // Controller包
// Mapper XML文件输出路径
.pathInfo(Collections.singletonMap(
OutputFile.xml,
System.getProperty("user.dir") + "/src/main/resources/mapper"
));
})
// 4. 策略配置(生成规则)
.strategyConfig(builder -> {
builder.addInclude("material_info") // 需要生成的表名(多个表用逗号分隔)
// 实体类策略
.entityBuilder()
.enableLombok() // 启用Lombok
.enableTableFieldAnnotation() // 字段添加注解
// Controller策略
.controllerBuilder()
.enableRestStyle() // 生成REST风格接口
// Service策略
.serviceBuilder()
.formatServiceFileName("%sService") // Service命名格式
// Mapper策略
.mapperBuilder()
.enableBaseResultMap() // 生成BaseResultMap
.enableBaseColumnList(); // 生成BaseColumnList
})
// 5. 模板引擎(使用Freemarker)
.templateEngine(new FreemarkerTemplateEngine())
// 执行生成
.execute();
}
}
package com.example.generator;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.Collections;
public class CodeGenerator1 {
public static void main(String[] args) {
// 1. 配置数据库连接
FastAutoGenerator.create(
"jdbc:mysql://192.168.0.181:3310/mes?useSSL=false&serverTimezone=UTC",
"root",
"root_mes@123456~"
)
// 2. 全局配置
.globalConfig(builder -> {
builder.author("yourName") // 作者名
.outputDir(System.getProperty("user.dir") + "/src/main/java") // 代码输出目录
.disableOpenDir(); // 生成后不打开文件夹
})
// 3. 包配置
.packageConfig(builder -> {
builder.parent("com.example") // 父包名
.entity("entity") // 实体类包
.mapper("mapper") // Mapper接口包
.service("service") // Service接口包
.serviceImpl("service.impl") // Service实现包
.controller("controller") // Controller包
// Mapper XML文件输出路径
.pathInfo(Collections.singletonMap(
OutputFile.xml,
System.getProperty("user.dir") + "/src/main/resources/mapper"
));
})
// 4. 策略配置
.strategyConfig(builder -> {
builder.addInclude("material_info") // 需要生成的表名
// 实体类策略
.entityBuilder()
.enableLombok() // 启用Lombok
.enableTableFieldAnnotation() // 字段添加注解
// Controller策略
.controllerBuilder()
.enableRestStyle() // 生成REST风格接口
// Service策略
.serviceBuilder()
.formatServiceFileName("%sService") // Service命名格式
// Mapper策略
.mapperBuilder()
.enableBaseResultMap() // 生成BaseResultMap
.enableBaseColumnList(); // 生成BaseColumnList
})
// 5. 模板引擎(改用Velocity)
.templateEngine(new VelocityTemplateEngine())
// 执行生成
.execute();
System.out.println("代码生成完成!");
}
}
\ No newline at end of file
package com.example.mapper;
import com.example.entity.Department;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author MyBatis-Plus
* @since 2025-09-25
*/
public interface DepartmentMapper extends BaseMapper<Department> {
}
package com.example.mapper;
import com.example.entity.MaterialInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 物料主数据表 Mapper 接口
* </p>
*
* @author yourName
* @since 2025-09-25
*/
public interface MaterialInfoMapper extends BaseMapper<MaterialInfo> {
}
package com.example.service;
import com.example.entity.Department;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author MyBatis-Plus
* @since 2025-09-25
*/
public interface DepartmentService extends IService<Department> {
}
package com.example.service;
import com.example.entity.MaterialInfo;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 物料主数据表 服务类
* </p>
*
* @author yourName
* @since 2025-09-25
*/
public interface MaterialInfoService extends IService<MaterialInfo> {
}
package com.example.service.codeGeneratorService;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.example.entity.codeGeneratorEntity.DatabaseConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
@Service
public class CodeGeneratorService {
/**
* 生成代码
* @param dbConfig 数据库配置
* @param tables 表名列表
* @param packageName 包名
* @param author 作者
*/
@Autowired
private DatabaseService databaseService;
/**
* 获取数据库表列表
*/
public void generateCode(DatabaseConfig dbConfig, List<String> tables,
String packageName, String author) {
FastAutoGenerator.create(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword())
.globalConfig(builder -> {
builder.author(author)
.outputDir(System.getProperty("user.dir") + "/src/main/java")
.disableOpenDir();
})
.packageConfig(builder -> {
builder.parent(packageName)
.entity("entity")
.mapper("mapper")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
.pathInfo(Collections.singletonMap(OutputFile.xml,
System.getProperty("user.dir") + "/src/main/resources/mapper"));
})
.strategyConfig(builder -> {
builder.addInclude(tables)
.entityBuilder()
.naming(NamingStrategy.underline_to_camel)
.columnNaming(NamingStrategy.underline_to_camel)
.enableLombok()
.controllerBuilder()
.enableRestStyle()
.serviceBuilder()
.formatServiceFileName("%sService")
.mapperBuilder()
.enableBaseResultMap()
.enableBaseColumnList();
})
.templateEngine(new VelocityTemplateEngine())
.execute();
}
/**
* 获取数据库中的所有表
*/
public List<String> getTableList(DatabaseConfig dbConfig) {
// 这里需要实现获取数据库表列表的逻辑
// 可以使用JDBC元数据获取
return databaseService.getTableList(dbConfig);
}
/**
* 测试数据库连接
*/
public boolean testConnection(DatabaseConfig dbConfig) {
return databaseService.testConnection(dbConfig);
}
}
\ No newline at end of file
package com.example.service.codeGeneratorService;
import com.example.entity.codeGeneratorEntity.DatabaseConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
@EnableConfigurationProperties
public class DatabaseConfigService {
@Autowired
private Environment environment;
/**
* 获取当前主数据源配置
*/
public DatabaseConfig getPrimaryDatabaseConfig() {
// 获取主数据源名称
String primaryDataSource = environment.getProperty("spring.datasource.dynamic.primary", "sqlserver");
return getDatabaseConfig(primaryDataSource);
}
/**
* 获取指定数据源配置
*/
public DatabaseConfig getDatabaseConfig(String dataSourceName) {
DatabaseConfig config = new DatabaseConfig();
// 从配置文件中读取数据源信息
String url = environment.getProperty("spring.datasource.dynamic.datasource." + dataSourceName + ".url");
String username = environment.getProperty("spring.datasource.dynamic.datasource." + dataSourceName + ".username");
String password = environment.getProperty("spring.datasource.dynamic.datasource." + dataSourceName + ".password");
String driverClassName = environment.getProperty("spring.datasource.dynamic.datasource." + dataSourceName + ".driver-class-name");
if (url != null) {
config.setUrl(url);
config.setUsername(username);
config.setPassword(password);
config.setDriverClassName(driverClassName);
config.setDbType(dataSourceName);
return config;
}
return null;
}
/**
* 获取所有数据源配置
*/
public Map<String, DatabaseConfig> getAllDatabaseConfigs() {
Map<String, DatabaseConfig> configs = new HashMap<>();
String[] dataSources = {"mysql", "oracle", "sqlserver"};
for (String dataSource : dataSources) {
DatabaseConfig config = getDatabaseConfig(dataSource);
if (config != null && config.getUrl() != null) {
configs.put(dataSource, config);
}
}
return configs;
}
/**
* 测试数据库连接
*/
public boolean testConnection(DatabaseConfig config) {
if (config == null || config.getUrl() == null) {
return false;
}
try {
Class.forName(config.getDriverClassName());
try (java.sql.Connection connection = java.sql.DriverManager.getConnection(
config.getUrl(), config.getUsername(), config.getPassword())) {
return connection.isValid(5);
}
} catch (Exception e) {
return false;
}
}
}
\ No newline at end of file
package com.example.service.codeGeneratorService;
import com.example.entity.codeGeneratorEntity.DatabaseConfig;
import org.springframework.stereotype.Service;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
@Service
public class DatabaseService {
/**
* 获取数据库中的所有表
*/
public List<String> getTableList(DatabaseConfig dbConfig) {
List<String> tables = new ArrayList<>();
try (Connection connection = DriverManager.getConnection(
dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword())) {
DatabaseMetaData metaData = connection.getMetaData();
String[] types = {"TABLE"};
ResultSet resultSet = metaData.getTables(null, null, "%", types);
while (resultSet.next()) {
String tableName = resultSet.getString("TABLE_NAME");
tables.add(tableName);
}
} catch (Exception e) {
throw new RuntimeException("获取表列表失败: " + e.getMessage(), e);
}
return tables;
}
/**
* 测试数据库连接
*/
public boolean testConnection(DatabaseConfig dbConfig) {
try (Connection connection = DriverManager.getConnection(
dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword())) {
return connection.isValid(5); // 5秒超时
} catch (Exception e) {
return false;
}
}
}
\ No newline at end of file
package com.example.service.impl;
import com.example.entity.Department;
import com.example.mapper.DepartmentMapper;
import com.example.service.DepartmentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author MyBatis-Plus
* @since 2025-09-25
*/
@Service
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements DepartmentService {
}
package com.example.service.impl;
import com.example.entity.MaterialInfo;
import com.example.mapper.MaterialInfoMapper;
import com.example.service.MaterialInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 物料主数据表 服务实现类
* </p>
*
* @author yourName
* @since 2025-09-25
*/
@Service
public class MaterialInfoServiceImpl extends ServiceImpl<MaterialInfoMapper, MaterialInfo> implements MaterialInfoService {
}
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher # Spring Boot 2.6+ 需要这个配置
# Swagger 配置
swagger:
enabled: true
datasource:
dynamic:
primary: sqlserver
# 默认数据源
strict: false # 关闭严格模式
datasource:
# MySQL数据源
mysql:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.181:3310/mes?useSSL=false&serverTimezone=UTC
username: root # 替换为你的MySQL用户名
password: root_mes@123456~ # 替换为你的MySQL密码
# Oracle数据源
oracle:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@//192.168.0.181:1522/ORCLPDB1 # ORCL为你的Oracle实例名
username: mes # 替换为你的Oracle用户名
password: root_mes123456 # 替换为你的Oracle密码
sqlserver:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://192.168.0.181:1434;databaseName=mes;encrypt=false
username: sa
password: root_mes123456
# MyBatis-Plus配置
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml # Mapper XML路径
type-aliases-package: com.example.entity # 实体类包路径
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志(调试用)
global-config:
db-config:
id-type: auto # 主键自增策略
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.DepartmentMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.example.entity.Department">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="organization_id" property="organizationId" />
<result column="parent_id" property="parentId" />
<result column="status" property="status" />
<result column="creatoruserid" property="creatoruserid" />
<result column="creationtime" property="creationtime" />
<result column="lastmodifieruserid" property="lastmodifieruserid" />
<result column="lastmodificationtime" property="lastmodificationtime" />
<result column="deleteruserid" property="deleteruserid" />
<result column="deletiontime" property="deletiontime" />
<result column="isdeleted" property="isdeleted" />
<result column="level_desc" property="levelDesc" />
<result column="is_production" property="isProduction" />
<result column="code" property="code" />
<result column="location" property="location" />
<result column="property" property="property" />
<result column="note" property="note" />
<result column="sys_dept_id" property="sysDeptId" />
<result column="measure_unit_name" property="measureUnitName" />
<result column="currency_type_name" property="currencyTypeName" />
<result column="capacity_type_name" property="capacityTypeName" />
<result column="measure_unit" property="measureUnit" />
<result column="currency_type" property="currencyType" />
<result column="capacity_type" property="capacityType" />
<result column="product_type" property="productType" />
<result column="belong_code" property="belongCode" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, organization_id, parent_id, status, creatoruserid, creationtime, lastmodifieruserid, lastmodificationtime, deleteruserid, deletiontime, isdeleted, level_desc, is_production, code, location, property, note, sys_dept_id, measure_unit_name, currency_type_name, capacity_type_name, measure_unit, currency_type, capacity_type, product_type, belong_code
</sql>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.MaterialInfoMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.example.entity.MaterialInfo">
<id column="id" property="id" />
<result column="creationtime" property="creationtime" />
<result column="creatoruserid" property="creatoruserid" />
<result column="lastmodificationtime" property="lastmodificationtime" />
<result column="lastmodifieruserid" property="lastmodifieruserid" />
<result column="isdeleted" property="isdeleted" />
<result column="deletiontime" property="deletiontime" />
<result column="deleteruserid" property="deleteruserid" />
<result column="name" property="name" />
<result column="brand" property="brand" />
<result column="specifications" property="specifications" />
<result column="batch" property="batch" />
<result column="unit_price" property="unitPrice" />
<result column="min_num" property="minNum" />
<result column="tempcode" property="tempcode" />
<result column="code" property="code" />
<result column="material_type_name" property="materialTypeName" />
<result column="inspect_duration" property="inspectDuration" />
<result column="purchase_duration" property="purchaseDuration" />
<result column="first_lot" property="firstLot" />
<result column="tail_lot" property="tailLot" />
<result column="standard_log" property="standardLog" />
<result column="safe_stock_day" property="safeStockDay" />
<result column="safe_stock_quantity" property="safeStockQuantity" />
<result column="category_name" property="categoryName" />
<result column="category_code" property="categoryCode" />
<result column="category_id" property="categoryId" />
<result column="material_property" property="materialProperty" />
<result column="root_category_id" property="rootCategoryId" />
<result column="code_rule_id" property="codeRuleId" />
<result column="code_rule_type" property="codeRuleType" />
<result column="drawing" property="drawing" />
<result column="material_type" property="materialType" />
<result column="measure_unit" property="measureUnit" />
<result column="measure_unit_name" property="measureUnitName" />
<result column="version" property="version" />
<result column="product_type" property="productType" />
<result column="status" property="status" />
<result column="latest" property="latest" />
<result column="iscreatesupplyrouting" property="iscreatesupplyrouting" />
<result column="iscreatecheckrouting" property="iscreatecheckrouting" />
<result column="description" property="description" />
<result column="quintiq_ortems" property="quintiqOrtems" />
<result column="isync" property="isync" />
<result column="issend" property="issend" />
<result column="measure_unit2" property="measureUnit2" />
<result column="measure_unit_name2" property="measureUnitName2" />
<result column="linkmaterialid" property="linkmaterialid" />
<result column="measure_unit3" property="measureUnit3" />
<result column="measure_unit_name3" property="measureUnitName3" />
<result column="zjltofjl1" property="zjltofjl1" />
<result column="supply_id" property="supplyId" />
<result column="supply_name" property="supplyName" />
<result column="supply_code" property="supplyCode" />
<result column="istrade" property="istrade" />
<result column="ser" property="ser" />
<result column="iscommon" property="iscommon" />
<result column="iscreatepoolrouting" property="iscreatepoolrouting" />
<result column="variety" property="variety" />
<result column="spec" property="spec" />
<result column="category_id2" property="categoryId2" />
<result column="utility_material" property="utilityMaterial" />
<result column="special_product" property="specialProduct" />
<result column="bottle_type" property="bottleType" />
<result column="bottle_type_str" property="bottleTypeStr" />
<result column="max_inventory_day" property="maxInventoryDay" />
<result column="max_inventory_quantity" property="maxInventoryQuantity" />
<result column="min_inventory_day" property="minInventoryDay" />
<result column="min_inventory_quantity" property="minInventoryQuantity" />
<result column="minimum_supply" property="minimumSupply" />
<result column="start_time" property="startTime" />
<result column="end_time" property="endTime" />
<result column="equip_id" property="equipId" />
<result column="bigpro" property="bigpro" />
<result column="smallpro" property="smallpro" />
<result column="isthree" property="isthree" />
<result column="is_minus" property="isMinus" />
<result column="remark" property="remark" />
<result column="match_bigpro_id" property="matchBigproId" />
<result column="match_bigpro_code" property="matchBigproCode" />
<result column="match_smallpro_id" property="matchSmallproId" />
<result column="match_smallpro_code" property="matchSmallproCode" />
<result column="full_name" property="fullName" />
<result column="is_include_store" property="isIncludeStore" />
<result column="is_average_four_week" property="isAverageFourWeek" />
<result column="stocksynctime" property="stocksynctime" />
<result column="inventory_host_cost" property="inventoryHostCost" />
<result column="beforeplanid" property="beforeplanid" />
<result column="plannum" property="plannum" />
<result column="plancount" property="plancount" />
<result column="new_long_id" property="newLongId" />
<result column="new_oldnumber" property="newOldnumber" />
<result column="min_quantity" property="minQuantity" />
<result column="material_plan_type" property="materialPlanType" />
<result column="min_production" property="minProduction" />
<result column="max_production" property="maxProduction" />
<result column="invisable" property="invisable" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, creationtime, creatoruserid, lastmodificationtime, lastmodifieruserid, isdeleted, deletiontime, deleteruserid, name, brand, specifications, batch, unit_price, min_num, tempcode, code, material_type_name, inspect_duration, purchase_duration, first_lot, tail_lot, standard_log, safe_stock_day, safe_stock_quantity, category_name, category_code, category_id, material_property, root_category_id, code_rule_id, code_rule_type, drawing, material_type, measure_unit, measure_unit_name, version, product_type, status, latest, iscreatesupplyrouting, iscreatecheckrouting, description, quintiq_ortems, isync, issend, measure_unit2, measure_unit_name2, linkmaterialid, measure_unit3, measure_unit_name3, zjltofjl1, supply_id, supply_name, supply_code, istrade, ser, iscommon, iscreatepoolrouting, variety, spec, category_id2, utility_material, special_product, bottle_type, bottle_type_str, max_inventory_day, max_inventory_quantity, min_inventory_day, min_inventory_quantity, minimum_supply, start_time, end_time, equip_id, bigpro, smallpro, isthree, is_minus, remark, match_bigpro_id, match_bigpro_code, match_smallpro_id, match_smallpro_code, full_name, is_include_store, is_average_four_week, stocksynctime, inventory_host_cost, beforeplanid, plannum, plancount, new_long_id, new_oldnumber, min_quantity, material_plan_type, min_production, max_production, invisable
</sql>
</mapper>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MyBatis-Plus 代码生成器</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<style>
:root {
--primary-color: #667eea;
--secondary-color: #764ba2;
--success-color: #28a745;
--danger-color: #dc3545;
--warning-color: #ffc107;
--info-color: #17a2b8;
}
body {
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
min-height: 100vh;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
padding: 20px 0;
}
.card {
border: none;
border-radius: 15px;
box-shadow: 0 15px 35px rgba(0,0,0,0.3);
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.98);
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
}
.card-header {
background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
color: white;
border-radius: 15px 15px 0 0 !important;
font-weight: bold;
padding: 20px;
}
.btn-primary {
background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
border: none;
border-radius: 8px;
padding: 12px 24px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-primary:hover {
background: linear-gradient(45deg, #5a67d8, #6b46c1);
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(0,0,0,0.3);
}
.btn-outline-primary {
border: 2px solid var(--primary-color);
color: var(--primary-color);
border-radius: 8px;
padding: 10px 20px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-outline-primary:hover {
background: var(--primary-color);
color: white;
transform: translateY(-2px);
}
.table-list {
max-height: 400px;
overflow-y: auto;
border: 2px solid #e9ecef;
border-radius: 12px;
padding: 15px;
background: #f8f9fa;
}
.table-list::-webkit-scrollbar {
width: 8px;
}
.table-list::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.table-list::-webkit-scrollbar-thumb {
background: var(--primary-color);
border-radius: 4px;
}
.status-indicator {
width: 14px;
height: 14px;
border-radius: 50%;
display: inline-block;
margin-right: 10px;
animation: pulse 2s infinite;
}
.connected {
background-color: var(--success-color);
}
.disconnected {
background-color: var(--danger-color);
}
.connecting {
background-color: var(--warning-color);
}
.form-control {
border-radius: 10px;
border: 2px solid #e9ecef;
padding: 12px 15px;
transition: all 0.3s ease;
font-size: 14px;
}
.form-control:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.3rem rgba(102, 126, 234, 0.25);
transform: translateY(-2px);
}
.form-select {
border-radius: 10px;
border: 2px solid #e9ecef;
padding: 12px 15px;
transition: all 0.3s ease;
}
.form-select:focus {
border-color: var(--primary-color);
box-shadow: 0 0 0 0.3rem rgba(102, 126, 234, 0.25);
}
.result-box {
background: linear-gradient(45deg, #f8f9fa, #e9ecef);
border-radius: 12px;
padding: 20px;
margin-top: 25px;
border-left: 4px solid var(--success-color);
}
.config-badge {
background: linear-gradient(45deg, var(--info-color), #2c9faf);
color: white;
padding: 5px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
}
.table-item {
padding: 12px 15px;
border-radius: 8px;
margin-bottom: 8px;
background: white;
border: 1px solid #e9ecef;
transition: all 0.3s ease;
}
.table-item:hover {
background: #f8f9fa;
border-color: var(--primary-color);
transform: translateX(5px);
}
.table-item.selected {
background: rgba(102, 126, 234, 0.1);
border-color: var(--primary-color);
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid rgba(255,255,255,0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.stats-box {
background: linear-gradient(45deg, #f8f9fa, #e9ecef);
border-radius: 12px;
padding: 15px;
text-align: center;
margin-bottom: 20px;
}
.stats-number {
font-size: 24px;
font-weight: bold;
color: var(--primary-color);
}
.stats-label {
font-size: 12px;
color: #6c757d;
text-transform: uppercase;
}
</style>
</head>
<body>
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-lg-12">
<div class="card">
<div class="card-header text-center py-4">
<h2><i class="fas fa-code me-2"></i>MyBatis-Plus 智能代码生成器</h2>
<p class="mb-0">支持多数据源动态切换</p>
</div>
<div class="card-body p-5">
<!-- 统计信息 -->
<div class="row mb-4">
<div class="col-md-3">
<div class="stats-box">
<div class="stats-number" id="totalTables">0</div>
<div class="stats-label">总表数</div>
</div>
</div>
<div class="col-md-3">
<div class="stats-box">
<div class="stats-number" id="selectedTables">0</div>
<div class="stats-label">已选表</div>
</div>
</div>
<div class="col-md-3">
<div class="stats-box">
<div class="stats-number" id="dataSourceCount">3</div>
<div class="stats-label">数据源</div>
</div>
</div>
<div class="col-md-3">
<div class="stats-box">
<div class="stats-number">100%</div>
<div class="stats-label">生成成功率</div>
</div>
</div>
</div>
<!-- 数据库连接状态 -->
<div class="row mb-4">
<div class="col-md-8">
<div class="d-flex align-items-center mb-3">
<span class="status-indicator" id="connectionStatus"></span>
<span id="connectionText">正在检测连接状态...</span>
<span class="config-badge ms-2" id="dataSourceBadge">sqlserver</span>
</div>
<div class="progress mb-2" style="height: 8px;">
<div id="connectionProgress" class="progress-bar" style="width: 0%"></div>
</div>
</div>
<div class="col-md-4 text-end">
<button class="btn btn-outline-primary me-2" onclick="loadConfig()">
<i class="fas fa-sync-alt me-2"></i>刷新配置
</button>
<button class="btn btn-outline-info" onclick="showAdvancedConfig()">
<i class="fas fa-cog me-2"></i>高级设置
</button>
</div>
</div>
<!-- 数据库配置信息 -->
<div class="row mb-4">
<div class="col-md-3">
<label class="form-label fw-bold"><i class="fas fa-database me-2"></i>选择数据源</label>
<select class="form-select" id="dataSourceSelect" onchange="changeDataSource()">
<option value="sqlserver">SQL Server (主数据源)</option>
<option value="mysql">MySQL</option>
<option value="oracle">Oracle</option>
</select>
</div>
<div class="col-md-5">
<label class="form-label fw-bold"><i class="fas fa-link me-2"></i>数据库URL</label>
<input type="text" class="form-control" id="dbUrl" readonly>
</div>
<div class="col-md-2">
<label class="form-label fw-bold"><i class="fas fa-user me-2"></i>用户名</label>
<input type="text" class="form-control" id="dbUsername" readonly>
</div>
<div class="col-md-2">
<label class="form-label fw-bold"><i class="fas fa-plug me-2"></i>操作</label>
<div class="d-flex">
<button class="btn btn-sm btn-success me-2" onclick="testConnection()" title="测试连接">
<i class="fas fa-plug"></i>
</button>
<button class="btn btn-sm btn-primary" onclick="loadTables()" title="加载表">
<i class="fas fa-table"></i>
</button>
</div>
</div>
</div>
<hr>
<!-- 表选择区域 -->
<div class="row mb-4">
<div class="col-md-8">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5><i class="fas fa-database me-2"></i>数据表列表</h5>
<div>
<button class="btn btn-sm btn-outline-primary me-2" onclick="selectAllTables()">
<i class="fas fa-check-square me-1"></i>全选
</button>
<button class="btn btn-sm btn-outline-secondary me-2" onclick="deselectAllTables()">
<i class="fas fa-times-circle me-1"></i>取消
</button>
<button class="btn btn-sm btn-outline-info" onclick="filterTables()">
<i class="fas fa-filter me-1"></i>筛选
</button>
</div>
</div>
<div class="table-list" id="tableList">
<div class="text-center py-5">
<i class="fas fa-table fs-1 text-muted mb-3"></i>
<p class="text-muted">请先点击加载表按钮获取数据表</p>
<button class="btn btn-primary mt-2" onclick="loadTables()">
<i class="fas fa-table me-2"></i>加载数据表
</button>
</div>
</div>
</div>
<div class="col-md-4">
<h5><i class="fas fa-cog me-2"></i>生成配置</h5>
<div class="mb-3">
<label class="form-label fw-bold"><i class="fas fa-code me-2"></i>包名</label>
<input type="text" class="form-control" id="packageName" value="com.example"
placeholder="例如: com.company.project">
</div>
<div class="mb-3">
<label class="form-label fw-bold"><i class="fas fa-user me-2"></i>作者</label>
<input type="text" class="form-control" id="author" value="MyBatis-Plus"
placeholder="您的姓名">
</div>
<div class="mb-3">
<label class="form-label fw-bold"><i class="fas fa-layer-group me-2"></i>生成选项</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="generateEntity" checked>
<label class="form-check-label" for="generateEntity">实体类</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="generateMapper" checked>
<label class="form-check-label" for="generateMapper">Mapper接口</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="generateService" checked>
<label class="form-check-label" for="generateService">Service层</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="generateController" checked>
<label class="form-check-label" for="generateController">Controller层</label>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-bold"><i class="fas fa-bolt me-2"></i>操作</label>
<div class="d-grid gap-2">
<button class="btn btn-success" onclick="generateCode()">
<i class="fas fa-bolt me-2"></i>生成代码
</button>
<button class="btn btn-outline-secondary" onclick="clearSelection()">
<i class="fas fa-trash me-2"></i>清空选择
</button>
</div>
</div>
</div>
</div>
<!-- 结果展示 -->
<div class="result-box" id="resultBox" style="display: none;">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0"><i class="fas fa-info-circle me-2"></i>生成结果</h5>
<button class="btn btn-sm btn-outline-secondary" onclick="clearResult()">
<i class="fas fa-times"></i>
</button>
</div>
<div id="result"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
let tables = [];
let currentConfig = null;
let currentDataSource = 'sqlserver';
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', function() {
loadConfig();
updateStats();
});
// 加载数据库配置
async function loadConfig(dataSourceName = currentDataSource) {
try {
showLoadingStatus('正在加载配置...');
const response = await axios.get(`/api/code-generator/config/${dataSourceName}`);
currentConfig = response.data;
document.getElementById('dbUrl').value = currentConfig.url;
document.getElementById('dbUsername').value = currentConfig.username;
document.getElementById('dataSourceBadge').textContent = dataSourceName;
updateConnectionStatus('loading', '配置加载完成,正在测试连接...');
await testConnection(dataSourceName);
} catch (error) {
showError('加载配置失败: ' + error.message);
updateConnectionStatus('disconnected', '配置加载失败');
}
}
// 切换数据源
async function changeDataSource() {
const selectedDataSource = document.getElementById('dataSourceSelect').value;
currentDataSource = selectedDataSource;
await loadConfig(currentDataSource);
}
// 测试数据库连接
async function testConnection(dataSourceName = currentDataSource) {
try {
updateConnectionStatus('loading', '正在测试连接...');
const response = await axios.get(`/api/code-generator/test-connection/${dataSourceName}`);
if (response.data.includes('成功')) {
updateConnectionStatus('connected', `${dataSourceName} 连接成功`);
} else {
updateConnectionStatus('disconnected', `${dataSourceName} 连接失败`);
}
} catch (error) {
updateConnectionStatus('disconnected', '连接测试失败: ' + error.message);
}
}
// 更新连接状态显示
function updateConnectionStatus(status, message) {
const statusElement = document.getElementById('connectionStatus');
const textElement = document.getElementById('connectionText');
const progressElement = document.getElementById('connectionProgress');
statusElement.className = 'status-indicator ' + status;
textElement.textContent = message;
if (status === 'connected') {
textElement.className = 'text-success fw-bold';
progressElement.className = 'progress-bar bg-success';
progressElement.style.width = '100%';
} else if (status === 'disconnected') {
textElement.className = 'text-danger';
progressElement.className = 'progress-bar bg-danger';
progressElement.style.width = '100%';
} else {
textElement.className = 'text-warning';
progressElement.className = 'progress-bar bg-warning progress-bar-striped progress-bar-animated';
progressElement.style.width = '50%';
}
}
// 显示加载状态
function showLoadingStatus(message) {
updateConnectionStatus('loading', message);
}
// 加载表列表
async function loadTables() {
try {
showLoadingStatus('正在加载表列表...');
const response = await axios.get(`/api/code-generator/tables/${currentDataSource}`);
tables = response.data;
renderTableList();
updateStats();
updateConnectionStatus('connected', `已加载 ${tables.length} 张表`);
} catch (error) {
showError('加载表失败: ' + error.message);
updateConnectionStatus('disconnected', '加载表失败');
}
}
// 渲染表列表
function renderTableList() {
const container = document.getElementById('tableList');
if (tables.length === 0) {
container.innerHTML = `
<div class="text-center py-5">
<i class="fas fa-exclamation-triangle fs-1 text-warning mb-3"></i>
<p class="text-muted">未找到数据表或连接失败</p>
<button class="btn btn-primary mt-2" onclick="loadTables()">
<i class="fas fa-redo me-2"></i>重新加载
</button>
</div>
`;
return;
}
let html = '';
tables.forEach(table => {
html += `
<div class="table-item" onclick="toggleTableSelection('${table}')">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="table-${table}" value="${table}">
<label class="form-check-label" for="table-${table}">
<i class="fas fa-table me-2 text-primary"></i>${table}
</label>
</div>
</div>
`;
});
container.innerHTML = html;
}
// 切换表选择
function toggleTableSelection(table) {
const checkbox = document.getElementById(`table-${table}`);
const tableItem = checkbox.closest('.table-item');
checkbox.checked = !checkbox.checked;
if (checkbox.checked) {
tableItem.classList.add('selected');
} else {
tableItem.classList.remove('selected');
}
updateStats();
}
// 生成代码
async function generateCode() {
const selectedTables = getSelectedTables();
if (selectedTables.length === 0) {
showWarning('请至少选择一个数据表');
return;
}
const request = {
tables: selectedTables,
packageName: document.getElementById('packageName').value,
author: document.getElementById('author').value,
options: {
entity: document.getElementById('generateEntity').checked,
mapper: document.getElementById('generateMapper').checked,
service: document.getElementById('generateService').checked,
controller: document.getElementById('generateController').checked
}
};
try {
showLoading('正在生成代码,请稍候...');
const response = await axios.post(`/api/code-generator/generate/${currentDataSource}`, request);
document.getElementById('resultBox').style.display = 'block';
document.getElementById('result').innerHTML = `
<div class="alert alert-success">
<i class="fas fa-check-circle me-2"></i>
<strong>生成成功!</strong> ${response.data}
</div>
<div class="mt-3">
<h6><i class="fas fa-database me-2"></i>数据源: <span class="badge bg-primary">${currentDataSource}</span></h6>
<h6><i class="fas fa-table me-2"></i>生成的表 (${selectedTables.length}张):</h6>
<div class="row mt-2">
${selectedTables.map(table => `
<div class="col-md-3 mb-2">
<span class="badge bg-success">${table}</span>
</div>
`).join('')}
</div>
<div class="mt-3">
<h6><i class="fas fa-code me-2"></i>生成的文件:</h6>
<ul class="list-group list-group-flush">
${selectedTables.map(table => `
<li class="list-group-item">
<i class="fas fa-file-code me-2 text-primary"></i>
${request.options.entity ? `${table}.java (实体)` : ''}
${request.options.mapper ? `${table}Mapper.java (Mapper)` : ''}
${request.options.service ? `${table}Service.java (Service)` : ''}
${request.options.controller ? `${table}Controller.java (Controller)` : ''}
</li>
`).join('')}
</ul>
</div>
</div>
`;
} catch (error) {
showError('生成代码失败: ' + error.response.data);
}
}
// 获取选中的表
function getSelectedTables() {
return tables.filter(table => {
const checkbox = document.getElementById(`table-${table}`);
return checkbox && checkbox.checked;
});
}
// 全选表
function selectAllTables() {
tables.forEach(table => {
const checkbox = document.getElementById(`table-${table}`);
if (checkbox) {
checkbox.checked = true;
checkbox.closest('.table-item').classList.add('selected');
}
});
updateStats();
}
// 取消全选
function deselectAllTables() {
tables.forEach(table => {
const checkbox = document.getElementById(`table-${table}`);
if (checkbox) {
checkbox.checked = false;
checkbox.closest('.table-item').classList.remove('selected');
}
});
updateStats();
}
// 清空选择
function clearSelection() {
deselectAllTables();
}
// 更新统计信息
function updateStats() {
const selectedCount = getSelectedTables().length;
document.getElementById('totalTables').textContent = tables.length;
document.getElementById('selectedTables').textContent = selectedCount;
}
// 筛选表
function filterTables() {
const filterText = prompt('请输入表名筛选条件 (支持模糊匹配):', '');
if (filterText) {
const filteredTables = tables.filter(table =>
table.toLowerCase().includes(filterText.toLowerCase())
);
if (filteredTables.length === 0) {
alert('没有找到匹配的表');
return;
}
// 高亮匹配的表
tables.forEach(table => {
const tableItem = document.getElementById(`table-${table}`)?.closest('.table-item');
if (tableItem) {
if (table.toLowerCase().includes(filterText.toLowerCase())) {
tableItem.style.backgroundColor = '#e3f2fd';
} else {
tableItem.style.backgroundColor = '';
}
}
});
}
}
// 显示高级设置
function showAdvancedConfig() {
alert('高级设置功能正在开发中...');
}
// 显示错误信息
function showError(message) {
document.getElementById('resultBox').style.display = 'block';
document.getElementById('result').innerHTML = `
<div class="alert alert-danger">
<i class="fas fa-exclamation-circle me-2"></i>
<strong>错误!</strong> ${message}
</div>
`;
}
// 显示警告信息
function showWarning(message) {
document.getElementById('resultBox').style.display = 'block';
document.getElementById('result').innerHTML = `
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle me-2"></i>
<strong>警告!</strong> ${message}
</div>
`;
}
// 显示加载中
function showLoading(message) {
document.getElementById('resultBox').style.display = 'block';
document.getElementById('result').innerHTML = `
<div class="text-center py-4">
<div class="loading-spinner mb-3"></div>
<p class="mb-0">${message}</p>
</div>
`;
}
// 清空结果
function clearResult() {
document.getElementById('resultBox').style.display = 'none';
document.getElementById('result').innerHTML = '';
}
// 清空选择
function clearSelection() {
deselectAllTables();
}
</script>
</body>
</html>
\ No newline at end of file
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Demo1ApplicationTests {
@Test
void contextLoads() {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment