Browse Source

基本完成

soft5566 2 years ago
parent
commit
53bd7026a2
28 changed files with 3091 additions and 0 deletions
  1. 34 0
      .gitignore
  2. BIN
      .mvn/wrapper/maven-wrapper.jar
  3. 2 0
      .mvn/wrapper/maven-wrapper.properties
  4. 1 0
      cron.txt
  5. 308 0
      mvnw
  6. 205 0
      mvnw.cmd
  7. 103 0
      pom.xml
  8. 16 0
      src/main/java/com/chkj/pdata/PdataApplication.java
  9. 94 0
      src/main/java/com/chkj/pdata/common/AES.java
  10. 40 0
      src/main/java/com/chkj/pdata/entity/AccessToken.java
  11. 22 0
      src/main/java/com/chkj/pdata/entity/AddUserReturn.java
  12. 58 0
      src/main/java/com/chkj/pdata/entity/CommonEntity.java
  13. 22 0
      src/main/java/com/chkj/pdata/entity/MemAddReturn.java
  14. 31 0
      src/main/java/com/chkj/pdata/entity/MemReturnFromWeixin.java
  15. 374 0
      src/main/java/com/chkj/pdata/entity/MemWeixin.java
  16. 304 0
      src/main/java/com/chkj/pdata/entity/MemberEntity.java
  17. 59 0
      src/main/java/com/chkj/pdata/entity/MemberEntityHeadImg.java
  18. 199 0
      src/main/java/com/chkj/pdata/task/BakMember.java
  19. 31 0
      src/main/java/com/chkj/pdata/task/MyScheduledTask.java
  20. 587 0
      src/main/java/com/chkj/pdata/task/PushMember.java
  21. 144 0
      src/main/java/com/chkj/pdata/task/SavaBlobToPng.java
  22. 292 0
      src/main/java/com/chkj/pdata/util/DBUtils.java
  23. 21 0
      src/main/java/com/chkj/pdata/util/DateTime.java
  24. 82 0
      src/main/java/com/chkj/pdata/util/FileUtil.java
  25. 37 0
      src/main/java/com/chkj/pdata/util/HttpRequestUtils.java
  26. 3 0
      src/main/resources/META-INF/MANIFEST.MF
  27. 9 0
      src/main/resources/application.properties
  28. 13 0
      src/test/java/com/chkj/pdata/PdataApplicationTests.java

+ 34 - 0
.gitignore

@@ -0,0 +1,34 @@
+HELP.md
+target/
+head_image/
+!.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/

BIN
.mvn/wrapper/maven-wrapper.jar


+ 2 - 0
.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1,2 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar

+ 1 - 0
cron.txt

@@ -0,0 +1 @@
+*/30 * * * * *

+ 308 - 0
mvnw

@@ -0,0 +1,308 @@
+#!/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.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   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 /usr/local/etc/mavenrc ] ; then
+    . /usr/local/etc/mavenrc
+  fi
+
+  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
+        JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+      else
+        JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=$(java-config --jre-home)
+  fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -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 "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+    JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); 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="$(\unset -f command 2>/dev/null; \command -v 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
+
+# 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/.." || exit 1; pwd)
+    fi
+    # end of workaround
+  done
+  printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    # Remove \r in case we run on Windows within Git Bash
+    # and check out the repository with auto CRLF management
+    # enabled. Otherwise, we may read lines that are delimited with
+    # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+    # splitting rules.
+    tr -s '\r\n' ' ' < "$1"
+  fi
+}
+
+log() {
+  if [ "$MVNW_VERBOSE" = true ]; then
+    printf '%s\n' "$1"
+  fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# 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.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+    log "Found $wrapperJarPath"
+else
+    log "Couldn't find $wrapperJarPath, downloading it ..."
+
+    if [ -n "$MVNW_REPOURL" ]; then
+      wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+    else
+      wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+    fi
+    while IFS="=" read -r key value; do
+      # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+      safeValue=$(echo "$value" | tr -d '\r')
+      case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+      esac
+    done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+    log "Downloading from: $wrapperUrl"
+
+    if $cygwin; then
+      wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+    fi
+
+    if command -v wget > /dev/null; then
+        log "Found wget ... using wget"
+        [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        else
+            wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+        fi
+    elif command -v curl > /dev/null; then
+        log "Found curl ... using curl"
+        [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+        if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+            curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+        else
+            curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+        fi
+    else
+        log "Falling back to using Java to download"
+        javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+        # For Cygwin, switch paths to Windows format before running javac
+        if $cygwin; then
+          javaSource=$(cygpath --path --windows "$javaSource")
+          javaClass=$(cygpath --path --windows "$javaClass")
+        fi
+        if [ -e "$javaSource" ]; then
+            if [ ! -e "$javaClass" ]; then
+                log " - Compiling MavenWrapperDownloader.java ..."
+                ("$JAVA_HOME/bin/javac" "$javaSource")
+            fi
+            if [ -e "$javaClass" ]; then
+                log " - Running MavenWrapperDownloader.java ..."
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+  case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+  esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+  wrapperSha256Result=false
+  if command -v sha256sum > /dev/null; then
+    if echo "$wrapperSha256Sum  $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+      wrapperSha256Result=true
+    fi
+  elif command -v shasum > /dev/null; then
+    if echo "$wrapperSha256Sum  $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+      wrapperSha256Result=true
+    fi
+  else
+    echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+    echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+    exit 1
+  fi
+  if [ $wrapperSha256Result = false ]; then
+    echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+    echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+    echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+    exit 1
+  fi
+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 "$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
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  $MAVEN_DEBUG_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 205 - 0
mvnw.cmd

@@ -0,0 +1,205 @@
+@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 Apache Maven Wrapper startup batch script, version 3.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@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 keystroke 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 "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\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 WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperUrl" SET WRAPPER_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 WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+    )
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Couldn't find %WRAPPER_JAR%, downloading it ...
+        echo Downloading from: %WRAPPER_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('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+		"}"
+    if "%MVNW_VERBOSE%" == "true" (
+        echo Finished downloading %WRAPPER_JAR%
+    )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+    IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+    powershell -Command "&{"^
+       "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+       "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+       "  Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+       "  Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+       "  Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+       "  exit 1;"^
+       "}"^
+       "}"
+    if ERRORLEVEL 1 goto error
+)
+
+@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 "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\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%
+
+cmd /C exit /B %ERROR_CODE%

+ 103 - 0
pom.xml

@@ -0,0 +1,103 @@
+<?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>3.1.0</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.chkj</groupId>
+    <artifactId>pdata</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>pdata</name>
+    <description>pdata</description>
+    <properties>
+        <java.version>17</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.15.1</version>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.19</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.10.1</version>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/org.json/json -->
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20230618</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <!--打包文件名,headerImage:8081,-->
+<!--        <finalName>headerImage</finalName>-->
+        <!--打包文件名,pushData:8082,-->
+        <finalName>pushData</finalName>
+        <plugins>
+            <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>
+        </plugins>
+    </build>
+
+</project>

+ 16 - 0
src/main/java/com/chkj/pdata/PdataApplication.java

@@ -0,0 +1,16 @@
+package com.chkj.pdata;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+
+@SpringBootApplication
+@EnableScheduling
+public class PdataApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(PdataApplication.class, args);
+    }
+
+}

+ 94 - 0
src/main/java/com/chkj/pdata/common/AES.java

@@ -0,0 +1,94 @@
+package com.chkj.pdata.common;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class AES {
+    public static String exeAES(String src) {
+        // app_key
+        String cKey = "5AA49F3E4CACA380";
+        // 需要加密的字串
+        String cSrc = src;
+        // app_secret 取前16位;
+        String cIv = "58D34C81D82B3517";
+        // 加密
+        try {
+            return AES.Encrypt(cSrc, cKey, cIv);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    public static String Encrypt(String sSrc, String sKey, String sIv) throws Exception {
+
+        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+        int blockSize = cipher.getBlockSize();
+
+        byte[] dataBytes = sSrc.getBytes();
+        int plaintextLength = dataBytes.length;
+        if (plaintextLength % blockSize != 0) {
+            plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
+        }
+
+        byte[] plaintext = new byte[plaintextLength];
+        System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
+
+        SecretKeySpec keyspec = new SecretKeySpec(sKey.getBytes(), "AES");
+        IvParameterSpec ivspec = new IvParameterSpec(sIv.getBytes());
+
+        cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
+        byte[] encrypted = cipher.doFinal(plaintext);
+
+        return byte2hex(encrypted).toLowerCase();
+    }
+
+    public static String Decrypt(String sSrc, String sKey, String sIv) throws Exception {
+
+        byte[] encrypted1 = hex2byte(sSrc);
+
+        Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+        SecretKeySpec keyspec = new SecretKeySpec(sKey.getBytes(), "AES");
+        IvParameterSpec ivspec = new IvParameterSpec(sIv.getBytes());
+
+        cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
+
+        byte[] original = cipher.doFinal(encrypted1);
+        String originalString = new String(original);
+
+        return originalString;
+    }
+
+    public static byte[] hex2byte(String strhex) {
+        if (strhex == null) {
+            return null;
+        }
+        int l = strhex.length();
+        if (l % 2 == 1) {
+            return null;
+        }
+        byte[] b = new byte[l / 2];
+        for (int i = 0; i != l / 2; i++) {
+            b[i] = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2),
+                    16);
+        }
+
+        return b;
+    }
+
+    public static String byte2hex(byte[] b) {
+        String hs = "";
+        String stmp = "";
+        for (int n = 0; n < b.length; n++) {
+            stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
+            if (stmp.length() == 1) {
+                hs = hs + "0" + stmp;
+            } else {
+                hs = hs + stmp;
+            }
+        }
+
+        return hs.toUpperCase();
+    }
+}

+ 40 - 0
src/main/java/com/chkj/pdata/entity/AccessToken.java

@@ -0,0 +1,40 @@
+package com.chkj.pdata.entity;
+
+public class AccessToken {
+    private String token_type;
+    private String access_token;
+    private String ocode;
+    private int expires_in;
+
+    public String getToken_type() {
+        return token_type;
+    }
+
+    public void setToken_type(String token_type) {
+        this.token_type = token_type;
+    }
+
+    public String getAccess_token() {
+        return access_token;
+    }
+
+    public void setAccess_token(String access_token) {
+        this.access_token = access_token;
+    }
+
+    public String getOcode() {
+        return ocode;
+    }
+
+    public void setOcode(String ocode) {
+        this.ocode = ocode;
+    }
+
+    public int getExpires_in() {
+        return expires_in;
+    }
+
+    public void setExpires_in(int expires_in) {
+        this.expires_in = expires_in;
+    }
+}

+ 22 - 0
src/main/java/com/chkj/pdata/entity/AddUserReturn.java

@@ -0,0 +1,22 @@
+package com.chkj.pdata.entity;
+
+public class AddUserReturn {
+    private int errcode;
+    private String errmsg;
+
+    public int getErrcode() {
+        return errcode;
+    }
+
+    public void setErrcode(int errcode) {
+        this.errcode = errcode;
+    }
+
+    public String getErrmsg() {
+        return errmsg;
+    }
+
+    public void setErrmsg(String errmsg) {
+        this.errmsg = errmsg;
+    }
+}

+ 58 - 0
src/main/java/com/chkj/pdata/entity/CommonEntity.java

@@ -0,0 +1,58 @@
+package com.chkj.pdata.entity;
+
+import java.util.List;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+* 实体类都继承的类
+*
+*/
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CommonEntity {
+    /**
+     * 前台的排序条件
+     */
+    @ApiModelProperty(hidden = true)
+    private List<String> orderData;
+
+    /**
+     * 当前页
+     */
+    @ApiModelProperty(value = "当前页",name = "currentPage",required = true)
+    private Integer currentPage;
+
+    /**
+    * 每页显示条数
+    */
+    @ApiModelProperty(hidden = true)
+    private Integer pageSize;
+
+    /**
+     * 开始下标
+     */
+    @ApiModelProperty(hidden = true)
+    private Integer start;
+
+    /**
+    * 开始下标(oracle用)
+    */
+    @ApiModelProperty(hidden = true)
+    private Integer startIndex;
+
+    /**
+    * 结束下标(oracle用)
+    */
+    @ApiModelProperty(hidden = true)
+    private Integer endIndex;
+
+    /**
+     * 字符串格式的排序条件
+     */
+    @ApiModelProperty(hidden = true)
+    private String orderStr;
+}

+ 22 - 0
src/main/java/com/chkj/pdata/entity/MemAddReturn.java

@@ -0,0 +1,22 @@
+package com.chkj.pdata.entity;
+
+public class MemAddReturn {
+    private int errcode;
+    private String errmsg;
+
+    public int getErrcode() {
+        return errcode;
+    }
+
+    public void setErrcode(int errcode) {
+        this.errcode = errcode;
+    }
+
+    public String getErrmsg() {
+        return errmsg;
+    }
+
+    public void setErrmsg(String errmsg) {
+        this.errmsg = errmsg;
+    }
+}

+ 31 - 0
src/main/java/com/chkj/pdata/entity/MemReturnFromWeixin.java

@@ -0,0 +1,31 @@
+package com.chkj.pdata.entity;
+
+public class MemReturnFromWeixin {
+    private int errcode;
+    private String errmsg;
+    private Object[] userlist;
+
+    public int getErrcode() {
+        return errcode;
+    }
+
+    public void setErrcode(int errcode) {
+        this.errcode = errcode;
+    }
+
+    public String getErrmsg() {
+        return errmsg;
+    }
+
+    public void setErrmsg(String errmsg) {
+        this.errmsg = errmsg;
+    }
+
+    public Object[] getUserlist() {
+        return userlist;
+    }
+
+    public void setUserlist(Object[] userlist) {
+        this.userlist = userlist;
+    }
+}

+ 374 - 0
src/main/java/com/chkj/pdata/entity/MemWeixin.java

@@ -0,0 +1,374 @@
+package com.chkj.pdata.entity;
+
+import java.lang.reflect.Field;
+
+public class MemWeixin {
+    private String weixiao_stu_id;
+    private String card_number;
+    private String name;
+    private int gender;
+    private byte head_image;
+    private int identity_type;
+    private String grade;
+    private String campus;
+    private String employer;
+    private String dorm_number;
+    private String physical_chip_number;
+    private String physical_card_number;
+    private String nation;
+    private String birthday;
+    private String origin_place;
+    private String graduated_school;
+    private String address;
+    private String contact_person;
+    private String contact_phone;
+    private String qq;
+    private String email;
+    private int card_type;
+    private String identity_title;
+    private String college;
+    private String profession;
+//     private String class;
+    private Class<?> classObj; // 班级对象
+    private String id_card;
+    private int country;
+    private String telephone;
+    private int data_source;
+    private String start_at;
+    private String expire_at;
+    private String job_title;
+    private String serial_number;
+    private String en_name;
+    private String office_phone;
+    private String school_period;
+    private String register_year;
+    private int[] organization;
+    private int[] department;
+
+    public String getWeixiao_stu_id() {
+        return weixiao_stu_id;
+    }
+
+    public void setWeixiao_stu_id(String weixiao_stu_id) {
+        this.weixiao_stu_id = weixiao_stu_id;
+    }
+
+    public String getCard_number() {
+        return card_number;
+    }
+
+    public void setCard_number(String card_number) {
+        this.card_number = card_number;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getGender() {
+        return gender;
+    }
+
+    public void setGender(int gender) {
+        this.gender = gender;
+    }
+
+    public byte getHead_image() {
+        return head_image;
+    }
+
+    public void setHead_image(byte head_image) {
+        this.head_image = head_image;
+    }
+
+    public int getIdentity_type() {
+        return identity_type;
+    }
+
+    public void setIdentity_type(int identity_type) {
+        this.identity_type = identity_type;
+    }
+
+    public String getGrade() {
+        return grade;
+    }
+
+    public void setGrade(String grade) {
+        this.grade = grade;
+    }
+
+    public String getCampus() {
+        return campus;
+    }
+
+    public void setCampus(String campus) {
+        this.campus = campus;
+    }
+
+    public String getEmployer() {
+        return employer;
+    }
+
+    public void setEmployer(String employer) {
+        this.employer = employer;
+    }
+
+    public String getDorm_number() {
+        return dorm_number;
+    }
+
+    public void setDorm_number(String dorm_number) {
+        this.dorm_number = dorm_number;
+    }
+
+    public String getPhysical_chip_number() {
+        return physical_chip_number;
+    }
+
+    public void setPhysical_chip_number(String physical_chip_number) {
+        this.physical_chip_number = physical_chip_number;
+    }
+
+    public String getPhysical_card_number() {
+        return physical_card_number;
+    }
+
+    public void setPhysical_card_number(String physical_card_number) {
+        this.physical_card_number = physical_card_number;
+    }
+
+    public String getNation() {
+        return nation;
+    }
+
+    public void setNation(String nation) {
+        this.nation = nation;
+    }
+
+    public String getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(String birthday) {
+        this.birthday = birthday;
+    }
+
+    public String getOrigin_place() {
+        return origin_place;
+    }
+
+    public void setOrigin_place(String origin_place) {
+        this.origin_place = origin_place;
+    }
+
+    public String getGraduated_school() {
+        return graduated_school;
+    }
+
+    public void setGraduated_school(String graduated_school) {
+        this.graduated_school = graduated_school;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getContact_person() {
+        return contact_person;
+    }
+
+    public void setContact_person(String contact_person) {
+        this.contact_person = contact_person;
+    }
+
+    public String getContact_phone() {
+        return contact_phone;
+    }
+
+    public void setContact_phone(String contact_phone) {
+        this.contact_phone = contact_phone;
+    }
+
+    public String getQq() {
+        return qq;
+    }
+
+    public void setQq(String qq) {
+        this.qq = qq;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public int getCard_type() {
+        return card_type;
+    }
+
+    public void setCard_type(int card_type) {
+        this.card_type = card_type;
+    }
+
+    public String getIdentity_title() {
+        return identity_title;
+    }
+
+    public void setIdentity_title(String identity_title) {
+        this.identity_title = identity_title;
+    }
+
+    public String getCollege() {
+        return college;
+    }
+
+    public void setCollege(String college) {
+        this.college = college;
+    }
+
+    public String getProfession() {
+        return profession;
+    }
+
+    public void setProfession(String profession) {
+        this.profession = profession;
+    }
+
+    public Class<?> getClassObj() {
+        return classObj;
+    }
+
+    public void setClassObj(Class<?> classObj) {
+        this.classObj = classObj;
+    }
+
+    public String getId_card() {
+        return id_card;
+    }
+
+    public void setId_card(String id_card) {
+        this.id_card = id_card;
+    }
+
+    public int getCountry() {
+        return country;
+    }
+
+    public void setCountry(int country) {
+        this.country = country;
+    }
+
+    public String getTelephone() {
+        return telephone;
+    }
+
+    public void setTelephone(String telephone) {
+        this.telephone = telephone;
+    }
+
+    public int getData_source() {
+        return data_source;
+    }
+
+    public void setData_source(int data_source) {
+        this.data_source = data_source;
+    }
+
+    public String getStart_at() {
+        return start_at;
+    }
+
+    public void setStart_at(String start_at) {
+        this.start_at = start_at;
+    }
+
+    public String getExpire_at() {
+        return expire_at;
+    }
+
+    public void setExpire_at(String expire_at) {
+        this.expire_at = expire_at;
+    }
+
+    public String getJob_title() {
+        return job_title;
+    }
+
+    public void setJob_title(String job_title) {
+        this.job_title = job_title;
+    }
+
+    public String getSerial_number() {
+        return serial_number;
+    }
+
+    public void setSerial_number(String serial_number) {
+        this.serial_number = serial_number;
+    }
+
+    public String getEn_name() {
+        return en_name;
+    }
+
+    public void setEn_name(String en_name) {
+        this.en_name = en_name;
+    }
+
+    public String getOffice_phone() {
+        return office_phone;
+    }
+
+    public void setOffice_phone(String office_phone) {
+        this.office_phone = office_phone;
+    }
+
+    public String getSchool_period() {
+        return school_period;
+    }
+
+    public void setSchool_period(String school_period) {
+        this.school_period = school_period;
+    }
+
+    public String getRegister_year() {
+        return register_year;
+    }
+
+    public void setRegister_year(String register_year) {
+        this.register_year = register_year;
+    }
+
+    public int[] getOrganization() {
+        return organization;
+    }
+
+    public void setOrganization(int[] organization) {
+        this.organization = organization;
+    }
+
+    public int[] getDepartment() {
+        return department;
+    }
+
+    public void setDepartment(int[] department) {
+        this.department = department;
+    }
+
+    // 通过反射获取班级属性名
+    public String getClassName() throws Exception {
+        Field field = classObj.getDeclaredField("class");
+        field.setAccessible(true);
+        return (String) field.get(null);
+    }
+}

+ 304 - 0
src/main/java/com/chkj/pdata/entity/MemberEntity.java

@@ -0,0 +1,304 @@
+package com.chkj.pdata.entity;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@ApiModel
+@Data
+@EqualsAndHashCode(callSuper = false)
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MemberEntity extends CommonEntity implements Serializable {
+
+    /**
+     * serialVersionUID
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键自增字段
+     */
+    @ApiModelProperty(value = "主键自增字段", name = "mid")
+    private int mid;
+    /**
+     * 学工号,如:weixiao2164257621
+     */
+    @ApiModelProperty(value = "学工号,如:weixiao2164257621", name = "mcardNumber")
+    private String mcardNumber;
+    /**
+     * 姓名,如:张三
+     */
+    @ApiModelProperty(value = "姓名,如:张三", name = "mname")
+    private String mname;
+    /**
+     * 性别,如:男
+     */
+    @ApiModelProperty(value = "性别,如:男", name = "mgender")
+    private String mgender;
+    /**
+     * 年级,如:2016
+     */
+    @ApiModelProperty(value = "年级,如:2016", name = "mgrade")
+    private String mgrade;
+    /**
+     * 学院名称,如:信息科学与技术学院
+     */
+    @ApiModelProperty(value = "学院名称,如:信息科学与技术学院", name = "mcollege")
+    private String mcollege;
+    /**
+     * 系的名称,如:计算机系
+     */
+    @ApiModelProperty(value = "系的名称,如:计算机系", name = "mprofession")
+    private String mprofession;
+    /**
+     * 专业名称,如:软件工程
+     */
+    @ApiModelProperty(value = "专业名称,如:软件工程", name = "mmajor")
+    private String mmajor;
+    /**
+     * 班级,如:软件工程1班
+     */
+    @ApiModelProperty(value = "班级,如:软件工程1班", name = "mclass")
+    private String mclass;
+    /**
+     * 身份类型,如:1学生,2老师
+     */
+    @ApiModelProperty(value = "身份类型,如:1学生,2老师", name = "midentityType")
+    private String midentityType;
+    /**
+     * 身份名称,如:本科生
+     */
+    @ApiModelProperty(value = "身份名称,如:本科生", name = "midentityTitle")
+    private String midentityTitle;
+    /**
+     * 证件类型(默认是:身份证),如:身份证,能支持[身份证]、[回乡证]、[台胞证] 、[外国护照]和[其它]
+     */
+    @ApiModelProperty(value = "证件类型(默认是:身份证),如:1身份证,能支持[身份证]、[回乡证]、[台胞证] 、[外国护照]和[其它]", name = "mcardType")
+    private String mcardType;
+    /**
+     * 证件号码,如:4XXX***7
+     */
+    @ApiModelProperty(value = "证件号码,如:4XXX***7", name = "midCard")
+    private String midCard;
+    /**
+     * 国家,如:CHN
+     */
+    @ApiModelProperty(value = "国家,如:CHN", name = "mcountry")
+    private String mcountry;
+    /**
+     * 手机号,如:137***8
+     */
+    @ApiModelProperty(value = "手机号,如:137***8", name = "mtelephone")
+    private String mtelephone;
+    /**
+     * 组织架构(我自己来拼),如:老师:南昌交通学院/教职工/所在部门,学生:南昌交通学院/学生/学院/年级/专业/班级
+     */
+    @ApiModelProperty(value = "组织架构(我自己来拼),如:老师:南昌交通学院/教职工/所在部门,学生:南昌交通学院/学生/学院/年级/专业/班级", name = "morganization")
+    private String morganization;
+    /**
+     * 校区,如:墨轩湖校区
+     */
+    @ApiModelProperty(value = "校区,如:墨轩湖校区", name = "mcampus")
+    private String mcampus;
+    /**
+     * 工作单位,如:XX研究所
+     */
+    @ApiModelProperty(value = "工作单位,如:XX研究所", name = "memployer")
+    private String memployer;
+    /**
+     * 楼栋,如:m01墨轩湖1栋,没有m是黄家湖
+     */
+    @ApiModelProperty(value = "楼栋,如:m01墨轩湖1栋,没有m是黄家湖", name = "mbuilding")
+    private String mbuilding;
+    /**
+     * 宿舍号,如:A栋206
+     */
+    @ApiModelProperty(value = "宿舍号,如:206", name = "mdormNumber")
+    private String mdormNumber;
+    /**
+     * 备注,如:00000000
+     */
+    @ApiModelProperty(value = "备注,如:00000000", name = "mremark")
+    private String mremark;
+    /**
+     * 邮箱,如:weixiao@tencent.com
+     */
+    @ApiModelProperty(value = "邮箱,如:weixiao@tencent.com", name = "memail")
+    private String memail;
+    /**
+     * 有效时间,如:2019-01-01 00:00:00
+     */
+    @ApiModelProperty(value = "有效时间,如:2019-01-01 00:00:00", name = "mexpireAt")
+    private Date mexpireAt;
+    /**
+     * QQ号, 如:12345678
+     */
+    @ApiModelProperty(value = "QQ号, 如:12345678", name = "mqq")
+    private String mqq;
+    /**
+     * 民族, 如:汉族
+     */
+    @ApiModelProperty(value = "民族, 如:汉族", name = "mnation")
+    private String mnation;
+    /**
+     * 户籍,如:陕西省
+     */
+    @ApiModelProperty(value = "户籍,如:陕西省", name = "moriginPlace")
+    private String moriginPlace;
+    /**
+     * 生源地
+     */
+    @ApiModelProperty(value = "生源地", name = "msourcePlace")
+    private String msourcePlace;
+    /**
+     * 毕业学校,如:XX中学
+     */
+    @ApiModelProperty(value = "毕业学校,如:XX中学", name = "mgraduatedSchool")
+    private String mgraduatedSchool;
+    /**
+     * 家庭住址,如:仙桃市郑场镇潘阳村八组
+     */
+    @ApiModelProperty(value = "家庭住址,如:仙桃市郑场镇潘阳村八组", name = "maddress")
+    private String maddress;
+    /**
+     * 学段,如:大学
+     */
+    @ApiModelProperty(value = "学段,如:大学", name = "mschoolPeriod")
+    private String mschoolPeriod;
+    /**
+     * 学制
+     */
+    @ApiModelProperty(value = "学制", name = "meducational")
+    private String meducational;
+    /**
+     * 入学年份,如:2022
+     */
+    @ApiModelProperty(value = "入学年份,如:2022", name = "mregisterYear")
+    private String mregisterYear;
+    /**
+     * 职务
+     */
+    @ApiModelProperty(value = "职务", name = "mposition")
+    private String mposition;
+    /**
+     * 部门
+     */
+    @ApiModelProperty(value = "部门", name = "mdepartment")
+    private String mdepartment;
+    /**
+     * 生日
+     */
+    @ApiModelProperty(value = "生日", name = "mbirthday")
+    private String mbirthday;
+    /**
+     * 编号
+     */
+    @ApiModelProperty(value = "编号", name = "midNumber")
+    private String midNumber;
+    /**
+     * 有效开始时间
+     */
+    @ApiModelProperty(value = "有效开始时间", name = "mvalidStartTime")
+    private Date mvalidStartTime;
+    /**
+     * 有效期
+     */
+    @ApiModelProperty(value = "有效期", name = "mvalidityPeriod")
+    private String mvalidityPeriod;
+    /**
+     * 在校(离线)
+     */
+    @ApiModelProperty(value = "在校(离线)", name = "minOutSchool")
+    private String minOutSchool;
+    /**
+     * 角色
+     */
+    @ApiModelProperty(value = "角色", name = "mrole")
+    private String mrole;
+    /**
+     * 标签
+     */
+    @ApiModelProperty(value = "标签", name = "mlabel")
+    private String mlabel;
+    /**
+     * 物理卡号
+     */
+    @ApiModelProperty(value = "物理卡号", name = "mphysicalCardNumber")
+    private String mphysicalCardNumber;
+    /**
+     * 物理芯片号
+     */
+    @ApiModelProperty(value = "物理芯片号", name = "mphysicalChipNumber")
+    private String mphysicalChipNumber;
+    /**
+     * 推送范围
+     */
+    @ApiModelProperty(value = "推送范围", name = "mpushScope")
+    private String mpushScope;
+    /**
+     * 信息添加时间(自动生成)
+     */
+    @ApiModelProperty(value = "信息添加时间(自动生成)", name = "mcreateAt")
+    private Date mcreateAt;
+    /**
+     * 信息组合字段更新时间(用脚本生成)
+     */
+    @ApiModelProperty(value = "信息组合字段更新时间(用脚本生成)", name = "mupdateAt")
+    private Date mupdateAt;
+    /**
+     * 记录推送到微信的时间(推送到微信时使用)
+     */
+    @ApiModelProperty(value = "记录推送到微信的时间(推送到微信时使用)", name = "mpushTime")
+    private Date mpushTime;
+
+    public MemberEntity(int id, String cardNumber, String name, String gender, String grade, String college, String profession,
+                        String mmajor, String mclass, String identity_type, String identity_title, String card_type, String id_card,
+                        String country, String organization, String campus, String employer, String building, String dorm_number,
+                        String remark, String physical_chip_number, String physical_card_number, String email,
+                        Date expire_at, String qq, String nation, String origin_place, String graduated_school,
+                        String address, String school_period, String educational, String in_out_school, String register_year) {
+
+        this.mid = id;
+        this.mcardNumber = cardNumber;
+        this.mname = name;
+        this.mgender = gender;
+        this.mgrade = grade;
+        this.mcollege = college;
+        this.mprofession = profession;
+        this.mmajor = mmajor;
+        this.mclass = mclass;
+        this.midentityType = identity_type;
+        this.midentityTitle = identity_title;
+        this.mcardType = card_type;
+        this.midCard = id_card;
+        this.mcountry = country;
+        this.morganization = organization;
+        this.mcampus = campus;
+        this.memployer = employer;
+        this.mbuilding = building;
+        this.mdormNumber = dorm_number;
+        this.mremark = remark;
+        this.mphysicalChipNumber = physical_chip_number;
+        this.mphysicalCardNumber = physical_card_number;
+        this.memail = email;
+        this.mexpireAt = expire_at;
+        this.mqq = qq;
+        this.mnation = nation;
+        this.moriginPlace = origin_place;
+        this.mgraduatedSchool = graduated_school;
+        this.maddress = address;
+        this.mschoolPeriod = school_period;
+        this.meducational = educational;
+        this.minOutSchool = in_out_school;
+        this.mregisterYear = register_year;
+    }
+}

+ 59 - 0
src/main/java/com/chkj/pdata/entity/MemberEntityHeadImg.java

@@ -0,0 +1,59 @@
+package com.chkj.pdata.entity;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@ApiModel
+@Data
+@EqualsAndHashCode(callSuper = false)
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class MemberEntityHeadImg extends CommonEntity implements Serializable {
+
+    /**
+     * serialVersionUID
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键自增字段
+     */
+    @ApiModelProperty(value = "主键自增字段", name = "mid")
+    private int mid;
+    /**
+     * 学工号,如:weixiao2164257621
+     */
+    @ApiModelProperty(value = "学工号,如:weixiao2164257621", name = "mcardNumber")
+    private String mcardNumber;
+    /**
+     * 姓名,如:张三
+     */
+    @ApiModelProperty(value = "姓名,如:张三", name = "mname")
+    private String mname;
+    /**
+     * 证件号码,如:4XXX***7
+     */
+    @ApiModelProperty(value = "证件号码,如:4XXX***7", name = "midCard")
+    private String midCard;
+    /**
+     * 头像
+     */
+    @ApiModelProperty(value = "头像", name = "mheadImage")
+    private byte[] mheadImage;
+
+    public void memberEntityHeadImg(int id, String cardNumber, String name, String id_card, byte[] head_img) {
+        this.mid = id;
+        this.mcardNumber = cardNumber;
+        this.mname = name;
+        this.midCard = id_card;
+        this.mheadImage = head_img;
+    }
+}

+ 199 - 0
src/main/java/com/chkj/pdata/task/BakMember.java

@@ -0,0 +1,199 @@
+package com.chkj.pdata.task;
+
+import com.chkj.pdata.entity.AccessToken;
+import com.chkj.pdata.entity.MemReturnFromWeixin;
+import com.chkj.pdata.util.DBUtils;
+import com.chkj.pdata.util.FileUtil;
+import com.chkj.pdata.util.HttpRequestUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.http.ResponseEntity;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class BakMember {
+
+    final String BaseURL = "https://open.wecard.qq.com/cgi-bin/";
+
+    FileUtil myWriter = new FileUtil();
+
+    /**
+     * 成员备份任务
+     */
+    public void member_bak_task() {
+        Map<String, Object> map;
+        List<String> card_numbers = new LinkedList<>();
+        // 查询没有推送的记录
+        String selectSql = "SELECT `学工号` as card_number_cy FROM `成员列表` WHERE `手机(完整手机号仅限超级管理员导出)` LIKE '%**%'" +
+                " OR `证件号码(完整证件号码仅限超级管理员导出)` LIKE '%******%' LIMIT 1000";
+//        String selectSql = "SELECT `学工号` as card_number_cy FROM `成员列表` WHERE `更新手机和身份证状态`=0 LIMIT 1000";
+        // 返回查询的成员列表
+        map = DBUtils.getAll(selectSql);
+        ResultSet rs = (ResultSet) map.get("rs");
+        PreparedStatement stmt = (PreparedStatement) map.get("stmt");
+        Connection conn = (Connection) map.get("conn");
+        try {
+            while (rs.next()) {
+                card_numbers.add(rs.getString("card_number_cy"));
+            }
+
+            if (card_numbers.size() > 0) {
+                // 获取 access_token
+                String access_token = getAccessToken();
+
+                if (!"".equals(access_token)) {
+                    // 推送成员信息
+                    pullChengyuan(card_numbers, access_token);
+                } else {
+                    myWriter.writeToFile("查询【成员列表】获取 access_token 失败!", "abnormal");
+                }
+            } else {
+                System.out.println("1");
+//                myWriter.writeToFile("没有要更新的 手机 和 身份证 的记录!", "bak");
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        } catch (JsonProcessingException e) {
+            throw new RuntimeException(e);
+        } finally {
+            DBUtils.closeResultSet(rs);
+            DBUtils.closeStatement(stmt);
+            DBUtils.closeConnection(conn);
+        }
+    }
+
+    /**
+     * 获取 access_token
+     *
+     * @return 返回 access_token
+     * @throws JsonProcessingException 异常
+     */
+    public String getAccessToken() throws JsonProcessingException {
+        // 获取 access_token 接口
+        final String URL = BaseURL + "oauth2/token";
+        // 查询参数
+        Map<String, String> queryParams = new HashMap<>();
+        // 请求参数
+        Map<String, String> requestBody = new HashMap<>();
+        requestBody.put("app_key", "505888BB58CE4DF0");
+        requestBody.put("app_secret", "6102F58C83240854331AF196861E6E5F");
+        requestBody.put("grant_type", "client_credentials");
+        requestBody.put("scope", "base");
+        requestBody.put("ocode", "1015730314");
+        // 携带参数访问接口
+        ResponseEntity<String> stringResponseEntity = HttpRequestUtils.httpPost(URL, requestBody, queryParams);
+        // 判断是否返回null
+        if (stringResponseEntity == null) {
+            return "";
+        }
+//        String token_type = "";
+        String access_token;
+//        String ocode = null;
+//        int expires_in = 0;
+
+        String body = stringResponseEntity.getBody();
+        String code = stringResponseEntity.getStatusCode().toString();
+        ObjectMapper objectMapper = new ObjectMapper(); // 创建ObjectMapper对象
+        AccessToken accessToken = objectMapper.readValue(body, AccessToken.class); // 将JSON字符串转换成User对象
+        if (code.contains("200") && code.contains("OK")) {
+//            token_type = accessToken.getToken_type();
+            access_token = accessToken.getAccess_token();
+//            ocode = accessToken.getOcode();
+//            expires_in = accessToken.getExpires_in();
+        } else {
+            access_token = "";
+            myWriter.writeToFile("错误状态码," + code.split(" ")[0], "");
+            myWriter.writeToFile("错误信息," + body, "");
+        }
+        // 返回access_token
+        return access_token;
+    }
+
+    /**
+     * 拉取成员
+     *
+     * @param card_numbers 成员列表
+     * @param access_token access_token
+     */
+    private void pullChengyuan(List<String> card_numbers, String access_token) {
+        // 查询参数
+        Map<String, String> queryParams = new HashMap<>();
+        // 请求参数
+        Map<String, List<String>> requestBody = new HashMap<>();
+        requestBody.put("card_numbers", card_numbers);
+        // 创建用户接口
+        final String URL = BaseURL + "user/get-user-by-card-numbers?access_token=" + access_token;
+        // 调用批量获取成员接口
+        ResponseEntity<String> stringResponseEntity = HttpRequestUtils.httpPost(URL, requestBody, queryParams);
+        // 判断是否返回null
+        if (stringResponseEntity == null) {
+            return;
+        }
+        // 获取响应体
+        String body = stringResponseEntity.getBody();
+        // 获取响应码
+        String code = stringResponseEntity.getStatusCode().toString();
+        // 判断响应码是否是成功
+        if (code.contains("200") && code.contains("OK")) {
+            try {
+                ObjectMapper objectMapper = new ObjectMapper(); // 创建ObjectMapper对象
+                MemReturnFromWeixin memReturnFromWeixin = objectMapper.readValue(body, MemReturnFromWeixin.class);
+                // 如果用户信息列表数组长度不等于0,说明有该成员信息
+                if (memReturnFromWeixin.getUserlist().length != 0) {
+                    for (int i = 0; i < memReturnFromWeixin.getUserlist().length; i++) {
+                        String objectString = memReturnFromWeixin.getUserlist()[i].toString();
+                        String[] arr = objectString.substring(1, objectString.length() - 1).split(", ");
+                        String card_number = "", name = "", id_card = "", telephone = "";
+                        for (String s : arr) {
+                            String[] split = s.split("=");
+                            if (split[0].equals("card_number")) {
+                                if (split.length > 1)
+                                    card_number = split[1];
+                            }
+                            if (split[0].equals("name")) {
+                                if (split.length > 1)
+                                    name = split[1];
+                            }
+                            if (split[0].equals("id_card")) {
+                                if (split.length > 1)
+                                    id_card = split[1];
+                            }
+                            if (split[0].equals("telephone")) {
+                                if (split.length > 1)
+                                    telephone = split[1];
+                            }
+                        }
+                        if (card_number.isEmpty() || name.isEmpty()) {
+                            System.out.println("学工号 或 姓名 为空!");
+                        } else {
+                            String condition = "";
+                            if (!"".equals(id_card))
+                                condition += "`证件号码(完整证件号码仅限超级管理员导出)`='" + id_card + "',";
+                            if (!"".equals(telephone))
+                                condition += "`手机(完整手机号仅限超级管理员导出)`='" + telephone + "',";
+                            condition += "`更新手机和身份证状态`=" + 1 + ",";
+                            String update_sql = "UPDATE `成员列表` SET " + condition.substring(0, condition.length() - 1)
+                                    + " WHERE `学工号` like '%" + card_number + "%' AND `姓名` like '%" + name + "%'";
+                            int num = DBUtils.update(update_sql);
+                            if (num > 0) {
+                                myWriter.writeToFile(card_number + " " + name + "身份证和手机 更新成功!", "bak");
+                            } else {
+                                myWriter.writeToFile(card_number + " " + name + "身份证和手机 更新失败!", "bak");
+
+                            }
+                        }
+                    }
+                }
+            } catch (JsonProcessingException e) {
+                System.out.println(e.getMessage());
+            }
+        }
+    }
+}

+ 31 - 0
src/main/java/com/chkj/pdata/task/MyScheduledTask.java

@@ -0,0 +1,31 @@
+package com.chkj.pdata.task;
+
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MyScheduledTask {
+
+    SavaBlobToPng savaBlobToPng = new SavaBlobToPng();
+
+    BakMember bakMember = new BakMember();
+
+    PushMember pushMember = new PushMember();
+
+    @Scheduled(cron = "${cron.expression}") // 定时任务
+//    @Scheduled(cron = "0 */2 * * * *") // 定时任务
+    public void runTask() {
+
+        // 备份任务,先需要到微校后台导出数据,再根据导出的【学工号】和【姓名】,更新脱敏的【手机】和【身份证】
+//        bakMember.member_bak_task();
+
+        // 保存头像
+//         savaBlobToPng.blobToPngTask();
+
+        // 推送数据
+        pushMember.pushMember_task();
+
+        // 删除数据
+//        pushMember.delMembers();
+    }
+}

+ 587 - 0
src/main/java/com/chkj/pdata/task/PushMember.java

@@ -0,0 +1,587 @@
+package com.chkj.pdata.task;
+
+import com.chkj.pdata.entity.MemReturnFromWeixin;
+import com.chkj.pdata.entity.MemberEntity;
+import com.chkj.pdata.util.DBUtils;
+import com.chkj.pdata.util.FileUtil;
+import com.chkj.pdata.util.HttpRequestUtils;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.*;
+
+public class PushMember {
+
+    final String BaseURL = "https://open.wecard.qq.com/cgi-bin/";
+
+    FileUtil myWriter = new FileUtil();
+    BakMember bakMember = new BakMember();
+
+    /**
+     * 推送成员任务
+     */
+    public void pushMember_task() {
+        // 推送任务
+        try {
+            // 获取没有推送的记录
+            List<MemberEntity> members = getMembers();
+            if (members.size() > 0) {
+                // 获取 access_token
+                String access_token = bakMember.getAccessToken();
+
+                if (!"".equals(access_token)) {
+                    // 推送成员信息
+                    pushMember(members, access_token);
+                } else {
+                    myWriter.writeToFile("推送【member】获取 access_token 失败!", "abnormal");
+                }
+            } else {
+                if (!myWriter.readFromFile("none"))
+                    myWriter.writeToFile("没有要推送的记录!", "none");
+            }
+        } catch (JsonProcessingException e) {
+            myWriter.writeToFile(e.getMessage(), "abnormal");
+        }
+    }
+
+    /**
+     * 查询表,找出没有推送的记录
+     *
+     * @return 成员记录集
+     */
+    private List<MemberEntity> getMembers() {
+        // 查询没有推送的记录
+        String selectSql = "SELECT * FROM member where m_status = 0 limit 100";
+        // 返回查询的成员列表
+        return DBUtils.queryAll(selectSql);
+    }
+
+    /**
+     * 读取csv文件,获取card_number
+     *
+     * @return
+     */
+    private List<String> readCsv() {
+        // 读取文件
+        String csvFile = "2023-06-28-ok-log.csv";
+        String line;
+        List<String> list = new ArrayList<>();
+        BufferedReader br = null;
+        try {
+            br = new BufferedReader(new FileReader(csvFile));
+            br.readLine();
+            while ((line = br.readLine()) != null) {
+                list.add(line.split(",")[2]);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (br != null) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * 批量删除用户信息
+     */
+    public void delMembers() {
+        try {
+            // 批量删除成员接口
+            final String URL = BaseURL + "user/manage/batch-delete";
+            // 获取 access_token
+            String access_token = bakMember.getAccessToken();
+
+            // 获取card_numbers
+            List<String> cardNumbers = readCsv();
+
+            RestTemplate restTemplate = new RestTemplate();
+            HttpHeaders headers = new HttpHeaders();
+            headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
+            headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+            JSONArray jsonArray = new JSONArray(cardNumbers);
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("card_numbers", jsonArray);
+            HttpEntity<String> request = new HttpEntity<>(jsonObject.toString(), headers);
+            ResponseEntity<String> response = restTemplate.postForEntity(URL + "?access_token=" + access_token, request, String.class);
+            System.out.println(response.getBody());
+            // 写入日志文件
+            myWriter.writeToFile(response.toString(), "delMember");
+        } catch (JsonProcessingException e) {
+            myWriter.writeToFile(e.getMessage(), "abnormal");
+        }
+    }
+
+    /**
+     * 推送用户信息
+     *
+     * @param members      成员列表
+     * @param access_token access_token
+     * @throws JsonProcessingException 异常
+     */
+    private void pushMember(List<MemberEntity> members, String access_token) throws JsonProcessingException {
+        // 创建用户接口
+        final String URL = BaseURL + "user/manage/create?access_token=" + access_token;
+        // 用户信息主动推送同步
+//        final String URL = BaseURL + "user/manage/sync-user-info?access_token" + access_token;
+        // 循环每个成员,检查成员是否存在
+        for (MemberEntity member : members) {
+            // 学工号 或 姓名 为空,则不处理
+            if (member.getMcardNumber() == null || member.getMname() == null || member.getMidCard() == null) {
+                setLocalTable("该【学工号】或【姓名】或【身份证号】为空", member);
+                continue;
+            }
+
+            if (member.getMcardNumber().equals(member.getMidCard())) {
+                setLocalTable("【姓名】和【身份证号】相同", member);
+                continue;
+            }
+
+            StringBuilder sb = new StringBuilder();
+            sb.append("该成员");
+            boolean bool = checkMember(member, access_token, "card_number") && checkMember(member, access_token, "id_card");
+            if (bool) {
+                sb.append("【学工号】或【身份证号】");
+            }
+            sb.append("微校不存在,");
+
+            // 不存在该成员,则推送
+            if (bool) {
+                myWriter.writeToFile(sb + member.getMcardNumber(), "abnormal");
+                // 查询参数
+                Map<String, String> queryParams = new HashMap<>();
+                // 请求参数
+                Map<String, String> requestBody = new HashMap<>();
+                // 学工号
+                String cardNumber = member.getMcardNumber();
+                // 如果是数字开头的
+                if (Character.isDigit(cardNumber.charAt(0))) {
+                    // 如果是学生,14位学号,取前4位,则为年份,2021级之后学工号用身份证号填充
+                    if (cardNumber.length() == 14) {
+                        if (Integer.parseInt(cardNumber.substring(0, 4)) >= 2021) {
+                            // 2021级及之后的学生,用【身份证号】作为【学工号】
+                            requestBody.put("card_number", member.getMidCard());
+                        } else {
+                            // 2021级之前的学生,用【学号】为【学工号】
+                            requestBody.put("card_number", member.getMcardNumber());
+                        }
+                    } else {
+                        // 教职工,【工号】作为【学工号】
+                        requestBody.put("card_number", member.getMcardNumber());
+                    }
+                } else if (Character.isLetter(cardNumber.charAt(0))) {
+                    // 如果是字母开头的,教职工(外聘等),【工号】作为【学工号】
+                    requestBody.put("card_number", member.getMcardNumber());
+                } else {
+                    // 既不是数字开头,也不是字母开头,记录到日志,待人工处理
+                    setLocalTable("该学工号特殊,需要人工进行判别,此处跳过", member);
+                    continue;
+                }
+                // 编号 serial_number
+                requestBody.put("serial_number", requestBody.get("card_number"));
+                // 姓名
+                requestBody.put("name", member.getMname());
+                // 年级
+                if (member.getMgrade() != null) requestBody.put("grade", member.getMgrade());
+                // 学院名称
+                String college = member.getMcollege();
+                if (college != null) requestBody.put("college", college);
+                // 系的名称(学校数据库推送的数据中没有系,但对应微校的是专业,所有忽略)
+//                if (member.getMprofession() != null) {
+//                    requestBody.put("profession", member.getMprofession());
+//                }
+                // 班级
+                if (member.getMclass() != null) requestBody.put("class", member.getMclass());
+                // 身份类型
+                String identityType = member.getMidentityType();
+                if (identityType != null) {
+                    if ("1".equals(identityType)) requestBody.put("identity_type", "学生");
+                    else if ("2".equals(identityType)) requestBody.put("identity_type", "教职工");
+                    else {
+                        // 既不是1,也不是2,记录到日志,待人工处理
+                        setLocalTable("该身份既不是1,也不是2,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                } else {
+                    // null,记录到日志,待人工处理
+                    setLocalTable("该身份为【null】,需要人工进行判别,此处跳过", member);
+                    continue;
+                }
+                // 组织架构:根据身份类型判断如下
+                // 1 学生:南昌交通学院/学生/学院/年级/专业/班级
+                // 2 教职工:南昌交通学院/教职工/所在部门
+                StringBuilder org = new StringBuilder();
+                org.append("南昌交通学院");
+                if ("1".equals(identityType)) { // 学生
+                    if (member.getMinOutSchool() != null)
+                        // 非 null, 1在校 0毕业
+                        org.append("1".equals(member.getMinOutSchool()) ? "/学生" : "/校友");
+                    else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该学生在校/离校【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 学院,非空加上学院
+                    if (college != null) org.append("/").append(college);
+                    else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该学生学院【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 年级,非空加上年级
+                    if (member.getMgrade() != null) org.append("/").append(member.getMgrade());
+                    else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该学生年级【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 专业,非空加上专业
+                    if (member.getMmajor() != null) {
+                        org.append("/").append(member.getMmajor());
+                        requestBody.put("profession", member.getMmajor());
+                    } else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该学生专业【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 班级,非空加上班级
+                    if (member.getMclass() != null) org.append("/").append(member.getMclass());
+                    else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该学生班级【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 设置组织结构
+                    requestBody.put("organization", org.toString());
+                } else {  // 教职工
+                    if (member.getMinOutSchool() != null)
+                        // 非 null, 1在职 0离线
+                        if ("1".equals(member.getMinOutSchool())) org.append("/教职工");
+                        else {
+                            // 0,记录到日志,待人工处理
+                            setLocalTable("该教职工【已离职】,需要人工进行判别,此处跳过", member);
+                            continue;
+                        }
+                    else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该教职工在职/离职为【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 学院,非null 就加上学院,否则
+                    if (college != null) org.append("/").append(college);
+                    else {
+                        // null,记录到日志,待人工处理
+                        setLocalTable("该学生学院【null】,需要人工进行判别,此处跳过", member);
+                        continue;
+                    }
+                    // 设置组织结构
+                    requestBody.put("organization", org.toString());
+                }
+                // 身份名称
+                if (member.getMidentityTitle() != null) {
+                    requestBody.put("identity_title", member.getMidentityTitle());
+                } else {
+                    // 班级以“(专)”结尾
+                    if (member.getMclass() != null) if (member.getMclass().endsWith("(专)")) {
+                        requestBody.put("school_period", "专科生");
+                    } else if (member.getMeducational() != null) {  // 学制,4-5年的是大专以上,也就是大学,其他不推此字段
+                        if (Integer.parseInt(member.getMeducational()) >= 4) {
+                            requestBody.put("school_period", "本科生");
+                        } else if (Integer.parseInt(member.getMeducational()) <= 3) {
+                            requestBody.put("school_period", "专科生");
+                        }
+                    }
+                }
+                // 证件类型
+                if ("身份证".equals(member.getMcardType())) requestBody.put("card_type", "1");
+                else requestBody.put("card_type", member.getMcardType());
+                // 证件号
+                String idCard = member.getMidCard();
+                if (idCard != null) {
+                    if (idCard.startsWith("0000000") || idCard.trim().length() != 18) {
+                        // 非法证件号,记录到日志,待人工处理
+                        setLocalTable("该证件号非法,需要人工进行判别,此处跳过", member);
+                        continue;
+                    } else {
+                        requestBody.put("id_card", idCard);
+                    }
+                } else {
+                    // 非法证件号,记录到日志,待人工处理
+                    setLocalTable("该证件号【null】,需要人工进行判别,此处跳过", member);
+                    continue;
+                }
+                // 性别,1男  2女
+                String gender = member.getMgender();
+                if (gender != null) {
+                    if ("1".equals(gender)) {
+                        requestBody.put("gender", "男");
+                    } else if ("2".equals(gender)) {
+                        requestBody.put("gender", "女");
+                    }
+                } else {
+                    // 根据身份证号判别性别
+                    char genderCode = idCard.charAt(16); //获取第17位字符,下标从0开始
+                    if (genderCode % 2 == 0) {
+                        requestBody.put("gender", "女");
+                    } else {
+                        requestBody.put("gender", "男");
+                    }
+                }
+                // 国家
+                if (member.getMcountry() != null) requestBody.put("country", member.getMcountry());
+                else requestBody.put("country", "CHN");
+                // 员工正常
+                // requestBody.put("staff_status", "正常");
+                // 手机号不推送
+                // requestBody.put("telephone", members.get(0).getMtelephone());
+                // 校区
+                String building = member.getMbuilding();
+                int build = 0;
+                if (member.getMcampus() != null) {
+                    requestBody.put("campus", member.getMcampus());
+                } else {
+                    if (building != null) {
+                        if (building.toLowerCase().startsWith("m")) {
+                            build = Integer.parseInt(building.substring(1));
+                            requestBody.put("campus", "墨轩湖校区");
+                        } else {
+                            build = Integer.parseInt(building);
+                            requestBody.put("campus", "黄家湖校区");
+                        }
+                    }
+                }
+                // 工作单位、宿舍号
+                // 如果是学生,14位学号也是学生
+                if ("1".equals(identityType) || (Character.isDigit(cardNumber.charAt(0)) && cardNumber.length() == 14)) { // 学生
+                    // 工作单位
+                    if (member.getMemployer() != null) requestBody.put("employer", member.getMemployer());
+                    else requestBody.put("employer", "南昌交通学院");
+
+                    // 宿舍号 = 楼栋 + 宿舍
+                    StringBuilder drom = new StringBuilder();
+                    if (building != null) drom.append(build).append("栋");
+                    if (member.getMdormNumber() != null) drom.append(member.getMdormNumber());
+                    if (!"".contentEquals(drom)) {
+                        requestBody.put("dorm_number", drom.toString());
+                    }
+                } else {  // 教职工
+                    // 工作单位
+                    if (member.getMemployer() != null) requestBody.put("employer", member.getMemployer());
+                    else requestBody.put("employer", college);
+                }
+                // 备注
+                StringBuilder remark = new StringBuilder();
+                remark.append(member.getMcardNumber());
+                if (member.getMremark() != null) remark.append("|").append(member.getMremark());
+                requestBody.put("remark", remark.toString());
+                // 物理芯片号
+                if (member.getMphysicalChipNumber() != null)
+                    requestBody.put("physical_chip_number", member.getMphysicalChipNumber());
+                // 物理卡号
+                if (member.getMphysicalCardNumber() != null) {
+                    requestBody.put("physical_card_number", member.getMphysicalCardNumber());
+                    requestBody.put("physical_card_status", "正常");
+                }
+                // 邮箱
+                if (member.getMemail() != null) requestBody.put("email", member.getMemail());
+                // 有效时间
+                if (member.getMexpireAt() != null) requestBody.put("expire_at", String.valueOf(member.getMexpireAt()));
+                // qq
+                if (member.getMqq() != null) requestBody.put("qq", member.getMqq());
+                // 名族
+                if (member.getMnation() != null) requestBody.put("nation", member.getMnation());
+                // 户籍
+                if (member.getMoriginPlace() != null) requestBody.put("origin_place", member.getMoriginPlace());
+                // 毕业院校
+                if (member.getMgraduatedSchool() != null)
+                    requestBody.put("graduated_school", member.getMgraduatedSchool());
+                // 住址
+                if (member.getMaddress() != null) requestBody.put("address", member.getMaddress());
+                // 学段
+                if (member.getMschoolPeriod() != null) {
+                    requestBody.put("school_period", member.getMschoolPeriod());
+                } else {
+                    // 学制,3-5年的是大专以上,也就是大学,其他不推此字段
+                    if (member.getMeducational() != null) {
+                        if (Integer.parseInt(member.getMeducational()) >= 3) {
+                            requestBody.put("school_period", "大学");
+//                        } else {
+//                            requestBody.put("school_period", "高职");
+                        }
+                    }
+                }
+                // 入学年份
+                if (member.getMregisterYear() != null) requestBody.put("register_year", member.getMregisterYear());
+                // ===============================================================================
+                // 调用创建用户接口,执行推送
+                ResponseEntity<String> stringResponseEntity = HttpRequestUtils.httpPost(URL, requestBody, queryParams);
+                System.out.println(stringResponseEntity);
+                // 判断是否返回null
+                if (stringResponseEntity == null) {
+                    return;
+                }
+                // 获取响应体
+                String body = stringResponseEntity.getBody();
+                // 获取响应码
+                String code = stringResponseEntity.getStatusCode().toString();
+                // 判断响应码是否是成功
+                if (code.contains("200") && code.contains("OK")) {
+                    // 标记为2已推送
+                    int updateCount = updateLocalTable(2, member);
+                    if (updateCount > 0) {
+                        if (cardNumber.length() == 14 && Integer.parseInt(cardNumber.substring(0, 4)) >= 2021) {
+                            myWriter.writeToFile("成员推送成功," + member.getMidCard(), "ok");
+                        } else {
+                            myWriter.writeToFile("成员推送成功," + cardNumber, "ok");
+                        }
+                    } else {
+                        myWriter.writeToFile("成员推送失败," + member.getMcardNumber() + "|" + member.getMidCard(), "");
+                    }
+                } else {
+                    myWriter.writeToFile("错误状态码," + code.split(" ")[0], "");
+                    myWriter.writeToFile("错误信息," + body, "");
+                }
+            } else { // 存在该成员
+                // 标记为1已存在
+                int updateCount = updateLocalTable(1, member);
+                if (updateCount > 0) {
+                    myWriter.writeToFile("成员已存在,m_status已标记为1,m_status_time为标记时间,以后不再推送," + member.getMcardNumber() + "|"
+                            + member.getMname() + "|" + member.getMidCard(), "");
+                } else {
+                    myWriter.writeToFile("成员已存在,m_status 和 m_status_time标记失败," + member.getMcardNumber() + "|"
+                            + member.getMname() + "|" + member.getMidCard(), "");
+                }
+            }
+        }
+    }
+
+    /**
+     * 更新本地数据表
+     *
+     * @param status 状态
+     * @param member 成员
+     * @return 返回值
+     */
+    private int updateLocalTable(int status, MemberEntity member) {
+        // m_status:0未确认,1已存在,2已推送 3有异常
+        String updateSql = "update member set m_status = " + status + ", m_status_time = now() " + " where m_id = " + member.getMid() + " and m_card_number = '" + member.getMcardNumber() + "'";
+        return DBUtils.update(updateSql);
+    }
+
+    /**
+     * 检查用户是否存在,存在返回true,不存在false
+     *
+     * @param member       成员列表
+     * @param access_token access_token
+     * @return 成员存在true  不存在false
+     * @throws JsonProcessingException 异常
+     */
+    private boolean checkMember(MemberEntity member, String access_token, String idNumber) throws JsonProcessingException {
+        // 搜索成员接口
+        final String URL = BaseURL + "user/search?access_token=" + access_token;
+        String card_number;
+        if ("card_number".equals(idNumber)) {  // 学工号是学号
+            card_number = member.getMcardNumber();
+        } else {  // 学工号是身份证号
+            card_number = member.getMidCard();
+        }
+        // 以下是查询是否存在该成员
+        // 查询参数
+        Map<String, String> queryParams = new HashMap<>();
+        // 请求参数
+        Map<String, String> requestBody = new HashMap<>();
+        requestBody.put("keywords", card_number);
+        // 执行查询
+        ResponseEntity<String> stringResponseEntity = HttpRequestUtils.httpPost(URL, requestBody, queryParams);
+        // 判断是否返回null
+        if (stringResponseEntity == null) {
+            return false;
+        }
+
+        // 获取响应体
+        String body = stringResponseEntity.getBody();
+        // 获取状态码部分
+        String code = stringResponseEntity.getStatusCode().toString();
+        if (code.contains("200") && code.contains("OK")) {
+            ObjectMapper objectMapper = new ObjectMapper(); // 创建ObjectMapper对象
+            MemReturnFromWeixin memReturnFromWeixin = objectMapper.readValue(body, MemReturnFromWeixin.class);
+            // 如果用户信息列表数组是空数组或者数组长度等于0,说明没有该成员信息
+            if ("[]".equals(Arrays.toString(memReturnFromWeixin.getUserlist())) || memReturnFromWeixin.getUserlist().length == 0) {
+                // 微信没有该成员学工号或者身份证号
+                return true;
+            } else {
+                String string = Arrays.toString(memReturnFromWeixin.getUserlist());
+                // 去除字符串中的特殊字符
+                String cleanString = string.replaceAll("[{}\\[\\]\"]", "");
+
+                // 使用逗号分隔字符串,获取键值对数组
+                String[] keyValuePairs = cleanString.split(",");
+
+                // 遍历键值对数组,提取card_type的值和qq的值
+//                String cardNumber = "";
+                String identityType = "";
+                String idCard = "";
+                for (String pair : keyValuePairs) {
+                    String[] keyValue = pair.split("=");
+                    if (keyValue.length == 2) {
+                        String key = keyValue[0].trim();
+                        String value = keyValue[1].trim();
+
+                        if (key.equals("identity_type")) {
+                            identityType = value;
+                        } else if (key.equals("id_card")) {
+                            idCard = value;
+//                        } else if (key.equals("card_number")) {
+//                            cardNumber = value;
+                        }
+                    }
+                }
+
+                // 身份1学生 2教职工、身份证号id_card,如果二个都相等,则认为微校存在此用户成员,否则认为没有
+                if (identityType.equals(member.getMidentityType()) && idCard.equals(member.getMidCard())) {
+                    return false;
+                } else {
+                    // 微校没有有该成员
+                    return true;
+                }
+            }
+        } else {
+            myWriter.writeToFile("错误状态码," + code.split(" ")[0], "");
+            myWriter.writeToFile("错误信息," + body, "");
+            return false;
+        }
+    }
+
+    /**
+     * 推送异常公共函数
+     *
+     * @param member 成员
+     */
+    private void setLocalTable(String cause, MemberEntity member) {
+        // 不能标记为3,因为经过测试后台数据不是一次到位,比如有的card_number到了,但是学院没有到,造成以后都没有推送
+        myWriter.writeToFile(cause + ",m_status暂时不需要标记,," + member.getMcardNumber() + "|"
+                + member.getMname() + "|" + member.getMidCard(), "abnormal");
+//        int updateCount = updateLocalTable(3, member);
+//        if (updateCount > 0)
+//            myWriter.writeToFile(cause + ",m_status已标记为3,m_status_time为标记时间,人工处理后再推送," +  member.getMcardNumber() + "|"
+//                    + member.getMname() + "|" + member.getMidCard(), "abnormal");
+//        else myWriter.writeToFile(cause + ",m_status 和 m_status_time 标记失败," + member.getMcardNumber() + "|"
+//                + member.getMname() + "|" + member.getMidCard(), "abnormal");
+    }
+}

+ 144 - 0
src/main/java/com/chkj/pdata/task/SavaBlobToPng.java

@@ -0,0 +1,144 @@
+package com.chkj.pdata.task;
+
+import com.chkj.pdata.entity.MemberEntityHeadImg;
+import com.chkj.pdata.util.DBUtils;
+import com.chkj.pdata.util.FileUtil;
+
+import javax.imageio.ImageIO;
+import javax.sound.midi.MidiFileFormat;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+
+public class SavaBlobToPng {
+
+    FileUtil myWriter = new FileUtil();
+
+    /**
+     * 获取要保存的图片记录
+     */
+    public void blobToPngTask() {
+        String sql = "SELECT m_id, m_card_number, m_head_image FROM member_head_image WHERE m_head_image_status=0 " +
+                " AND m_head_image_status_time IS NULL LIMIT 100";
+        Map<String, Object> parentMap = DBUtils.getAll(sql);
+        ResultSet parentRs = (ResultSet) parentMap.get("rs");
+        PreparedStatement parentStmt = (PreparedStatement) parentMap.get("stmt");
+        Connection parentConn = (Connection) parentMap.get("conn");
+        try {
+            while (parentRs.next()) {
+                MemberEntityHeadImg memberEntityHeadImg = new MemberEntityHeadImg();
+                memberEntityHeadImg.setMid(parentRs.getInt("m_id"));
+                memberEntityHeadImg.setMcardNumber(parentRs.getString("m_card_number"));
+                memberEntityHeadImg.setMheadImage(parentRs.getBytes("m_head_image"));
+                sql = "SELECT m_card_number, m_name, m_id_card " +
+                        " FROM member " +
+                        " WHERE m_card_number='" + parentRs.getString("m_card_number") + "'";
+                Map<String, Object> map = DBUtils.getAll(sql);
+                ResultSet rs = (ResultSet) map.get("rs");
+                PreparedStatement stmt = (PreparedStatement) map.get("stmt");
+                Connection conn = (Connection) map.get("conn");
+                if (rs.next()) {
+                    memberEntityHeadImg.setMname(rs.getString("m_name"));
+                    memberEntityHeadImg.setMidCard(rs.getString("m_id_card"));
+                    blobToPng(memberEntityHeadImg);
+                } else {
+                    updateLocalTableOfHeadImage(2, memberEntityHeadImg);
+                }
+                rs.close();
+                stmt.close();
+                conn.close();
+            }
+        } catch (SQLException e) {
+            System.out.println(e.getMessage());
+        }
+
+        try {
+            parentRs.close();
+            parentStmt.close();
+            parentConn.close();
+        } catch (SQLException e) {
+            System.out.println(e.getMessage());
+        }
+    }
+
+    /**
+     * 将blob数据转换成png图片
+     *
+     * @param member 成员
+     */
+    private void blobToPng(MemberEntityHeadImg member) {
+        try {
+            byte[] mheadImage = member.getMheadImage();
+            ByteArrayInputStream inputStream = new ByteArrayInputStream(mheadImage);
+            BufferedImage image = ImageIO.read(inputStream);
+
+            String dir = null;
+            StringBuilder sb = new StringBuilder();
+            if (member.getMcardNumber() != null) {
+                sb.append(member.getMcardNumber()).append("-");
+                if (member.getMcardNumber().length() == 14) {
+                    dir = member.getMcardNumber().substring(0, 4);
+                }
+            }
+            if (member.getMname() != null)
+                sb.append(member.getMname()).append("-");
+            if (member.getMidCard() != null) {
+                sb.append(member.getMidCard()).append("-");
+            } else {
+                myWriter.writeToFile("身份证号为【null】," + sb, "headImage");
+                updateLocalTableOfHeadImage(2, member);
+                return;
+            }
+            sb.setLength(sb.length() - 1);
+            sb.append(".png");
+
+            if (image == null) {
+                myWriter.writeToFile("图片保存失败,图片为【null】," + sb, "headImage");
+                updateLocalTableOfHeadImage(2, member);
+                return;
+            }
+
+            String filePath = "./head_image" + File.separator + dir;
+            File directory = new File(filePath);
+            File outputFile = new File(filePath + File.separator + sb);
+            if (!directory.exists()) {
+                boolean result = directory.mkdirs();
+                if (result) {
+                    ImageIO.write(image, "PNG", outputFile);
+
+                    myWriter.writeToFile("图片保存成功," + sb, "headImage");
+                    updateLocalTableOfHeadImage(1, member);
+                } else {
+                    myWriter.writeToFile("头像文件夹" + filePath + "创建失败!", "headImage");
+                }
+            } else {
+                ImageIO.write(image, "PNG", outputFile);
+
+                myWriter.writeToFile("图片保存成功," + sb, "headImage");
+                updateLocalTableOfHeadImage(1, member);
+            }
+        } catch (IOException e) {
+            myWriter.writeToFile("图片保存失败," + e.getMessage(), "headImage");
+            updateLocalTableOfHeadImage(2, member);
+        }
+    }
+
+    /**
+     * 记录头像保存状态
+     *
+     * @param status 1保存成功, 2保存失败
+     * @param member 成员
+     */
+    private void updateLocalTableOfHeadImage(int status, MemberEntityHeadImg member) {
+        // m_status:0未确认,1已存在,2已推送 3有异常
+        String updateSql = "update member_head_image set m_head_image_status = " + status + ", m_head_image_status_time = now() "
+                + " where m_id = " + member.getMid() + " and m_card_number = '" + member.getMcardNumber() + "'";
+        DBUtils.update(updateSql);
+    }
+}

+ 292 - 0
src/main/java/com/chkj/pdata/util/DBUtils.java

@@ -0,0 +1,292 @@
+package com.chkj.pdata.util;
+
+import com.chkj.pdata.entity.MemberEntity;
+import com.chkj.pdata.entity.MemberEntityHeadImg;
+
+import java.sql.*;
+import java.util.Date;
+import java.util.*;
+
+public class DBUtils {
+    private static final String URL = "jdbc:mysql://172.16.20.77:3306/memdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
+    private static final String USERNAME = "memdb";
+    private static final String PASSWORD = "6RHZJYjrT83Ri88C";
+//    private static final String URL = "jdbc:mysql://localhost:3306/member?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
+//    private static final String USERNAME = "root";
+//    private static final String PASSWORD = "123456";
+
+    private static Connection getConnection() throws SQLException {
+        return DriverManager.getConnection(URL, USERNAME, PASSWORD);
+    }
+
+    public static void closeConnection(Connection conn) {
+        if (conn != null) {
+            try {
+                conn.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static void closeStatement(Statement stmt) {
+        if (stmt != null) {
+            try {
+                stmt.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static void closeResultSet(ResultSet rs) {
+        if (rs != null) {
+            try {
+                rs.close();
+            } catch (SQLException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // 新增数据,返回新增数据的ID
+//    public int insert(String name, int age) {
+//        Connection conn = null;
+//        PreparedStatement stmt = null;
+//        int id = -1;
+//        try {
+//            conn = getConnection();
+//            String sql = "INSERT INTO user(name, age) VALUES(?, ?)";
+//            stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
+//            stmt.setString(1, name);
+//            stmt.setInt(2, age);
+//            stmt.executeUpdate();
+//            ResultSet rs = stmt.getGeneratedKeys();
+//            if (rs.next()) {
+//                id = rs.getInt(1);
+//            }
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        } finally {
+//            closeResultSet(stmt.getGeneratedKeys());
+//            closeStatement(stmt);
+//            closeConnection(conn);
+//        }
+//        return id;
+//    }
+
+//    // 根据ID删除数据,返回删除的行数
+//    public int delete(int id) {
+//        Connection conn = null;
+//        PreparedStatement stmt = null;
+//        int rows = -1;
+//        try {
+//            conn = getConnection();
+//            String sql = "DELETE FROM user WHERE id = ?";
+//            stmt = conn.prepareStatement(sql);
+//            stmt.setInt(1, id);
+//            rows = stmt.executeUpdate();
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        } finally {
+//            closeStatement(stmt);
+//            closeConnection(conn);
+//        }
+//        return rows;
+//    }
+
+    // 根据ID更新数据,返回更新的行数
+    public static int update(String sql) {
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        int rows = -1;
+        try {
+            conn = getConnection();
+            stmt = conn.prepareStatement(sql);
+            rows = stmt.executeUpdate();
+        } catch (SQLException e) {
+            e.printStackTrace();
+        } finally {
+            closeStatement(stmt);
+            closeConnection(conn);
+        }
+        return rows;
+    }
+
+    public static Map<String, Object> getAll(String sql) {
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+        Map<String, Object> map = new HashMap<>();
+        try {
+            conn = getConnection();
+            stmt = conn.prepareStatement(sql);
+            rs = stmt.executeQuery();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            map.put("rs", rs);
+            map.put("stmt", stmt);
+            map.put("conn", conn);
+        }
+
+        return map;
+    }
+
+    // 查询所有数据,返回数据列表
+    public static List<MemberEntity> queryAll(String sql) {
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+        List<MemberEntity> memberEntities = new ArrayList<>();
+        try {
+            conn = getConnection();
+            stmt = conn.prepareStatement(sql);
+            rs = stmt.executeQuery();
+            while (rs.next()) {
+                // id
+                int id = rs.getInt("m_id");
+                // 学工号
+                String cardNumber = rs.getString("m_card_number");
+                // 姓名
+                String name = rs.getString("m_name");
+                // 性别
+                String gender = rs.getString("m_gender");
+                // 年级
+                String grade = rs.getString("m_grade");
+                // 学院名称
+                String college = rs.getString("m_college");
+                // 系的名称
+                String profession = rs.getString("m_profession");
+                // 专业
+                String mmajor = rs.getString("m_major");
+                // 班级
+                String mclass = rs.getString("m_class");
+                // 身份类型
+                String identity_type = rs.getString("m_identity_type");
+                // 身份名称
+                String identity_title = rs.getString("m_identity_title");
+                // 证件类型
+                String card_type = rs.getString("m_card_type");
+                // 证件号
+                String id_card = rs.getString("m_id_card");
+                // 国家
+                String country = rs.getString("m_country");
+                // 手机号不推送
+//                String telephone = rs.getString("m_telephone");
+                // 组织架构
+                String organization = rs.getString("m_organization");
+                // 校区
+                String campus = rs.getString("m_campus");
+                // 工作单位
+                String employer = rs.getString("m_employer");
+                // 楼栋
+                String building = rs.getString("m_building");
+                // 宿舍号
+                String dorm_number = rs.getString("m_dorm_number");
+                // 备注
+                String remark = rs.getString("m_remark");
+                // 物理芯片号
+                String physical_chip_number = rs.getString("m_physical_chip_number");
+                // 物理卡号
+                String physical_card_number = rs.getString("m_physical_card_number");
+                // 邮箱
+                String email = rs.getString("m_email");
+                // 有效时间
+                Date expire_at = rs.getDate("m_expire_at");
+                // qq
+                String qq = rs.getString("m_qq");
+                // 名族
+                String nation = rs.getString("m_nation");
+                // 户籍
+                String origin_place = rs.getString("m_origin_place");
+                // 毕业院校
+                String graduated_school = rs.getString("m_graduated_school");
+                // 住址
+                String address = rs.getString("m_address");
+                // 学段
+                String school_period = rs.getString("m_school_period");
+                // 学制
+                String educational = rs.getString("m_educational");
+                // 1在职(在校) 0离职(毕业)
+                String in_out_school = rs.getString("m_in_out_school");
+                // 入学年份
+                String register_year = rs.getString("m_register_year");
+                memberEntities.add(new MemberEntity(id, cardNumber, name, gender, grade, college, profession, mmajor,
+                        mclass, identity_type, identity_title, card_type, id_card, country, organization, campus,
+                        employer, building, dorm_number, remark, physical_chip_number, physical_card_number,
+                        email, expire_at, qq, nation, origin_place, graduated_school, address, school_period,
+                        educational, in_out_school, register_year));
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        } finally {
+            closeResultSet(rs);
+            closeStatement(stmt);
+            closeConnection(conn);
+        }
+        return memberEntities;
+    }
+
+    // 查询所有数据,返回数据列表
+    public static List<MemberEntityHeadImg> queryAllHeadImg(String sql) {
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        ResultSet rs = null;
+        List<MemberEntityHeadImg> memberEntityHeadImgs = new ArrayList<>();
+        try {
+            conn = getConnection();
+            stmt = conn.prepareStatement(sql);
+            rs = stmt.executeQuery();
+            while (rs.next()) {
+                // id
+                int id = rs.getInt("m_id");
+                // 学工号
+                String cardNumber = rs.getString("m_card_number");
+                // 姓名
+                String name = rs.getString("m_name");
+                // 证件号
+                String id_card = rs.getString("m_id_card");
+                // 证件号
+                byte[] head_img = rs.getBytes("m_head_image");
+
+                memberEntityHeadImgs.add(new MemberEntityHeadImg(id, cardNumber, name, id_card, head_img));
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        } finally {
+            closeResultSet(rs);
+            closeStatement(stmt);
+            closeConnection(conn);
+        }
+        return memberEntityHeadImgs;
+    }
+
+    // 根据ID查询数据,返回查询到的数据,如果未查询到返回null
+//    public MemberEntity queryById(int id) {
+//        Connection conn = null;
+//        PreparedStatement stmt = null;
+//        ResultSet rs = null;
+//        MemberEntity user = null;
+//        try {
+//            conn = getConnection();
+//            String sql = "SELECT * FROM user WHERE id = ?";
+//            stmt = conn.prepareStatement(sql);
+//            stmt.setInt(1, id);
+//            rs = stmt.executeQuery();
+//            if (rs.next()) {
+//                String name = rs.getString("name");
+//                int age = rs.getInt("age");
+//                user = new MemberEntity(id, name, age);
+//            }
+//        } catch (SQLException e) {
+//            e.printStackTrace();
+//        } finally {
+//            closeResultSet(rs);
+//            closeStatement(stmt);
+//            closeConnection(conn);
+//        }
+//        return user;
+//    }
+
+}

+ 21 - 0
src/main/java/com/chkj/pdata/util/DateTime.java

@@ -0,0 +1,21 @@
+package com.chkj.pdata.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateTime {
+    /**
+     * 获取日期时间
+     *
+     * @return 当前日期时间
+     */
+    public String getDateTime() {
+        // 获取当前日期时间
+        Date date = new Date();
+        // 定义日期时间格式
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        // 将日期时间转换为字符串
+        // 打印当前日期时间
+        return format.format(date);
+    }
+}

+ 82 - 0
src/main/java/com/chkj/pdata/util/FileUtil.java

@@ -0,0 +1,82 @@
+package com.chkj.pdata.util;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class FileUtil {
+    private final static String ps = File.separator;
+
+    public String getPath() {
+        String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
+        if (System.getProperty("os.name").contains("dows")) {
+            path = path.substring(1);
+        }
+        if (path.contains("jar")) {
+            path = path.substring(0, path.lastIndexOf("."));
+            return path.substring(0, path.lastIndexOf("/")).replace("file:", "") + ps;
+        }
+        return path
+                .replace("target/classes/", "")
+                .replace("file:", "") + ps;
+    }
+
+    public void writeToFile(String content, String tipClass) {
+        String basePath = getPath();
+        // 获取当前日期时间
+        DateTime dateTime = new DateTime();
+        String dt = dateTime.getDateTime();
+
+        String directoryPath = basePath + "logs";
+        File directory = new File(directoryPath);
+        if (!directory.exists()) {
+            boolean created = directory.mkdirs();
+            if (created) {
+                System.out.println("创建目录成功: " + directoryPath);
+            } else {
+                System.out.println("创建目录失败: " + directoryPath);
+            }
+        }
+
+        String filename = basePath + "logs" + ps;
+        //  定义当天日志文件
+        if ("abnormal".equals(tipClass)) filename += dt.substring(0, 10) + "-abnormal-log.csv";  // 异常日志,需要人工处理
+        else if ("ok".equals(tipClass)) filename += dt.substring(0, 10) + "-ok-log.csv";  // 可以推送的信息日志,不需要人工处理
+        else if ("headImage".equals(tipClass))
+            filename += dt.substring(0, 10) + "-headImage-log.csv";  // 头像转png文件日志,不需要人工处理
+        else if ("none".equals(tipClass))
+            filename += dt.substring(0, 10) + "-none-log.csv";  // 目前没有推送信息日志,会打印时间、提示,不需要人工处理
+        else if ("bak".equals(tipClass)) filename += dt.substring(0, 10) + "-bak-log.csv";  // 备份 手机 和 身份证,不需要人工处理
+        else if ("delMember".equals(tipClass))
+            filename += dt.substring(0, 10) + "-delMember-log.csv";  // 备份 手机 和 身份证,不需要人工处理
+        else filename += dt.substring(0, 10) + "-log.csv";  // 记录成功和失败日志,一般不需要人工处理
+
+        FileWriter fileWriter;
+        try {
+            if (new File(filename).exists()) { // 判断文件是否存在
+                fileWriter = new FileWriter(filename, true); // 如果存在则以追加方式打开文件
+            } else {
+                fileWriter = new FileWriter(filename); // 如果不存在则创建新文件
+                fileWriter.append("时间,原因,具体信息" + "\r\n"); // 写表头
+            }
+            fileWriter.append(dt).append(",").append(content).append("\r\n"); // 将Properties对象中的信息写入到文件中
+            fileWriter.close(); // 关闭文件流
+        } catch (IOException e) {
+            System.out.println(e.getMessage());
+        }
+    }
+
+    public boolean readFromFile(String tipClass) {
+        String basePath = getPath();
+        // 获取当前日期时间
+        DateTime dateTime = new DateTime();
+        String dt = dateTime.getDateTime();
+        String ps = File.separator;
+        String filename = basePath + "logs" + ps;
+        //  定义当天日志文件
+        if ("none".equals(tipClass)) filename += dt.substring(0, 10) + "-none-log.csv";  // 目前没有推送信息日志,会打印时间、提示,不需要人工处理
+
+        // 判断文件是否存在
+        return new File(filename).exists();
+    }
+}

+ 37 - 0
src/main/java/com/chkj/pdata/util/HttpRequestUtils.java

@@ -0,0 +1,37 @@
+package com.chkj.pdata.util;
+
+import org.springframework.http.*;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Map;
+
+
+public class HttpRequestUtils {
+
+    private static final RestTemplate restTemplate = new RestTemplate();
+
+    static FileUtil myWriter = new FileUtil();
+
+    public static ResponseEntity<String> httpGet(String url, Map<String, String> queryParams) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
+        HttpEntity<String> entity = new HttpEntity<>(headers);
+
+        return restTemplate.exchange(url, HttpMethod.GET, entity, String.class, queryParams);
+    }
+
+    public static ResponseEntity<String> httpPost(String url, Object requestBody, Map<String, String> queryParams) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
+        headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+        HttpEntity<Object> entity = new HttpEntity<>(requestBody, headers);
+
+        try {
+            // 执行可能会抛出Connection reset异常的代码
+            return restTemplate.exchange(url, HttpMethod.POST, entity, String.class, queryParams);
+        } catch (Exception e) {
+            myWriter.writeToFile(e.getMessage(), "abnormal");
+            return null;
+        }
+    }
+}

+ 3 - 0
src/main/resources/META-INF/MANIFEST.MF

@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: com.chkj.pdata.PdataApplication
+

+ 9 - 0
src/main/resources/application.properties

@@ -0,0 +1,9 @@
+cron.expression=*/30 * * * * *
+
+#server.servlet.context-path=/kong
+#headImage
+#server.port=8081
+
+#push member
+server.port=8082
+

+ 13 - 0
src/test/java/com/chkj/pdata/PdataApplicationTests.java

@@ -0,0 +1,13 @@
+package com.chkj.pdata;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class PdataApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}