commit 4d22f42ee9e32e8efb5e1bc5913be27019b237e3
Author: lijiazhuo <13787924+lijiazhuosky@user.noreply.gitee.com>
Date: Mon Jan 19 14:45:35 2026 +0800
first commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a2a3040
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,31 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### 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/
+
+### VS Code ###
+.vscode/
diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java
new file mode 100644
index 0000000..74f4de4
--- /dev/null
+++ b/.mvn/wrapper/MavenWrapperDownloader.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+ private static final String WRAPPER_VERSION = "0.5.5";
+ /**
+ * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+ */
+ private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
+
+ /**
+ * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+ * use instead of the default one.
+ */
+ private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+ ".mvn/wrapper/maven-wrapper.properties";
+
+ /**
+ * Path where the maven-wrapper.jar will be saved to.
+ */
+ private static final String MAVEN_WRAPPER_JAR_PATH =
+ ".mvn/wrapper/maven-wrapper.jar";
+
+ /**
+ * Name of the property which should be used to override the default download url for the wrapper.
+ */
+ private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+ public static void main(String args[]) {
+ System.out.println("- Downloader started");
+ File baseDirectory = new File(args[0]);
+ System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+ // If the maven-wrapper.properties exists, read it and check if it contains a custom
+ // wrapperUrl parameter.
+ File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+ String url = DEFAULT_DOWNLOAD_URL;
+ if (mavenWrapperPropertyFile.exists()) {
+ FileInputStream mavenWrapperPropertyFileInputStream = null;
+ try {
+ mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+ Properties mavenWrapperProperties = new Properties();
+ mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+ url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+ } catch (IOException e) {
+ System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+ } finally {
+ try {
+ if (mavenWrapperPropertyFileInputStream != null) {
+ mavenWrapperPropertyFileInputStream.close();
+ }
+ } catch (IOException e) {
+ // Ignore ...
+ }
+ }
+ }
+ System.out.println("- Downloading from: " + url);
+
+ File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+ if (!outputFile.getParentFile().exists()) {
+ if (!outputFile.getParentFile().mkdirs()) {
+ System.out.println(
+ "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+ }
+ }
+ System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+ try {
+ downloadFileFromURL(url, outputFile);
+ System.out.println("Done");
+ System.exit(0);
+ } catch (Throwable e) {
+ System.out.println("- Error downloading");
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+ if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
+ String username = System.getenv("MVNW_USERNAME");
+ char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
+ Authenticator.setDefault(new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(username, password);
+ }
+ });
+ }
+ URL website = new URL(urlString);
+ ReadableByteChannel rbc;
+ rbc = Channels.newChannel(website.openStream());
+ FileOutputStream fos = new FileOutputStream(destination);
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ fos.close();
+ rbc.close();
+ }
+
+}
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
new file mode 100644
index 0000000..0d5e649
Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..7d59a01
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29
diff --git a/mvnw b/mvnw
new file mode 100644
index 0000000..822f699
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,322 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# M2_HOME - location of maven2's installed home dir
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ]; then
+
+ if [ -f /etc/mavenrc ]; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ]; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false
+darwin=false
+mingw=false
+case "$(uname)" in
+CYGWIN*) cygwin=true ;;
+MINGW*) mingw=true ;;
+Darwin*)
+ darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ export JAVA_HOME="$(/usr/libexec/java_home)"
+ else
+ export JAVA_HOME="/Library/Java/Home"
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ]; then
+ if [ -r /etc/gentoo-release ]; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+if [ -z "$M2_HOME" ]; then
+ ## resolve links - $0 may be a link to maven's home
+ PRG="$0"
+
+ # need this for relative symlinks
+ while [ -h "$PRG" ]; do
+ ls=$(ls -ld "$PRG")
+ link=$(expr "$ls" : '.*-> \(.*\)$')
+ if expr "$link" : '/.*' >/dev/null; then
+ PRG="$link"
+ else
+ PRG="$(dirname "$PRG")/$link"
+ fi
+ done
+
+ saveddir=$(pwd)
+
+ M2_HOME=$(dirname "$PRG")/..
+
+ # make it fully qualified
+ M2_HOME=$(cd "$M2_HOME" && pwd)
+
+ cd "$saveddir"
+ # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=$(cygpath --unix "$M2_HOME")
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME="$( (
+ cd "$M2_HOME"
+ pwd
+ ))"
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME="$( (
+ cd "$JAVA_HOME"
+ pwd
+ ))"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then
+ if $darwin; then
+ javaHome="$(dirname \"$javaExecutable\")"
+ javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f \"$javaExecutable\")"
+ fi
+ javaHome="$(dirname \"$javaExecutable\")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ]; then
+ if [ -n "$JAVA_HOME" ]; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(which java)"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ]; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+ if [ -z "$1" ]; then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ]; do
+ if [ -d "$wdir"/.mvn ]; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(
+ cd "$wdir/.."
+ pwd
+ )
+ fi
+ # end of workaround
+ done
+ echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ echo "$(tr -s '\n' ' ' <"$1")"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(pwd)")
+if [ -z "$BASE_DIR" ]; then
+ exit 1
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found .mvn/wrapper/maven-wrapper.jar"
+ fi
+else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+ fi
+ if [ -n "$MVNW_REPOURL" ]; then
+ jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ else
+ jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ fi
+ while IFS="=" read key value; do
+ case "$key" in wrapperUrl)
+ jarUrl="$value"
+ break
+ ;;
+ esac
+ done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Downloading from: $jarUrl"
+ fi
+ wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget >/dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found wget ... using wget"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget "$jarUrl" -O "$wrapperJarPath"
+ else
+ wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
+ fi
+ elif command -v curl >/dev/null; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Found curl ... using curl"
+ fi
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl -o "$wrapperJarPath" "$jarUrl" -f
+ else
+ curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
+ fi
+
+ else
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo "Falling back to using Java to download"
+ fi
+ javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaClass" ]; then
+ if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Compiling MavenWrapperDownloader.java ..."
+ fi
+ # Compiling the Java class
+ ("$JAVA_HOME/bin/javac" "$javaClass")
+ fi
+ if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+ # Running the downloader
+ if [ "$MVNW_VERBOSE" = true ]; then
+ echo " - Running MavenWrapperDownloader.java ..."
+ fi
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+ echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$M2_HOME" ] &&
+ M2_HOME=$(cygpath --path --windows "$M2_HOME")
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..84d60ab
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,182 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+
+FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %DOWNLOAD_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..133737d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,84 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.1.RELEASE
+
+
+ com.example
+ sso
+ 0.0.1-SNAPSHOT
+ jar
+ sso
+ Demo project for Spring Boot
+
+
+ 1.8
+
+
+
+
+ com.auth0
+ java-jwt
+ 3.8.1
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.2
+
+
+ com.alibaba
+ fastjson
+ 1.2.45
+
+
+ commons-codec
+ commons-codec
+ 1.19.0
+
+
+ com.fasterxml.jackson.dataformat
+ jackson-dataformat-xml
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/src/main/java/com/example/sso/SsoApplication.java b/src/main/java/com/example/sso/SsoApplication.java
new file mode 100644
index 0000000..6b7596b
--- /dev/null
+++ b/src/main/java/com/example/sso/SsoApplication.java
@@ -0,0 +1,18 @@
+package com.example.sso;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@EnableScheduling
+@EnableAsync
+
+public class SsoApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(SsoApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/example/sso/config/SSOConfig.java b/src/main/java/com/example/sso/config/SSOConfig.java
new file mode 100644
index 0000000..010fcd0
--- /dev/null
+++ b/src/main/java/com/example/sso/config/SSOConfig.java
@@ -0,0 +1,24 @@
+package com.example.sso.config;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.NotBlank;
+
+@Configuration
+@ConfigurationProperties(prefix = "sso")
+@NoArgsConstructor
+@AllArgsConstructor
+@Validated
+@Getter
+@Setter
+public class SSOConfig {
+ @NotBlank private String iss;
+ @NotBlank private String acs;
+ @NotBlank private String secret;
+}
diff --git a/src/main/java/com/example/sso/controller/AddController.java b/src/main/java/com/example/sso/controller/AddController.java
new file mode 100644
index 0000000..8bcbba1
--- /dev/null
+++ b/src/main/java/com/example/sso/controller/AddController.java
@@ -0,0 +1,70 @@
+package com.example.sso.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.example.sso.dao.Add;
+import com.example.sso.dao.Del;
+import com.example.sso.util.*;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.http.MediaType;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+
+@RestController
+@Slf4j
+public class AddController {
+ @PostMapping(value = "add",produces = MediaType.TEXT_PLAIN_VALUE)
+ public String receiveParams(
+ @RequestParam("msg_signature") String msgSignature,
+ @RequestParam("timestamp") String timeStamp,
+ @RequestParam("nonce") String nonce,
+ @RequestBody String data
+ ) throws AesException {
+
+ String sToken = "9jtKosB";
+ String sCorpID = "wwc276f7a0347c310b";
+ String sEncodingAESKey = "p5oRQgLuqAUtO9z8S5ArrgegjVY1kKl7gSMMdmBWk7e";
+
+ WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
+ String s = wxcpt.DecryptMsg(msgSignature, timeStamp, nonce, data);
+ log.info("我是消息 " + s);
+ JSONObject result = QiWeiUtil.result(s);
+ String CreateTime = result.getString("CreateTime");
+ String ChangeType = result.getString("ChangeType");
+ String UserID = result.getString("UserID");
+ String ExternalUserID = result.getString("ExternalUserID");
+ String Source = result.getString("Source");
+ String WelcomeCode = result.getString("WelcomeCode");
+ if (ChangeType.equals("add_external_contact")) {
+ Add.add(CreateTime, ChangeType, UserID, ExternalUserID);
+
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("welcome_code",WelcomeCode);
+ JSONObject text = new JSONObject();
+ text.put("content","尊敬的客户,感谢您选择与银建合作。为便于您接入我司内部管理系统,请点击以下链接完成注册,以获取授权访问权限。注册链接:https://www.jiyuankeshang.com/corp_join/68c2a407bf5e56180de1db75?host_corp_id=wwc276f7a0347c310b ");
+ jsonObject.put("text",text);
+ String jsonString = jsonObject.toJSONString();
+
+ String tokencreat = QiWeiUtil.newtoken();
+ JSONObject jsonObject2 = JSON.parseObject(tokencreat);
+ String string = jsonObject2.getString("access_token");
+ String welcome = QiWeiUtil.welcome(jsonString, string);
+ log.info("欢迎 " +welcome );
+ }else if (ChangeType.equals("del_external_contact")){
+ if (Source != null && Source != "" ) {
+ Del.del(CreateTime, ChangeType, UserID, ExternalUserID, Source);
+ }else {
+ Del.dels(CreateTime, ChangeType, UserID, ExternalUserID);
+ }
+ }else if (ChangeType.equals("del_follow_user")){
+ Add.del(CreateTime, ChangeType, UserID, ExternalUserID);
+ }
+
+ return "200";
+ }
+
+
+}
diff --git a/src/main/java/com/example/sso/controller/CreatAndYaoQingController.java b/src/main/java/com/example/sso/controller/CreatAndYaoQingController.java
new file mode 100644
index 0000000..9a03128
--- /dev/null
+++ b/src/main/java/com/example/sso/controller/CreatAndYaoQingController.java
@@ -0,0 +1,42 @@
+package com.example.sso.controller;
+
+
+import com.example.sso.util.AesException;
+import com.example.sso.util.WXBizMsgCrypt;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@Slf4j
+public class CreatAndYaoQingController {
+ //创建和邀请
+ // @GetMapping("/add")
+ public String receiveParams(
+ @RequestParam("msg_signature") String msgSignature,
+ @RequestParam("timestamp") String timeStamp,
+ @RequestParam("nonce") String nonce,
+ @RequestParam("echostr") String echoStr
+ ) throws AesException {
+
+ String sToken = "9jtKosB";
+ String sCorpID = "wwc276f7a0347c310b";
+ String sEncodingAESKey = "p5oRQgLuqAUtO9z8S5ArrgegjVY1kKl7gSMMdmBWk7e";
+
+ WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(sToken, sEncodingAESKey, sCorpID);
+
+ String sEchoStr = "";
+ try {
+ sEchoStr = wxcpt.VerifyURL(msgSignature, timeStamp,
+ nonce, echoStr);
+ System.out.println("verifyurl echostr: " + sEchoStr);
+ // 验证URL成功,将sEchoStr返回
+ // HttpUtils.SetResponse(sEchoStr);
+ } catch (Exception e) {
+ //验证URL失败,错误原因请查看异常
+ e.printStackTrace();
+ }
+
+
+ return sEchoStr;
+ }
+}
diff --git a/src/main/java/com/example/sso/controller/TuiSong.java b/src/main/java/com/example/sso/controller/TuiSong.java
new file mode 100644
index 0000000..aa4f128
--- /dev/null
+++ b/src/main/java/com/example/sso/controller/TuiSong.java
@@ -0,0 +1,31 @@
+package com.example.sso.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.example.sso.util.V5utils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@RestController
+public class TuiSong {
+ @PostMapping("tuisong")
+ public void tuisong(@RequestBody JSONObject data) {
+ log.info("数据 " + data.toJSONString());
+ JSONObject object = data.getJSONObject("data");
+ String mode_type = object.getString("mode_type");
+ String account_type = object.getString("account_type)");
+ String date = object.getString("date");
+
+ String beisen_id = object.getString("beisen_id");
+ if ((mode_type.equals("自营") ||mode_type.equals("DP") && (account_type.equals("预收款")) &&(date !=null && date !="") ) ) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("username", beisen_id);
+ String jsonString = jsonObject.toJSONString();
+ V5utils.delusername(jsonString);
+ }
+
+
+ }
+}
diff --git a/src/main/java/com/example/sso/dao/Add.java b/src/main/java/com/example/sso/dao/Add.java
new file mode 100644
index 0000000..db4f73a
--- /dev/null
+++ b/src/main/java/com/example/sso/dao/Add.java
@@ -0,0 +1,76 @@
+package com.example.sso.dao;
+
+import com.alibaba.fastjson.JSONObject;
+import com.example.sso.util.V5utils;
+
+public class Add {
+ public static void add(String CreateTime,String ChangeType, String UserID,String ExternalUserID) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("app_id", "628eeaace7f28c00089a60cc");
+ jsonObject.put("entry_id", "68f88b49bf5e56180dbf35fe");
+ jsonObject.put("is_start_trigger", true);
+ JSONObject data = new JSONObject();
+
+
+ JSONObject data_sources = new JSONObject();
+ data_sources.put("value", CreateTime);
+ data.put("create_time_jy", data_sources );
+
+ JSONObject match_field = new JSONObject();
+ match_field.put("value","添加企业客户");
+ data.put("event_jy", match_field );
+
+ JSONObject serialno = new JSONObject();
+ serialno.put("value", UserID);
+ data.put("userid_jy", serialno );
+
+ JSONObject serialno1 = new JSONObject();
+ serialno1.put("value", UserID);
+ data.put("corp_user_jy", serialno1 );
+
+ JSONObject lossSeqNo1 = new JSONObject();
+ lossSeqNo1.put("value", ExternalUserID);
+ data.put("external_userid_jy", lossSeqNo1);
+
+
+ jsonObject.put("data", data);
+ String jsonString = jsonObject.toJSONString();
+ V5utils.add(jsonString);
+
+ }
+
+ public static void del(String CreateTime,String ChangeType, String UserID,String ExternalUserID) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("app_id", "628eeaace7f28c00089a60cc");
+ jsonObject.put("entry_id", "68f88b49bf5e56180dbf35fe");
+ jsonObject.put("is_start_trigger", true);
+ JSONObject data = new JSONObject();
+
+
+ JSONObject data_sources = new JSONObject();
+ data_sources.put("value", CreateTime);
+ data.put("create_time_jy", data_sources );
+
+ JSONObject match_field = new JSONObject();
+ match_field.put("value","删除跟进成员");
+ data.put("event_jy", match_field );
+
+ JSONObject serialno = new JSONObject();
+ serialno.put("value", UserID);
+ data.put("userid_jy", serialno );
+
+ JSONObject serialno1 = new JSONObject();
+ serialno1.put("value", UserID);
+ data.put("corp_user_jy", serialno1 );
+
+ JSONObject lossSeqNo1 = new JSONObject();
+ lossSeqNo1.put("value", ExternalUserID);
+ data.put("external_userid_jy", lossSeqNo1);
+
+
+ jsonObject.put("data", data);
+ String jsonString = jsonObject.toJSONString();
+ V5utils.add(jsonString);
+
+ }
+}
diff --git a/src/main/java/com/example/sso/dao/Del.java b/src/main/java/com/example/sso/dao/Del.java
new file mode 100644
index 0000000..3e851a9
--- /dev/null
+++ b/src/main/java/com/example/sso/dao/Del.java
@@ -0,0 +1,101 @@
+package com.example.sso.dao;
+
+import com.alibaba.fastjson.JSONObject;
+import com.example.sso.util.V5utils;
+
+public class Del {
+ public static void del(String CreateTime,String ChangeType, String UserID,String ExternalUserID,String Source) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("app_id", "628eeaace7f28c00089a60cc");
+ jsonObject.put("entry_id", "68f88b49bf5e56180dbf35fe");
+ jsonObject.put("is_start_trigger", true);
+ JSONObject data = new JSONObject();
+
+
+ JSONObject data_sources = new JSONObject();
+ data_sources.put("value", CreateTime);
+ data.put("create_time_jy", data_sources );
+
+ JSONObject match_field = new JSONObject();
+ match_field.put("value","删除企业客户");
+ data.put("event_jy", match_field );
+
+ JSONObject serialno = new JSONObject();
+ serialno.put("value", UserID);
+ data.put("userid_jy", serialno );
+
+ JSONObject serialno1 = new JSONObject();
+ serialno1.put("value", UserID);
+ data.put("corp_user_jy", serialno1 );
+
+ JSONObject lossSeqNo1 = new JSONObject();
+ lossSeqNo1.put("value", ExternalUserID);
+ data.put("external_userid_jy", lossSeqNo1);
+
+
+ if (Source.equals("DELETE_BY_TRANSFER")){
+ JSONObject lossSeqNo11 = new JSONObject();
+ lossSeqNo11.put("value", "离职继承");
+ data.put("event_jy", lossSeqNo11);
+ }else {
+ JSONObject lossSeqNo11 = new JSONObject();
+ lossSeqNo11.put("value", "异常删除");
+ data.put("event_jy", lossSeqNo11);
+ }
+
+
+
+
+
+
+ jsonObject.put("data", data);
+ String jsonString = jsonObject.toJSONString();
+ V5utils.add(jsonString);
+
+ }
+
+
+ public static void dels(String CreateTime,String ChangeType, String UserID,String ExternalUserID ) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("app_id", "628eeaace7f28c00089a60cc");
+ jsonObject.put("entry_id", "68f88b49bf5e56180dbf35fe");
+ jsonObject.put("is_start_trigger", true);
+ JSONObject data = new JSONObject();
+
+
+ JSONObject data_sources = new JSONObject();
+ data_sources.put("value", CreateTime);
+ data.put("create_time_jy", data_sources );
+
+ JSONObject match_field = new JSONObject();
+ match_field.put("value","删除企业客户");
+ data.put("event_jy", match_field );
+
+ JSONObject serialno = new JSONObject();
+ serialno.put("value", UserID);
+ data.put("userid_jy", serialno );
+
+ JSONObject serialno1 = new JSONObject();
+ serialno1.put("value", UserID);
+ data.put("corp_user_jy", serialno1 );
+
+ JSONObject lossSeqNo1 = new JSONObject();
+ lossSeqNo1.put("value", ExternalUserID);
+ data.put("external_userid_jy", lossSeqNo1);
+
+ JSONObject lossSeqNo11 = new JSONObject();
+ lossSeqNo11.put("value", "异常删除");
+ data.put("event_jy", lossSeqNo11);
+
+
+
+
+
+
+
+ jsonObject.put("data", data);
+ String jsonString = jsonObject.toJSONString();
+ V5utils.add(jsonString);
+
+ }
+}
diff --git a/src/main/java/com/example/sso/service/SSOService.java b/src/main/java/com/example/sso/service/SSOService.java
new file mode 100644
index 0000000..70b2470
--- /dev/null
+++ b/src/main/java/com/example/sso/service/SSOService.java
@@ -0,0 +1,44 @@
+package com.example.sso.service;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.example.sso.config.SSOConfig;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpSession;
+import java.util.Calendar;
+import java.util.Date;
+
+@Service
+@NoArgsConstructor
+@AllArgsConstructor
+public class SSOService {
+ @Getter @Setter @Autowired private SSOConfig ssoConfig;
+ public String getResponse(String request, String username, HttpSession httpSession) {
+ Algorithm algorithm = Algorithm.HMAC256((String) httpSession.getAttribute("sso_secret"));
+ JWTVerifier verifier = JWT.require(algorithm)
+ .withIssuer("com.jiandaoyun")
+ .build();
+ DecodedJWT decoded = verifier.verify(request);
+ if (!"sso_req".equals(decoded.getClaim("type").asString())) {
+ return "";
+ }
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date());
+ calendar.add(Calendar.HOUR_OF_DAY, 1);
+ return JWT.create()
+ .withIssuer("com.jiandaoyun")
+ .withClaim("type", "sso_res")
+ .withClaim("username", username)
+ .withAudience("com.jiandaoyun")
+ .withExpiresAt(calendar.getTime())
+ .sign(algorithm);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/sso/test/A.java b/src/main/java/com/example/sso/test/A.java
new file mode 100644
index 0000000..792a95d
--- /dev/null
+++ b/src/main/java/com/example/sso/test/A.java
@@ -0,0 +1,64 @@
+package com.example.sso.test;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+
+public class A {
+ public static void main(String[] args) {
+ String xmlString = "1761534307";
+
+ try {
+ // 创建解析器工厂和解析器
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ // 将字符串转换为输入源并进行解析
+ Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
+
+ // 标准化文档(可选,但能处理一些空白字符问题)
+ doc.getDocumentElement().normalize();
+
+ // 获取根元素
+ Element root = doc.getDocumentElement();
+
+ // 提取具体数据
+ String toUserName = getTextContentByTagName(root, "ToUserName");
+ String fromUserName = getTextContentByTagName(root, "FromUserName");
+ String createTime = getTextContentByTagName(root, "CreateTime");
+ String msgType = getTextContentByTagName(root, "MsgType");
+ String event = getTextContentByTagName(root, "Event");
+ String changeType = getTextContentByTagName(root, "ChangeType");
+ String userID = getTextContentByTagName(root, "UserID");
+ String externalUserID = getTextContentByTagName(root, "ExternalUserID");
+ String welcomeCode = getTextContentByTagName(root, "WelcomeCode");
+
+ // 打印结果
+ System.out.println("ToUserName: " + toUserName);
+ System.out.println("FromUserName: " + fromUserName);
+ System.out.println("CreateTime: " + createTime);
+ System.out.println("MsgType: " + msgType);
+ System.out.println("Event: " + event);
+ System.out.println("ChangeType: " + changeType);
+ System.out.println("UserID: " + userID);
+ System.out.println("ExternalUserID: " + externalUserID);
+ System.out.println("WelcomeCode: " + welcomeCode);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 辅助方法:根据标签名获取元素的文本内容
+ private static String getTextContentByTagName(Element element, String tagName) {
+ NodeList nodeList = element.getElementsByTagName(tagName);
+ if (nodeList.getLength() > 0) {
+ return nodeList.item(0).getTextContent();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/example/sso/test/B.java b/src/main/java/com/example/sso/test/B.java
new file mode 100644
index 0000000..7ce2f08
--- /dev/null
+++ b/src/main/java/com/example/sso/test/B.java
@@ -0,0 +1,64 @@
+package com.example.sso.test;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+
+public class B {
+ public static void main(String[] args) {
+ String xmlString = "1761537016";
+
+ try {
+ // 创建解析器工厂和解析器
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ // 将字符串转换为输入源并进行解析
+ Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
+
+ // 标准化文档(可选,但能处理一些空白字符问题)
+ doc.getDocumentElement().normalize();
+
+ // 获取根元素
+ Element root = doc.getDocumentElement();
+
+ // 提取具体数据
+ String toUserName = getTextContentByTagName(root, "ToUserName");
+ String fromUserName = getTextContentByTagName(root, "FromUserName");
+ String createTime = getTextContentByTagName(root, "CreateTime");
+ String msgType = getTextContentByTagName(root, "MsgType");
+ String event = getTextContentByTagName(root, "Event");
+ String changeType = getTextContentByTagName(root, "ChangeType");
+ String userID = getTextContentByTagName(root, "UserID");
+ String externalUserID = getTextContentByTagName(root, "ExternalUserID");
+ String welcomeCode = getTextContentByTagName(root, "WelcomeCode");
+
+ // 打印结果
+ System.out.println("ToUserName: " + toUserName);
+ System.out.println("FromUserName: " + fromUserName);
+ System.out.println("CreateTime: " + createTime);
+ System.out.println("MsgType: " + msgType);
+ System.out.println("Event: " + event);
+ System.out.println("ChangeType: " + changeType);
+ System.out.println("UserID: " + userID);
+ System.out.println("ExternalUserID: " + externalUserID);
+ System.out.println("WelcomeCode: " + welcomeCode);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 辅助方法:根据标签名获取元素的文本内容
+ private static String getTextContentByTagName(Element element, String tagName) {
+ NodeList nodeList = element.getElementsByTagName(tagName);
+ if (nodeList.getLength() > 0) {
+ return nodeList.item(0).getTextContent();
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/example/sso/test/C.java b/src/main/java/com/example/sso/test/C.java
new file mode 100644
index 0000000..362b9b2
--- /dev/null
+++ b/src/main/java/com/example/sso/test/C.java
@@ -0,0 +1,26 @@
+package com.example.sso.test;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class C {
+
+ public static void main(String[] args) {
+ // 您提供的时间戳(单位:秒)
+ long timestampInSeconds = 1761537016L;
+
+ // 1. 将秒转换为毫秒,然后创建 Date 对象
+ Date date = new Date(timestampInSeconds * 1000L);
+
+ // 2. 创建格式化器,并设置其时间为 UTC
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC")); // 关键步骤:设置时区
+
+ // 3. 格式化输出
+ String utcTime = sdf.format(date);
+ System.out.println("UTC 时间: " + utcTime); // 输出:2025-10-27 08:30:16
+
+
+ }
+}
diff --git a/src/main/java/com/example/sso/util/AesException.java b/src/main/java/com/example/sso/util/AesException.java
new file mode 100644
index 0000000..2ae6e36
--- /dev/null
+++ b/src/main/java/com/example/sso/util/AesException.java
@@ -0,0 +1,59 @@
+package com.example.sso.util;
+
+@SuppressWarnings("serial")
+public class AesException extends Exception {
+
+ public final static int OK = 0;
+ public final static int ValidateSignatureError = -40001;
+ public final static int ParseXmlError = -40002;
+ public final static int ComputeSignatureError = -40003;
+ public final static int IllegalAesKey = -40004;
+ public final static int ValidateCorpidError = -40005;
+ public final static int EncryptAESError = -40006;
+ public final static int DecryptAESError = -40007;
+ public final static int IllegalBuffer = -40008;
+ //public final static int EncodeBase64Error = -40009;
+ //public final static int DecodeBase64Error = -40010;
+ //public final static int GenReturnXmlError = -40011;
+
+ private int code;
+
+ private static String getMessage(int code) {
+ switch (code) {
+ case ValidateSignatureError:
+ return "签名验证错误";
+ case ParseXmlError:
+ return "xml解析失败";
+ case ComputeSignatureError:
+ return "sha加密生成签名失败";
+ case IllegalAesKey:
+ return "SymmetricKey非法";
+ case ValidateCorpidError:
+ return "corpid校验失败";
+ case EncryptAESError:
+ return "aes加密失败";
+ case DecryptAESError:
+ return "aes解密失败";
+ case IllegalBuffer:
+ return "解密后得到的buffer非法";
+// case EncodeBase64Error:
+// return "base64加密错误";
+// case DecodeBase64Error:
+// return "base64解密错误";
+// case GenReturnXmlError:
+// return "xml生成失败";
+ default:
+ return null; // cannot be
+ }
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ AesException(int code) {
+ super(getMessage(code));
+ this.code = code;
+ }
+
+}
diff --git a/src/main/java/com/example/sso/util/ByteGroup.java b/src/main/java/com/example/sso/util/ByteGroup.java
new file mode 100644
index 0000000..f4f3dbf
--- /dev/null
+++ b/src/main/java/com/example/sso/util/ByteGroup.java
@@ -0,0 +1,26 @@
+package com.example.sso.util;
+
+import java.util.ArrayList;
+
+class ByteGroup {
+ ArrayList byteContainer = new ArrayList();
+
+ public byte[] toBytes() {
+ byte[] bytes = new byte[byteContainer.size()];
+ for (int i = 0; i < byteContainer.size(); i++) {
+ bytes[i] = byteContainer.get(i);
+ }
+ return bytes;
+ }
+
+ public ByteGroup addBytes(byte[] bytes) {
+ for (byte b : bytes) {
+ byteContainer.add(b);
+ }
+ return this;
+ }
+
+ public int size() {
+ return byteContainer.size();
+ }
+}
diff --git a/src/main/java/com/example/sso/util/PKCS7Encoder.java b/src/main/java/com/example/sso/util/PKCS7Encoder.java
new file mode 100644
index 0000000..2bb447d
--- /dev/null
+++ b/src/main/java/com/example/sso/util/PKCS7Encoder.java
@@ -0,0 +1,67 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.example.sso.util;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+/**
+ * 提供基于PKCS7算法的加解密接口.
+ */
+class PKCS7Encoder {
+ static Charset CHARSET = Charset.forName("utf-8");
+ static int BLOCK_SIZE = 32;
+
+ /**
+ * 获得对明文进行补位填充的字节.
+ *
+ * @param count 需要进行填充补位操作的明文字节个数
+ * @return 补齐用的字节数组
+ */
+ static byte[] encode(int count) {
+ // 计算需要填充的位数
+ int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+ if (amountToPad == 0) {
+ amountToPad = BLOCK_SIZE;
+ }
+ // 获得补位所用的字符
+ char padChr = chr(amountToPad);
+ String tmp = new String();
+ for (int index = 0; index < amountToPad; index++) {
+ tmp += padChr;
+ }
+ return tmp.getBytes(CHARSET);
+ }
+
+ /**
+ * 删除解密后明文的补位字符
+ *
+ * @param decrypted 解密后的明文
+ * @return 删除补位字符后的明文
+ */
+ static byte[] decode(byte[] decrypted) {
+ int pad = (int) decrypted[decrypted.length - 1];
+ if (pad < 1 || pad > 32) {
+ pad = 0;
+ }
+ return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+ }
+
+ /**
+ * 将数字转化成ASCII码对应的字符,用于对明文进行补码
+ *
+ * @param a 需要转化的数字
+ * @return 转化得到的字符
+ */
+ static char chr(int a) {
+ byte target = (byte) (a & 0xFF);
+ return (char) target;
+ }
+
+}
diff --git a/src/main/java/com/example/sso/util/QiWeiUtil.java b/src/main/java/com/example/sso/util/QiWeiUtil.java
new file mode 100644
index 0000000..300dc8e
--- /dev/null
+++ b/src/main/java/com/example/sso/util/QiWeiUtil.java
@@ -0,0 +1,207 @@
+package com.example.sso.util;
+
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+
+public class QiWeiUtil {
+ public static JSONObject result(String xmlString) {
+ // String xmlString = "1761534307";
+
+ JSONObject jsonObject = null;
+ try {
+ // 创建解析器工厂和解析器
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ // 将字符串转换为输入源并进行解析
+ Document doc = builder.parse(new InputSource(new StringReader(xmlString)));
+
+ // 标准化文档(可选,但能处理一些空白字符问题)
+ doc.getDocumentElement().normalize();
+
+ // 获取根元素
+ Element root = doc.getDocumentElement();
+
+ // 提取具体数据
+ String toUserName = getTextContentByTagName(root, "ToUserName");
+ String fromUserName = getTextContentByTagName(root, "FromUserName");
+ String createTime = getTextContentByTagName(root, "CreateTime");
+ String msgType = getTextContentByTagName(root, "MsgType");
+ String event = getTextContentByTagName(root, "Event");
+ String changeType = getTextContentByTagName(root, "ChangeType");
+ String userID = getTextContentByTagName(root, "UserID");
+ String externalUserID = getTextContentByTagName(root, "ExternalUserID");
+ String welcomeCode = getTextContentByTagName(root, "WelcomeCode");
+ String source = getTextContentByTagName(root, "Source");
+
+ // 打印结果
+ System.out.println("ToUserName: " + toUserName);
+ System.out.println("FromUserName: " + fromUserName);
+ System.out.println("CreateTime: " + createTime);
+ System.out.println("MsgType: " + msgType);
+ System.out.println("Event: " + event);
+ System.out.println("ChangeType: " + changeType);
+ System.out.println("UserID: " + userID);
+ System.out.println("ExternalUserID: " + externalUserID);
+ System.out.println("WelcomeCode: " + welcomeCode);
+ System.out.println("Source: " + source);
+
+ jsonObject = new JSONObject();
+ String time = TimeUtil.time(createTime);
+
+ jsonObject.put("CreateTime", time);
+ jsonObject.put("ChangeType", changeType);
+ jsonObject.put("UserID", userID);
+ jsonObject.put("ExternalUserID", externalUserID);
+ jsonObject.put("Source", source);
+ jsonObject.put("WelcomeCode", welcomeCode);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return jsonObject;
+ }
+
+ // 辅助方法:根据标签名获取元素的文本内容
+ private static String getTextContentByTagName(Element element, String tagName) {
+ NodeList nodeList = element.getElementsByTagName(tagName);
+ if (nodeList.getLength() > 0) {
+ return nodeList.item(0).getTextContent();
+ }
+ return null;
+ }
+
+
+ public static String token(){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpGet httpPost = new HttpGet("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wwc276f7a0347c310b&corpsecret=m-h_vn1sLr4PSw87SS-l-gRZN3uuHcYdCrFz0gDh-Ds");
+
+ String responseBody = null;
+ try {
+
+
+
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+
+
+ public static String welcome(String jsonBody,String token){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpPost httpPost = new HttpPost("https://qyapi.weixin.qq.com/cgi-bin/externalcontact/send_welcome_msg?access_token=" + token);
+
+ String responseBody = null;
+ try {
+
+
+
+ StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
+ httpPost.setEntity(entity);
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+
+ public static String newtoken() {
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpGet httpGet = new HttpGet("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wwc276f7a0347c310b&corpsecret=8jSj7EF1J6P1zzDeqzMxc-1c4EV3tTGyB5yljB2RWtk");
+
+ String responseBody = null;
+ try {
+
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpGet);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+}
diff --git a/src/main/java/com/example/sso/util/SHA1.java b/src/main/java/com/example/sso/util/SHA1.java
new file mode 100644
index 0000000..b17d985
--- /dev/null
+++ b/src/main/java/com/example/sso/util/SHA1.java
@@ -0,0 +1,61 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.example.sso.util;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * SHA1 class
+ *
+ * 计算消息签名接口.
+ */
+class SHA1 {
+
+ /**
+ * 用SHA1算法生成安全签名
+ * @param token 票据
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @param encrypt 密文
+ * @return 安全签名
+ * @throws AesException
+ */
+ public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException
+ {
+ try {
+ String[] array = new String[] { token, timestamp, nonce, encrypt };
+ StringBuffer sb = new StringBuffer();
+ // 字符串排序
+ Arrays.sort(array);
+ for (int i = 0; i < 4; i++) {
+ sb.append(array[i]);
+ }
+ String str = sb.toString();
+ // SHA1签名生成
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ md.update(str.getBytes());
+ byte[] digest = md.digest();
+
+ StringBuffer hexstr = new StringBuffer();
+ String shaHex = "";
+ for (int i = 0; i < digest.length; i++) {
+ shaHex = Integer.toHexString(digest[i] & 0xFF);
+ if (shaHex.length() < 2) {
+ hexstr.append(0);
+ }
+ hexstr.append(shaHex);
+ }
+ return hexstr.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.ComputeSignatureError);
+ }
+ }
+}
diff --git a/src/main/java/com/example/sso/util/TimeUtil.java b/src/main/java/com/example/sso/util/TimeUtil.java
new file mode 100644
index 0000000..2e30cf9
--- /dev/null
+++ b/src/main/java/com/example/sso/util/TimeUtil.java
@@ -0,0 +1,44 @@
+package com.example.sso.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class TimeUtil {
+ public static String time(String time) {
+ long timestampInSeconds = Long.parseLong(time);
+ // 您提供的时间戳(单位:秒)
+
+
+ // 1. 将秒转换为毫秒,然后创建 Date 对象
+ Date date = new Date(timestampInSeconds * 1000L);
+
+ // 2. 创建格式化器,并设置其时间为 UTC
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC")); // 关键步骤:设置时区
+
+ // 3. 格式化输出
+ String utcTime = sdf.format(date);
+ System.out.println("UTC 时间: " + utcTime); // 输出:2025-10-27 08:30:16
+ return utcTime;
+ }
+
+
+ public static void main(String[] args) {
+ long timestampInSeconds = Long.parseLong("1761880638");
+ // 您提供的时间戳(单位:秒)
+
+
+ // 1. 将秒转换为毫秒,然后创建 Date 对象
+ Date date = new Date(timestampInSeconds * 1000L);
+
+ // 2. 创建格式化器,并设置其时间为 UTC
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ sdf.setTimeZone(TimeZone.getTimeZone("UTC")); // 关键步骤:设置时区
+
+ // 3. 格式化输出
+ String utcTime = sdf.format(date);
+ System.out.println("UTC 时间: " + utcTime); // 输出:2025-10-27 08:30:16
+
+ }
+}
diff --git a/src/main/java/com/example/sso/util/V5utils.java b/src/main/java/com/example/sso/util/V5utils.java
new file mode 100644
index 0000000..6465ccb
--- /dev/null
+++ b/src/main/java/com/example/sso/util/V5utils.java
@@ -0,0 +1,233 @@
+package com.example.sso.util;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+public class V5utils {
+ /*
+ 查询多条数据
+ */
+ public static String list(String jsonBody){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpPost httpPost = new HttpPost("https://www.jiyuankeshang.com/api/v5/app/entry/data/list");
+
+ String responseBody = null;
+ try {
+ // 设置请求头
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setHeader("Authorization", "Bearer " + "BkIyzlh1onqnqu9cQ3ralDQBjECn97ex");
+
+
+ StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
+ httpPost.setEntity(entity);
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+
+ public static String delusername(String jsonBody){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpPost httpPost = new HttpPost("https://www.jiyuankeshang.com/api/v5/corp/user/delete");
+
+ String responseBody = null;
+ try {
+ // 设置请求头
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setHeader("Authorization", "Bearer " + "BkIyzlh1onqnqu9cQ3ralDQBjECn97ex");
+
+
+ StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
+ httpPost.setEntity(entity);
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+
+
+ public static String delete(String jsonBody){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpPost httpPost = new HttpPost("https://www.jiyuankeshang.com/api/v5/app/entry/data/delete");
+
+ String responseBody = null;
+ try {
+ // 设置请求头
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setHeader("Authorization", "Bearer " + "BkIyzlh1onqnqu9cQ3ralDQBjECn97ex");
+
+
+ StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
+ httpPost.setEntity(entity);
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+
+ //新增
+ public static String add(String jsonBody){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpPost httpPost = new HttpPost("https://www.jiyuankeshang.com/api/v5/app/entry/data/create");
+
+ String responseBody = null;
+ try {
+ // 设置请求头
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setHeader("Authorization", "Bearer " + "BkIyzlh1onqnqu9cQ3ralDQBjECn97ex");
+
+
+ StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
+ httpPost.setEntity(entity);
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+
+
+ public static String updata(String jsonBody){
+ CloseableHttpClient httpClient = HttpClients.createDefault();
+
+ // 创建 POST 请求对象
+ HttpPost httpPost = new HttpPost("https://www.jiyuankeshang.com/api/v5/app/entry/data/update");
+
+ String responseBody = null;
+ try {
+ // 设置请求头
+ httpPost.setHeader("Content-Type", "application/json");
+ httpPost.setHeader("Authorization", "Bearer " + "BkIyzlh1onqnqu9cQ3ralDQBjECn97ex");
+
+
+ StringEntity entity = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);
+ httpPost.setEntity(entity);
+
+ // 执行请求,获取响应对象
+ CloseableHttpResponse response = httpClient.execute(httpPost);
+
+ try {
+ // 从响应对象中获取响应实体
+ HttpEntity responseEntity = response.getEntity();
+
+ // 处理响应数据
+ responseBody = EntityUtils.toString(responseEntity);
+ System.out.println(responseBody);
+ } finally {
+ // 关闭响应对象
+ response.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ // 关闭 HttpClient
+ httpClient.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return responseBody;
+ }
+}
diff --git a/src/main/java/com/example/sso/util/WXBizMsgCrypt.java b/src/main/java/com/example/sso/util/WXBizMsgCrypt.java
new file mode 100644
index 0000000..fc976ee
--- /dev/null
+++ b/src/main/java/com/example/sso/util/WXBizMsgCrypt.java
@@ -0,0 +1,291 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+/**
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ */
+package com.example.sso.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+
+
+/**
+ * 提供接收和推送给企业微信消息的加解密接口(UTF8编码的字符串).
+ *
+ * - 第三方回复加密消息给企业微信
+ * - 第三方收到企业微信发送的消息,验证消息的安全性,并对消息进行解密。
+ *
+ * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案
+ *
+ * - 在官方网站下载JCE无限制权限策略文件(JDK7的下载地址:
+ * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
+ * - 下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
+ * - 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
+ * - 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件
+ *
+ */
+public class WXBizMsgCrypt {
+ static Charset CHARSET = Charset.forName("utf-8");
+ Base64 base64 = new Base64();
+ byte[] aesKey;
+ String token;
+ String receiveid;
+
+ /**
+ * 构造函数
+ * @param token 企业微信后台,开发者设置的token
+ * @param encodingAesKey 企业微信后台,开发者设置的EncodingAESKey
+ * @param receiveid, 不同场景含义不同,详见文档
+ *
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public WXBizMsgCrypt(String token, String encodingAesKey, String receiveid) throws AesException {
+ if (encodingAesKey.length() != 43) {
+ throw new AesException(AesException.IllegalAesKey);
+ }
+
+ this.token = token;
+ this.receiveid = receiveid;
+ aesKey = Base64.decodeBase64(encodingAesKey + "=");
+ }
+
+ // 生成4个字节的网络字节序
+ byte[] getNetworkBytesOrder(int sourceNumber) {
+ byte[] orderBytes = new byte[4];
+ orderBytes[3] = (byte) (sourceNumber & 0xFF);
+ orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
+ orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
+ orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
+ return orderBytes;
+ }
+
+ // 还原4个字节的网络字节序
+ int recoverNetworkBytesOrder(byte[] orderBytes) {
+ int sourceNumber = 0;
+ for (int i = 0; i < 4; i++) {
+ sourceNumber <<= 8;
+ sourceNumber |= orderBytes[i] & 0xff;
+ }
+ return sourceNumber;
+ }
+
+ // 随机生成16位字符串
+ String getRandomStr() {
+ String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+ Random random = new Random();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < 16; i++) {
+ int number = random.nextInt(base.length());
+ sb.append(base.charAt(number));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 对明文进行加密.
+ *
+ * @param text 需要加密的明文
+ * @return 加密后base64编码的字符串
+ * @throws AesException aes加密失败
+ */
+ String encrypt(String randomStr, String text) throws AesException {
+ ByteGroup byteCollector = new ByteGroup();
+ byte[] randomStrBytes = randomStr.getBytes(CHARSET);
+ byte[] textBytes = text.getBytes(CHARSET);
+ byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
+ byte[] receiveidBytes = receiveid.getBytes(CHARSET);
+
+ // randomStr + networkBytesOrder + text + receiveid
+ byteCollector.addBytes(randomStrBytes);
+ byteCollector.addBytes(networkBytesOrder);
+ byteCollector.addBytes(textBytes);
+ byteCollector.addBytes(receiveidBytes);
+
+ // ... + pad: 使用自定义的填充方式对明文进行补位填充
+ byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
+ byteCollector.addBytes(padBytes);
+
+ // 获得最终的字节流, 未加密
+ byte[] unencrypted = byteCollector.toBytes();
+
+ try {
+ // 设置加密模式为AES的CBC模式
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+ SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+ // 加密
+ byte[] encrypted = cipher.doFinal(unencrypted);
+
+ // 使用BASE64对加密后的字符串进行编码
+ String base64Encrypted = base64.encodeToString(encrypted);
+
+ return base64Encrypted;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.EncryptAESError);
+ }
+ }
+
+ /**
+ * 对密文进行解密.
+ *
+ * @param text 需要解密的密文
+ * @return 解密得到的明文
+ * @throws AesException aes解密失败
+ */
+ String decrypt(String text) throws AesException {
+ byte[] original;
+ try {
+ // 设置解密模式为AES的CBC模式
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+ SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+ cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
+
+ // 使用BASE64对密文进行解码
+ byte[] encrypted = Base64.decodeBase64(text);
+
+ // 解密
+ original = cipher.doFinal(encrypted);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.DecryptAESError);
+ }
+
+ String xmlContent, from_receiveid;
+ try {
+ // 去除补位字符
+ byte[] bytes = PKCS7Encoder.decode(original);
+
+ // 分离16位随机字符串,网络字节序和receiveid
+ byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+
+ int xmlLength = recoverNetworkBytesOrder(networkOrder);
+
+ xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
+ from_receiveid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
+ CHARSET);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.IllegalBuffer);
+ }
+
+ // receiveid不相同的情况
+ if (!from_receiveid.equals(receiveid)) {
+ throw new AesException(AesException.ValidateCorpidError);
+ }
+ return xmlContent;
+
+ }
+
+ /**
+ * 将企业微信回复用户的消息加密打包.
+ *
+ * - 对要发送的消息进行AES-CBC加密
+ * - 生成安全签名
+ * - 将消息密文和安全签名打包成xml格式
+ *
+ *
+ * @param replyMsg 企业微信待回复用户的消息,xml格式的字符串
+ * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
+ * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
+ *
+ * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String EncryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
+ // 加密
+ String encrypt = encrypt(getRandomStr(), replyMsg);
+
+ // 生成安全签名
+ if (timeStamp == "") {
+ timeStamp = Long.toString(System.currentTimeMillis());
+ }
+
+ String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt);
+
+ // System.out.println("发送给平台的签名是: " + signature[1].toString());
+ // 生成发送的xml
+ String result = XMLParse.generate(encrypt, signature, timeStamp, nonce);
+ return result;
+ }
+
+ /**
+ * 检验消息的真实性,并且获取解密后的明文.
+ *
+ * - 利用收到的密文生成安全签名,进行签名验证
+ * - 若验证通过,则提取xml中的加密消息
+ * - 对消息进行解密
+ *
+ *
+ * @param msgSignature 签名串,对应URL参数的msg_signature
+ * @param timeStamp 时间戳,对应URL参数的timestamp
+ * @param nonce 随机串,对应URL参数的nonce
+ * @param postData 密文,对应POST请求的数据
+ *
+ * @return 解密后的原文
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String DecryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
+ throws AesException {
+
+ // 密钥,公众账号的app secret
+ // 提取密文
+ Object[] encrypt = XMLParse.extract(postData);
+
+ // 验证安全签名
+ String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString());
+
+ // 和URL中的签名比较是否相等
+ // System.out.println("第三方收到URL中的签名:" + msg_sign);
+ // System.out.println("第三方校验签名:" + signature);
+ if (!signature.equals(msgSignature)) {
+ throw new AesException(AesException.ValidateSignatureError);
+ }
+
+ // 解密
+ String result = decrypt(encrypt[1].toString());
+ return result;
+ }
+
+ /**
+ * 验证URL
+ * @param msgSignature 签名串,对应URL参数的msg_signature
+ * @param timeStamp 时间戳,对应URL参数的timestamp
+ * @param nonce 随机串,对应URL参数的nonce
+ * @param echoStr 随机串,对应URL参数的echostr
+ *
+ * @return 解密之后的echostr
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String VerifyURL(String msgSignature, String timeStamp, String nonce, String echoStr)
+ throws AesException {
+ String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr);
+
+ if (!signature.equals(msgSignature)) {
+ throw new AesException(AesException.ValidateSignatureError);
+ }
+
+ String result = decrypt(echoStr);
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/sso/util/XMLParse.java b/src/main/java/com/example/sso/util/XMLParse.java
new file mode 100644
index 0000000..9770302
--- /dev/null
+++ b/src/main/java/com/example/sso/util/XMLParse.java
@@ -0,0 +1,104 @@
+/**
+ * 对企业微信发送给企业后台的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+// ------------------------------------------------------------------------
+
+package com.example.sso.util;
+
+import java.io.StringReader;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * XMLParse class
+ *
+ * 提供提取消息格式中的密文及生成回复消息格式的接口.
+ */
+class XMLParse {
+
+ /**
+ * 提取出xml数据包中的加密消息
+ * @param xmltext 待提取的xml字符串
+ * @return 提取出的加密消息字符串
+ * @throws AesException
+ */
+ public static Object[] extract(String xmltext) throws AesException {
+ Object[] result = new Object[3];
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+
+ String FEATURE = null;
+ // This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
+ // Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
+ FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
+ dbf.setFeature(FEATURE, true);
+
+ // If you can't completely disable DTDs, then at least do the following:
+ // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
+ // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
+ // JDK7+ - http://xml.org/sax/features/external-general-entities
+ FEATURE = "http://xml.org/sax/features/external-general-entities";
+ dbf.setFeature(FEATURE, false);
+
+ // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
+ // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
+ // JDK7+ - http://xml.org/sax/features/external-parameter-entities
+ FEATURE = "http://xml.org/sax/features/external-parameter-entities";
+ dbf.setFeature(FEATURE, false);
+
+ // Disable external DTDs as well
+ FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+ dbf.setFeature(FEATURE, false);
+
+ // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
+ dbf.setXIncludeAware(false);
+ dbf.setExpandEntityReferences(false);
+
+ // And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then
+ // ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
+ // (http://cwe.mitre.org/data/definitions/918.html) and denial
+ // of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."
+
+ // remaining parser logic
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ StringReader sr = new StringReader(xmltext);
+ InputSource is = new InputSource(sr);
+ Document document = db.parse(is);
+
+ Element root = document.getDocumentElement();
+ NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+ result[0] = 0;
+ result[1] = nodelist1.item(0).getTextContent();
+ return result;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.ParseXmlError);
+ }
+ }
+
+ /**
+ * 生成xml消息
+ * @param encrypt 加密后的消息密文
+ * @param signature 安全签名
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @return 生成的xml字符串
+ */
+ public static String generate(String encrypt, String signature, String timestamp, String nonce) {
+
+ String format = "\n" + "\n"
+ + "\n"
+ + "%3$s\n" + "\n" + "";
+ return String.format(format, encrypt, signature, timestamp, nonce);
+
+ }
+}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
new file mode 100644
index 0000000..1ce4ec6
--- /dev/null
+++ b/src/main/resources/application.yaml
@@ -0,0 +1,13 @@
+sso:
+ iss: https://www.jiandaoyun.com/sso/custom/5e6456c078aba300063b2fff/iss
+ acs: https://www.jiandaoyun.com/sso/custom/5e6456c078aba300063b2fff/acs
+ secret: 11
+server:
+ port: 3015
+jdy:
+ appkey: BkIyzlh1onqnqu9cQ3ralDQBjECn97ex
+ appid: 61bae73aebe2f500080d567b
+ formid: 61bae7bc5aa1e60008dbd378 #
+ formid_account: 11 #
+#测试环境
+
diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..c57a06f
--- /dev/null
+++ b/src/main/resources/logback-spring.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+ ${LOG_PATH}/${LOG_FILE}.log
+
+
+
+
+ ${LOG_PATH}/${LOG_FILE}.%d{yyyy-MM-dd}.log
+
+ ${MAX_HISTORY}
+
+
+
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/com/example/sso/SsoApplicationTests.java b/src/test/java/com/example/sso/SsoApplicationTests.java
new file mode 100644
index 0000000..1a3000a
--- /dev/null
+++ b/src/test/java/com/example/sso/SsoApplicationTests.java
@@ -0,0 +1,27 @@
+package com.example.sso;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import org.junit.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+
+@SpringBootTest
+class SsoApplicationTests {
+
+ @Test
+ void context() {
+ String json = "[{\"name\":\"1111\",\"code\":\"123\"},{\"name\":\"1111\",\"code\":\"123\"},{\"name\":\"1234\",\"code\":\"111\"}]";
+ List list = JSONObject.parseArray(json);
+ HashSet hs = new HashSet(list);
+ String jsonSet = JSON.toJSONString(hs);
+ JSONArray newjsonarray= new JSONArray(Collections.singletonList(jsonSet));
+ System.out.println(newjsonarray);
+ }
+
+}