Explorar o código

迁移定时任务 新增了jobservice服务

shiyj %!s(int64=7) %!d(string=hai) anos
pai
achega
5622b29950
Modificáronse 44 ficheiros con 16565 adicións e 5 borrados
  1. 31 0
      JobService/.gitignore
  2. 114 0
      JobService/.mvn/wrapper/MavenWrapperDownloader.java
  3. BIN=BIN
      JobService/.mvn/wrapper/maven-wrapper.jar
  4. 1 0
      JobService/.mvn/wrapper/maven-wrapper.properties
  5. 286 0
      JobService/mvnw
  6. 161 0
      JobService/mvnw.cmd
  7. 86 0
      JobService/pom.xml
  8. 754 0
      JobService/src/main/java/com/java110/job/Api/PrvncFtpToFileSystemConfigAction.java
  9. 49 0
      JobService/src/main/java/com/java110/job/Java110JobserviceApplication.java
  10. 36 0
      JobService/src/main/java/com/java110/job/common/CustomizedPropertyPlaceholderConfigurer.java
  11. 165 0
      JobService/src/main/java/com/java110/job/dao/IPrvncFtpFileDAO.java
  12. 223 0
      JobService/src/main/java/com/java110/job/dao/impl/PrvncFtpFileDAOImpl.java
  13. 55 0
      JobService/src/main/java/com/java110/job/model/FtpTaskLog.java
  14. 91 0
      JobService/src/main/java/com/java110/job/model/FtpTaskLogDetail.java
  15. 440 0
      JobService/src/main/java/com/java110/job/smo/DownloadFileFromFtpToTable.java
  16. 47 0
      JobService/src/main/java/com/java110/job/smo/IPrvncFtpFileBMO.java
  17. 54 0
      JobService/src/main/java/com/java110/job/smo/IPrvncFtpFileSMO.java
  18. 376 0
      JobService/src/main/java/com/java110/job/smo/PrvncFtpToFileSystemQuartz.java
  19. 52 0
      JobService/src/main/java/com/java110/job/smo/impl/PrvncFtpFileBMOImpl.java
  20. 55 0
      JobService/src/main/java/com/java110/job/smo/impl/PrvncFtpFileSMOImpl.java
  21. 90 0
      JobService/src/main/java/com/java110/job/task/PrvncFtpToFileSystemJob.java
  22. 1068 0
      JobService/src/main/java/com/java110/job/util/FTPClientTemplate.java
  23. 94 0
      JobService/src/main/resources/application-dev.yml
  24. 3 0
      JobService/src/main/resources/application.yml
  25. 15 0
      JobService/src/main/resources/banner.txt
  26. 75 0
      JobService/src/main/resources/dataSource.yml
  27. 587 0
      JobService/src/main/resources/static/css/bootstrap-theme.css
  28. 6760 0
      JobService/src/main/resources/static/css/bootstrap.css
  29. 34 0
      JobService/src/main/resources/static/css/prvncFtpToFileSystemConfigList.css
  30. 656 0
      JobService/src/main/resources/static/js/bootstrap-paginator.js
  31. 2363 0
      JobService/src/main/resources/static/js/bootstrap.js
  32. 7 0
      JobService/src/main/resources/static/js/bootstrap.min.js
  33. 5 0
      JobService/src/main/resources/static/js/jquery.min.js
  34. 703 0
      JobService/src/main/resources/static/js/prvncFtpToFileSystemConfigList.js
  35. 549 0
      JobService/src/main/resources/static/jsp/prvncFtpToFileSystemConfigList.jsp
  36. 16 0
      JobService/src/test/java/com/java110/job/Java110JobserviceApplicationTests.java
  37. BIN=BIN
      docs/images/0001.png
  38. BIN=BIN
      docs/images/0002.jpg
  39. BIN=BIN
      docs/images/0003.png
  40. 4 3
      docs/index.html
  41. 8 0
      java110-common/src/main/java/com/java110/common/constant/RuleDomain.java
  42. 18 0
      java110-common/src/main/java/com/java110/common/exception/TaskException.java
  43. 427 0
      java110-db/src/main/resources/mapper/job/PrvncFtpFileDAO.xml
  44. 7 2
      pom.xml

+ 31 - 0
JobService/.gitignore

@@ -0,0 +1,31 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/

+ 114 - 0
JobService/.mvn/wrapper/MavenWrapperDownloader.java

@@ -0,0 +1,114 @@
+/*
+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.
+*/
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.util.Properties;
+
+public class MavenWrapperDownloader {
+
+    /**
+     * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
+     */
+    private static final String DEFAULT_DOWNLOAD_URL =
+            "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
+
+    /**
+     * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
+     * use instead of the default one.
+     */
+    private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
+            ".mvn/wrapper/maven-wrapper.properties";
+
+    /**
+     * Path where the maven-wrapper.jar will be saved to.
+     */
+    private static final String MAVEN_WRAPPER_JAR_PATH =
+            ".mvn/wrapper/maven-wrapper.jar";
+
+    /**
+     * Name of the property which should be used to override the default download url for the wrapper.
+     */
+    private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
+
+    public static void main(String args[]) {
+        System.out.println("- Downloader started");
+        File baseDirectory = new File(args[0]);
+        System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
+
+        // If the maven-wrapper.properties exists, read it and check if it contains a custom
+        // wrapperUrl parameter.
+        File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
+        String url = DEFAULT_DOWNLOAD_URL;
+        if (mavenWrapperPropertyFile.exists()) {
+            FileInputStream mavenWrapperPropertyFileInputStream = null;
+            try {
+                mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
+                Properties mavenWrapperProperties = new Properties();
+                mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
+                url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
+            } catch (IOException e) {
+                System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
+            } finally {
+                try {
+                    if (mavenWrapperPropertyFileInputStream != null) {
+                        mavenWrapperPropertyFileInputStream.close();
+                    }
+                } catch (IOException e) {
+                    // Ignore ...
+                }
+            }
+        }
+        System.out.println("- Downloading from: : " + url);
+
+        File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
+        if (!outputFile.getParentFile().exists()) {
+            if (!outputFile.getParentFile().mkdirs()) {
+                System.out.println(
+                        "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
+            }
+        }
+        System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
+        try {
+            downloadFileFromURL(url, outputFile);
+            System.out.println("Done");
+            System.exit(0);
+        } catch (Throwable e) {
+            System.out.println("- Error downloading");
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    private static void downloadFileFromURL(String urlString, File destination) throws Exception {
+        URL website = new URL(urlString);
+        ReadableByteChannel rbc;
+        rbc = Channels.newChannel(website.openStream());
+        FileOutputStream fos = new FileOutputStream(destination);
+        fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+        fos.close();
+        rbc.close();
+    }
+
+}

BIN=BIN
JobService/.mvn/wrapper/maven-wrapper.jar


+ 1 - 0
JobService/.mvn/wrapper/maven-wrapper.properties

@@ -0,0 +1 @@
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip

+ 286 - 0
JobService/mvnw

@@ -0,0 +1,286 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Maven2 Start Up Batch script
+#
+# Required ENV vars:
+# ------------------
+#   JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+#   M2_HOME - location of maven2's installed home dir
+#   MAVEN_OPTS - parameters passed to the Java VM when running Maven
+#     e.g. to debug Maven itself, use
+#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+  if [ -f /etc/mavenrc ] ; then
+    . /etc/mavenrc
+  fi
+
+  if [ -f "$HOME/.mavenrc" ] ; then
+    . "$HOME/.mavenrc"
+  fi
+
+fi
+
+# OS specific support.  $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "`uname`" in
+  CYGWIN*) cygwin=true ;;
+  MINGW*) mingw=true;;
+  Darwin*) darwin=true
+    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+    if [ -z "$JAVA_HOME" ]; then
+      if [ -x "/usr/libexec/java_home" ]; then
+        export JAVA_HOME="`/usr/libexec/java_home`"
+      else
+        export JAVA_HOME="/Library/Java/Home"
+      fi
+    fi
+    ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+  if [ -r /etc/gentoo-release ] ; then
+    JAVA_HOME=`java-config --jre-home`
+  fi
+fi
+
+if [ -z "$M2_HOME" ] ; then
+  ## resolve links - $0 may be a link to maven's home
+  PRG="$0"
+
+  # need this for relative symlinks
+  while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+      PRG="$link"
+    else
+      PRG="`dirname "$PRG"`/$link"
+    fi
+  done
+
+  saveddir=`pwd`
+
+  M2_HOME=`dirname "$PRG"`/..
+
+  # make it fully qualified
+  M2_HOME=`cd "$M2_HOME" && pwd`
+
+  cd "$saveddir"
+  # echo Using m2 at $M2_HOME
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --unix "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME="`(cd "$M2_HOME"; pwd)`"
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
+  # TODO classpath?
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+  javaExecutable="`which javac`"
+  if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
+    # readlink(1) is not available as standard on Solaris 10.
+    readLink=`which readlink`
+    if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
+      if $darwin ; then
+        javaHome="`dirname \"$javaExecutable\"`"
+        javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
+      else
+        javaExecutable="`readlink -f \"$javaExecutable\"`"
+      fi
+      javaHome="`dirname \"$javaExecutable\"`"
+      javaHome=`expr "$javaHome" : '\(.*\)/bin'`
+      JAVA_HOME="$javaHome"
+      export JAVA_HOME
+    fi
+  fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+  if [ -n "$JAVA_HOME"  ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+    fi
+  else
+    JAVACMD="`which java`"
+  fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+  echo "Error: JAVA_HOME is not defined correctly." >&2
+  echo "  We cannot execute $JAVACMD" >&2
+  exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+  echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+
+  if [ -z "$1" ]
+  then
+    echo "Path not specified to find_maven_basedir"
+    return 1
+  fi
+
+  basedir="$1"
+  wdir="$1"
+  while [ "$wdir" != '/' ] ; do
+    if [ -d "$wdir"/.mvn ] ; then
+      basedir=$wdir
+      break
+    fi
+    # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+    if [ -d "${wdir}" ]; then
+      wdir=`cd "$wdir/.."; pwd`
+    fi
+    # end of workaround
+  done
+  echo "${basedir}"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+  if [ -f "$1" ]; then
+    echo "$(tr -s '\n' ' ' < "$1")"
+  fi
+}
+
+BASE_DIR=`find_maven_basedir "$(pwd)"`
+if [ -z "$BASE_DIR" ]; then
+  exit 1;
+fi
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Found .mvn/wrapper/maven-wrapper.jar"
+    fi
+else
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
+    fi
+    jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
+    while IFS="=" read key value; do
+      case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
+      esac
+    done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
+    if [ "$MVNW_VERBOSE" = true ]; then
+      echo "Downloading from: $jarUrl"
+    fi
+    wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
+
+    if command -v wget > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found wget ... using wget"
+        fi
+        wget "$jarUrl" -O "$wrapperJarPath"
+    elif command -v curl > /dev/null; then
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Found curl ... using curl"
+        fi
+        curl -o "$wrapperJarPath" "$jarUrl"
+    else
+        if [ "$MVNW_VERBOSE" = true ]; then
+          echo "Falling back to using Java to download"
+        fi
+        javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
+        if [ -e "$javaClass" ]; then
+            if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Compiling MavenWrapperDownloader.java ..."
+                fi
+                # Compiling the Java class
+                ("$JAVA_HOME/bin/javac" "$javaClass")
+            fi
+            if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
+                # Running the downloader
+                if [ "$MVNW_VERBOSE" = true ]; then
+                  echo " - Running MavenWrapperDownloader.java ..."
+                fi
+                ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
+            fi
+        fi
+    fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
+if [ "$MVNW_VERBOSE" = true ]; then
+  echo $MAVEN_PROJECTBASEDIR
+fi
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+  [ -n "$M2_HOME" ] &&
+    M2_HOME=`cygpath --path --windows "$M2_HOME"`
+  [ -n "$JAVA_HOME" ] &&
+    JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
+  [ -n "$CLASSPATH" ] &&
+    CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
+  [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+    MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
+fi
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+exec "$JAVACMD" \
+  $MAVEN_OPTS \
+  -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+  "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

+ 161 - 0
JobService/mvnw.cmd

@@ -0,0 +1,161 @@
+@REM ----------------------------------------------------------------------------
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM    https://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM ----------------------------------------------------------------------------
+
+@REM ----------------------------------------------------------------------------
+@REM Maven2 Start Up Batch script
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM M2_HOME - location of maven2's installed home dir
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM     e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on"  echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
+if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"
+FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO (
+	IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+    echo Found %WRAPPER_JAR%
+) else (
+    echo Couldn't find %WRAPPER_JAR%, downloading it ...
+	echo Downloading from: %DOWNLOAD_URL%
+    powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"
+    echo Finished downloading %WRAPPER_JAR%
+)
+@REM End of extension
+
+%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
+if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%" == "on" pause
+
+if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
+
+exit /B %ERROR_CODE%

+ 86 - 0
JobService/pom.xml

@@ -0,0 +1,86 @@
+<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>MicroCommunity</artifactId>
+        <groupId>com.java110</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>com.java110</groupId>
+    <artifactId>JobService</artifactId>
+    <packaging>jar</packaging>
+
+    <name>JobService</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.7</maven.compiler.source>
+        <maven.compiler.target>1.7</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.java110</groupId>
+            <artifactId>java110-service</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.java110</groupId>
+            <artifactId>java110-event</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.quartz-scheduler</groupId>
+            <artifactId>quartz</artifactId>
+            <version>1.8.6</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>JobService</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>2.10</version>
+                <executions>
+                    <execution>
+                        <id>unpack</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>unpack</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <groupId>com.java110</groupId>
+                                    <artifactId>java110-config</artifactId>
+                                    <version>${microcommunity.version}</version>
+                                    <type>jar</type>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>${project.build.directory}/classes</outputDirectory>
+                                </artifactItem>
+                            </artifactItems>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <mainClass>com.java110.user.UserServiceApplicationStart</mainClass>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 754 - 0
JobService/src/main/java/com/java110/job/Api/PrvncFtpToFileSystemConfigAction.java

@@ -0,0 +1,754 @@
+package com.java110.job.Api;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.java110.common.util.SpringBeanInvoker;
+import com.java110.job.common.CustomizedPropertyPlaceholderConfigurer;
+import com.java110.job.dao.IPrvncFtpFileDAO;
+import com.java110.job.task.PrvncFtpToFileSystemJob;
+import org.apache.commons.validator.GenericValidator;
+import org.apache.commons.validator.util.ValidatorUtils;
+import org.quartz.CronTrigger;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 将ftp上的文件保存到支持的文件系统
+ * 
+ * @author wuxw7 add by 20170103
+ * 
+ */
+@RestController
+public class PrvncFtpToFileSystemConfigAction{
+
+	private static final Logger logger = LoggerFactory.getLogger(PrvncFtpToFileSystemConfigAction.class);
+
+	private static final String defaultCronExpression = "0 * * * * ?";// 每分钟执行一次
+
+	private static final String prefixJobName = "PrvncFtpToSystem_"; // job
+	// 名称前缀,防止和其他的job名称产生冲突
+
+	private static final String RUNFLAG_START = "1";
+
+	private static final String RUNFLAG_STOP = "0";
+	@Autowired
+	private IPrvncFtpFileDAO iprvncFtpFileDAO;
+	// 每页数据条数
+	private static int pageSize = 20;
+
+	public JSONObject resultMsg;
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 查询配置的需要下载任务的列表
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/queryFtpItems" , method = RequestMethod.POST)
+	public String queryFtpItems(@RequestBody String queryftpinfo,HttpServletRequest request) {
+
+		JSONObject queryftp = JSONObject.parseObject(queryftpinfo);
+		String curPage = queryftp.getString("curPage");
+		curPage = curPage == null || "".equals(curPage) ? "1" : curPage;
+
+		// 查询在用状态时的下载任务列表
+		Map info = new HashMap();
+		info.put("curPage", curPage);
+		info.put("pageSize", pageSize);
+		Map resultInfo = getPrvncFtpFileDAO().queryFtpItems(info);
+
+		// 获取总数据数
+		int dataCount = resultInfo.get("ITEMSCOUNT") == null ? 0 : Integer.parseInt(resultInfo.get("ITEMSCOUNT").toString());
+		// 计算页数
+		if (dataCount % pageSize == 0) {
+			dataCount /= pageSize;
+		} else {
+			dataCount = dataCount / pageSize + 1;
+		}
+
+		// 获取数据
+		List<Map> ftpItems = resultInfo.get("DATA") == null ? null : (List) resultInfo.get("DATA");
+
+		// {"total":10,"rows":[{},{}]}
+
+		JSONObject data = new JSONObject();
+		data.put("total", dataCount);
+		data.put("currentPage", curPage);
+		if (ftpItems != null && ftpItems.size() > 0) {
+			JSONArray rows = new JSONArray();
+			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+			for (int itemIndex = 0; itemIndex < ftpItems.size(); itemIndex++) {
+
+				// 处理时间显示和界面显示传输类型
+				Map ftpItemMap = ftpItems.get(itemIndex);
+				ftpItemMap.put("U_OR_D_NAME", "task.tamplete.name." + ftpItemMap.get("U_OR_D"));// 暂且写死,最终还是读取配置
+				ftpItemMap.put("CREATE_DATE", df.format(ftpItemMap.get("CREATE_DATE")));// 暂且写死,最终还是读取配置
+				rows.add(JSONObject.parseObject(JSONObject.toJSONString(ftpItems.get(itemIndex))));
+			}
+			data.put("rows", rows);
+			resultMsg = data;
+			return data.toString();
+		}
+		data.put("rows", "[]");
+		resultMsg = data;
+		return data.toString();
+	}
+
+	/**
+	 * 增加Ftp配置
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/addFtpItem" , method = RequestMethod.POST)
+	public String addFtpItem(@RequestBody String addFtpIteminfo,HttpServletRequest request) {
+		JSONObject addFtpItem = JSONObject.parseObject(addFtpIteminfo);
+		// 请求参数
+		String ftpItemJson = addFtpItem.getString("ftpItemJson");
+		JSONObject ftpItemJsonObj = null;
+		try {
+			// 校验格式是否正确
+			ftpItemJsonObj = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "addFtpItem";
+		}
+
+		// 将ftpItemJson装为Map保存操作
+		Map paramIn = JSONObject.parseObject(ftpItemJsonObj.getJSONObject("taskInfo").toJSONString(), Map.class);
+
+		// 数据规范性校验
+
+		// 在prvncCrm.properties 文件中获取对应处理类
+		Object dealClassObj = CustomizedPropertyPlaceholderConfigurer.getContextProperty("task.deal.class." + paramIn.get("uOrD"));
+		// Object dealClassObj = "provInner.DownloadFileFromFtpToTFS";
+		if (dealClassObj == null) {
+			resultMsg = this.createResultMsg("1999", "对应模板不存在,请联系管理员", "");
+			return "addFtpItem";
+		}
+		String dealClass = dealClassObj.toString();
+
+		long taskId = getPrvncFtpFileDAO().newCreateTaskId();
+		// 保存数据
+		paramIn.put("taskId", taskId);
+		paramIn.put("dealClass", dealClass);
+
+		int addFtpItemFlag = getPrvncFtpFileDAO().addFtpItem(paramIn);
+
+		if (addFtpItemFlag > 0) {
+			// #taskId#,#itemSpecId#,#value#
+			// 保存属性信息
+			JSONArray taskAttrs = ftpItemJsonObj.getJSONArray("taskAttrs");
+			List<Map> taskAttrsList = new ArrayList<Map>();
+			for (int taskAttrIndex = 0; taskAttrIndex < taskAttrs.size(); taskAttrIndex++) {
+				JSONObject taskAttr = taskAttrs.getJSONObject(taskAttrIndex);
+				Map taskAttrMap = new HashMap();
+				taskAttrMap.put("taskId", taskId);
+				taskAttrMap.put("itemSpecId", taskAttr.get("itemSpecId"));
+				taskAttrMap.put("value", taskAttr.get("value"));
+				taskAttrsList.add(taskAttrMap);
+			}
+			int addFtpItemAttrFlag = getPrvncFtpFileDAO().addFtpItemAttrs(taskAttrsList);
+			if (addFtpItemAttrFlag > 0) {
+				resultMsg = this.createResultMsg("0000", "成功", ftpItemJson);
+			} else {
+				resultMsg = this.createResultMsg("1999", "保存属性失败", "");
+			}
+			return resultMsg.toString();
+		}
+		resultMsg = this.createResultMsg("1999", "保存数据失败", "");
+		return resultMsg.toString();
+	}
+
+	/**
+	 * 编辑Ftp配置,编辑时将会修改所有的ftpItem 信息,所以传递是所有字段需要传递全
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/editFtpItem",method = RequestMethod.POST)
+	public String editFtpItem(@RequestBody String editFtpItem,HttpServletRequest request) {
+		JSONObject editftpitem =  JSONObject.parseObject(editFtpItem);
+		// 请求参数为{"taskId":"12","taskName":"经办人照片同步处理","ftpUserName":"weblogic",.....}
+		String ftpItemJson = editftpitem.getString("ftpItemJson");
+		JSONObject ftpItemJsonObj = null;
+		try {
+			// 校验格式是否正确
+			ftpItemJsonObj = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "editFtpItem";
+		}
+
+		// 将ftpItemJson装为Map保存操作
+		Map paramIn = JSONObject.parseObject(ftpItemJsonObj.getJSONObject("taskInfo").toJSONString(), Map.class);
+
+		// 在prvncCrm.properties 文件中获取对应处理类
+		Object dealClassObj = CustomizedPropertyPlaceholderConfigurer.getContextProperty("task.deal.class." + paramIn.get("uOrD"));
+		// Object dealClassObj = "provInner.DownloadFileFromFtpToTFS";
+		if (dealClassObj == null) {
+			resultMsg = this.createResultMsg("1999", "对应模板不存在,请联系管理员", "");
+			return "editFtpItem";
+		}
+		String dealClass = dealClassObj.toString();
+
+		paramIn.put("dealClass", dealClass);
+
+		// 根据taskId 查询记录是否存在,如果不存在直接返回失败
+		Map ftpItem = getPrvncFtpFileDAO().queryFtpItemByTaskId(paramIn);
+		// 判断是否有对应的数据
+		if (ftpItem != null && ftpItem.containsKey("TASKID")) {
+			// 更新数据
+			int updateFtpItemFlag = getPrvncFtpFileDAO().updateFtpItemByTaskId(paramIn);
+			if (updateFtpItemFlag > 0) {
+				// 首先先删除
+				getPrvncFtpFileDAO().deleteFtpItemAttrsbyTaskId(paramIn);
+				// 保存属性信息
+				JSONArray taskAttrs = ftpItemJsonObj.getJSONArray("taskAttrs");
+				List<Map> taskAttrsList = new ArrayList<Map>();
+				for (int taskAttrIndex = 0; taskAttrIndex < taskAttrs.size(); taskAttrIndex++) {
+					JSONObject taskAttr = taskAttrs.getJSONObject(taskAttrIndex);
+					Map taskAttrMap = new HashMap();
+					taskAttrMap.put("taskId", paramIn.get("taskId"));
+					taskAttrMap.put("itemSpecId", taskAttr.get("itemSpecId"));
+					taskAttrMap.put("value", taskAttr.get("value"));
+					taskAttrsList.add(taskAttrMap);
+				}
+				int addFtpItemAttrFlag = getPrvncFtpFileDAO().addFtpItemAttrs(taskAttrsList);
+				if (addFtpItemAttrFlag > 0) {
+					resultMsg = this.createResultMsg("0000", "成功", ftpItemJson);
+				} else {
+					resultMsg = this.createResultMsg("1999", "更新属性失败", "");
+				}
+				return "editFtpItem";
+			}
+			resultMsg = this.createResultMsg("1999", "修改的数据不存在或修改失败", "");
+			return "editFtpItem";
+		}
+		resultMsg = this.createResultMsg("1999", "未找到对应的数据更新失败【" + paramIn.get("taskId") + "】", "");
+		return "editFtpItem";
+	}
+
+	/**
+	 * 删除ftp配置
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/deleteFtpItem",method = RequestMethod.POST)
+	public String deleteFtpItem(@RequestBody String deleteFtpItemInfo,HttpServletRequest request) {
+
+		JSONObject delteftpinfo = JSONObject.parseObject(deleteFtpItemInfo);
+		// 请求参数为{"tasks":[{"taskId":1},{"taskId":2}],"state":"DELETE"}
+		String ftpItemJson = delteftpinfo.getString("ftpItemJson");
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.deleteFtpItem】入参为:" + ftpItemJson, ftpItemJson);
+		}
+
+		JSONObject paramIn = null;
+
+		try {
+			// 校验格式是否正确
+			paramIn = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson + e, "");
+			return "deleteFtpItem";
+		}
+
+		// 传入报文不为空
+		if (paramIn == null || !paramIn.containsKey("tasks") || !paramIn.containsKey("state")) {
+
+			resultMsg = createResultMsg("1999", "传入参数格式不正确(必须包含tasks 和  state节点):" + ftpItemJson, "");
+			return "deleteFtpItem";
+		}
+
+		// 校验当前是否为启动侦听
+		if (!"DELETE".equals(paramIn.get("state"))) {
+
+			resultMsg = createResultMsg("1999", "传入参数格式不正确(state的值必须是DELETE):" + ftpItemJson, "");
+			return "deleteFtpItem";
+		}
+
+		// 查询需要操作的任务
+		JSONArray taskInfos = paramIn.getJSONArray("tasks");
+		String taskIds = "";
+
+		for (int taskIndex = 0; taskIndex < taskInfos.size(); taskIndex++) {
+			taskIds += (taskInfos.getJSONObject(taskIndex).getString("taskId") + ",");
+		}
+
+		if (taskIds.length() > 0) {
+			taskIds = taskIds.substring(0, taskIds.length() - 1);
+		}
+		// 将ftpItemJson装为Map保存操作
+		Map paramInfo = new HashMap();
+		paramInfo.put("taskIds", taskIds.split(","));
+		// 更新数据
+		int updateFtpItemFlag = getPrvncFtpFileDAO().deleteFtpItemByTaskId(paramInfo);
+		if (updateFtpItemFlag > 0) {
+			resultMsg = this.createResultMsg("0000", "成功", ftpItemJson);
+			return "deleteFtpItem";
+		}
+
+		resultMsg = this.createResultMsg("1999", "删除数据已经不存在,或删除失败", "");
+
+		return "deleteFtpItem";
+	}
+
+	/**
+	 * 根据taskId 获取 ftp配置信息
+	 * 
+	 * @return
+	 */
+
+	@RequestMapping(path = "/FtpToFileSystem/queryFtpItemByTaskId" , method = RequestMethod.POST)
+	public String queryFtpItemByTaskId(@RequestBody String queryFtpItemByTaskId,HttpServletRequest request) {
+		JSONObject queryFtpItemByTask = JSONObject.parseObject(queryFtpItemByTaskId);
+		// 请求参数
+		String ftpItemJson = queryFtpItemByTask.getString("ftpItemJson");
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.queryFtpItemByTaskId】入参为:" + ftpItemJson, ftpItemJson);
+		}
+
+		try {
+			// 校验格式是否正确
+			JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "queryFtpItemByTaskId";
+		}
+
+		// 将ftpItemJson装为Map保存操作
+		Map paramIn = JSONObject.parseObject(ftpItemJson, Map.class);
+
+		// 根据taskId 查询记录是否存在,如果不存在直接返回失败
+		Map ftpItem = getPrvncFtpFileDAO().queryFtpItemByTaskId(paramIn);
+		// 判断是否有对应的数据
+		if (ftpItem != null && ftpItem.containsKey("TASKID")) {
+			// 更新数据
+			this.createResultMsg("0000", "成功", JSONObject.toJSONString(ftpItem));
+			return "queryFtpItemByTaskId";
+		}
+		resultMsg = this.createResultMsg("1999", "删除数据已经不存在,或删除失败", "");
+
+		return "queryFtpItemByTaskId";
+	}
+
+	/**
+	 * 查询任务模板 ftpItemJson:{'uOrD':'U'}
+	 * 
+	 * @return
+	 */
+
+	@RequestMapping(path = "/FtpToFileSystem/questTaskTample" , method = RequestMethod.POST)
+	public String questTaskTample(@RequestBody String questTaskTample,HttpServletRequest request) {
+		JSONObject questtasktample = JSONObject.parseObject(questTaskTample);
+		// 请求参数
+		String ftpItemJson = questtasktample.getString("ftpItemJson");
+		// 请求参数为{"taskId":"12"}
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.queryFtpItemByTaskId】入参为:" + ftpItemJson, ftpItemJson);
+		}
+		JSONObject paramIn = null;
+		try {
+			// 校验格式是否正确
+			paramIn = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "questTaskTample";
+		}
+
+		String tample = paramIn.getString("uOrD");
+
+		Map info = new HashMap();
+		info.put("domain", tample);
+
+		List<Map> itemSpecs = getPrvncFtpFileDAO().queryItemSpec(info);
+		String taskItems = JSONObject.toJSONString(itemSpecs);
+
+		resultMsg = this.createResultMsg("0000", "成功", "{\"U_OR_D\":\"" + tample + "\",\"TASK_ITEMS\":" + taskItems + "}");
+		return "questTaskTample";
+	}
+
+	/**
+	 * 根据TaskId 获取任务属性
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/queryTaskAttrs" , method = RequestMethod.POST)
+	public String queryTaskAttrs(@RequestBody String queryTaskAttrsInfo,HttpServletRequest request) {
+
+		JSONObject querytaskattrs = JSONObject.parseObject(queryTaskAttrsInfo);
+
+		// 请求参数为{"taskId":"12"}
+		String ftpItemJson = querytaskattrs.getString("ftpItemJson");
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.queryTaskAttrs】入参为:" + ftpItemJson, ftpItemJson);
+		}
+		JSONObject paramIn = null;
+		try {
+			// 校验格式是否正确
+			paramIn = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "questTaskTample";
+		}
+
+		long taskId = paramIn.getLong("taskId");
+
+		Map info = new HashMap();
+		info.put("taskId", taskId);
+
+		List<Map> itemAttrs = getPrvncFtpFileDAO().queryFtpItemAttrsByTaskId(info);
+		String itemsAttrs = JSONObject.toJSONString(itemAttrs);
+
+		resultMsg = this.createResultMsg("0000", "成功", "{\"TASK_ATTRS\":" + itemsAttrs + "}");
+		return "queryTaskAttrs";
+	}
+
+	/**
+	 * 启动侦听(多节点启动)
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/startJob",method = RequestMethod.POST)
+	public String startJob(@RequestBody String startInfo , HttpServletRequest request) {
+
+		JSONObject startinfo = JSONObject.parseObject(startInfo);
+		// 请求参数为{"tasks":[{"taskId":1},{"taskId":2}],"state":"START"}
+		String ftpItemJson = startinfo.getString("ftpItemJson");
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.startJob】入参为:" + ftpItemJson, ftpItemJson);
+		}
+		JSONObject paramIn = null;
+		try {
+			// 校验格式是否正确
+			paramIn = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "startJob";
+		}
+
+		// 传入报文不为空
+		if (paramIn == null || !paramIn.containsKey("tasks") || !paramIn.containsKey("state")) {
+
+			resultMsg = createResultMsg("1999", "传入参数格式不正确(必须包含tasks 和  state节点):" + ftpItemJson, "");
+			return "startJob";
+		}
+
+		// 校验当前是否为启动侦听
+		if (!"START".equals(paramIn.get("state"))) {
+
+			resultMsg = createResultMsg("1999", "传入参数格式不正确(state的值必须是START):" + ftpItemJson, "");
+			return "startJob";
+		}
+
+		// 查询需要操作的任务
+		JSONArray taskInfos = paramIn.getJSONArray("tasks");
+
+		String taskIds = "";
+
+		for (int taskIndex = 0; taskIndex < taskInfos.size(); taskIndex++) {
+			taskIds += (taskInfos.getJSONObject(taskIndex).getString("taskId") + ",");
+		}
+
+		if (taskIds.length() > 0) {
+			taskIds = taskIds.substring(0, taskIds.length() - 1);
+		}
+
+		Map info = new HashMap();
+
+		info.put("taskIds", taskIds.split(","));
+
+		List<Map> doFtpItems = getPrvncFtpFileDAO().queryFtpItemsByTaskIds(info);
+
+		// 获取Spring调度器
+		Scheduler scheduler = (Scheduler) SpringBeanInvoker.getBean("schedulerFactoryBean");
+		int linstenCount = 0;
+		int updateTaskStateFailCount = 0;
+		try {
+			for (int doIndex = 0; doIndex < doFtpItems.size(); doIndex++) {
+				Map doFtpItem = doFtpItems.get(doIndex);
+
+				// 侦听运行状态
+				String runState = doFtpItem.get("RUN_STATE") == null ? "1" : doFtpItem.get("RUN_STATE").toString();// 如果为空,为了操作正常,默认为1,也就是启动状态,在后面再关闭一次
+
+				// 获取taskId
+				String taskId = doFtpItem.get("TASKID").toString();// 这个就不用三目判断了,因为如果为空,则直接抛出异常,正常情况下不会出现空的情况
+
+				// 获取定时时间
+				String cronExpression = doFtpItem.get("TASKCRON") == null ? defaultCronExpression : doFtpItem.get("TASKCRON").toString();// 如果没有配置则,每一分运行一次
+
+				String jobName = prefixJobName + taskId;
+
+				String triggerName = prefixJobName + taskId;
+
+				JobDetail jobDetail = scheduler.getJobDetail(jobName, PrvncFtpToFileSystemJob.JOB_GROUP_NAME);
+				// 说明这个没有启动,则需要重新启动,如果启动着不做处理
+				if (jobDetail == null) {
+					// 任务名称
+					String taskCfgName = (String) doFtpItem.get("TASKNAME");
+
+					JobDetail warnJob = new JobDetail(jobName, PrvncFtpToFileSystemJob.JOB_GROUP_NAME, PrvncFtpToFileSystemJob.class);
+
+					warnJob.getJobDataMap().put(PrvncFtpToFileSystemJob.JOB_DATA_CONFIG_NAME, taskCfgName);
+
+					warnJob.getJobDataMap().put(PrvncFtpToFileSystemJob.JOB_DATA_TASK_ID, taskId);
+
+					CronTrigger warnTrigger = new CronTrigger(triggerName, triggerName, cronExpression);
+
+					// 错过执行后,立即执行
+					warnTrigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW);
+
+					scheduler.scheduleJob(warnJob, warnTrigger);
+
+					// 修改数据状态,将任务数据状态改为运行状态
+
+					Map updateTaskInfo = new HashMap();
+
+					updateTaskInfo.put("taskId", taskId);
+					updateTaskInfo.put("runFlag", RUNFLAG_START);
+					// 这里更新状态没有成功的,只是在后台打印日志,再前台不进行展示
+					int updateTaskStateFlag = getPrvncFtpFileDAO().updateFtpItemByTaskId(updateTaskInfo);
+					if (updateTaskStateFlag < 1) {
+						logger.error("---侦听【" + taskId + "】启动成功,但是更新任务状态失败,请关注!!!", info);
+						updateTaskStateFailCount++;
+					}
+
+				}
+				linstenCount++;
+			}
+			String resultMsgStr = "侦听启动成功,启动目标侦听个数为【" + doFtpItems.size() + "】,成功启动个数为【" + linstenCount + "】";
+			if (updateTaskStateFailCount > 0) {
+				resultMsgStr += (",有【" + updateTaskStateFailCount + "】任务启动成功,更新数据失败");
+			}
+			resultMsg = this.createResultMsg("0000", resultMsgStr, taskIds);
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			logger.error("调度器启动出错:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "调度器启动出错:" + e, "");
+			return "startJob";
+		}
+
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.startJob】出参为:" + resultMsg, resultMsg);
+		}
+		return "startJob";
+	}
+
+	/**
+	 * 停止侦听
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/stopJob",method = RequestMethod.POST)
+	public String stopJob(@RequestBody String stopjobInfo,HttpServletRequest request) {
+
+		JSONObject stopjob = JSONObject.parseObject(stopjobInfo);
+		// 请求参数为{"tasks":[{"taskId":1},{"taskId":2}],"state":"STOP"}
+		String ftpItemJson = stopjob.getString("ftpItemJson");
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.stopJob】入参为:" + ftpItemJson, ftpItemJson);
+		}
+		JSONObject paramIn = null;
+		try {
+			// 校验格式是否正确
+			paramIn = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "stopJob";
+		}
+
+		// 传入报文不为空
+		if (paramIn == null || !paramIn.containsKey("tasks") || !paramIn.containsKey("state")) {
+
+			resultMsg = createResultMsg("1999", "传入参数格式不正确(必须包含tasks 和  state节点):" + ftpItemJson, "");
+			return "stopJob";
+		}
+
+		// 校验当前是否为启动侦听
+		if (!"STOP".equals(paramIn.get("state"))) {
+
+			resultMsg = createResultMsg("1999", "传入参数格式不正确(state的值必须是START):" + ftpItemJson, "");
+			return "stopJob";
+		}
+
+		// 查询需要操作的任务
+		JSONArray taskInfos = paramIn.getJSONArray("tasks");
+
+		String taskIds = "";
+
+		for (int taskIndex = 0; taskIndex < taskInfos.size(); taskIndex++) {
+			taskIds += (taskInfos.getJSONObject(taskIndex).getString("taskId") + ",");
+		}
+
+		if (taskIds.length() > 0) {
+			taskIds = taskIds.substring(0, taskIds.length() - 1);
+		}
+
+		Map info = new HashMap();
+
+		info.put("taskIds", taskIds.split(","));
+
+		List<Map> doFtpItems = getPrvncFtpFileDAO().queryFtpItemsByTaskIds(info);
+
+		// 获取Spring调度器
+		Scheduler scheduler = (Scheduler) SpringBeanInvoker.getBean("schedulerFactoryBean");
+
+		int linstenCount = 0;
+		int updateTaskStateFailCount = 0;
+		try {
+			for (Map doFtpItem : doFtpItems) {
+
+				// 获取taskId
+				String taskId = doFtpItem.get("TASKID").toString();// 这个就不用三目判断了,因为如果为空,则直接抛出异常,正常情况下不会出现空的情况
+
+				// 获取定时时间
+				String cronExpression = doFtpItem.get("TASKCRON") == null ? defaultCronExpression : doFtpItem.get("TASKCRON").toString();// 如果没有配置则,每一分运行一次
+
+				String jobName = prefixJobName + taskId;
+
+				String triggerName = prefixJobName + taskId;
+				scheduler.deleteJob(jobName, PrvncFtpToFileSystemJob.JOB_GROUP_NAME);
+
+				// 修改数据状态,将任务数据状态改为运行状态
+
+				Map updateTaskInfo = new HashMap();
+
+				updateTaskInfo.put("taskId", taskId);
+				updateTaskInfo.put("runFlag", RUNFLAG_STOP);
+				// 这里更新状态没有成功的,只是在后台打印日志,再前台不进行展示
+				int updateTaskStateFlag = getPrvncFtpFileDAO().updateFtpItemByTaskId(updateTaskInfo);
+				if (updateTaskStateFlag < 1) {
+					logger.error("---侦听【" + taskId + "】停止成功,但是更新任务状态失败,请关注!!!", info);
+					updateTaskStateFailCount++;
+				}
+				linstenCount++;
+
+				String resultMsgStr = "侦听停止成功,停止目标侦听个数为【" + doFtpItems.size() + "】,成功停止个数为【" + linstenCount + "】";
+				if (updateTaskStateFailCount > 0) {
+					resultMsgStr += (",有【" + updateTaskStateFailCount + "】任务停止成功,更新数据失败");
+				}
+				resultMsg = this.createResultMsg("0000", resultMsgStr, taskIds);
+			}
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			logger.error("调度器停止出错:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "调度器停止出错:" + e, "");
+			return "stopJob";
+		}
+
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemConfigAction.startJob】出参为:" + resultMsg, resultMsg);
+		}
+		return "stopJob";
+	}
+
+	/**
+	 * 根据任务名称或任务ID模糊查询
+	 * 
+	 * @return
+	 */
+	@RequestMapping(path = "/FtpToFileSystem/searchTaskByNameOrId" , method = RequestMethod.POST)
+	public String searchTaskByNameOrId(@RequestBody String searchTaskByNameOrIdInfo,HttpServletRequest request) {
+		JSONObject searchTaskByNameOrIdObj = JSONObject.parseObject(searchTaskByNameOrIdInfo);
+		String ftpItemJson = searchTaskByNameOrIdObj.getString("ftpItemJson");
+		JSONObject ftpItemJsonObj = null;
+		try {
+			// 校验格式是否正确
+			// {"taskName":"经办人照片同步处理"}
+			ftpItemJsonObj = JSONObject.parseObject(ftpItemJson);
+		} catch (Exception e) {
+			logger.error("传入参数格式不正确:" + ftpItemJson, e);
+			resultMsg = createResultMsg("1999", "传入参数格式不正确:" + ftpItemJson, "");
+			return "addFtpItem";
+		}
+
+		// 将ftpItemJson装为Map保存操作
+		Map paramIn = JSONObject.parseObject(ftpItemJsonObj.toJSONString(), Map.class);
+
+		String taskNameOrTaskId = paramIn.get("taskName") == null ? "1" : paramIn.get("taskName").toString();
+
+		taskNameOrTaskId = ValidatorUtils.getValueAsString(paramIn, "taskName");
+
+		// 规则校验
+		JSONObject data = new JSONObject();
+		data.put("total", 1); // 搜索不进行分页处理
+		data.put("currentPage", 1);
+		List<Map> ftpItems = null;
+		// 说明是taskId
+		if (GenericValidator.isInt(taskNameOrTaskId) || GenericValidator.isLong(taskNameOrTaskId)) {
+			// 根据taskId 查询记录
+			paramIn.put("taskId", taskNameOrTaskId);
+			Map ftpItem = getPrvncFtpFileDAO().queryFtpItemByTaskId(paramIn);
+			if (ftpItem != null && ftpItem.containsKey("FTP_ITEM_ATTRS")) {
+				ftpItem.remove("FTP_ITEM_ATTRS");// 前台暂时用不到,所以这里将属性移除
+
+				ftpItems = new ArrayList<Map>();
+				ftpItems.add(ftpItem);
+			}
+		} else {
+			ftpItems = getPrvncFtpFileDAO().searchFtpItemByTaskName(paramIn);
+		}
+
+		JSONArray rows = new JSONArray();
+		if (ftpItems != null && ftpItems.size() > 0) {
+			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+			for (Map ftpItemMap : ftpItems) {
+
+				// 处理时间显示和界面显示传输类型
+				ftpItemMap.put("U_OR_D_NAME", CustomizedPropertyPlaceholderConfigurer.getContextProperty("task.tamplete.name." + ftpItemMap.get("U_OR_D")));// 暂且写死,最终还是读取配置
+				ftpItemMap.put("CREATE_DATE", df.format(ftpItemMap.get("CREATE_DATE")));// 暂且写死,最终还是读取配置
+				rows.add(JSONObject.parseObject(JSONObject.toJSONString(ftpItemMap)));
+			}
+		}
+		data.put("rows", rows);
+		resultMsg = data;
+		return "searchTaskByNameOrId";
+	}
+
+	/**
+	 * 创建公用输出
+	 * 
+	 * @return
+	 */
+	private JSONObject createResultMsg(String resultCode, String resultMsg, String resultInfo) {
+		JSONObject data = new JSONObject();
+		data.put("RESULT_CODE", resultCode);
+		data.put("RESULT_MSG", resultMsg);
+		data.put("RESULT_INFO", resultInfo);
+		return data;
+	}
+
+	public IPrvncFtpFileDAO getPrvncFtpFileDAO() {
+		if (this.iprvncFtpFileDAO == null) {
+			this.iprvncFtpFileDAO = ((IPrvncFtpFileDAO) SpringBeanInvoker.getBean("provInner.PrvncFtpFileDAO"));
+		}
+		return iprvncFtpFileDAO;
+	}
+
+}

+ 49 - 0
JobService/src/main/java/com/java110/job/Java110JobserviceApplication.java

@@ -0,0 +1,49 @@
+package com.java110.job;
+
+import com.java110.service.init.ServiceStartInit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import java.nio.charset.Charset;
+
+@SpringBootApplication(
+        scanBasePackages = {"com.java110.service", "com.java110.job", "com.java110.core", "com.java110.cache", "com.java110.db"},
+        excludeName = {"com.java110.core.smo.jobservice"}
+)
+@EnableDiscoveryClient
+@EnableFeignClients(basePackages = {"com.java110.core.smo.community"})
+public class Java110JobserviceApplication {
+    private static Logger logger = LoggerFactory.getLogger(Java110JobserviceApplication.class);
+
+    private static final String LISTENER_PATH = "java110.job.listeners";
+
+    /**
+     * 实例化RestTemplate,通过@LoadBalanced注解开启均衡负载能力.
+     *
+     * @return restTemplate
+     */
+    @Bean
+    @LoadBalanced
+    public RestTemplate restTemplate() {
+        StringHttpMessageConverter m = new StringHttpMessageConverter(Charset.forName("UTF-8"));
+        RestTemplate restTemplate = new RestTemplateBuilder().additionalMessageConverters(m).build();
+        return restTemplate;
+    }
+
+    public static void main(String[] args) throws Exception {
+        ApplicationContext context = SpringApplication.run(Java110JobserviceApplication.class, args);
+        ServiceStartInit.initSystemConfig(context);
+        //加载业务侦听
+        // SystemStartLoadBusinessConfigure.initSystemConfig(LISTENER_PATH);
+    }
+}

+ 36 - 0
JobService/src/main/java/com/java110/job/common/CustomizedPropertyPlaceholderConfigurer.java

@@ -0,0 +1,36 @@
+package com.java110.job.common;
+
+
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+
+import java.util.Map;
+
+/**
+ * 自定义PropertyPlaceholderConfigurer返回properties内容
+ * 
+ * @author 吕振龙
+ * 
+ */
+public class CustomizedPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
+
+
+	private static Map<String, Object> ctxPropertiesMap;
+
+	/**
+	 * @return the ctxPropertiesMap
+	 */
+	public static Map<String, Object> getCtxPropertiesMap() {
+		return ctxPropertiesMap;
+	}
+
+
+	/**根据KEY查询值
+	 * @param name
+	 * @return
+	 */
+	public static Object getContextProperty(String name) {
+		return ctxPropertiesMap.get(name);
+	}
+
+
+}

+ 165 - 0
JobService/src/main/java/com/java110/job/dao/IPrvncFtpFileDAO.java

@@ -0,0 +1,165 @@
+package com.java110.job.dao;
+
+import com.java110.job.model.*;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IPrvncFtpFileDAO {
+
+
+	/**
+	 * 保存执行任务的日志,任务的执行状态
+	 * @param
+	 * @return Map
+	 */
+	public long saveTaskRunLog(FtpTaskLog loginfo);
+	/**
+	 * 更新执行任务的日志
+	 * @param
+	 * @return Map
+	 */
+	public void updateTaskRunLog(FtpTaskLog loginfo);
+	/**
+	 * 保存执行任务的详细日志,包含任务的传输信息,如果下载线程信息,线程是否执行完成,下载的起始,需要下载的数据大小
+	 * @param
+	 * @return Map
+	 */
+	public int saveTaskRunDetailLog(FtpTaskLogDetail logdetail);
+
+	/**
+	 * 执行存过,处理任务执行前后的事情
+	 */
+	public void saveDbFunction(String function);
+
+	/**
+	 * 执行存过(带参数),处理任务执行前后的事情
+	 */
+	public void saveDbFunctionWithParam(Map info);
+
+	/**
+	 * 执行配置的sql
+	 * @param dbsql
+	 * @return 000777
+	 */
+	public List execConfigSql(String dbsql);
+
+	/**
+	 * 查询文件下载在文件系统的配置任务列表
+	 * @param info
+	 * @return   001
+	 */
+	public Map queryFtpItems(Map info);
+	
+	
+	/**
+	 * 保存文件下载配置
+	 * @param info
+	 * @return  0022
+	 */
+	public int addFtpItem(Map info);
+	
+	
+	/**
+	 * 根据TaskId 查询ftp配置信息
+	 * @param info
+	 * @return 0004
+	 */
+	public Map queryFtpItemByTaskId(Map info);
+	
+	/**
+	 * 根据任务名称搜素
+	 * @param info
+	 * @return 000666
+	 */
+	public List<Map> searchFtpItemByTaskName(Map info);
+	
+	
+	/**
+	 * 修改ftp配置信息
+	 * @param info
+	 * @return  003
+	 */
+	public int updateFtpItemByTaskId(Map info);
+	
+	/**
+	 * 删除ftp配置信息
+	 * @param info
+	 * @return 0006
+	 */
+	public int deleteFtpItemByTaskId(Map info);
+	
+	
+	/**
+	 * 根据taskids 获取将要操作的ftp配置信息 
+	 * @param info
+	 * @return   002
+	 */
+	public List<Map> queryFtpItemsByTaskIds(Map info);
+	
+	/**
+	 * 查询FTPItem的属性信息
+	 * @param info
+	 * @return 0007
+	 */
+	public List<Map> queryFtpItemAttrsByTaskId(Map info);
+	
+	/**
+	 * 创建taskId
+	 * @return   000011
+	 */
+	public long newCreateTaskId();
+	
+	/**
+	 * 保存FTPItem的属性信息
+	 * @return  00333
+	 */
+	public int addFtpItemAttrs(List<Map> infos);
+	
+	/**
+	 * 查询没有下载过的文件名
+	 * @param info
+	 * @return  0005
+	 */
+	public List<Map> queryFileNamesWithOutFtpLog(Map info);
+
+
+	/**
+	 * 查询ItemSpec
+	 * @param info
+	 * @return 0009
+	 */
+	public List<Map> queryItemSpec(Map info);
+	
+	/**
+	 * 删除属性
+	 * @param info
+	 * @return 00044
+	 */
+	public int deleteFtpItemAttrsbyTaskId(Map info);
+
+
+	public List queryTableColInfo(String tablename,String colnames);
+
+	/**
+	 * 修改ftp配置信息(状态)
+	 * @param info
+	 * @return
+	 */
+	public int updateFtpItemRunState(Map info);
+
+	/**
+	 * 保存下载文件名称
+	 * @param info
+	 * @return
+	 */
+	public int addDownloadFileName(Map info);
+
+	/**
+	 * 保存FTP下载的一行数据到表中
+	 * @param
+	 * @return Map
+	 */
+	public void insertFileData2Table(String insertSQL);
+
+}

+ 223 - 0
JobService/src/main/java/com/java110/job/dao/impl/PrvncFtpFileDAOImpl.java

@@ -0,0 +1,223 @@
+package com.java110.job.dao.impl;
+
+import com.java110.core.base.dao.BaseServiceDao;
+import com.java110.job.dao.IPrvncFtpFileDAO;
+import com.java110.job.model.FtpTaskLog;
+import com.java110.job.model.FtpTaskLogDetail;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.HashMap;
+
+import java.util.List;
+import java.util.Map;
+@Service("prvncFtpFileDAOImpl")
+@Transactional
+public class PrvncFtpFileDAOImpl extends BaseServiceDao implements IPrvncFtpFileDAO {
+
+	public long saveTaskRunLog(FtpTaskLog loginfo){
+		// TODO Auto-generated method stub
+		return sqlSessionTemplate.insert("PrvncFtpFileDAO.saveTaskRunLog",loginfo);
+	}
+
+	public void updateTaskRunLog(FtpTaskLog loginfo){
+		// TODO Auto-generated method stub
+		sqlSessionTemplate.update("PrvncFtpFileDAO.updateTaskRunLog",loginfo);
+	}
+	public int saveTaskRunDetailLog(FtpTaskLogDetail logdetail){
+		// TODO Auto-generated method stub
+		return sqlSessionTemplate.insert("PrvncFtpFileDAO.saveTaskRunDetailLog",logdetail);
+	}
+
+
+
+	@Override
+	public List execConfigSql(String dbsql){
+		return  sqlSessionTemplate.selectList("PrvncFtpFileDAO.execConfigSql", dbsql);
+	}
+	/**
+	 * 查询文件下载在文件系统的配置任务列表
+	 * @param info
+	 * @return
+	 */
+	public Map queryFtpItems(Map info){
+		Map resultInfo = new HashMap();
+		//1.0查询总数
+		Integer allCNT = (Integer) sqlSessionTemplate.selectOne("PrvncFtpFileDAO.queryFtpItemsCount", info);
+		resultInfo.put("ITEMSCOUNT", allCNT);
+		List datas = sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryFtpItems",info);
+		resultInfo.put("DATA", datas);
+		return resultInfo;
+	}
+	/**
+	 * 创建taskId
+	 * @return
+	 */
+	public long newCreateTaskId(){
+		Long tastId = (Long) sqlSessionTemplate.selectOne("PrvncFtpFileDAO.newCreateTaskId");
+		return tastId;
+	}
+	/**
+	 * 保存文件下载配置
+	 * @param info
+	 * @return
+	 */
+	public int addFtpItem(Map info){
+//		return  Integer.parseInt(sqlSessionTemplate.insert("PrvncFtpFileDAO.addFtpItem", info).toString());
+		sqlSessionTemplate.insert("PrvncFtpFileDAO.addFtpItem", info);
+		return 1;
+	}
+	/**
+	 * 根据TaskId 查询ftp配置信息
+	 * @param info
+	 * @return
+	 */
+	public Map queryFtpItemByTaskId(Map info){
+		Object data = sqlSessionTemplate.selectOne("PrvncFtpFileDAO.queryFtpItemByTaskId", info);
+		Map ftpItem = null ;
+		if(data != null){
+			ftpItem = (Map)data;
+			//查ftpitem属性
+			List<Map> ftpItemAttrs = sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryFtpItemAttrsByTaskId",info);
+			ftpItem.put("FTP_ITEM_ATTRS", ftpItemAttrs);
+		}
+		
+		return ftpItem;
+	}
+	
+	/**
+	 * 根据任务名称搜素
+	 * @param info
+	 * @return
+	 */
+	public List<Map> searchFtpItemByTaskName(Map info){
+		return sqlSessionTemplate.selectList("PrvncFtpFileDAO.searchFtpItemByTaskName",info);
+	}
+	/**
+	 * 修改ftp配置信息
+	 * @param info
+	 * @return
+	 */
+	public int updateFtpItemByTaskId(Map info){
+		return sqlSessionTemplate.update("PrvncFtpFileDAO.updateFtpItemByTaskId", info);
+	}
+	/**
+	 * 删除ftp配置信息
+	 * @param info
+	 * @return
+	 */
+	public int deleteFtpItemByTaskId(Map info){
+		return sqlSessionTemplate.update("PrvncFtpFileDAO.deleteFtpItemByTaskId", info);
+	}
+	
+	/**
+	 * 根据taskids 获取将要操作的ftp配置信息 
+	 * @param info
+	 * @return
+	 */
+	public List<Map> queryFtpItemsByTaskIds(Map info){
+		return sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryFtpItemsByTaskIds",info);
+	}
+	
+	/**
+	 * 查询FTPItem的属性信息
+	 * @param info
+	 * @return
+	 */
+	public List<Map> queryFtpItemAttrsByTaskId(Map info){
+		return sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryFtpItemAttrsByTaskId",info);
+	}
+	
+	/**
+	 * 删除属性
+	 * @param info
+	 * @return
+	 */
+	public int deleteFtpItemAttrsbyTaskId(Map info){
+		return sqlSessionTemplate.delete("PrvncFtpFileDAO.deleteFtpItemAttrsbyTaskId", info);
+	}
+
+	@Override
+	public List<Map> queryTableColInfo(String tablename, String colnames) {
+		// TODO Auto-generated method stub
+		Map para=new HashMap();
+		if(tablename.indexOf(".")>0){
+			String username=tablename.substring(0,tablename.indexOf("."));
+			tablename=tablename.substring(tablename.indexOf(".")+1);
+			para.put("username", username.toUpperCase());
+		}
+		para.put("tablename", tablename.toUpperCase());
+		para.put("colnames", "'"+colnames.toUpperCase().replaceAll(",", "','")+"'");
+		return sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryTableColInfo",para);
+	}
+
+	/**
+	 * 保存FTPItem的属性信息
+	 * @return
+	 */
+	public int addFtpItemAttrs(List<Map> infos){
+		for(Map info :infos){
+			sqlSessionTemplate.insert("PrvncFtpFileDAO.addFtpItemAttrs",info);
+		}
+		
+		return 1;
+	}
+	
+	/**
+	 * 查询没有下载过的文件名
+	 * @param info
+	 * @return
+	 */
+	public List<Map> queryFileNamesWithOutFtpLog(Map info){
+		return sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryFileNamesWithOutFtpLog",info);
+	}
+	/**
+	 * 查询ItemSpec
+	 * @param info
+	 * @return
+	 */
+	public List<Map> queryItemSpec(Map info){
+		return sqlSessionTemplate.selectList("PrvncFtpFileDAO.queryItemSpec",info);
+	}
+
+	/**
+	 * 修改ftp配置信息(状态)
+	 * @param info
+	 * @return
+	 */
+	public int updateFtpItemRunState(Map info){
+		return sqlSessionTemplate.update("PrvncFtpFileDAO.updateFtpItemRunState", info);
+	}
+
+	/**
+	 * 保存下载文件名称
+	 * @param info
+	 * @return
+	 */
+	public int addDownloadFileName(Map info){
+//		return  Integer.parseInt(getSqlMapClientTemplate().insert("PrvncFtpFileDAO.addDownloadFileName", info).toString());
+
+		return  sqlSessionTemplate.insert("PrvncFtpFileDAO.addDownloadFileName", info);
+	}
+
+	/**
+	 * 执行存过,处理任务执行前后的事情
+	 */
+	public void saveDbFunction(String function){
+		Map para=new HashMap();
+		para.put("functionname", function);
+		sqlSessionTemplate.selectOne("PrvncFtpFileDAO.calltaskfunction",para);
+	}
+
+	/**
+	 * 执行存过(带参数),处理任务执行前后的事情
+	 */
+	public void saveDbFunctionWithParam(Map info){
+		sqlSessionTemplate.selectOne("PrvncFtpFileDAO.calltaskfunctionwithparam",info);
+	}
+
+	public void insertFileData2Table(String insertSQL){
+		// TODO Auto-generated method stub
+		sqlSessionTemplate.update("PrvncFtpFileDAO.insertFileData2Table",insertSQL);
+	}
+}

+ 55 - 0
JobService/src/main/java/com/java110/job/model/FtpTaskLog.java

@@ -0,0 +1,55 @@
+package com.java110.job.model;
+
+public class FtpTaskLog {
+	private long logid;
+	private long taskid;
+	private String uord;
+	private String state;
+	private String serverfilename;
+	private String localfilename;
+	private long filelength;
+	public long getLogid() {
+		return logid;
+	}
+	public void setLogid(long logid) {
+		this.logid = logid;
+	}
+	public long getTaskid() {
+		return taskid;
+	}
+	public void setTaskid(long taskid) {
+		this.taskid = taskid;
+	}
+	public String getUord() {
+		return uord;
+	}
+	public void setUord(String uord) {
+		this.uord = uord;
+	}
+	public String getState() {
+		return state;
+	}
+	public void setState(String state) {
+		this.state = state;
+	}
+	public String getServerfilename() {
+		return serverfilename;
+	}
+	public void setServerfilename(String serverfilename) {
+		this.serverfilename = serverfilename;
+	}
+	public String getLocalfilename() {
+		return localfilename;
+	}
+	public void setLocalfilename(String localfilename) {
+		this.localfilename = localfilename;
+	}
+	public long getFilelength() {
+		return filelength;
+	}
+	public void setFilelength(long filelength) {
+		this.filelength = filelength;
+	}
+	
+	
+}

+ 91 - 0
JobService/src/main/java/com/java110/job/model/FtpTaskLogDetail.java

@@ -0,0 +1,91 @@
+package com.java110.job.model;
+
+public class FtpTaskLogDetail {
+
+	private long id;
+	private long logid;
+	private long taskid;
+	private String state;
+	private int tnum;
+	private long begin;
+	private long end;
+	private long havedown;
+	private String data;
+	private String remark;
+	private String serverfilename;
+	private String localfilename;
+	public long getId() {
+		return id;
+	}
+	public void setId(long id) {
+		this.id = id;
+	}
+	public long getLogid() {
+		return logid;
+	}
+	public void setLogid(long logid) {
+		this.logid = logid;
+	}
+	public long getTaskid() {
+		return taskid;
+	}
+	public void setTaskid(long taskid) {
+		this.taskid = taskid;
+	}
+	public String getState() {
+		return state;
+	}
+	public void setState(String state) {
+		this.state = state;
+	}
+	public int getTnum() {
+		return tnum;
+	}
+	public void setTnum(int tnum) {
+		this.tnum = tnum;
+	}
+	public long getBegin() {
+		return begin;
+	}
+	public void setBegin(long begin) {
+		this.begin = begin;
+	}
+	public long getEnd() {
+		return end;
+	}
+	public void setEnd(long end) {
+		this.end = end;
+	}
+	public long getHavedown() {
+		return havedown;
+	}
+	public void setHavedown(long havedown) {
+		this.havedown = havedown;
+	}
+	public String getData() {
+		return data;
+	}
+	public void setData(String data) {
+		this.data = data;
+	}
+	public String getRemark() {
+		return remark;
+	}
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+	public String getServerfilename() {
+		return serverfilename;
+	}
+	public void setServerfilename(String serverfilename) {
+		this.serverfilename = serverfilename;
+	}
+	public String getLocalfilename() {
+		return localfilename;
+	}
+	public void setLocalfilename(String localfilename) {
+		this.localfilename = localfilename;
+	}
+	
+	
+}

+ 440 - 0
JobService/src/main/java/com/java110/job/smo/DownloadFileFromFtpToTable.java

@@ -0,0 +1,440 @@
+package com.java110.job.smo;
+
+import com.java110.job.util.FTPClientTemplate;
+import org.apache.commons.net.ftp.FTP;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPReply;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 从Ftp文件系统下载文件内容存到对应配置的表中
+ * 
+ * 
+ * @author wuxw7 2016-01-04
+ * 
+ */
+public class DownloadFileFromFtpToTable extends PrvncFtpToFileSystemQuartz {
+
+	private static final String ITEM_SPEC_CD_10011 = "10011";// FTP地址
+	private static final String ITEM_SPEC_CD_10012 = "10012";// FTP端口号
+	private static final String ITEM_SPEC_CD_10013 = "10013";// FTP账号
+	private static final String ITEM_SPEC_CD_10014 = "10014";// FTP密码
+	private static final String ITEM_SPEC_CD_10015 = "10015";// FTP路径
+	private static final String ITEM_SPEC_CD_10016 = "10016";// 本地路径
+	private static final String ITEM_SPEC_CD_10007 = "10007";// 文件头
+	private static final String ITEM_SPEC_CD_10008 = "10008";// 分隔符
+	private static final String ITEM_SPEC_CD_10009 = "10009";// 总记录数
+	private static final String ITEM_SPEC_CD_10010 = "10010";// 处理脚本
+
+	/**
+	 * 如果运行失败时,需要在ftpItemConfigInfo 中PRE_METHOD_FLAG 值改成E,remark 备注错误原因
+	 */
+	@Override
+	protected void process(Map ftpItemConfigInfo) throws Exception {
+		// TODO Auto-generated method stub
+
+		String taskId = ftpItemConfigInfo.get("TASKID").toString();
+		FTPClientTemplate ftpClientTemplate = null;
+		// 1.0 读取配置,包括ftp 服务器信息,和tfs相关配置,根据taskId 关联信息
+		if (!ftpItemConfigInfo.containsKey("FTP_ITEM_ATTRS") || ftpItemConfigInfo.get("FTP_ITEM_ATTRS") == null) {
+
+			ftpItemConfigInfo.put("PRE_METHOD_FLAG", "E");
+			ftpItemConfigInfo.put("remark", "当前ftp任务【" + taskId + "】没有配置属性,在从Ftp文件系统下载文件存到TFS文件系统模板中必须配置属性");
+			return;
+		}
+		List<Map> ftpItemAttrs = (List<Map>) ftpItemConfigInfo.get("FTP_ITEM_ATTRS");
+		// FTP_ITEM_ATTRS
+		String ftpIp = null;
+		int ftpPort = 21;
+		String ftpUsername = null;
+		String ftpPassword = null;
+		String ftpPath = null;
+		String titleflag = null;
+		String sign = null;
+		String linecountflag = null;
+		String dbsql = null; // 处理脚本
+		String localPath = "";// 本地文件保存路径
+		int tnum = ftpItemConfigInfo.get("TNUM") == null ? 1 : Integer.parseInt(ftpItemConfigInfo.get("TNUM").toString());
+
+		// 如果没有配置默认获取指定目录下的所有文件
+		String fileName = ftpItemConfigInfo.get("FILE_NAME") == null ? "" : ftpItemConfigInfo.get("FILE_NAME").toString();
+
+		// 文件名如果为空,直接返回再不处理
+		if ("".equals(fileName)) {
+			ftpItemConfigInfo.put("PRE_METHOD_FLAG", "E");
+			ftpItemConfigInfo.put("remark", "当前ftp任务【" + taskId + "】没有配置文件名,在从Ftp文件系统下载文件存到TFS文件系统模板中必须配置文件名");
+			return;
+		}
+		// 获取属性表中的数据
+		for (Map ftpItemAttr : ftpItemAttrs) {
+			if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10011.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				ftpIp = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10012.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				ftpPort = ftpItemAttr.get("VALUE") == null ? 21 : Integer.parseInt(ftpItemAttr.get("VALUE").toString());
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10013.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				ftpUsername = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10014.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				ftpPassword = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10015.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				ftpPath = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10007.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				titleflag = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10008.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				sign = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10009.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				linecountflag = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10010.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				dbsql = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			} else if (ftpItemAttr.containsKey("ITEM_SPEC_ID") && ITEM_SPEC_CD_10016.equals(ftpItemAttr.get("ITEM_SPEC_ID").toString())) {
+				localPath = ftpItemAttr.get("VALUE") == null ? "" : ftpItemAttr.get("VALUE").toString();
+			}
+		}
+
+		// 将 contentSpiltChar totalCount dealSql fileTop属性回写到
+
+		ftpItemConfigInfo.put("sign", sign);
+		ftpItemConfigInfo.put("linecountflag", linecountflag);
+		ftpItemConfigInfo.put("dbsql", dbsql);
+		ftpItemConfigInfo.put("titleflag", titleflag);
+		ftpItemConfigInfo.put("localPath", localPath);
+		ftpItemConfigInfo.put("port", ftpPort);
+		ftpItemConfigInfo.put("username", ftpUsername);
+		ftpItemConfigInfo.put("pwd", ftpPassword);
+		ftpItemConfigInfo.put("ip", ftpIp);
+
+		// 初始化FTPClientTemplate
+		ftpClientTemplate = new FTPClientTemplate(ftpIp, ftpPort, ftpUsername, ftpPassword, ftpPath, null, 0, tnum, 100);
+
+		if (!ftpPath.endsWith("/")) {
+			ftpPath += "/";
+		}
+
+		// 处理文件名
+		List<String> fileNames = dealFileName(fileName);
+
+		// **** 则不支持select出来文件名是list 的情况,如果是list 默认处理第一个
+		// 校验文件名是中是否存在****(4个),表示通配符,如果不存在就是确定唯一文件名
+		fileName = fileNames.get(0);
+		if (fileName != null && fileName.contains("****")) {
+
+			String[] reFileNames = ftpClientTemplate.listNames(ftpPath + fileName, true);
+			List<String> fNames = new ArrayList<String>();
+			for (int reFileNamesIndex = 0; reFileNamesIndex < reFileNames.length; reFileNamesIndex++) {
+				if (reFileNames[reFileNamesIndex] != null && !"".equals(reFileNames[reFileNamesIndex])) {
+					fNames.add(reFileNames[reFileNamesIndex].replace(ftpPath, ""));
+				}
+			}
+			// 多文件处理
+			anyFilesDownload(ftpItemConfigInfo, taskId, ftpClientTemplate, ftpPath, fNames);
+			return;
+		}
+		// 单文件支持文件名为list,如果是list,则处理list所有文件
+		// 单文件处理
+		anyFilesDownload(ftpItemConfigInfo, taskId, ftpClientTemplate, ftpPath, fileNames);
+
+	}
+
+	/**
+	 * 文件名是中是存在****,多文件下载处理
+	 * 
+	 * @param ftpItemConfigInfo
+	 * @param taskId
+	 * @param ftpClientTemplate
+	 * @param ftpPath
+	 * @param
+	 * @param
+	 * @param
+	 * @throws Exception
+	 */
+	private void anyFilesDownload(Map ftpItemConfigInfo, String taskId, FTPClientTemplate ftpClientTemplate, String ftpPath, List<String> fileNames) throws Exception {
+		// 这种需要列出所有文件,根据名称匹配
+		String param = "";
+		// 获取FTP上的文件
+		List<Map> needDownloadFiles = null;
+		String downLoadFailFileNames = "";// 下载失败的fileName
+		String downLoadSuccessFileNames = "";// 下载失败的fileName
+		for (String fileName : fileNames) {
+			if (fileName.length() > 0) {
+				// 查询数据库,那写文件还没有下载
+				Map logInfo = new HashMap();
+				logInfo.put("fileNames", fileName);
+				logInfo.put("taskId", taskId);
+				needDownloadFiles = this.getPrvncFtpFileDAO().queryFileNamesWithOutFtpLog(logInfo);
+			}
+
+			if (needDownloadFiles == null || needDownloadFiles.size() < 1) {
+				continue;
+			}
+			ftpItemConfigInfo.put("newFileName", fileName);
+
+			// 保存文件至table
+			Map resultInfo = downLoadFileToTable(ftpPath + fileName, ftpClientTemplate, ftpItemConfigInfo);
+
+			Map remoteFileInfo = new HashMap();
+
+			if (resultInfo.containsKey("SAVE_FILE_FLAG") && "S".equals(resultInfo.get("SAVE_FILE_FLAG"))) {
+				param += (fileName + "@@");
+				// 将下载成功的文件名需要保存至表中,防止以后重复下载
+				remoteFileInfo.put("taskId", taskId);
+				remoteFileInfo.put("fileName", fileName);
+				saveDownLoadSuccessFile(remoteFileInfo);
+				// 记录成功时的文件名
+				downLoadSuccessFileNames += (fileName + ",");
+			} else {
+				// 记录下载失败的文件名
+				downLoadFailFileNames += (fileName + ",");
+			}
+			// }
+		}
+		// 做这个校验主要为了,如果一个都没有成功,就不去调事后过程
+		if ("".equals(param)) {
+			ftpItemConfigInfo.put("PRE_METHOD_FLAG", "E");
+			ftpItemConfigInfo.put("remark", "当前ftp任务【" + taskId + "】没有可下载的文件,或下载文件时失败");
+			return;
+		}
+		ftpItemConfigInfo.put("PRE_METHOD_FLAG", "S");
+		ftpItemConfigInfo.put("remark", "当前ftp任务【" + taskId + "】下载成功{" + downLoadSuccessFileNames + "},失败的{" + downLoadFailFileNames + "}");
+		ftpItemConfigInfo.put("param", param);
+		return;
+	}
+
+	/**
+	 * 下载并保存文件至表中。
+	 * 
+	 * @param remoteFileInfo
+	 */
+	private void saveDownLoadSuccessFile(Map remoteFileInfo) {
+		// TODO Auto-generated method stub
+		int addDownloadFlag = this.getPrvncFtpFileDAO().addDownloadFileName(remoteFileInfo);
+		if (addDownloadFlag < 1) {
+			logger.error("---【DownloadFileFromFtpToTFS.saveDownLoadSuccessFile】保存下载文件名失败", remoteFileInfo);
+		}
+	}
+
+	/**
+	 * 下载文件并且存至tfs文件系统
+	 * 
+	 * @param remoteFileNameTmp
+	 * @param
+	 * @return
+	 */
+	private Map downLoadFileToTable(String remoteFileNameTmp, FTPClientTemplate ftpClientTemplate, Map ftpItemConfigInfo) {
+		Map resultInfo = new HashMap();
+		String tfsReturnFileName = null;
+		long block = 10 * 1024;// 默认
+		if (ftpClientTemplate == null) {
+			resultInfo.put("SAVE_FILE_FLAG", "E");
+			return resultInfo;
+		}
+		String localPathName = ftpItemConfigInfo.get("localPath").toString().endsWith("/") ? ftpItemConfigInfo.get("localPath").toString()
+				+ ftpItemConfigInfo.get("newFileName").toString() : ftpItemConfigInfo.get("localPath").toString() + "/" + ftpItemConfigInfo.get("newFileName").toString();
+		ftpItemConfigInfo.put("localfilename", localPathName);// 本地带路径的文件名回写,后面读文件时使用
+		try {
+			File file = new File(localPathName);
+			RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");// 建立随机访问
+			FTPClient ftpClient = new FTPClient();
+			ftpClient.connect(ftpClientTemplate.getHost(), ftpClientTemplate.getPort());
+			if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
+				if (!ftpClient.login(ftpClientTemplate.getUsername(), ftpClientTemplate.getPassword())) {
+					resultInfo.put("SAVE_FILE_FLAG", "E");
+					resultInfo.put("remark", "登录失败,用户名【" + ftpClientTemplate.getUsername() + "】密码【" + ftpClientTemplate.getPassword() + "】");
+					return resultInfo;
+				}
+			}
+			ftpClient.setControlEncoding("UTF-8");
+			ftpClient.setFileType(FTP.BINARY_FILE_TYPE); // 二进制
+			ftpClient.enterLocalPassiveMode(); // 被动模式
+			ftpClient.sendCommand("PASV");
+			ftpClient.sendCommand("SIZE " + remoteFileNameTmp + "\r\n");
+			String replystr = ftpClient.getReplyString();
+			String[] replystrL = replystr.split(" ");
+			long filelen = 0;
+			if (Integer.valueOf(replystrL[0]) == 213) {
+				filelen = Long.valueOf(replystrL[1].trim());
+			} else {
+				resultInfo.put("SAVE_FILE_FLAG", "E");
+				resultInfo.put("remark", "无法获取要下载的文件的大小!");
+				return resultInfo;
+			}
+			accessFile.setLength(filelen);
+			accessFile.close();
+			ftpClient.disconnect();
+
+			int tnum = Integer.valueOf(ftpItemConfigInfo.get("TNUM").toString());
+			block = (filelen + tnum - 1) / tnum;// 每个线程下载的快大小
+			ThreadPoolExecutor cachedThreadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
+			List<Future<Map>> threadR = new ArrayList<Future<Map>>();
+			for (int i = 0; i < tnum; i++) {
+				logger.debug("发起线程:" + i);
+				// 保存线程日志
+				ftpItemConfigInfo.put("threadrunstate", "R");
+				ftpItemConfigInfo.put("remark", "开始下载文件");
+				ftpItemConfigInfo.put("data", "文件名:" + remoteFileNameTmp);
+				long start = i * block;
+				long end = (i + 1) * block - 1;
+				ftpItemConfigInfo.put("begin", start);
+				ftpItemConfigInfo.put("end", end);
+				saveTaskLogDetail(ftpItemConfigInfo);
+				Map para = new HashMap();
+				para.putAll(ftpItemConfigInfo);
+				para.put("serverfilename", remoteFileNameTmp);
+				para.put("filelength", filelen);
+				para.put("tnum", i + 0);
+				para.put("threadDownSize", block);
+				para.put("transferflag", FTPClientTemplate.TransferType.download);
+				FTPClientTemplate dumpThread = new FTPClientTemplate(para);
+				Future<Map> runresult = cachedThreadPool.submit(dumpThread);
+				threadR.add(runresult);
+			}
+
+			do {
+				// 等待下载完成
+				Thread.sleep(1000);
+			} while (cachedThreadPool.getCompletedTaskCount() < threadR.size());
+
+			saveDownFileData(ftpItemConfigInfo);
+			// 下载已经完成,多线程保存数据至表中
+
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			logger.error("保存文件失败:", e);
+			resultInfo.put("SAVE_FILE_FLAG", "E");
+			resultInfo.put("remark", "保存文件失败:" + e);
+			return resultInfo;
+		}
+		resultInfo.put("SAVE_FILE_FLAG", "S");
+		return resultInfo;
+
+	}
+
+	@Override
+	protected void post(Map ftpItemConfigInfo) {
+		// TODO Auto-generated method stub
+		if (ftpItemConfigInfo != null && ftpItemConfigInfo.containsValue("AFTERFLAG") && "0".equals(ftpItemConfigInfo.get("AFTERFLAG"))
+				&& ftpItemConfigInfo.containsKey("AFTERFUNCTION") && ftpItemConfigInfo.get("AFTERFUNCTION") != null && !"".equals(ftpItemConfigInfo.get("AFTERFUNCTION"))) {
+			// 这个时候确定已经进入了事后过程
+			if (ftpItemConfigInfo.containsKey("retVal") && !"0000".equals(ftpItemConfigInfo.get("retVal"))) {
+				ftpItemConfigInfo.put("threadrunstate", "E3");
+				ftpItemConfigInfo.put("remark", ftpItemConfigInfo.get("retVal"));
+				saveTaskLogDetail(ftpItemConfigInfo);
+
+			}
+
+		}
+	}
+
+	/**
+	 * 保存下载的文件里的内容到配置的数据表中,多线程同时保存
+	 */
+	public void saveDownFileData(Map taskInfo) {
+		// 先分配每个线程处理的起止位置
+		List contthr = contSaveThreadContInfo(taskInfo);
+		// 启动多个线程,保存文件内容
+		if (contthr != null) {
+			try {
+				int tnum = Integer.valueOf(taskInfo.get("TNUM").toString());
+				ThreadPoolExecutor cachedThreadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
+				List<Future<Map>> threadR = new ArrayList<Future<Map>>();
+				for (int i = 0; i < tnum; i++) {
+					logger.debug("发起线程:" + i);
+					Map tmp = (Map) contthr.get(i);
+					Map para = new HashMap();
+					para.putAll(taskInfo);
+					para.putAll(tmp);
+					para.put("transferflag", FTPClientTemplate.TransferType.savedata);
+					FTPClientTemplate dumpThread = new FTPClientTemplate(para);
+					Future<Map> runresult = cachedThreadPool.submit(dumpThread);
+					threadR.add(runresult);
+				}
+				do {
+					// 等待保存数据
+					Thread.sleep(1000);
+				} while (cachedThreadPool.getCompletedTaskCount() < threadR.size());
+				taskInfo.put("SAVE_FILE_FLAG", "S");
+				logger.debug("文件内容保存完毕!");
+			} catch (Exception ex) {
+				logger.error("保存文件失败", ex);
+				taskInfo.put("SAVE_FILE_FLAG", "E");
+				taskInfo.put("remark", "保存文件失败" + ex);
+			} catch (Throwable ex) {
+				logger.error("保存文件失败", ex);
+				taskInfo.put("SAVE_FILE_FLAG", "E");
+				taskInfo.put("remark", "保存文件失败" + ex);
+			}
+		}
+	}
+
+	/**
+	 * 分配每个线程处理的起止位置
+	 */
+	public static List contSaveThreadContInfo(Map taskInfo) {
+		List contlist = new ArrayList();
+		try {
+			RandomAccessFile raf = new RandomAccessFile(taskInfo.get("localfilename").toString(), "r");
+			int tnum = Integer.valueOf(taskInfo.get("TNUM").toString());
+
+			long filelen = raf.length();
+			if (filelen != 0L) {
+				long block = (filelen + tnum - 1) / tnum;// 每个线程下载的快大小
+				long begin = 0;
+				// 修复在保存数据时的线程数太大时,无法去除titleflag 行的问题处理
+				if ("0".equals(taskInfo.get("linecountflag"))) {
+					String temp = raf.readLine();
+					begin += temp.length();
+				}
+				if ("0".equals(taskInfo.get("titleflag"))) {
+					String temp = raf.readLine();
+					begin += temp.length();
+				}
+				for (int i = 0; i < tnum; i++) {
+					if (i == tnum - 1) {
+						Map tmp = new HashMap();
+						tmp.put("begin", begin);
+						tmp.put("end", filelen - 1);
+						contlist.add(tmp);
+						break;
+					}
+					long end = (i + 1) * block - 1;
+					// 处理如果有总数行和文件头行时,线程数大于数据行数,映入的问题
+					if (end < begin) {
+						begin = 0;
+						end = begin;
+						Map tmp = new HashMap();
+						tmp.put("begin", begin);
+						tmp.put("end", end);
+						contlist.add(tmp);
+						begin = end + 1;
+						continue;
+					}
+					while (end > 0) {
+						raf.seek(end);
+						if (raf.readByte() == '\n') {
+							Map tmp = new HashMap();
+							tmp.put("begin", begin);
+							tmp.put("end", end);
+							contlist.add(tmp);
+							begin = end + 1;
+							break;
+						}
+						end--;
+					}
+				}
+			}
+			raf.close();
+		} catch (Exception ex) {
+			ex.printStackTrace();
+			return null;
+		}
+		return contlist;
+	}
+
+}

+ 47 - 0
JobService/src/main/java/com/java110/job/smo/IPrvncFtpFileBMO.java

@@ -0,0 +1,47 @@
+package com.java110.job.smo;
+
+import com.java110.job.model.*;
+import java.util.Map;
+
+public interface IPrvncFtpFileBMO {
+
+	/**
+     * 保存执行任务的日志,任务的执行状态
+     * @param 
+     * @return Map
+     */
+	public long saveTaskRunLog(FtpTaskLog loginfo);
+	/**
+     * 更新执行任务的日志
+     * @param 
+     * @return Map
+     */
+	public void updateTaskRunLog(FtpTaskLog loginfo);
+	/**
+     * 保存执行任务的详细日志,包含任务的传输信息,如果下载线程信息,线程是否执行完成,下载的起始,需要下载的数据大小
+     * @param 
+     * @return Map
+     */
+	public int saveTaskRunDetailLog(FtpTaskLogDetail logdetail);
+	/**
+     * 更新执行任务的详细日志,包含任务的传输信息,异常信息,当前正在处理的数据信息,线程处理的信息
+     * @param 
+     * @return Map
+     */
+	/**
+	 * 执行存过,处理任务执行前后的事情
+	 */
+	public void saveDbFunction(String function);
+	
+	/**
+	 * 执行存过(带参数),处理任务执行前后的事情
+	 */
+	public void saveDbFunctionWithParam(Map info);
+
+	/**
+	 * 保存FTP下载的一行数据到表中
+	 * @param
+	 * @return Map
+	 */
+	public void insertFileData2Table(String insertSQL);
+}

+ 54 - 0
JobService/src/main/java/com/java110/job/smo/IPrvncFtpFileSMO.java

@@ -0,0 +1,54 @@
+package com.java110.job.smo;
+
+import com.java110.job.model.*;
+
+import java.util.Map;
+
+/** 
+ * FTP任务管理SMO,在此类管理所有事务
+ *  
+ * @author 师延俊
+ * @version
+ */  
+public interface IPrvncFtpFileSMO {
+
+	/**
+     * 保存执行任务的日志,任务的执行状态
+     * @param 
+     * @return Map
+	 * 00004
+     */
+	public long saveTaskRunLog(FtpTaskLog loginfo);
+	/**
+     * 更新执行任务的日志
+     * @param 
+     * @return Map
+	 * 00033
+     */
+	public void updateTaskRunLog(FtpTaskLog loginfo);
+	/**
+     * 保存执行任务的详细日志,包含任务的传输信息,如果下载线程信息,线程是否执行完成,下载的起始,需要下载的数据大小
+     * @param
+     * @return Map  0006
+     */
+	public int saveTaskRunDetailLog(FtpTaskLogDetail logdetail);
+	/**
+	 * 执行存过,处理任务执行前后的事情
+	 * 00011
+	 */
+	public void saveDbFunction(String function);
+	
+	
+	/**
+	 * 执行存过(带参数),处理任务执行前后的事情
+	 * 00002
+	 */
+	public void saveDbFunctionWithParam(Map info);
+
+	/**
+	 * 保存FTP下载的一行数据到表中
+	 * @param
+	 * @return Map
+	 */
+	public void insertFileData2Table(String insertSQL);
+}

+ 376 - 0
JobService/src/main/java/com/java110/job/smo/PrvncFtpToFileSystemQuartz.java

@@ -0,0 +1,376 @@
+package com.java110.job.smo;
+import com.java110.common.constant.RuleDomain;
+import com.java110.common.util.DateUtil;
+import com.java110.common.util.StringUtil;
+import com.java110.job.dao.IPrvncFtpFileDAO;
+
+import com.java110.job.model.FtpTaskLog;
+import com.java110.job.model.FtpTaskLogDetail;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Ftp定时任务执行类,所有的任务都在这里执行,主要为了ftp文件保存到文件系统,业务逻辑单独处理
+ * 
+ * 特别注意,事前过程调用是没有传递参数的,事后过程调用是需要传递一个param的参数,需要在子类process方法中写入,如果不需要传也要传个""过来,
+ * 相应过程需要两个参数,一个是入参一个是出参
+ * 
+ * @author wuxw7 add by 2016-01-03
+ * 
+ */
+public abstract class PrvncFtpToFileSystemQuartz {
+
+	protected static final Logger logger = LoggerFactory.getLogger(PrvncFtpToFileSystemQuartz.class);
+	@Autowired
+	private IPrvncFtpFileDAO iprvncFtpFileDAO;
+	@Autowired
+	private IPrvncFtpFileSMO iprvncFtpFileSMO;
+
+	/*private IPrvncDumpSMO prvncDumpSMO;*/
+	// 运行状态,R:正在执行 T:等待运行 TD1:文件下载失败 TD2:文件内容保存失败 TU1:数据文件生成失败 TU2:数据文件上传失败
+	private static final String TASK_STATE_R = "R";// 正在运行
+	private static final String TASK_STATE_T = "T";// 等待运行
+	private static final String TASK_STATE_E1 = "E1";// 执行事前过程失败
+	private static final String TASK_STATE_E2 = "E2";// 处理数据失败
+	private static final String TASK_STATE_E3 = "E3";// 执行事后过程失败
+
+	public void initTask() {
+
+		// 将所有的任务状态改为等待运行状态
+		Map paramIn = new HashMap();
+		paramIn.put("oldRunState", "R");
+		paramIn.put("runState", "T");
+		int updateFtpItemRunStateFlag = iprvncFtpFileDAO.updateFtpItemRunState(paramIn);
+		if (updateFtpItemRunStateFlag < 1) {
+			logger.error("--【PrvncFtpToFileSystemQuartz.initTask】,没有需要更新的内容(没有下载一半后停止应用的情况)", paramIn);
+		}
+	}
+
+	/**
+	 * 启动任务
+	 * 
+	 * @param ftpItemConfigInfo
+	 */
+	public void startFtpTask(Map ftpItemConfigInfo) throws Exception {
+
+		// 这么做是为了,单线程调用,防止多线程导致数据重复处理
+		if (!ftpItemConfigInfo.containsKey("RUN_STATE") || "R".equals(ftpItemConfigInfo.get("RUN_STATE"))) {
+			return;
+		}
+
+		long taskId = Long.parseLong(ftpItemConfigInfo.get("TASKID").toString());
+
+		if (logger.isDebugEnabled()) {
+			logger.debug("---【PrvncFtpToFileSystemQuartz.startFtpTask】:任务【" + taskId + "】开始运行!", taskId);
+		}
+
+		// 保存任务执行主要日志信息
+		long taskLogID = insertTaskInfo(ftpItemConfigInfo);
+
+		ftpItemConfigInfo.put("logid", taskLogID);
+		ftpItemConfigInfo.put("taskid", taskId);
+		ftpItemConfigInfo.put("threadrunstate", TASK_STATE_R);
+		ftpItemConfigInfo.put("tnum", 1);
+		// 修改任务状态为正在执行状态
+		updateTaskState(taskId, TASK_STATE_R);
+		// 方法调用是否成功,S成功(默认),E表示失败(在方法中失败时,需要修改)
+		ftpItemConfigInfo.put("PRE_METHOD_FLAG", "S");
+		try {
+			// 1.0空方法,让子类去实现
+			prepare(ftpItemConfigInfo);
+
+			// 2.0调用事前过程
+			if (ftpItemConfigInfo.containsKey("PREFLAG") && "0".equals(ftpItemConfigInfo.get("PREFLAG"))) {
+				callPreFunction(ftpItemConfigInfo);
+			}
+
+			if (ftpItemConfigInfo.containsKey("PRE_METHOD_FLAG") && "E".equals(ftpItemConfigInfo.get("PRE_METHOD_FLAG"))) {
+				// 此时调用事前过程失败,直接返回 查询标识为E,更新日志
+				udpateTaskLog(ftpItemConfigInfo);
+				updateTaskState(taskId, TASK_STATE_E1);
+				return;
+			}
+
+			// 3.0核心业务处理逻辑,需要子类去实现
+			process(ftpItemConfigInfo);
+
+			if (ftpItemConfigInfo.containsKey("PRE_METHOD_FLAG") && "E".equals(ftpItemConfigInfo.get("PRE_METHOD_FLAG"))) {
+				// 程序处理失败,直接返回
+				ftpItemConfigInfo.put("threadrunstate", TASK_STATE_E2);
+				updateTaskState(taskId, TASK_STATE_E2);
+				udpateTaskLog(ftpItemConfigInfo);
+				saveTaskLogDetail(ftpItemConfigInfo);// 保存detail
+				return;
+			}
+			// 记录详细日志
+			ftpItemConfigInfo.put("threadrunstate", "T");
+			saveTaskLogDetail(ftpItemConfigInfo);
+
+			// 4.0调用事后过程
+			if (ftpItemConfigInfo.containsKey("AFTERFLAG") && "0".equals(ftpItemConfigInfo.get("AFTERFLAG"))) {
+				callAfterFunction(ftpItemConfigInfo);
+			}
+			if (ftpItemConfigInfo.containsKey("PRE_METHOD_FLAG") && "E".equals(ftpItemConfigInfo.get("PRE_METHOD_FLAG"))) {
+				// 此时调用事前过程失败,直接返回 查询标识为E,更新日志
+				udpateTaskLog(ftpItemConfigInfo);
+				updateTaskState(taskId, TASK_STATE_E3);
+				return;
+			}
+			// 5.0空方法,让子类去实现
+			post(ftpItemConfigInfo);
+		} catch (Exception ex) {
+			ftpItemConfigInfo.put("threadrunstate", TASK_STATE_E2);
+			udpateTaskLog(ftpItemConfigInfo);
+			ftpItemConfigInfo.put("threadrunstate", TASK_STATE_E2);
+			ftpItemConfigInfo.put("remark", ex);
+			saveTaskLogDetail(ftpItemConfigInfo);
+			updateTaskState(taskId, TASK_STATE_E2);
+			// 接续向外抛出去
+			logger.error("处理出现问题:", ex);
+			return;
+		}
+
+		// 修改任务状态为执行完毕状态
+		updateTaskState(taskId, TASK_STATE_T);
+		ftpItemConfigInfo.put("threadrunstate", TASK_STATE_T);
+		udpateTaskLog(ftpItemConfigInfo);
+
+		// 发送任务运行结果通知短信给相关人员 **暂时不调用短信
+		if (!TASK_STATE_T.equals(ftpItemConfigInfo.get("RUN_STATE").toString())) {
+			/*sendErrLogPhoneMsg(ftpItemConfigInfo, taskLogID);*/
+		}
+
+	}
+
+	// 如果有事前存过需要调用,则先调用存过
+	public void callPreFunction(Map taskInfo) {
+
+		if (taskInfo.containsKey("PREFUNCTION") && taskInfo.get("PREFUNCTION") != null && !"".equals(taskInfo.get("PREFUNCTION"))) {
+			try {
+				iprvncFtpFileSMO.saveDbFunction(taskInfo.get("PREFUNCTION").toString());
+				taskInfo.put("threadrunstate", "T");
+				taskInfo.put("remark", "调用事前存过结束");
+				saveTaskLogDetail(taskInfo);
+			} catch (Exception ex) {
+				logger.error("调用事前存过失败:", ex);
+				taskInfo.put("threadrunstate", "E1");
+				taskInfo.put("remark", "调用事前存过失败" + ex);
+				taskInfo.put("PRE_METHOD_FLAG", "E");
+				saveTaskLogDetail(taskInfo);
+			}
+		}
+	}
+
+	/**
+	 * 主要业务处理(上传下载),让子类去实现
+	 * 
+	 * @param ftpItemConfigInfo
+	 */
+	protected abstract void process(Map ftpItemConfigInfo) throws Exception;
+
+	// 如果有事后存过需要调用,则调用存过
+	public void callAfterFunction(Map taskInfo) {
+
+		if (taskInfo.containsKey("AFTERFUNCTION") && taskInfo.get("AFTERFUNCTION") != null && !"".equals(taskInfo.get("AFTERFUNCTION"))) {
+			try {
+				taskInfo.put("functionname", taskInfo.get("AFTERFUNCTION"));
+				// taskInfo 参数param需要在process方法中需要自己写入
+				iprvncFtpFileSMO.saveDbFunctionWithParam(taskInfo);
+				taskInfo.put("threadrunstate", "T");
+				taskInfo.put("remark", "调用事后存过结束");
+				saveTaskLogDetail(taskInfo);
+			} catch (Exception ex) {
+				ex.printStackTrace();
+				taskInfo.put("threadrunstate", "E3");
+				taskInfo.put("remark", "调用事后存过失败" + ex);
+				taskInfo.put("PRE_METHOD_FLAG", "E");
+				saveTaskLogDetail(taskInfo);
+			}
+		}
+	}
+
+	/**
+	 * 修改任务状态
+	 * 
+	 * @return
+	 */
+	private void updateTaskState(long taskId, String state) {
+		Map info = new HashMap();
+
+		info.put("taskId", taskId);
+		info.put("runState", state);
+		int updateFtpItemFlag = iprvncFtpFileDAO.updateFtpItemByTaskId(info);
+		// 这里只是后台提示,不进行日志保存
+		if (updateFtpItemFlag < 1) {
+			logger.error("---【PrvncFtpToFileSystemQuartz.updateTaskState】修改任务【" + taskId + "】的状态失败", info);
+		}
+	}
+
+	/**
+	 * 修改任务执行日志的状态
+	 */
+	private void udpateTaskLog(Map taskInfo) {
+		FtpTaskLog loginfo = new FtpTaskLog();
+		loginfo.setLogid(Long.valueOf(taskInfo.get("logid").toString()));
+		loginfo.setState(taskInfo.get("threadrunstate").toString());
+		iprvncFtpFileSMO.updateTaskRunLog(loginfo);
+	}
+
+	/**
+	 * 保存任务执行的详细日志
+	 */
+	protected void saveTaskLogDetail(Map taskInfo) {
+		FtpTaskLogDetail logdetail = new FtpTaskLogDetail();
+		logdetail.setLogid(Long.valueOf(taskInfo.get("logid").toString()));
+		logdetail.setTaskid(Long.valueOf(taskInfo.get("taskid").toString()));
+		logdetail.setState((String) taskInfo.get("threadrunstate"));
+		logdetail.setTnum(Integer.valueOf(taskInfo.get("tnum").toString()));
+		if (taskInfo.get("begin") != null) {
+			logdetail.setBegin(Long.valueOf(taskInfo.get("begin").toString()));
+		}
+		if (taskInfo.get("end") != null) {
+			logdetail.setEnd(Long.valueOf(taskInfo.get("end").toString()));
+		}
+		if (taskInfo.get("havedown") != null) {
+			logdetail.setHavedown(Long.valueOf(taskInfo.get("havedown").toString()));
+		}
+		logdetail.setRemark(taskInfo.get("remark") == null ? "" : (taskInfo.get("remark").toString().trim().length() > 2000 ? taskInfo.get("remark").toString().trim().substring(0,
+				1600) : taskInfo.get("remark").toString().trim()));
+		logdetail.setData(taskInfo.get("data") == null ? "" : taskInfo.get("data").toString());
+		logdetail.setServerfilename(taskInfo.get("serverfilename") == null ? "" : taskInfo.get("serverfilename").toString());
+		logdetail.setLocalfilename(taskInfo.get("localfilename") == null ? "" : taskInfo.get("localfilename").toString());
+		int logdetailid = iprvncFtpFileSMO.saveTaskRunDetailLog(logdetail);
+		taskInfo.put("logdetailid", logdetailid);
+	}
+
+	// /**
+	// * 修改任务执行的详细日志的状态
+	// */
+	// private void updateTaskLogDetail(Map taskInfo){
+	// FtpTaskLogDetail logdetail=new FtpTaskLogDetail();//
+	// logdetail.setId(Long.valueOf(taskInfo.get("logdetailid").toString()));
+	// logdetail.setState(taskInfo.get("threadrunstate").toString());
+	// logdetail.setRemark((String)taskInfo.get("remark"));
+	// logdetail.setData((String)taskInfo.get("data"));
+	// if(taskInfo.get("downedlength")!=null)
+	// logdetail.setHavedown(Long.valueOf(taskInfo.get("downedlength").toString()));
+	// prvncFtpFileSMO.updateTaskRunDetailLog(logdetail);
+	// }
+
+	/**
+	 * 生成任务执行日志
+	 */
+	private long insertTaskInfo(Map taskInfo) {
+		FtpTaskLog loginfo = new FtpTaskLog();
+		loginfo.setTaskid(Long.valueOf(taskInfo.get("TASKID").toString()));
+		loginfo.setState("R");
+		loginfo.setServerfilename("");// taskInfo.get("serverfilename").toString()
+		loginfo.setLocalfilename("");// taskInfo.get("localfilename").toString()
+		loginfo.setUord(taskInfo.get("U_OR_D").toString());
+		return iprvncFtpFileSMO.saveTaskRunLog(loginfo);
+	}
+
+	/**
+	 * 如果任务运行有异常,则发送警告短信给配置的手机号码
+	 */
+	private void sendErrLogPhoneMsg(Map taskInfo, long taskLogID) {
+		Map msginfo = new HashMap();
+		String phone = (String) taskInfo.get("errphone");
+		if (phone != null && !"".equals(phone)) {
+			String[] phonelist = phone.split(",");
+			for (int i = 0; i < phonelist.length; i++) {
+				msginfo.put("taskid", taskInfo.get("taskid"));
+				msginfo.put("phone", phonelist[i]);
+				msginfo.put("msg", "通用FTP数据文件传接任务:" + (String) taskInfo.get("taskname") + "运行提示");
+
+				DateFormat df = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
+				String detail = "任务已于" + df.format(new Date()) + "运行完毕。运行过程中出现异常,详情请登录系统查看!";
+				msginfo.put("detail", detail);
+				/*prvncDumpSMO.saveTaskErrInfoPhoneMsg(msginfo);*/
+			}
+		}
+	}
+
+	/**
+	 * 处理文件名,校验文件名是中是否存在****(4个),表示通配符,如果不存在就是确定唯一文件名
+	 * 文件名支持日期型的如CRM_########001.txt 程序处理后是 CRM_20170105001.txt 文件名支持sql 语句生成的
+	 * 文件名支持通配符的如863_****.txt 程序下载所有以863_开头的文件 863_****001.txt
+	 * 以863_开头,以001结尾,****001.txt 以001结尾的
+	 * 
+	 * @param fileName
+	 * @return
+	 */
+	protected List<String> dealFileName(String fileName) {
+		// TODO Auto-generated method stub
+		List<String> results = new ArrayList<String>();
+		String result = "";
+		// 文件中使用的日期
+		if (StringUtils.contains(fileName, RuleDomain.REPLAY_TYPE_F)) {
+			result = StringUtil.replace(fileName, RuleDomain.REPLAY_TYPE_F, DateUtil.getFormatTimeString(new Date(), "yyyyMMddHHmm"));
+		} else if (StringUtils.contains(fileName, RuleDomain.REPLAY_TYPE_E)) {
+			result = StringUtil.replace(fileName, RuleDomain.REPLAY_TYPE_E, DateUtil.getFormatTimeString(new Date(), "yyyyMMddHH"));
+		} else if (StringUtils.contains(fileName, RuleDomain.REPLAY_TYPE_A)) {
+			result = StringUtil.replace(fileName, RuleDomain.REPLAY_TYPE_A, DateUtil.getFormatTimeString(new Date(), "yyyyMMdd"));
+		} else if (StringUtils.contains(fileName == null ? "" : fileName.toLowerCase(), RuleDomain.REPLAY_TYPE_SQL)) {
+			// 后期改造,文件名如果配置的是sql的话,以sql查询文件名
+			List<String> fileNames = this.getPrvncFtpFileDAO().execConfigSql(fileName);
+			// if (fileNames != null && fileNames.size() > 0) {
+			// result = fileNames.get(0);
+			// }
+			return fileNames;
+		} else {
+			result = fileName;
+		}
+		results.add(result);
+		return results;
+	}
+
+	/**
+	 * 空方法,如果在事前过程处理前,还需要做一定的处理,需要子类重写这个方法,实现业务逻辑
+	 * 
+	 * @param ftpItemConfigInfo
+	 */
+	protected void prepare(Map ftpItemConfigInfo) {
+
+	}
+
+	/**
+	 * 空方法,如果在事后过程处理完后,还需要做一定的处理,需要子类重写这个方法,实现业务逻辑
+	 * 
+	 * @param ftpItemConfigInfo
+	 */
+	protected void post(Map ftpItemConfigInfo) {
+
+	}
+
+	public IPrvncFtpFileDAO getPrvncFtpFileDAO() {
+		return iprvncFtpFileDAO;
+	}
+
+	public void setPrvncFtpFileDAO(IPrvncFtpFileDAO prvncFtpFileDAO) {
+		this.iprvncFtpFileDAO = prvncFtpFileDAO;
+	}
+
+	public IPrvncFtpFileSMO getPrvncFtpFileSMO() {
+		return iprvncFtpFileSMO;
+	}
+
+	public void setPrvncFtpFileSMO(IPrvncFtpFileSMO prvncFtpFileSMO) {
+		this.iprvncFtpFileSMO = prvncFtpFileSMO;
+	}
+
+	/*public IPrvncDumpSMO getPrvncDumpSMO() {
+		return prvncDumpSMO;
+	}
+
+	public void setPrvncDumpSMO(IPrvncDumpSMO prvncDumpSMO) {
+		this.prvncDumpSMO = prvncDumpSMO;
+	}
+*/
+}

+ 52 - 0
JobService/src/main/java/com/java110/job/smo/impl/PrvncFtpFileBMOImpl.java

@@ -0,0 +1,52 @@
+package com.java110.job.smo.impl;
+
+import com.java110.job.dao.IPrvncFtpFileDAO;
+import com.java110.job.model.*;
+import com.java110.job.smo.IPrvncFtpFileBMO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Map;
+@Service("prvncFtpFileBMOImpl")
+@Transactional
+public class PrvncFtpFileBMOImpl implements IPrvncFtpFileBMO {
+	@Autowired
+	private IPrvncFtpFileDAO iprvncFtpFileDAO;
+
+	@Override
+	public long saveTaskRunLog(FtpTaskLog loginfo) {
+		// TODO Auto-generated method stub
+		return iprvncFtpFileDAO.saveTaskRunLog(loginfo);
+	}
+
+	public void updateTaskRunLog(FtpTaskLog loginfo) {
+		// TODO Auto-generated method stub
+		iprvncFtpFileDAO.updateTaskRunLog(loginfo);
+	}
+	public int saveTaskRunDetailLog(FtpTaskLogDetail logdetail) {
+		// TODO Auto-generated method stub
+		return iprvncFtpFileDAO.saveTaskRunDetailLog(logdetail);
+	}
+
+	/**
+	 * 执行存过,处理任务执行前后的事情
+	 */
+	public void saveDbFunction(String function){
+		iprvncFtpFileDAO.saveDbFunction(function);
+	}
+
+	/**
+	 * 执行存过(带参数),处理任务执行前后的事情
+	 */
+	public void saveDbFunctionWithParam(Map info){
+		iprvncFtpFileDAO.saveDbFunctionWithParam(info);
+	}
+
+	@Override
+	public void insertFileData2Table(String insertSQL) {
+		// TODO Auto-generated method stub
+		iprvncFtpFileDAO.insertFileData2Table(insertSQL);
+	}
+	
+}

+ 55 - 0
JobService/src/main/java/com/java110/job/smo/impl/PrvncFtpFileSMOImpl.java

@@ -0,0 +1,55 @@
+package com.java110.job.smo.impl;
+
+import com.java110.job.model.*;
+import com.java110.job.smo.IPrvncFtpFileBMO;
+import com.java110.job.smo.IPrvncFtpFileSMO;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+
+import java.util.Map;
+@Service("prvncFtpFileSMOImpl")
+@Transactional
+public class PrvncFtpFileSMOImpl implements IPrvncFtpFileSMO {
+    /** logger */  
+    protected final Logger log= Logger.getLogger(getClass());
+	@Autowired
+	private IPrvncFtpFileBMO iPrvncFtpFileBMO;
+
+	@Override
+	public long saveTaskRunLog(FtpTaskLog loginfo) {
+		// TODO Auto-generated method stub
+		return iPrvncFtpFileBMO.saveTaskRunLog(loginfo);
+	}
+
+	public void updateTaskRunLog(FtpTaskLog loginfo) {
+		// TODO Auto-generated method stub
+		iPrvncFtpFileBMO.updateTaskRunLog(loginfo);
+	}
+	@Override
+	public int saveTaskRunDetailLog(FtpTaskLogDetail logdetail) {
+		// TODO Auto-generated method stub
+		return iPrvncFtpFileBMO.saveTaskRunDetailLog(logdetail);
+	}
+
+	/**
+	 * 执行存过,处理任务执行前后的事情
+	 */
+	public void saveDbFunction(String function){
+		iPrvncFtpFileBMO.saveDbFunction(function);
+	}
+	/**
+	 * 执行存过(带参数),处理任务执行前后的事情
+	 */
+	public void saveDbFunctionWithParam(Map info){
+		iPrvncFtpFileBMO.saveDbFunctionWithParam(info);
+	}
+
+	@Override
+	public void insertFileData2Table(String insertSQL) {
+		// TODO Auto-generated method stub
+		iPrvncFtpFileBMO.insertFileData2Table(insertSQL);
+	}
+}

+ 90 - 0
JobService/src/main/java/com/java110/job/task/PrvncFtpToFileSystemJob.java

@@ -0,0 +1,90 @@
+package com.java110.job.task;
+
+import com.java110.common.util.SpringBeanInvoker;
+import com.java110.job.dao.IPrvncFtpFileDAO;
+import com.java110.job.smo.PrvncFtpToFileSystemQuartz;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 将集团文件同步至本地支持的文件系统
+ * 
+ * @author wuxw7
+ * 
+ */
+
+public class PrvncFtpToFileSystemJob extends MethodInvokingJobDetailFactoryBean.StatefulMethodInvokingJob {
+	
+	private static final Logger logger = LoggerFactory.getLogger(PrvncFtpToFileSystemJob.class);
+
+	public static String JOB_DATA_CONFIG_NAME = "ftpToFileSystemTaskName";
+	public static String JOB_DATA_TASK_ID = "ftpToFileSystemTaskID";
+	public static String JOB_GROUP_NAME = "ftpToFileSystemJobGroup"; // 任务的 分组名称
+	@Autowired
+	private IPrvncFtpFileDAO prvncFtpFileDAO;
+	@Autowired
+	private PrvncFtpToFileSystemQuartz prvncDumpQuartz;
+	
+	protected void executeInternal(JobExecutionContext context) {
+		try {
+			
+			if(logger.isDebugEnabled()){
+				logger.debug("FTP通用数据文件传接任务:" +
+						 context.getJobDetail().getFullName() + " taskID:" +
+						 context.getJobDetail().getJobDataMap().get(JOB_DATA_TASK_ID) +
+						 " ftpfileTaskName:" +
+						 context.getJobDetail().getJobDataMap().get(JOB_DATA_CONFIG_NAME), context);
+			}
+
+			long taskId = Long.parseLong(context.getJobDetail().getJobDataMap()
+					.getString(JOB_DATA_TASK_ID));
+			// 根据taskId 查询配置信息
+			Map ftpItemConfigInfo = this.getFtpConfigInfo(taskId);
+			
+			//如果查询不到数据,或者是没有处理class,不在运行
+			if(ftpItemConfigInfo == null || !ftpItemConfigInfo.containsKey("DEAL_CLASS") || ftpItemConfigInfo.get("DEAL_CLASS") == null){
+				logger.error("---【PrvncFtpToFileSystemQuartz.executeInternal】查询到的ftp配置数据为空,或没有处理类", ftpItemConfigInfo);
+				return;
+			}
+			
+			String dealClass = ftpItemConfigInfo.get("DEAL_CLASS").toString();
+			prvncDumpQuartz = (PrvncFtpToFileSystemQuartz) SpringBeanInvoker.getBean(dealClass);
+			prvncDumpQuartz.startFtpTask(ftpItemConfigInfo);
+		} catch (Throwable ex) {
+			logger.error("执行任务失败:", ex);
+		}
+	}
+
+	/**
+	 * 查询配置相关信息
+	 * 
+	 * @param taskId
+	 * @return
+	 */
+	private Map getFtpConfigInfo(long taskId) {
+		Map info = new HashMap();
+		info.put("taskId", taskId);
+		Map ftpItem = getPrvncFtpFileDAO().queryFtpItemByTaskId(info);
+		if (logger.isDebugEnabled()) {
+			logger.debug(
+					"---【PrvncFtpToFileSystemQuartz.getFtpConfigInfo】查询到的配置数据为:"
+							+ ftpItem, ftpItem);
+		}
+		return ftpItem;
+	}
+
+	public IPrvncFtpFileDAO getPrvncFtpFileDAO() {
+		if (this.prvncFtpFileDAO == null) {
+			this.prvncFtpFileDAO = ((IPrvncFtpFileDAO) SpringBeanInvoker
+					.getBean("provInner.PrvncFtpFileDAO"));
+		}
+		return prvncFtpFileDAO;
+	}
+
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1068 - 0
JobService/src/main/java/com/java110/job/util/FTPClientTemplate.java


+ 94 - 0
JobService/src/main/resources/application-dev.yml

@@ -0,0 +1,94 @@
+jedis:
+  pool:
+    config:
+      maxTotal: 100
+      maxIdle: 20
+      maxWaitMillis: 20000
+    host: dev.redis.java110.com
+    port: 6379
+
+eureka:
+  instance:
+    leaseRenewalIntervalInSeconds: 10
+    leaseExpirationDurationInSeconds: 30
+    preferIpAddress: true
+    instanceId: ${spring.cloud.client.ip-address}:${server.port}
+  client:
+    serviceUrl:
+      defaultZone: http://dev.java110.com:8761/eureka/
+      #defaultZone: http://localhost:8761/eureka/
+server:
+  port: 8002
+  tomcat:
+    uri-encoding: UTF-8
+
+spring:
+  http:
+    encoding:
+      charset: UTF-8
+      enabled: true
+      force: true
+  application:
+    name: job-service
+  redis:
+    database: 0
+    host: dev.redis.java110.com
+    port: 6379
+    pool:
+      max-active: 300
+      max-wait: 10000
+      max-idle: 100
+      min-idle: 0
+      timeout: 0
+  datasource:
+    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+    minIdle: 5
+    validationQuery: SELECT 1 FROM DUAL
+    initialSize: 5
+    maxWait: 60000
+    filters: stat,wall,log4j
+    poolPreparedStatements: true
+    type: com.alibaba.druid.pool.DruidDataSource
+    url: jdbc:mysql://dev.db.java110.com:3306/TT?useUnicode=true&characterEncoding=utf-8
+    maxPoolPreparedStatementPerConnectionSize: 20
+    password: TT@12345678
+    testOnBorrow: false
+    testWhileIdle: true
+    minEvictableIdleTimeMillis: 300000
+    timeBetweenEvictionRunsMillis: 60000
+    testOnReturn: false
+    driverClassName: com.mysql.jdbc.Driver
+    maxActive: 20
+    username: TT
+
+#============== kafka ===================
+kafka:
+  consumer:
+    zookeeper:
+      connect: dev.zk.java110.com:2181
+    servers: dev.kafka.java110.com:9092
+    enable:
+      auto:
+        commit: true
+    session:
+      timeout: 6000
+    auto:
+      commit:
+        interval: 100
+      offset:
+        reset: latest
+    topic: test
+    group:
+      id: notifyBusinessStatus
+    concurrency: 10
+
+  producer:
+    zookeeper:
+      connect: dev.zk.java110.com:2181
+    servers: dev.kafka.java110.com:9092
+    retries: 0
+    batch:
+      size: 4096
+    linger: 1
+    buffer:
+      memory: 40960

+ 3 - 0
JobService/src/main/resources/application.yml

@@ -0,0 +1,3 @@
+spring:
+  profiles:
+    active: dev

+ 15 - 0
JobService/src/main/resources/banner.txt

@@ -0,0 +1,15 @@
+${AnsiColor.BRIGHT_RED}
+     __                    ____ ___________
+    |__|____ ___  _______ /_   /_   \   _  \
+    |  \__  \\  \/ /\__  \ |   ||   /  /_\  \
+    |  |/ __ \\   /  / __ \|   ||   \  \_/   \
+/\__|  (____  /\_/  (____  /___||___|\_____  /
+\______|    \/           \/                \/
+ ____ ___                    _________                  .__
+|    |   \______ ___________/   _____/ ______________  _|__| ____  ____
+|    |   /  ___// __ \_  __ \_____  \_/ __ \_  __ \  \/ /  |/ ___\/ __ \
+|    |  /\___ \\  ___/|  | \/        \  ___/|  | \/\   /|  \  \__\  ___/
+|______//____  >\___  >__| /_______  /\___  >__|    \_/ |__|\___  >___  >
+             \/     \/             \/     \/                    \/    \/
+
+ java110 UserService starting, more information scan https://github.com/java110/MicroCommunity

+ 75 - 0
JobService/src/main/resources/dataSource.yml

@@ -0,0 +1,75 @@
+dataSources:
+  ds0: !!com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.jdbc.Driver
+    url: jdbc:mysql://dev.db.java110.com:3306/hc_community?useUnicode=true&characterEncoding=utf-8
+    username: hc_community
+    password: hc_community@12345678
+    minIdle: 5
+    validationQuery: SELECT 1 FROM DUAL
+    initialSize: 5
+    maxWait: 60000
+    filters: stat,wall,log4j
+    poolPreparedStatements: true
+#  ds0_slave0: !!com.alibaba.druid.pool.DruidDataSource
+#    driverClassName: com.mysql.jdbc.Driver
+#    url: jdbc:mysql://dev.db.java110.com:3306/TT?useUnicode=true&characterEncoding=utf-8
+#    username: TT
+#    password: TT@12345678
+#    connectionTimeoutMilliseconds: 30000
+#    idleTimeoutMilliseconds: 60000
+#    maxPoolSize: 50
+#    minPoolSize: 1
+#    maintenanceIntervalMilliseconds: 30000
+  ds1: !!com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.jdbc.Driver
+    url: jdbc:mysql://dev.db.java110.com:3306/TT?useUnicode=true&characterEncoding=utf-8
+    username: TT
+    password: TT@12345678
+    minIdle: 5
+    validationQuery: SELECT 1 FROM DUAL
+    initialSize: 5
+    maxWait: 60000
+    filters: stat,wall,log4j
+    poolPreparedStatements: true
+#  ds1_slave0: !!com.alibaba.druid.pool.DruidDataSource
+#    driverClassName: com.mysql.jdbc.Driver
+#    url: jdbc:mysql://dev.db.java110.com:3306/TT?useUnicode=true&characterEncoding=utf-8
+#    username: TT
+#    password: TT@12345678
+#    connectionTimeoutMilliseconds: 30000
+#    idleTimeoutMilliseconds: 60000
+#    maxPoolSize: 50
+#    minPoolSize: 1
+#    maintenanceIntervalMilliseconds: 30000
+
+shardingRule:
+  tables:
+    business_xxx:
+      actualDataNodes: ds${0..1}.business_community
+      databaseStrategy:
+        inline:
+          shardingColumn: community_id
+          algorithmExpression: ds${Long.parseLong(community_id) % 2}
+
+  bindingTables:
+    - business_xxx
+
+  defaultDataSourceName: ds1
+  defaultDatabaseStrategy:
+    none:
+  defaultTableStrategy:
+    none:
+
+#  masterSlaveRules:
+#    ms_ds0:
+#     masterDataSourceName: ds0
+#     slaveDataSourceNames:
+#       - ds0_slave0
+#     loadBalanceAlgorithmType: ROUND_ROBIN
+#   ms_ds1:
+#     masterDataSourceName: ds1
+#     slaveDataSourceNames:
+#       - ds1_slave0
+#     loadBalanceAlgorithmType: ROUND_ROBIN
+props:
+  sql.show: true

+ 587 - 0
JobService/src/main/resources/static/css/bootstrap-theme.css

@@ -0,0 +1,587 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+          box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default.disabled,
+.btn-primary.disabled,
+.btn-success.disabled,
+.btn-info.disabled,
+.btn-warning.disabled,
+.btn-danger.disabled,
+.btn-default[disabled],
+.btn-primary[disabled],
+.btn-success[disabled],
+.btn-info[disabled],
+.btn-warning[disabled],
+.btn-danger[disabled],
+fieldset[disabled] .btn-default,
+fieldset[disabled] .btn-primary,
+fieldset[disabled] .btn-success,
+fieldset[disabled] .btn-info,
+fieldset[disabled] .btn-warning,
+fieldset[disabled] .btn-danger {
+  -webkit-box-shadow: none;
+          box-shadow: none;
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+  text-shadow: none;
+}
+.btn:active,
+.btn.active {
+  background-image: none;
+}
+.btn-default {
+  text-shadow: 0 1px 0 #fff;
+  background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+  background-image:      -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+  background-image:         linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #dbdbdb;
+  border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+  background-color: #e0e0e0;
+  background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+  background-color: #e0e0e0;
+  border-color: #dbdbdb;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+fieldset[disabled] .btn-default,
+.btn-default.disabled:hover,
+.btn-default[disabled]:hover,
+fieldset[disabled] .btn-default:hover,
+.btn-default.disabled:focus,
+.btn-default[disabled]:focus,
+fieldset[disabled] .btn-default:focus,
+.btn-default.disabled.focus,
+.btn-default[disabled].focus,
+fieldset[disabled] .btn-default.focus,
+.btn-default.disabled:active,
+.btn-default[disabled]:active,
+fieldset[disabled] .btn-default:active,
+.btn-default.disabled.active,
+.btn-default[disabled].active,
+fieldset[disabled] .btn-default.active {
+  background-color: #e0e0e0;
+  background-image: none;
+}
+.btn-primary {
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #245580;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+  background-color: #265a88;
+  background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+  background-color: #265a88;
+  border-color: #245580;
+}
+.btn-primary.disabled,
+.btn-primary[disabled],
+fieldset[disabled] .btn-primary,
+.btn-primary.disabled:hover,
+.btn-primary[disabled]:hover,
+fieldset[disabled] .btn-primary:hover,
+.btn-primary.disabled:focus,
+.btn-primary[disabled]:focus,
+fieldset[disabled] .btn-primary:focus,
+.btn-primary.disabled.focus,
+.btn-primary[disabled].focus,
+fieldset[disabled] .btn-primary.focus,
+.btn-primary.disabled:active,
+.btn-primary[disabled]:active,
+fieldset[disabled] .btn-primary:active,
+.btn-primary.disabled.active,
+.btn-primary[disabled].active,
+fieldset[disabled] .btn-primary.active {
+  background-color: #265a88;
+  background-image: none;
+}
+.btn-success {
+  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+  background-image:      -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
+  background-image:         linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+  background-color: #419641;
+  background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+  background-color: #419641;
+  border-color: #3e8f3e;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+fieldset[disabled] .btn-success,
+.btn-success.disabled:hover,
+.btn-success[disabled]:hover,
+fieldset[disabled] .btn-success:hover,
+.btn-success.disabled:focus,
+.btn-success[disabled]:focus,
+fieldset[disabled] .btn-success:focus,
+.btn-success.disabled.focus,
+.btn-success[disabled].focus,
+fieldset[disabled] .btn-success.focus,
+.btn-success.disabled:active,
+.btn-success[disabled]:active,
+fieldset[disabled] .btn-success:active,
+.btn-success.disabled.active,
+.btn-success[disabled].active,
+fieldset[disabled] .btn-success.active {
+  background-color: #419641;
+  background-image: none;
+}
+.btn-info {
+  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+  background-image:      -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
+  background-image:         linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+  background-color: #2aabd2;
+  background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+  background-color: #2aabd2;
+  border-color: #28a4c9;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+fieldset[disabled] .btn-info,
+.btn-info.disabled:hover,
+.btn-info[disabled]:hover,
+fieldset[disabled] .btn-info:hover,
+.btn-info.disabled:focus,
+.btn-info[disabled]:focus,
+fieldset[disabled] .btn-info:focus,
+.btn-info.disabled.focus,
+.btn-info[disabled].focus,
+fieldset[disabled] .btn-info.focus,
+.btn-info.disabled:active,
+.btn-info[disabled]:active,
+fieldset[disabled] .btn-info:active,
+.btn-info.disabled.active,
+.btn-info[disabled].active,
+fieldset[disabled] .btn-info.active {
+  background-color: #2aabd2;
+  background-image: none;
+}
+.btn-warning {
+  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
+  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+  background-color: #eb9316;
+  background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+  background-color: #eb9316;
+  border-color: #e38d13;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+fieldset[disabled] .btn-warning,
+.btn-warning.disabled:hover,
+.btn-warning[disabled]:hover,
+fieldset[disabled] .btn-warning:hover,
+.btn-warning.disabled:focus,
+.btn-warning[disabled]:focus,
+fieldset[disabled] .btn-warning:focus,
+.btn-warning.disabled.focus,
+.btn-warning[disabled].focus,
+fieldset[disabled] .btn-warning.focus,
+.btn-warning.disabled:active,
+.btn-warning[disabled]:active,
+fieldset[disabled] .btn-warning:active,
+.btn-warning.disabled.active,
+.btn-warning[disabled].active,
+fieldset[disabled] .btn-warning.active {
+  background-color: #eb9316;
+  background-image: none;
+}
+.btn-danger {
+  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+  background-image:      -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
+  background-image:         linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+  background-color: #c12e2a;
+  background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+  background-color: #c12e2a;
+  border-color: #b92c28;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+fieldset[disabled] .btn-danger,
+.btn-danger.disabled:hover,
+.btn-danger[disabled]:hover,
+fieldset[disabled] .btn-danger:hover,
+.btn-danger.disabled:focus,
+.btn-danger[disabled]:focus,
+fieldset[disabled] .btn-danger:focus,
+.btn-danger.disabled.focus,
+.btn-danger[disabled].focus,
+fieldset[disabled] .btn-danger.focus,
+.btn-danger.disabled:active,
+.btn-danger[disabled]:active,
+fieldset[disabled] .btn-danger:active,
+.btn-danger.disabled.active,
+.btn-danger[disabled].active,
+fieldset[disabled] .btn-danger.active {
+  background-color: #c12e2a;
+  background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+  background-color: #e8e8e8;
+  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+  background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+  background-color: #2e6da4;
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+  background-repeat: repeat-x;
+}
+.navbar-default {
+  background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+  background-image:      -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+  background-image:         linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-radius: 4px;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+  background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+  background-image:      -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+  background-image:         linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+  background-repeat: repeat-x;
+  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+  text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+  background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+  background-image:      -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
+  background-image:         linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+  background-repeat: repeat-x;
+  border-radius: 4px;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+  background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+  background-image:      -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
+  background-image:         linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
+  background-repeat: repeat-x;
+  -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+          box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+  border-radius: 0;
+}
+@media (max-width: 767px) {
+  .navbar .navbar-nav .open .dropdown-menu > .active > a,
+  .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+  .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+    color: #fff;
+    background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+    background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+    background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+    background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+    background-repeat: repeat-x;
+  }
+}
+.alert {
+  text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+  background-image:      -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
+  background-image:         linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #b2dba1;
+}
+.alert-info {
+  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+  background-image:      -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
+  background-image:         linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #9acfea;
+}
+.alert-warning {
+  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
+  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #f5e79e;
+}
+.alert-danger {
+  background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+  background-image:      -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
+  background-image:         linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #dca7a7;
+}
+.progress {
+  background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+  background-image:      -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+  background-image:         linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar {
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #286090 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #286090 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-success {
+  background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+  background-image:      -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
+  background-image:         linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-info {
+  background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+  background-image:      -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
+  background-image:         linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-warning {
+  background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+  background-image:      -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
+  background-image:         linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-danger {
+  background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+  background-image:      -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
+  background-image:         linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+  background-repeat: repeat-x;
+}
+.progress-bar-striped {
+  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:      -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+  background-image:         linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+  border-radius: 4px;
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+  text-shadow: 0 -1px 0 #286090;
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #2b669a;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+  text-shadow: none;
+}
+.panel {
+  -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+          box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image:      -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+  background-image:         linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image:      -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+  background-image:         linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+  background-image:      -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
+  background-image:         linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+  background-image:      -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
+  background-image:         linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+  background-image:      -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
+  background-image:         linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+  background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+  background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+  background-image:      -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
+  background-image:         linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+  background-repeat: repeat-x;
+}
+.well {
+  background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+  background-image:      -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+  background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+  background-image:         linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+  background-repeat: repeat-x;
+  border-color: #dcdcdc;
+  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+          box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 6760 - 0
JobService/src/main/resources/static/css/bootstrap.css


+ 34 - 0
JobService/src/main/resources/static/css/prvncFtpToFileSystemConfigList.css

@@ -0,0 +1,34 @@
+.task_run{
+    color:#5cb85c;
+}
+.task_stop{
+    color:#d9534f;
+}
+.required{
+    font-size:6px;
+    color:#d9534f;
+}
+.nopaddingright{
+    padding-right:0px;
+}
+.loading{
+    width:160px;
+    height:56px;
+    position: absolute;
+    top:50%;
+    left:50%;
+    line-height:56px;
+    color:#fff;
+    padding-left:60px;
+    font-size:15px;
+    background: #000 url(../images/loader.gif) no-repeat 10px 50%;
+    opacity: 0.7;
+    z-index:9999;
+    -moz-border-radius:20px;
+    -webkit-border-radius:20px;
+    border-radius:20px;
+    filter:progid:DXImageTransform.Microsoft.Alpha(opacity=70);
+}
+.modal-dialog-task{
+    width:80%;
+}

+ 656 - 0
JobService/src/main/resources/static/js/bootstrap-paginator.js

@@ -0,0 +1,656 @@
+/**
+ * bootstrap-paginator.js v0.5
+ * --
+ * Copyright 2013 Yun Lai <lyonlai1984@gmail.com>
+ * --
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function ($) {
+
+    "use strict"; // jshint ;_;
+
+
+    /* Paginator PUBLIC CLASS DEFINITION
+     * ================================= */
+
+    /**
+     * Boostrap Paginator Constructor
+     *
+     * @param element element of the paginator
+     * @param options the options to config the paginator
+     *
+     * */
+    var BootstrapPaginator = function (element, options) {
+        this.init(element, options);
+    },
+        old = null;
+
+    BootstrapPaginator.prototype = {
+
+        /**
+         * Initialization function of the paginator, accepting an element and the options as parameters
+         *
+         * @param element element of the paginator
+         * @param options the options to config the paginator
+         *
+         * */
+        init: function (element, options) {
+
+            this.$element = $(element);
+
+            var version = (options && options.bootstrapMajorVersion) ? options.bootstrapMajorVersion : $.fn.bootstrapPaginator.defaults.bootstrapMajorVersion,
+                id = this.$element.attr("id");
+            if (version === 2 && !this.$element.is("div")) {
+
+                throw "in Bootstrap version 2 the pagination must be a div element. Or if you are using Bootstrap pagination 3. Please specify it in bootstrapMajorVersion in the option";
+            } else if (version > 2 && !this.$element.is("ul")) {
+                throw "in Bootstrap version 3 the pagination root item must be an ul element."
+            }
+
+
+
+            this.currentPage = 1;
+
+            this.lastPage = 1;
+
+            this.setOptions(options);
+
+            this.initialized = true;
+        },
+
+        /**
+         * Update the properties of the paginator element
+         *
+         * @param options options to config the paginator
+         * */
+        setOptions: function (options) {
+
+            this.options = $.extend({}, (this.options || $.fn.bootstrapPaginator.defaults), options);
+
+            this.totalPages = parseInt(this.options.totalPages, 10);  //setup the total pages property.
+            this.numberOfPages = parseInt(this.options.numberOfPages, 10); //setup the numberOfPages to be shown
+
+            //move the set current page after the setting of total pages. otherwise it will cause out of page exception.
+            if (options && typeof (options.currentPage)  !== 'undefined') {
+
+                this.setCurrentPage(options.currentPage);
+            }
+
+            this.listen();
+
+            //render the paginator
+            this.render();
+
+            if (!this.initialized && this.lastPage !== this.currentPage) {
+                this.$element.trigger("page-changed", [this.lastPage, this.currentPage]);
+            }
+
+        },
+
+        /**
+         * Sets up the events listeners. Currently the pageclicked and pagechanged events are linked if available.
+         *
+         * */
+        listen: function () {
+
+            this.$element.off("page-clicked");
+
+            this.$element.off("page-changed");// unload the events for the element
+
+            if (typeof (this.options.onPageClicked) === "function") {
+                this.$element.bind("page-clicked", this.options.onPageClicked);
+            }
+
+            if (typeof (this.options.onPageChanged) === "function") {
+                this.$element.on("page-changed", this.options.onPageChanged);
+            }
+
+            this.$element.bind("page-clicked", this.onPageClicked);
+        },
+
+
+        /**
+         *
+         *  Destroys the paginator element, it unload the event first, then empty the content inside.
+         *
+         * */
+        destroy: function () {
+
+            this.$element.off("page-clicked");
+
+            this.$element.off("page-changed");
+
+            this.$element.removeData('bootstrapPaginator');
+
+            this.$element.empty();
+
+        },
+
+        /**
+         * Shows the page
+         *
+         * */
+        show: function (page) {
+
+            this.setCurrentPage(page);
+
+            this.render();
+
+            if (this.lastPage !== this.currentPage) {
+                this.$element.trigger("page-changed", [this.lastPage, this.currentPage]);
+            }
+        },
+
+        /**
+         * Shows the next page
+         *
+         * */
+        showNext: function () {
+            var pages = this.getPages();
+
+            if (pages.next) {
+                this.show(pages.next);
+            }
+
+        },
+
+        /**
+         * Shows the previous page
+         *
+         * */
+        showPrevious: function () {
+            var pages = this.getPages();
+
+            if (pages.prev) {
+                this.show(pages.prev);
+            }
+
+        },
+
+        /**
+         * Shows the first page
+         *
+         * */
+        showFirst: function () {
+            var pages = this.getPages();
+
+            if (pages.first) {
+                this.show(pages.first);
+            }
+
+        },
+
+        /**
+         * Shows the last page
+         *
+         * */
+        showLast: function () {
+            var pages = this.getPages();
+
+            if (pages.last) {
+                this.show(pages.last);
+            }
+
+        },
+
+        /**
+         * Internal on page item click handler, when the page item is clicked, change the current page to the corresponding page and
+         * trigger the pageclick event for the listeners.
+         *
+         *
+         * */
+        onPageItemClicked: function (event) {
+
+            var type = event.data.type,
+                page = event.data.page;
+
+            this.$element.trigger("page-clicked", [event, type, page]);
+
+        },
+
+        onPageClicked: function (event, originalEvent, type, page) {
+
+            //show the corresponding page and retrieve the newly built item related to the page clicked before for the event return
+
+            var currentTarget = $(event.currentTarget);
+
+            switch (type) {
+            case "first":
+                currentTarget.bootstrapPaginator("showFirst");
+                break;
+            case "prev":
+                currentTarget.bootstrapPaginator("showPrevious");
+                break;
+            case "next":
+                currentTarget.bootstrapPaginator("showNext");
+                break;
+            case "last":
+                currentTarget.bootstrapPaginator("showLast");
+                break;
+            case "page":
+                currentTarget.bootstrapPaginator("show", page);
+                break;
+            }
+
+        },
+
+        /**
+         * Renders the paginator according to the internal properties and the settings.
+         *
+         *
+         * */
+        render: function () {
+
+            //fetch the container class and add them to the container
+            var containerClass = this.getValueFromOption(this.options.containerClass, this.$element),
+                size = this.options.size || "normal",
+                alignment = this.options.alignment || "left",
+                pages = this.getPages(),
+                listContainer = this.options.bootstrapMajorVersion === 2 ? $("<ul></ul>") : this.$element,
+                listContainerClass = this.options.bootstrapMajorVersion === 2 ? this.getValueFromOption(this.options.listContainerClass, listContainer) : null,
+                first = null,
+                prev = null,
+                next = null,
+                last = null,
+                p = null,
+                i = 0;
+
+
+            this.$element.prop("class", "");
+
+            this.$element.addClass("pagination");
+
+            switch (size.toLowerCase()) {
+            case "large":
+            case "small":
+            case "mini":
+                this.$element.addClass($.fn.bootstrapPaginator.sizeArray[this.options.bootstrapMajorVersion][size.toLowerCase()]);
+                break;
+            default:
+                break;
+            }
+
+            if (this.options.bootstrapMajorVersion === 2) {
+                switch (alignment.toLowerCase()) {
+                case "center":
+                    this.$element.addClass("pagination-centered");
+                    break;
+                case "right":
+                    this.$element.addClass("pagination-right");
+                    break;
+                default:
+                    break;
+                }
+            }
+
+
+            this.$element.addClass(containerClass);
+
+            //empty the outter most container then add the listContainer inside.
+            this.$element.empty();
+
+            if (this.options.bootstrapMajorVersion === 2) {
+                this.$element.append(listContainer);
+
+                listContainer.addClass(listContainerClass);
+            }
+
+            //update the page element reference
+            this.pageRef = [];
+
+            if (pages.first) {//if the there is first page element
+                first = this.buildPageItem("first", pages.first);
+
+                if (first) {
+                    listContainer.append(first);
+                }
+
+            }
+
+            if (pages.prev) {//if the there is previous page element
+
+                prev = this.buildPageItem("prev", pages.prev);
+
+                if (prev) {
+                    listContainer.append(prev);
+                }
+
+            }
+
+
+            for (i = 0; i < pages.length; i = i + 1) {//fill the numeric pages.
+
+                p = this.buildPageItem("page", pages[i]);
+
+                if (p) {
+                    listContainer.append(p);
+                }
+            }
+
+            if (pages.next) {//if there is next page
+
+                next = this.buildPageItem("next", pages.next);
+
+                if (next) {
+                    listContainer.append(next);
+                }
+            }
+
+            if (pages.last) {//if there is last page
+
+                last = this.buildPageItem("last", pages.last);
+
+                if (last) {
+                    listContainer.append(last);
+                }
+            }
+        },
+
+        /**
+         *
+         * Creates a page item base on the type and page number given.
+         *
+         * @param page page number
+         * @param type type of the page, whether it is the first, prev, page, next, last
+         *
+         * @return Object the constructed page element
+         * */
+        buildPageItem: function (type, page) {
+
+            var itemContainer = $("<li></li>"),//creates the item container
+                itemContent = $("<a></a>"),//creates the item content
+                text = "",
+                title = "",
+                itemContainerClass = this.options.itemContainerClass(type, page, this.currentPage),
+                itemContentClass = this.getValueFromOption(this.options.itemContentClass, type, page, this.currentPage),
+                tooltipOpts = null;
+
+
+            switch (type) {
+
+            case "first":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "last":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "prev":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "next":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            case "page":
+                if (!this.getValueFromOption(this.options.shouldShowPage, type, page, this.currentPage)) { return; }
+                text = this.options.itemTexts(type, page, this.currentPage);
+                title = this.options.tooltipTitles(type, page, this.currentPage);
+                break;
+            }
+
+            itemContainer.addClass(itemContainerClass).append(itemContent);
+
+            itemContent.addClass(itemContentClass).html(text).on("click", null, {type: type, page: page}, $.proxy(this.onPageItemClicked, this));
+
+            if (this.options.pageUrl) {
+                itemContent.attr("href", this.getValueFromOption(this.options.pageUrl, type, page, this.currentPage));
+            }
+
+            if (this.options.useBootstrapTooltip) {
+                tooltipOpts = $.extend({}, this.options.bootstrapTooltipOptions, {title: title});
+
+                itemContent.tooltip(tooltipOpts);
+            } else {
+                itemContent.attr("title", title);
+            }
+
+            return itemContainer;
+
+        },
+
+        setCurrentPage: function (page) {
+            if (page > this.totalPages || page < 1) {// if the current page is out of range, throw exception.
+
+                throw "Page out of range";
+
+            }
+
+            this.lastPage = this.currentPage;
+
+            this.currentPage = parseInt(page, 10);
+
+        },
+
+        /**
+         * Gets an array that represents the current status of the page object. Numeric pages can be access via array mode. length attributes describes how many numeric pages are there. First, previous, next and last page can be accessed via attributes first, prev, next and last. Current attribute marks the current page within the pages.
+         *
+         * @return object output objects that has first, prev, next, last and also the number of pages in between.
+         * */
+        getPages: function () {
+
+            var totalPages = this.totalPages,// get or calculate the total pages via the total records
+                pageStart = (this.currentPage % this.numberOfPages === 0) ? (parseInt(this.currentPage / this.numberOfPages, 10) - 1) * this.numberOfPages + 1 : parseInt(this.currentPage / this.numberOfPages, 10) * this.numberOfPages + 1,//calculates the start page.
+                output = [],
+                i = 0,
+                counter = 0;
+
+            pageStart = pageStart < 1 ? 1 : pageStart;//check the range of the page start to see if its less than 1.
+
+            for (i = pageStart, counter = 0; counter < this.numberOfPages && i <= totalPages; i = i + 1, counter = counter + 1) {//fill the pages
+                output.push(i);
+            }
+
+            output.first = 1;//add the first when the current page leaves the 1st page.
+
+            if (this.currentPage > 1) {// add the previous when the current page leaves the 1st page
+                output.prev = this.currentPage - 1;
+            } else {
+                output.prev = 1;
+            }
+
+            if (this.currentPage < totalPages) {// add the next page when the current page doesn't reach the last page
+                output.next = this.currentPage + 1;
+            } else {
+                output.next = totalPages;
+            }
+
+            output.last = totalPages;// add the last page when the current page doesn't reach the last page
+
+            output.current = this.currentPage;//mark the current page.
+
+            output.total = totalPages;
+
+            output.numberOfPages = this.options.numberOfPages;
+
+            return output;
+
+        },
+
+        /**
+         * Gets the value from the options, this is made to handle the situation where value is the return value of a function.
+         *
+         * @return mixed value that depends on the type of parameters, if the given parameter is a function, then the evaluated result is returned. Otherwise the parameter itself will get returned.
+         * */
+        getValueFromOption: function (value) {
+
+            var output = null,
+                args = Array.prototype.slice.call(arguments, 1);
+
+            if (typeof value === 'function') {
+                output = value.apply(this, args);
+            } else {
+                output = value;
+            }
+
+            return output;
+
+        }
+
+    };
+
+
+    /* TYPEAHEAD PLUGIN DEFINITION
+     * =========================== */
+
+    old = $.fn.bootstrapPaginator;
+
+    $.fn.bootstrapPaginator = function (option) {
+
+        var args = arguments,
+            result = null;
+
+        $(this).each(function (index, item) {
+            var $this = $(item),
+                data = $this.data('bootstrapPaginator'),
+                options = (typeof option !== 'object') ? null : option;
+
+            if (!data) {
+                data = new BootstrapPaginator(this, options);
+
+                $this = $(data.$element);
+
+                $this.data('bootstrapPaginator', data);
+
+                return;
+            }
+
+            if (typeof option === 'string') {
+
+                if (data[option]) {
+                    result = data[option].apply(data, Array.prototype.slice.call(args, 1));
+                } else {
+                    throw "Method " + option + " does not exist";
+                }
+
+            } else {
+                result = data.setOptions(option);
+            }
+        });
+
+        return result;
+
+    };
+
+    $.fn.bootstrapPaginator.sizeArray = {
+
+        "2": {
+            "large": "pagination-large",
+            "small": "pagination-small",
+            "mini": "pagination-mini"
+        },
+        "3": {
+            "large": "pagination-lg",
+            "small": "pagination-sm",
+            "mini": ""
+        }
+
+    };
+
+    $.fn.bootstrapPaginator.defaults = {
+        containerClass: "",
+        size: "normal",
+        alignment: "left",
+        bootstrapMajorVersion: 2,
+        listContainerClass: "",
+        itemContainerClass: function (type, page, current) {
+            return (page === current) ? "active" : "";
+        },
+        itemContentClass: function (type, page, current) {
+            return "";
+        },
+        currentPage: 1,
+        numberOfPages: 5,
+        totalPages: 1,
+        pageUrl: function (type, page, current) {
+            return null;
+        },
+        onPageClicked: null,
+        onPageChanged: null,
+        useBootstrapTooltip: false,
+        shouldShowPage: function (type, page, current) {
+
+            var result = true;
+
+            switch (type) {
+            case "first":
+                result = (current !== 1);
+                break;
+            case "prev":
+                result = (current !== 1);
+                break;
+            case "next":
+                result = (current !== this.totalPages);
+                break;
+            case "last":
+                result = (current !== this.totalPages);
+                break;
+            case "page":
+                result = true;
+                break;
+            }
+
+            return result;
+
+        },
+        itemTexts: function (type, page, current) {
+            switch (type) {
+            case "first":
+                return "&lt;&lt;";
+            case "prev":
+                return "&lt;";
+            case "next":
+                return "&gt;";
+            case "last":
+                return "&gt;&gt;";
+            case "page":
+                return page;
+            }
+        },
+        tooltipTitles: function (type, page, current) {
+
+            switch (type) {
+            case "first":
+                return "Go to first page";
+            case "prev":
+                return "Go to previous page";
+            case "next":
+                return "Go to next page";
+            case "last":
+                return "Go to last page";
+            case "page":
+                return (page === current) ? "Current page is " + page : "Go to page " + page;
+            }
+        },
+        bootstrapTooltipOptions: {
+            animation: true,
+            html: true,
+            placement: 'top',
+            selector: false,
+            title: "",
+            container: false
+        }
+    };
+
+    $.fn.bootstrapPaginator.Constructor = BootstrapPaginator;
+
+
+
+}(window.jQuery));

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 2363 - 0
JobService/src/main/resources/static/js/bootstrap.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 7 - 0
JobService/src/main/resources/static/js/bootstrap.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 5 - 0
JobService/src/main/resources/static/js/jquery.min.js


+ 703 - 0
JobService/src/main/resources/static/js/prvncFtpToFileSystemConfigList.js

@@ -0,0 +1,703 @@
+$(document).ready(function(){
+  // 开始加载数据(任务数据)
+    loadTaskData();
+});
+/**
+ * 加载任务数据(分页查询)
+ */
+function loadTaskDataPage(curPage){
+	$.ajax({
+	      type: 'POST',
+	      url: '../FtpToFileSystem_queryFtpItems.action',
+	      data: {
+	    	curPage:curPage
+	      },
+	      dataType: 'json',
+	      success: function(data){
+	        // 成功时运行
+	        dealQueryData(data);
+	      },
+	      error:function(data){
+	        // 失败时运行,目前不处理
+	          $('#alertContext').html('网络超时!查询数据失败'+data);
+	          $('#alertModal').modal('show');
+	          return;
+	      }
+	    });
+}
+
+// 加载任务数据(主要是查询首页)
+function loadTaskData(){
+	// 查询首页
+	loadTaskDataPage(1);
+}
+/**
+ * 处理查询数据
+ */
+function dealQueryData(data){
+    var rows = data.rows;
+    var total = data.total;
+    if(rows == '[]' || rows.length == 0){
+    	 $('#tasksContext').html('');
+    	return ;
+    }
+    var trStrs = "";
+    for(var i = 0 ; i< rows.length;i++){
+        trStrs += createHtmlContext(rows[i]);
+        $('#tasksContext').html(trStrs);
+    }
+    //不显示分页
+    if(total == null || total == 1){
+    	return ;
+    }
+    // 处理分页问题
+    dealQueryPage(data);
+}
+// 处理分页问题
+function dealQueryPage(data){
+    var total = data.total;
+    var currentPage = data.currentPage;
+		var options = {
+            currentPage: currentPage,
+            totalPages: total,
+            bootstrapMajorVersion: 3,
+            onPageClicked: function(event, originalEvent, type,page){
+			loadTaskDataPage(page);
+		}
+        }
+        $('#saopPagination').bootstrapPaginator(options);
+	
+}
+function createHtmlContext(taskInfo){
+            var taskId = taskInfo.TASKID;
+            var taskName = taskInfo.TASKNAME;
+            var taskFileName = taskInfo.FILE_NAME;
+            var taskUOrD = taskInfo.U_OR_D;
+            var taskUOrDName = taskInfo.U_OR_D_NAME;
+            var taskRunState = taskInfo.RUN_STATE;
+            var taskRUNFlag = taskInfo.RUN_FLAG;
+            var taskTnum = taskInfo.TNUM;
+            var taskTaskcron = taskInfo.TASKCRON;
+            var taskErrPhone = taskInfo.ERRPHONE;
+            var taskUpnull = taskInfo.UPNULL;
+            var taskPreFlag = taskInfo.PREFLAG;
+            var taskPreFunction = taskInfo.PREFUNCTION;
+            var taskAfterFlag = taskInfo.AFTERFLAG;
+            var taskAfterFunction = taskInfo.AFTERFUNCTION;
+            var taskCreateDate = taskInfo.CREATE_DATE
+            var taskRunStateName = "运行失败";
+
+            if(taskRunState == 'R'){
+                taskRunStateName = "正在执行";
+            }else if(taskRunState == 'T'){
+                taskRunStateName = "等待运行";
+            }
+      var trStr = "<tr>"
+                   +"<td class='text-center'><input type='checkbox' name='choiceCheckBox' id='choice_"+taskId+"' value='"+taskId+"'></td>"
+                   +"<td class='text-center'>"+taskId+"</td>"
+                   +"<td class='text-center'>"+taskName+"</td>"
+                   +"<td class='text-center'>"+taskTaskcron+"</td>"
+                   +"<td class='text-center'>"+taskUOrDName+"</td>"
+                   +"<td class='text-center'>"+taskCreateDate+"</td>"
+                   +"<td class='text-center'>"+taskRunStateName+"</td>";
+       if(taskRUNFlag == "1"){
+                trStr += "<td class='text-center'><span class='glyphicon glyphicon-ok-sign task_run' ></span></td>";
+       }else{
+                trStr +=  "<td class='text-center'><span class='glyphicon glyphicon-remove-sign task_stop' ></span></td>"
+       }
+
+       trStr = trStr
+                + "<td class='text-center'>"+taskTnum+"</td>"
+                + "<td class='text-center'>"
+                + "            <a class='label label-info' href='../prvncFtpfileConfig!queryTaskLogList.action?taskid="+taskId+"' target='_blank'>日志</a>"
+                + "</td>";
+       // 将后台传过来的数据影藏放到页面上
+       trStr = trStr
+                + "<input type='hidden' name='taskName_"+taskId+"' id='taskName_"+taskId+"' value='"+taskName+"'/>"
+                + "<input type='hidden' name='taskFileName_"+taskId+"' id='taskFileName_"+taskId+"' value='"+taskFileName+"'/>"
+                + "<input type='hidden' name='taskUOrD_"+taskId+"' id='taskUOrD_"+taskId+"' value='"+taskUOrD+"'/>"
+                + "<input type='hidden' name='taskUOrDName_"+taskId+"' id='taskUOrDName_"+taskId+"' value='"+taskUOrDName+"'/>"
+                + "<input type='hidden' name='taskRunState_"+taskId+"' id='taskRunState_"+taskId+"' value='"+taskRunState+"'/>"
+                + "<input type='hidden' name='taskRUNFlag_"+taskId+"' id='taskRUNFlag_"+taskId+"' value='"+taskRUNFlag+"'/>"
+                + "<input type='hidden' name='taskTnum_"+taskId+"' id='taskTnum_"+taskId+"' value='"+taskTnum+"'/>"
+                + "<input type='hidden' name='taskTaskcron_"+taskId+"' id='taskTaskcron_"+taskId+"' value='"+taskTaskcron+"'/>"
+                + "<input type='hidden' name='taskErrPhone_"+taskId+"' id='taskErrPhone_"+taskId+"' value='"+taskErrPhone+"'/>"
+                + "<input type='hidden' name='taskUpnull_"+taskId+"' id='taskUpnull_"+taskId+"' value='"+taskUpnull+"'/>"
+                + "<input type='hidden' name='taskPreFlag_"+taskId+"' id='taskPreFlag_"+taskId+"' value='"+taskPreFlag+"'/>"
+                + "<input type='hidden' name='taskPreFunction_"+taskId+"' id='taskPreFunction_"+taskId+"' value='"+taskPreFunction+"'/>"
+                + "<input type='hidden' name='taskAfterFlag_"+taskId+"' id='taskAfterFlag_"+taskId+"' value='"+taskAfterFlag+"'/>"
+                + "<input type='hidden' name='taskAfterFunction_"+taskId+"' id='taskAfterFunction_"+taskId+"' value='"+taskAfterFunction+"'/>"
+                + "<input type='hidden' name='taskCreateDate_"+taskId+"' id='taskCreateDate_"+taskId+"' value='"+taskCreateDate+"'/>";
+       return trStr;
+}
+/**
+ * 启动任务
+ */
+function startJob(){
+    // 显示加载框
+    fadeLoader("ON");
+    // 加载所有checkbox {"tasks":[{"taskId":1},{"taskId":2}],"state":"START"}
+    var requestParam = '{"tasks":['
+    var requestTaskId = '';
+    var runTaskId = '';
+    $("input[name='choiceCheckBox']").each(
+        function(){
+            if($(this).prop('checked')){
+                    // 判断选中的是否已经是启动状态
+                    var taskRUNFlag = $('#taskRUNFlag_'+$(this).val()).val();
+                    // 说明已经启动,提示错误
+                    if(taskRUNFlag == 1){
+                        runTaskId += ($(this).val() + ',');
+                    }
+                   requestTaskId += '{"taskId":'+$(this).val()+'},';
+            }
+        }
+    );
+    if(runTaskId != ''){
+        runTaskId = runTaskId.substring(0,runTaskId.length-1)
+         $('#alertContext').html('任务ID【'+runTaskId+'】已经启动,无需再次启动');
+          $('#alertModal').modal('show');
+          // 关闭加载框
+          fadeLoader("OFF");
+          return;
+    }
+    // 没有选中任何任务
+    if(requestTaskId == ''){
+        $('#alertContext').html('没有选中任何任务');
+            $('#alertModal').modal('show');
+            // 关闭加载框
+            fadeLoader("OFF");
+            return;
+    }
+    requestTaskId = requestTaskId.substring(0,requestTaskId.length-1);
+
+    requestParam += requestTaskId + '],"state":"START"}';
+    // 请求处理
+     $.ajax({
+          type: 'POST',
+          url: '../FtpToFileSystem_startJob.action',
+          data: {
+                ftpItemJson:requestParam
+          },
+          dataType: 'json',
+          success: function(data){
+            // 重新加载数据
+            if(data.RESULT_CODE == '0000'){
+                loadTaskData();
+            }else{
+                $('#alertContext').html(data.RESULT_MSG);
+                $('#alertModal').modal('show');
+            }
+
+            fadeLoader("OFF");
+          },
+          error:function(data){
+            // 失败时运行,目前不处理
+            $('#alertContext').html('启动任务失败!'+data);
+            $('#alertModal').modal('show');
+            fadeLoader("OFF");
+          }
+        });
+    // 关闭加载框
+
+}
+
+/**
+ * 停止任务
+ */
+function stopJob(){
+    // 显示加载框
+   // 显示加载框
+       fadeLoader("ON");
+       // 加载所有checkbox {"tasks":[{"taskId":1},{"taskId":2}],"state":"STOP"}
+       var requestParam = '{"tasks":['
+       var requestTaskId = '';
+       var stopTaskId = '';
+       $("input[name='choiceCheckBox']").each(
+           function(){
+               if($(this).prop('checked')){
+                       var taskRUNFlag = $('#taskRUNFlag_'+$(this).val()).val();
+                       // 说明已经启动,提示错误
+                       if(taskRUNFlag == 0){
+                           stopTaskId += ($(this).val() + ',');
+                       }
+                      requestTaskId += '{"taskId":'+$(this).val()+'},';
+               }
+           }
+       );
+
+        if(stopTaskId != ''){
+               stopTaskId = stopTaskId.substring(0,stopTaskId.length-1)
+                $('#alertContext').html('任务ID【'+stopTaskId+'】已经停止,无需再次停止');
+                 $('#alertModal').modal('show');
+                 // 关闭加载框
+                 fadeLoader("OFF");
+                 return;
+        }
+       // 没有选中任何任务
+       if(requestTaskId == ''){
+           $('#alertContext').html('没有选中任何任务');
+               $('#alertModal').modal('show');
+               // 关闭加载框
+               fadeLoader("OFF");
+               return;
+       }
+       requestTaskId = requestTaskId.substring(0,requestTaskId.length-1);
+
+       requestParam += requestTaskId + '],"state":"STOP"}';
+       // 请求处理
+        $.ajax({
+             type: 'POST',
+             url: '../FtpToFileSystem_stopJob.action',
+             data: {
+                   ftpItemJson:requestParam
+             },
+             dataType: 'json',
+             success: function(data){
+               // 重新加载数据
+               if(data.RESULT_CODE == '0000'){
+                   loadTaskData();
+               }else{
+                   $('#alertContext').html(data.RESULT_MSG);
+                   $('#alertModal').modal('show');
+               }
+
+               fadeLoader("OFF");
+             },
+             error:function(data){
+               // 失败时运行,目前不处理
+               $('#alertContext').html('停止任务失败!'+data);
+               $('#alertModal').modal('show');
+               fadeLoader("OFF");
+             }
+           });
+       // 关闭加载框
+}
+/**
+ * 删除任务配置信息
+ */
+function deleteTask(){
+    // 显示加载框
+        fadeLoader("ON");
+        // 加载所有checkbox {"tasks":[{"taskId":1},{"taskId":2}],"state":"DELETE"}
+        var requestParam = '{"tasks":['
+        var requestTaskId = '';
+        var runTaskId = '';
+        $("input[name='choiceCheckBox']").each(
+            function(){
+                if($(this).prop('checked')){
+                        // 判断选中的是否已经是启动状态
+                        var taskRUNFlag = $('#taskRUNFlag_'+$(this).val()).val();
+                        // 说明已经启动,提示错误
+                        if(taskRUNFlag == 1){
+                            runTaskId += ($(this).val() + ',');
+                        }
+                       requestTaskId += '{"taskId":'+$(this).val()+'},';
+                }
+            }
+        );
+        if(runTaskId != ''){
+            runTaskId = runTaskId.substring(0,runTaskId.length-1)
+             $('#alertContext').html('任务ID【'+runTaskId+'】正在启动,请停止后再操作删除!');
+              $('#alertModal').modal('show');
+              // 关闭加载框
+              fadeLoader("OFF");
+              return;
+        }
+        // 没有选中任何任务
+        if(requestTaskId == ''){
+            $('#alertContext').html('没有选中任何任务');
+                $('#alertModal').modal('show');
+                // 关闭加载框
+                fadeLoader("OFF");
+                return;
+        }
+        requestTaskId = requestTaskId.substring(0,requestTaskId.length-1);
+
+        requestParam += requestTaskId + '],"state":"DELETE"}';
+        // 请求处理
+         $.ajax({
+              type: 'POST',
+              url: '../FtpToFileSystem_deleteFtpItem.action',
+              data: {
+                    ftpItemJson:requestParam
+              },
+              dataType: 'json',
+              success: function(data){
+                // 重新加载数据
+                if(data.RESULT_CODE == '0000'){
+                    loadTaskData();
+                }else{
+                    $('#alertContext').html(data.RESULT_MSG);
+                    $('#alertModal').modal('show');
+                }
+
+                fadeLoader("OFF");
+              },
+              error:function(data){
+                // 失败时运行,目前不处理
+                $('#alertContext').html('删除任务失败!'+data);
+                $('#alertModal').modal('show');
+                fadeLoader("OFF");
+              }
+            });
+        // 关闭加载框
+}
+/** 新增任务* */
+function newTask(){
+    $('#newTaskModal').modal('show').css({
+                        width: 'auto'
+                    });
+    // 清除老值
+    clearNewTaskInputValue();
+}
+/**
+ * 打开新的新增任务时需要清除原前的值。
+ */
+function clearNewTaskInputValue(){
+    $('#taskNameNew').val('');
+    $('#taskCronNew').val('');
+    $('#tNumNew').val('');
+    $('#upNulNew').val('');
+    $('#errPhoneNew').val('');
+    $('#preFlagNew').val('');
+    $('#preFunctionNew').val('');
+    $('#afterFlagNew').val('');
+    $('#afterFunctionNew').val('');
+    $('#uOrDNew').val('');
+    $('#fileNameNew').val('');
+
+    $("div[name='taskAttrsNew']").remove();
+
+    $('#error_alert_divNew').attr('class','alert alert-danger alert-dismissible hidden');
+}
+/** 编辑任务* */
+function editTask(){
+    var choiceCheckBoxCount = 0;
+    var taskId = 0;
+     $("input[name='choiceCheckBox']").each(
+                function(){
+                    if($(this).prop('checked')){
+                       choiceCheckBoxCount ++;
+                       taskId = $(this).val();
+                    }
+                }
+            );
+     if(choiceCheckBoxCount > 1){
+         $('#alertContext').html('编辑时只能选中一个任务操作,目前选中了【'+choiceCheckBoxCount+'】');
+          $('#alertModal').modal('show');
+          return ;
+     }
+     if(choiceCheckBoxCount < 1){
+         $('#alertContext').html('请选中一个任务,进行编辑!');
+         $('#alertModal').modal('show');
+         return ;
+     }
+
+    // 清除以前的数据
+    clearEditTaskInputValue();
+
+    // 将选中的数据填充值编辑面板
+    fillEditTaskInputValue(taskId);
+
+    $('#editTaskModal').modal('show').css({
+                            width: 'auto'
+                        });
+}
+
+/**
+ * 打开新的编辑任务时需要清除原前的值。
+ */
+function clearEditTaskInputValue(){
+    $('#taskIdEdit').val('');
+    $('#taskNameEdit').val('');
+    $('#taskCronEdit').val('');
+    $('#tNumEdit').val('');
+    $('#upNulEdit').val('');
+    $('#errPhoneEdit').val('');
+    $('#preFlagEdit').val('');
+    $('#preFunctionEdit').val('');
+    $('#afterFlagEdit').val('');
+    $('#afterFunctionEdit').val('');
+    $('#uOrDEdit').val('');
+    $('#fileNameEdit').val('');
+
+    $("div[name='taskAttrsEdit']").remove();
+    $('#error_alert_divEdit').attr('class','alert alert-danger alert-dismissible hidden');
+}
+/**
+ * 将选中的数据填充值编辑面板
+ */
+function fillEditTaskInputValue(taskId){
+    $('#taskIdEdit').val(taskId);
+    $('#taskNameEdit').val($('#taskName_'+taskId).val());
+    $('#taskCronEdit').val($('#taskTaskcron_'+taskId).val());
+    $('#tNumEdit').val($('#taskTnum_'+taskId).val());
+    $('#upNulEdit').val($('#taskUpNul_'+taskId).val());
+    $('#errPhoneEdit').val($('#taskErrPhone_'+taskId).val());
+    $('#upNulEdit').val($('#taskUpnull_'+taskId).val());
+    $('#preFlagEdit').val($('#taskPreFlag_'+taskId).val());
+    $('#preFunctionEdit').val($('#taskPreFunction_'+taskId).val());
+    $('#afterFlagEdit').val($('#taskAfterFlag_'+taskId).val());
+    $('#afterFunctionEdit').val($('#taskAfterFunction_'+taskId).val());
+    $('#uOrDEdit').val($('#taskUOrD_'+taskId).val());
+    $('#fileNameEdit').val($('#taskFileName_'+taskId).val());
+    // 根据当前的模板查询
+    var obj = new Object();
+    obj.value=$('#taskUOrD_'+taskId).val();
+    obj.taskId = taskId;
+    queryTaskAttr(obj,'Edit');  
+}
+/**
+ * 获取属性值
+ */
+function queryTaskAttrData(taskId){
+
+        var requestParam = "{'taskId':"+taskId+"}";
+
+        $.ajax({
+          type: 'POST',
+          url: '../FtpToFileSystem_queryTaskAttrs.action',
+          data: {
+                ftpItemJson:requestParam
+          },
+          dataType: 'json',
+          success: function(data){
+            // 重新加载数据
+            if(data.RESULT_CODE == '0000'){
+                // 将模板显示在新建任务面板上
+                fillEditTaskAttrInputValue(data);
+            }else{
+                $('#alertContext').html(data.RESULT_MSG);
+                $('#alertModal').modal('show');
+            }
+            fadeLoader("OFF");
+          },
+          error:function(data){
+            // 失败时运行,目前不处理
+            $('#alertContext').html('加载模板失败,可能是没有配置模板!'+data);
+            $('#alertModal').modal('show');
+            fadeLoader("OFF");
+          }
+        });
+}
+
+function fillEditTaskAttrInputValue(data){
+    var resultInfo = eval("("+data.RESULT_INFO+")");
+
+    var taskAttrs = resultInfo.TASK_ATTRS;
+
+    for(var taskAttrIndex = 0 ;taskAttrIndex < taskAttrs.length;taskAttrIndex ++){
+        var taskAttr = taskAttrs[taskAttrIndex];
+        var itemSpecCd = taskAttr.ITEM_SPEC_ID;
+        var value = taskAttr.VALUE;
+
+        $('#'+itemSpecCd+'Edit').val(value);
+    }
+}
+/**
+ * 获取任务属性
+ */
+function queryTaskAttr(obj,doType){
+
+    if(obj == null) {
+        return ;
+    }
+
+    var taskTample = obj.value;
+
+    var requestParam = "{'uOrD':'"+taskTample+"'}";
+    // 请求处理
+     $.ajax({
+          type: 'POST',
+          url: '../FtpToFileSystem_questTaskTample.action',
+          data: {
+                ftpItemJson:requestParam
+          },
+          dataType: 'json',
+          success: function(data){
+            // 重新加载数据
+            if(data.RESULT_CODE == '0000'){
+                // 将模板显示在新建任务面板上
+                showTample(eval("("+data.RESULT_INFO+")"),doType);
+                if(doType == "Edit"){ // 如果是编辑,填充数据
+                	// 调用后台查询对应数据填充属性
+                    queryTaskAttrData(obj.taskId);  	
+                }
+            }else{
+                $('#alertContext').html(data.RESULT_MSG);
+                $('#alertModal').modal('show');
+            }
+            fadeLoader("OFF");
+          },
+          error:function(data){
+            // 失败时运行,目前不处理
+            $('#alertContext').html('加载模板失败,可能是没有配置模板!'+data);
+            $('#alertModal').modal('show');
+            fadeLoader("OFF");
+          }
+        });
+}
+/**
+ * 显示模板
+ */
+function showTample(obj,doType){
+    var taskTample = obj.U_OR_D;
+    var taskItems = obj.TASK_ITEMS;
+    var taskAttrs = "";
+    for(var itemIntex = 0 ;itemIntex < taskItems.length; itemIntex++){
+        if(itemIntex % 3 == 0){
+            taskAttrs += "<div class='row' name='taskAttrs"+doType+"'>";
+        }
+        taskAttrs = taskAttrs
+                  + "<div class='col-md-4 form-group form-horizontal'>"
+                  + "<label class='col-md-4 control-label'>"+taskItems[itemIntex].NAME+":</label>"
+                  + "<div class='col-md-8'>"
+                  + "<input type='text' class='form-control' name='"+taskItems[itemIntex].ITEM_SPEC_CD+doType+"' id='"+taskItems[itemIntex].ITEM_SPEC_CD+doType+"'  placeholder='"+taskItems[itemIntex].DESCRIBE+"'/>"
+                  + "</div>"
+                  + "</div>";
+        if(itemIntex % 3 == 2){
+             taskAttrs += "</div>";
+         }
+    }
+    // 判断最后一行如果不够三个时需要加</div>的情况
+    if(taskItems.length % 3 != 0){
+        taskAttrs += "</div>";
+    }
+    $("div[name='taskAttrs"+doType+"']").remove();
+    $('#lastTastInfoDiv'+doType).after(taskAttrs);
+}
+/**
+ * 保存任务信息
+ */
+function saveTaskInfo(doType){
+
+    var taskNameNew = $('#taskName'+doType).val();
+    var taskCronNew = $('#taskCron'+doType).val();
+    var tNumNew = $('#tNum'+doType).val();
+    var upNulNew = $('#upNul'+doType).val();
+    var errPhoneNew = $('#errPhone'+doType).val();
+    var preFlagNew = $('#preFlag'+doType).val();
+    var preFunctionNew = $('#preFunction'+doType).val();
+    var afterFlagNew = $('#afterFlag'+doType).val();
+    var afterFunctionNew = $('#afterFunction'+doType).val();
+    var uOrDNew = $('#uOrD'+doType).val();
+    var fileNameNew = $('#fileName'+doType).val();
+    var taskId = -1;
+    var url = "../FtpToFileSystem_addFtpItem.action";// 新增时的URL
+    if(doType == 'Edit'){
+        url = '../FtpToFileSystem_editFtpItem.action';// 编辑时的URL
+        taskId = $('#taskId'+doType).val();
+    }
+    var taskAttrsInputs = $("div[name='taskAttrs"+doType+"'] input");
+    var taskAttrs = "["; // 任务属性#itemSpecId#,#value#
+    for(var taskAttrInputIndex = 0 ; taskAttrInputIndex < taskAttrsInputs.length;taskAttrInputIndex++){
+           var taskAttrsInput = taskAttrsInputs[taskAttrInputIndex];
+           taskAttrs += ('{"itemSpecId":"'+$(taskAttrsInput).attr('name').substring(0,$(taskAttrsInput).attr('name').length-doType.length)+'","value":"'+$(taskAttrsInput).val()+'"},');
+    }
+    // 模板配置有问题,无法获取属性信息
+    if(taskAttrs.length == 1){
+        $('#errorAlertInfo'+doType).html("模板配置有问题,无法获取属性信息,请联系管理员");
+        $('#error_alert_div'+doType).attr('class','alert alert-danger alert-dismissible show');
+        return;
+    }
+
+    taskAttrs = taskAttrs.substring(0,taskAttrs.length-1) + "]";
+
+     // 组装参数
+    var taskInfo = '{"taskId":'+taskId+',"taskName":"'+taskNameNew+'","taskCron":"'+taskCronNew+'","tNum":"'
+                        +tNumNew+'","upNull":"'+upNulNew+'","errPhone":"'+errPhoneNew+'","preFlag":"'
+                        +preFlagNew+'","preFunction":"'+preFunctionNew+'","afterFlag":"'+afterFlagNew+'","afterFunction":"'
+                        +afterFunctionNew+'","uOrD":"'+uOrDNew+'","fileName":"'+fileNameNew+'"}';
+    var requestParam = '{"taskInfo":'+taskInfo+',"taskAttrs":'+taskAttrs+'}'
+    var validateObj = validate(requestParam);
+    if(validateObj.RESULT_CODE != 0){ // 校验失败
+        $('#errorAlertInfo'+doType).html(validateObj.RESULT_MSG);
+        $('#error_alert_div'+doType).attr('class','alert alert-danger alert-dismissible show');
+        return;
+    }
+    fadeLoader("ON");
+
+    // 请求处理
+     $.ajax({
+          type: 'POST',
+          url: url,
+          data: {
+                ftpItemJson:requestParam
+          },
+          dataType: 'json',
+          success: function(data){
+            // 重新加载数据
+            if(data.RESULT_CODE == '0000'){
+                // 将模板显示在新建任务面板上
+                if(doType == 'Edit'){
+                    $('#editTaskModal').modal('hide');
+                }else{
+                    $('#newTaskModal').modal('hide');
+                }
+                loadTaskData();
+            }else{
+                $('#errorAlertInfo'+doType).html(data.RESULT_MSG);
+                $('#error_alert_div'+doType).attr('class','alert alert-danger alert-dismissible show');
+            }
+            fadeLoader("OFF");
+          },
+          error:function(data){
+            // 失败时运行,目前不处理
+            $('#errorAlertInfo'+doType).html(data.RESULT_MSG);
+            $('#error_alert_div'+doType).attr('class','alert alert-danger alert-dismissible show');
+            fadeLoader("OFF");
+          }
+        });
+}
+/**
+ * 根据任务名称或任务ID模糊查询
+ * @return
+ */
+function searchTaskByNameOrId(){
+	var taskName = $('#taskName').val();
+	
+	if(taskName == null || taskName == ''){
+		loadTaskDataPage(1);
+		return ;
+	}
+	var requestParam = '{"taskName":"'+taskName+'"}';
+	$.ajax({
+	      type: 'POST',
+	      url: '../FtpToFileSystem_searchTaskByNameOrId.action',
+	      data: {
+			ftpItemJson:requestParam
+	      },
+	      dataType: 'json',
+	      success: function(data){
+	        // 成功时运行
+	        dealQueryData(data);
+	      },
+	      error:function(data){
+	        // 失败时运行,目前不处理
+	          $('#alertContext').html('网络超时!查询数据失败'+data);
+	          $('#alertModal').modal('show');
+	          return;
+	      }
+	    });
+
+}
+/**
+ * 校验
+ */
+function validate(requestParam){
+    var validateObj = new Object();
+    validateObj.RESULT_CODE = 0;
+    validateObj.RESULT_MSG = '文件名称错误,请仔细检查';
+    return validateObj;
+}
+
+/** 加载层* */
+function fadeLoader(data){
+    if(data == 'ON'){
+        $('#loader').show();
+    }else{
+        $('#loader').hide();
+    }
+}
+

+ 549 - 0
JobService/src/main/resources/static/jsp/prvncFtpToFileSystemConfigList.jsp

@@ -0,0 +1,549 @@
+<%@ page language="java" pageEncoding="UTF-8"%>
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<title>能力开放平台-通用FTP数据文件与TFS传接</title>
+		<!--    <link rel="stylesheet" href="../ftpcss/bootstrap-combined.min.css"/>-->
+		<link rel="stylesheet" href="../css/bootstrap.min.css" />
+		<link rel="stylesheet"
+			href="../css/prvncFtpToFileSystemConfigList.css" />
+	</head>
+	<body>
+		<nav class="navbar navbar-default" role="navigation">
+		<div class="container">
+			<div class="row">
+				<div class="col-md-4">
+					<p class="navbar-text">
+						<span>位置:</span>
+						<a href="../">能力开放平台</a>
+						<span class="glyphicon glyphicon-menu-right "
+							style="font-size: 6px;"></span>
+						<span>通用FTP数据文件与TFS传接</span>
+					</p>
+				</div>
+			</div>
+		</div>
+		</nav>
+		<div class="container">
+			<div class="row">
+				<div class="col-md-3">
+					<div class="input-group">
+						<input type="text" id="taskName" class="form-control"
+							placeholder="请输入任务名称或任务ID">
+						<span class="input-group-btn">
+							<button class="btn btn-default" type="button" onclick="searchTaskByNameOrId()">
+								查询
+							</button> </span>
+					</div>
+				</div>
+				<div class="col-md-5">
+				</div>
+				<div class="col-md-4">
+					<div class="col-md-2">
+						<button class="btn btn-success" type="button" onclick="startJob()">
+							启动
+						</button>
+					</div>
+					<div class="col-md-2">
+						<button class="btn btn-danger" type="button" onclick="stopJob()">
+							停止
+						</button>
+					</div>
+					<div class="col-md-2">
+						<button class="btn btn-primary" type="button" onclick="newTask()">
+							新增
+						</button>
+					</div>
+					<div class="col-md-2">
+						<button class="btn btn-info" type="button" onclick="editTask()">
+							编辑
+						</button>
+					</div>
+					<div class="col-md-2">
+						<button class="btn btn-warning" type="button"
+							onclick="deleteTask()">
+							删除
+						</button>
+					</div>
+				</div>
+
+			</div>
+
+		</div>
+
+		<div class="container" style="margin-top: 20px">
+			<table class="table table-bordered table-hover">
+				<thead>
+					<tr class="active">
+						<th class="text-center">
+							选择
+						</th>
+						<th class="text-center">
+							任务ID
+						</th>
+						<th class="text-center">
+							任务名称
+						</th>
+						<th class="text-center">
+							运行时间
+						</th>
+						<th class="text-center">
+							传输类型
+						</th>
+						<th class="text-center">
+							创建时间
+						</th>
+						<th class="text-center">
+							运行状态
+						</th>
+						<th class="text-center">
+							启停状态
+						</th>
+						<th class="text-center">
+							线程数
+						</th>
+						<th class="text-center">
+							操作
+						</th>
+					</tr>
+				</thead>
+				<tbody id="tasksContext">
+
+				</tbody>
+			</table>
+
+		</div>
+		<!-- 分页 -->
+		<div class="container text-center">
+			<ul id="saopPagination" class="pagination">
+				
+			</ul>
+		</div>
+
+		<!-- 新增任务模态框(Modal) -->
+		<div class="modal fade" id="newTaskModal" tabindex="-1" role="dialog"
+			aria-labelledby="newTaskModalLabel" aria-hidden="true">
+			<div class="modal-dialog modal-dialog-task">
+				<div class="modal-content">
+					<div class="modal-header">
+						<button type="button" class="close" data-dismiss="modal"
+							aria-hidden="true">
+							&times;
+						</button>
+						<h4 class="modal-title" id="newTaskModalLabel">
+							新增任务
+						</h4>
+					</div>
+					<div class="modal-body">
+						<div class="alert alert-danger alert-dismissible hidden"
+							role="alert" aria-hidden="true" id="error_alert_divNew">
+							<button type="button" class="close"
+								onclick="$('#error_alert_div').attr('class','alert alert-danger alert-dismissible hidden');">
+								<span aria-hidden="true">&times;</span>
+							</button>
+							<strong>校验失败</strong>
+							<span id="errorAlertInfoNew"></span>
+						</div>
+						<div class="row">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									任务名称:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="taskNameNew"
+										id="taskNameNew" placeholder="请输入任务名称" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									执行时间:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="taskCronNew"
+										id="taskCronNew" placeholder="请输入执行时间,quartz 时间表达式" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									线程个数:
+								</label>
+								<div class="col-md-8">
+									<input type="number" class="form-control" name="tNumNew"
+										id="tNumNew" placeholder="请输入线程个数" />
+								</div>
+							</div>
+						</div>
+
+						<div class="row">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									是否空传:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="upNulNew" id="upNulNew">
+										<option value="0">
+											不需要空传
+										</option>
+										<option value="1">
+											需要空传
+										</option>
+									</select>
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									告警号码:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="errPhoneNew"
+										id="errPhoneNew" placeholder="请输入执行失败时的告警号码" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									事前处理:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="preFlagNew" id="preFlagNew">
+										<option value="1">
+											不需要事前处理
+										</option>
+										<option value="0">
+											需要事前处理
+										</option>
+									</select>
+								</div>
+							</div>
+						</div>
+
+						<div class="row">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									事前过程:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="preFunctionNew"
+										id="preFunctionNew" placeholder="请输入调用前处理过程名称" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									事后处理:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="afterFlagNew"
+										id="afterFlagNew">
+										<option value="1">
+											不需要事后处理
+										</option>
+										<option value="0">
+											需要事后处理
+										</option>
+									</select>
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									事后过程:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="afterFunctionNew"
+										id="afterFunctionNew" placeholder="请输入调用后处理过程名称" />
+								</div>
+							</div>
+						</div>
+
+						<div class="row" id="lastTastInfoDivNew">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									任务模板:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="uOrDNew" id="uOrDNew"
+										onchange="queryTaskAttr(this,'New')">
+										<option value="D">
+											FTP文件保存至TFS
+										</option>
+										<option value="U">
+											TFS文件保存至FTP
+										</option>
+										<option value="DT">
+											FTP文件保存至Table
+										</option>
+									</select>
+								</div>
+							</div>
+							<div class="col-md-8 form-group form-horizontal">
+								<label class="col-md-2 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									文件名称:
+								</label>
+								<div class="col-md-10">
+									<textarea class="form-control" id="fileNameNew"
+										name="fileNameNew" rows="2"
+										placeholder="请输入文件名称支持,时间格式######## sql语句和模糊匹配****"></textarea>
+								</div>
+							</div>
+						</div>
+
+
+					</div>
+					<div class="modal-footer">
+						<button type="button" class="btn btn-default" data-dismiss="modal">
+							关闭
+						</button>
+						<button type="button" class="btn btn-primary"
+							onclick="saveTaskInfo('New')">
+							保存
+						</button>
+					</div>
+				</div>
+				<!-- /.modal-content -->
+			</div>
+			<!-- /.modal -->
+		</div>
+
+
+
+		<!-- 编辑任务模态框(Modal) -->
+		<div class="modal fade" id="editTaskModal" tabindex="-1" role="dialog"
+			aria-labelledby="editTaskModalLabel" aria-hidden="true">
+			<div class="modal-dialog modal-dialog-task">
+				<div class="modal-content">
+					<div class="modal-header">
+						<button type="button" class="close" data-dismiss="modal"
+							aria-hidden="true">
+							&times;
+						</button>
+						<h4 class="modal-title" id="editTaskModalLabel">
+							编辑任务
+						</h4>
+					</div>
+					<div class="modal-body">
+						<div class="alert alert-danger alert-dismissible hidden"
+							role="alert" aria-hidden="true" id="error_alert_divEdit">
+							<button type="button" class="close"
+								onclick="$('#error_alert_div').attr('class','alert alert-danger alert-dismissible hidden');">
+								<span aria-hidden="true">&times;</span>
+							</button>
+							<strong>校验失败</strong>
+							<span id="errorAlertInfoEdit"></span>
+						</div>
+						<input type="hidden" id="taskIdEdit" name="taskIdEdit" value="" />
+						<div class="row">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									任务名称:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="taskNameEdit"
+										id="taskNameEdit" placeholder="请输入任务名称" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									执行时间:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="taskCronEdit"
+										id="taskCronEdit" placeholder="请输入执行时间,quartz 时间表达式" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									线程个数:
+								</label>
+								<div class="col-md-8">
+									<input type="number" class="form-control" name="tNumEdit"
+										id="tNumEdit" placeholder="请输入线程个数" />
+								</div>
+							</div>
+						</div>
+
+						<div class="row">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									是否空传:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="upNulEdit" id="upNulEdit">
+										<option value="0">
+											不需要空传
+										</option>
+										<option value="1">
+											需要空传
+										</option>
+									</select>
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									告警号码:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="errPhoneEdit"
+										id="errPhoneEdit" placeholder="请输入执行失败时的告警号码" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									事前处理:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="preFlagEdit"
+										id="preFlagEdit">
+										<option value="1">
+											不需要事前处理
+										</option>
+										<option value="0">
+											需要事前处理
+										</option>
+									</select>
+								</div>
+							</div>
+						</div>
+
+						<div class="row">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									事前过程:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control" name="preFunctionEdit"
+										id="preFunctionEdit" placeholder="请输入调用前处理过程名称" />
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									事后处理:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="afterFlagEdit"
+										id="afterFlagEdit">
+										<option value="1">
+											不需要事后处理
+										</option>
+										<option value="0">
+											需要事后处理
+										</option>
+									</select>
+								</div>
+							</div>
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									事后过程:
+								</label>
+								<div class="col-md-8">
+									<input type="text" class="form-control"
+										name="afterFunctionEdit" id="afterFunctionEdit"
+										placeholder="请输入调用后处理过程名称" />
+								</div>
+							</div>
+						</div>
+
+						<div class="row" id="lastTastInfoDivEdit">
+							<div class="col-md-4 form-group form-horizontal">
+								<label class="col-md-4 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									任务模板:
+								</label>
+								<div class="col-md-8">
+									<select class="form-control" name="uOrDEdit" id="uOrDEdit"
+										onchange="queryTaskAttr(this,'Edit')">
+										<option value="D">
+											FTP文件保存至TFS
+										</option>
+										<option value="U">
+											TFS文件保存至FTP
+										</option>
+										<option value="DT">
+											FTP文件保存至Table
+										</option>
+									</select>
+								</div>
+							</div>
+							<div class="col-md-8 form-group form-horizontal">
+								<label class="col-md-2 control-label nopaddingright">
+									<span class="glyphicon glyphicon-asterisk required"></span>
+									文件名称:
+								</label>
+								<div class="col-md-10">
+									<textarea class="form-control" id="fileNameEdit"
+										name="fileNameEdit" rows="2"
+										placeholder="请输入文件名称支持,时间格式######## sql语句和模糊匹配****"></textarea>
+								</div>
+							</div>
+						</div>
+
+
+					</div>
+					<div class="modal-footer">
+						<button type="button" class="btn btn-default" data-dismiss="modal">
+							关闭
+						</button>
+						<button type="button" class="btn btn-primary"
+							onclick=
+	saveTaskInfo('Edit');
+>
+							保存
+						</button>
+					</div>
+				</div>
+				<!-- /.modal-content -->
+			</div>
+			<!-- /.modal -->
+		</div>
+
+		<!--提示弹框-->
+		<div class="modal fade" id="alertModal" tabindex="-1" role="dialog"
+			aria-labelledby="alertModalLabel" aria-hidden="true">
+			<div class="modal-dialog">
+				<div class="modal-content">
+					<div class="modal-header">
+						<h4 class="modal-title" id="alertModalLabel">
+							温馨提示
+						</h4>
+					</div>
+					<div class="modal-body" id="alertContext"></div>
+					<div class="modal-footer modal-center">
+						<button type="button" class="btn btn-primary" data-dismiss="modal">
+							关闭
+						</button>
+					</div>
+				</div>
+				<!-- /.modal-content -->
+			</div>
+			<!-- /.modal -->
+		</div>
+
+		<!--加载效果-->
+		<div id="loader" style="display: none;">
+			<div id="loading" class="loading">
+				正在处理...
+			</div>
+			<div class="modal-backdrop in "></div>
+		</div>
+		<!--为了加速度,将js部分放入最后-->
+		<script type="text/javascript" src="../js/jquery.min.js"></script>
+		<script type="text/javascript" src="../js/bootstrap.min.js"></script>
+		<script type="text/javascript" src="../js/bootstrap-paginator.js"></script>
+		<script type="text/javascript"
+			src="../js/prvncFtpToFileSystemConfigList.js"></script>
+	</body>
+</html>

+ 16 - 0
JobService/src/test/java/com/java110/job/Java110JobserviceApplicationTests.java

@@ -0,0 +1,16 @@
+package com.java110.job;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class Java110JobserviceApplicationTests {
+
+    @Test
+    public void contextLoads() {
+    }
+
+}

BIN=BIN
docs/images/0001.png


BIN=BIN
docs/images/0002.jpg


BIN=BIN
docs/images/0003.png


+ 4 - 3
docs/index.html

@@ -70,8 +70,9 @@
 				</div>
 			</div>
 			<div class="col-md-6 col-sm-8 col-xs-12">
-				<div><img src="images/intro-image.png" class="img-responsive" alt="intro-image"></div>
-			</div>    
+				<!--<div><img src="images/intro-image.png" class="img-responsive" alt="intro-image"></div>-->
+				<div><img src="images/0003.png" class="img-responsive" alt="intro-image"></div>
+			</div>
 		</div>
 	</div>
 </section>
@@ -267,7 +268,7 @@
 				<h1 class="section-title">产品展示</h2>
 				<p class="section-para">我们对现有的产品做了一个演示环境,包含了业主管理、车位管理、小区管理等基础功能,方便各位合作伙伴及开发者朋友们更直观的了解我们的产品以及快速的加入到我们的开发者大军中来</p>
 					<div class="col-md-7 col-xs-12">
-						<div class="about-img"><img class="img-responsive" src="images/about-us.png" alt="about us image" /></div>
+						<div class="about-img"><img class="img-responsive" src="images/0001.png" alt="about us image" /></div>
 					</div>
 					<p class="section-para">带上用户密码吧:wuxw/admin</p>
 					<a class="btn btn-default" href="https://demo.java110.com/" role="button">去看产品 <i class="lnr lnr-arrow-right"></i></a></i></a>

+ 8 - 0
java110-common/src/main/java/com/java110/common/constant/RuleDomain.java

@@ -67,4 +67,12 @@ public class RuleDomain {
 
 
     public final static String REDIS_KEY_RULE_GROUP ="Rule_Group"; // redis key Rule
+
+
+    public final static String REPLAY_TYPE_A = "########";				//'yyyyMMdd'
+    public final static String REPLAY_TYPE_E = "##########";			//'yyyyMMddHH'
+    public final static String REPLAY_TYPE_F = "############";			//'yyyyMMddHHmm'
+    public final static String REPLAY_TYPE_SQL = "select";           //文件名支持sql查询
+
+
 }

+ 18 - 0
java110-common/src/main/java/com/java110/common/exception/TaskException.java

@@ -0,0 +1,18 @@
+package com.java110.common.exception;
+
+import java.util.Map;
+
+public class TaskException extends RuntimeException {
+	private Map errInfoMap;
+	public TaskException(Map errInfoMap, Throwable cause) {
+		super(cause);
+		this.errInfoMap = errInfoMap;
+	}
+	public Map getErrInfoMap() {
+		return errInfoMap;
+	}
+	public void setErrInfoMap(Map errInfoMap) {
+		this.errInfoMap = errInfoMap;
+	}
+	
+}

+ 427 - 0
java110-db/src/main/resources/mapper/job/PrvncFtpFileDAO.xml

@@ -0,0 +1,427 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+		PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+		"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="PrvncFtpFileDAO">
+
+
+	<insert id="saveTaskInfo"
+		parameterType="com.java110.job.model.FtpTaskInfo">
+		<selectKey keyProperty="taskid" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_taskid.NEXTVAL  AS taskid from dual
+	        ]]>
+		</selectKey>
+		insert into
+		CEP_FTP_TASK(taskid,taskname,taskcron,detailid,ftp_userid,p_path,l_path,file_name,create_date,state,u_or_d,ERRPHONE,tnum,upnull)
+		values(#taskid#,#taskname#,#taskcron#,#detailid#,#userid#,#ppath#,#lpath#,#filename#,sysdate,#state#,#uord#,#errphone#,#tnum#,#upnull#)
+	</insert>
+
+	<insert id="saveTaskDetailInfo"
+		parameterType="com.java110.job.model.FtpTaskDetail">
+		<selectKey keyProperty="detailid" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_taskid.NEXTVAL  AS detailid from dual
+	        ]]>
+		</selectKey>
+		insert into
+		CEP_FTP_TASKDETAIL(detailid,name,dbsql,titleflag,title,linecountflag,linecountname,sign,state,create_date,
+		preflag,prefunction,afterflag,afterfunction,filesplitflag,singlesplitsize)
+		values(#detailid#,#name#,#dbsql#,#titleflag#,#title#,#linecountflag#,#linecountname#,#sign#,#state#,sysdate,
+		#preflag#,#prefunction#,#afterflag#,#afterfunction#,#filesplitflag#,#singlesplitsize#)
+	</insert>
+	<update id="updateTaskDetailInfo"
+		parameterType="com.java110.job.model.FtpTaskDetail">
+		update CEP_FTP_TASKDETAIL
+		set
+		name=#name#,dbsql=#dbsql#,titleflag=#titleflag#,title=#title#,linecountflag=#linecountflag#,linecountname=#linecountname#,sign=#sign#,state=#state#,
+		preflag=#preflag#,prefunction=#prefunction#,afterflag=#afterflag#,afterfunction=#afterfunction#,filesplitflag=#filesplitflag#,singlesplitsize=#singlesplitsize#
+		where detailid=#detailid#
+	</update>
+	<delete id="deleteTaskDetailInfo" parameterType="long">
+		delete from
+		CEP_FTP_TASKDETAIL where taskid=#value#
+	</delete>
+	<insert id="saveFtpUserInfo"
+		parameterType="com.java110.job.model.FtpUserInfo">
+		<selectKey keyProperty="userid" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_taskid.NEXTVAL  AS userid from dual
+	        ]]>
+		</selectKey>
+		insert into
+		CEP_FTP_TASKUSER(ftp_userid,machine_id,username,pwd,ip,port,create_date,state,remark)
+		values(#userid#,#machineid#,#username#,#pwd#,#ip#,#port#,sysdate,#state#,#remark#)
+	</insert>
+
+	<insert id="saveTaskRunLog"
+		parameterType="com.java110.job.model.FtpTaskLog">
+		<selectKey keyProperty="logid" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_ftptasklog.NEXTVAL  AS logid from dual
+	        ]]>
+		</selectKey>
+		insert into
+		cep_ftp_tasklog(logid,taskid,u_or_d,create_date,state,serverfilename,localfilename,filelength)
+		values(#logid#,#taskid#,#uord#,sysdate,#state#,#serverfilename#,#localfilename#,#filelength#)
+	</insert>
+
+	<update id="updateTaskRunLog"
+		parameterType="com.java110.job.model.FtpTaskLog">
+		update cep_ftp_tasklog set update_date=sysdate
+		<if test="state !=null and state != ''">
+			,state = #state#
+		</if>
+		where logid=#logid#
+	</update>
+	<insert id="saveTaskRunDetailLog"
+		parameterType="com.java110.job.model.FtpTaskLogDetail">
+		<selectKey keyProperty="id" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_ftptasklogdetail.NEXTVAL  AS id from dual
+	        ]]>
+		</selectKey>
+		insert into
+		cep_ftp_tasklog_detail(id,logid,taskid,create_date,state,tnum,begin,end,data,havedown,remark,SERVERFILENAME,LOCALFILENAME)
+		values(#id#,#logid#,#taskid#,sysdate,#state#,#tnum#,#begin#,#end#,#data#,#havedown#,#remark#,#serverfilename#,#localfilename#)
+	</insert>
+	<update id="updateTaskRunDetailLog"
+		parameterType="com.java110.job.model.FtpTaskLogDetail">
+		update cep_ftp_tasklog_detail set update_date=sysdate
+		<if test="state !=null and state != ''">,state = #state#</if>
+		<if test="data !=null and data != ''">,data = #data#</if>
+		<if test="havedown !=null and havedown != ''">,havedown = #havedown#</if>
+		<if test="remark !=null and remark != ''">,remark = #remark#</if>
+		where id=#id#
+	</update>
+	<insert id="insertFileData2Table" parameterType="String">
+		$value$ 		
+	</insert>
+	<insert id="insertFileData2TableFailed" parameterType="String">
+		$value$ 		
+	</insert>
+
+	<select id="calltaskfunction" parameterType="map">
+		{ call $functionname$()}   
+    </select>
+
+
+	<select id="calltaskfunctionwithparam" parameterMap="TaskFunctionProcParameters">
+		{ call $functionname$(?,?)}
+    </select>
+
+
+	<insert id="addFtpItem" parameterType="map">
+		insert into saop_ftp_task(taskid,
+		taskname,
+		file_name,
+		u_or_d,
+		tnum,
+		taskcron,
+		errphone,
+		fileseq,
+		upnull,
+		preflag,
+		prefunction,
+		afterflag,
+		afterfunction,
+		deal_class)
+		values(#taskId#,
+		#taskName#,
+		#fileName#,
+		#uOrD#,
+		#tNum#,
+		#taskCron#,
+		#errPhone#,
+		#fileSeq#,
+		#upNull#,
+		#preFlag#,
+		#preFunction#,
+		#afterFlag#,
+		#afterFunction#,
+		#dealClass#
+		)
+	</insert>
+	<update id="updateTaskRunLog"
+			parameterType="com.java110.job.model.FtpTaskLog">
+		update cep_ftp_tasklog set update_date=sysdate
+		<if test="state != null  and state != ''">,state = #state#</if>
+		where logid=#logid#
+	</update>
+
+
+	<select id="queryTaskDetailInfo" parameterType="long"
+		resultType="java.util.HashMap">
+		select * from CEP_FTP_TASKDETAIL
+		where detailid=#value#
+	</select>
+	<select id="queryFtpUserInfo" parameterType="long" resultType="java.util.HashMap">
+		select ftp_userid,machine_id,username,pwd,ip,port,
+		state,
+		to_char(update_date,'yyyy-mm-dd hh24:mi:ss') updatedate,
+		to_char(create_date,'yyyy-mm-dd hh24:mi:ss') createdate,
+		remark
+		from CEP_FTP_TASKUSER
+		where ftp_userid=#value#
+	</select>
+
+
+	<select id="execConfigSql" parameterType="String" resultType="String">
+		$value$
+	</select>
+
+
+	<select id="queryFtpItemsCount" parameterType="map"
+		resultType="Integer">
+		SELECT count(1)
+		FROM SAOP_FTP_TASK A
+		WHERE A.STATE = 'A'
+	
+	</select>
+	<!-- 查询文件下载上传列表(配置项) -->
+	<select id="queryFtpItems" parameterType="map" resultType="java.util.HashMap">
+	<![CDATA[
+		select * from (
+		SELECT rownum as rn,A.TASKID,
+		       A.TASKNAME,
+		       A.FILE_NAME,
+		       A.U_OR_D,
+		       A.RUN_STATE,
+		       A.RUN_FLAG,
+		       A.TNUM,
+		       A.TASKCRON,
+		       A.ERRPHONE,
+		       A.FILESEQ,
+		       A.UPNULL,
+		       A.PREFLAG,
+		       A.PREFUNCTION,
+		       A.AFTERFLAG,
+		       A.AFTERFUNCTION,
+		       A.DEAL_CLASS,
+		       A.CREATE_DATE
+		  FROM SAOP_FTP_TASK A
+		 WHERE A.STATE = 'A') A1
+		 where  A1.rn > ((TO_NUMBER(#curPage#) -1) * TO_NUMBER(#pageSize#)) AND A1.rn <= (TO_NUMBER(#curPage#) * TO_NUMBER(#pageSize#))
+	]]>
+	</select>
+	<select id="newCreateTaskId" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_taskid.NEXTVAL  AS taskId from dual
+	        ]]>
+	</select>
+	<insert id="addFtpItem" parameterType="map">
+		insert into saop_ftp_task(taskid,
+		taskname,
+		file_name,
+		u_or_d,
+		tnum,
+		taskcron,
+		errphone,
+		fileseq,
+		upnull,
+		preflag,
+		prefunction,
+		afterflag,
+		afterfunction,
+		deal_class)
+		values(#taskId#,
+		#taskName#,
+		#fileName#,
+		#uOrD#,
+		#tNum#,
+		#taskCron#,
+		#errPhone#,
+		#fileSeq#,
+		#upNull#,
+		#preFlag#,
+		#preFunction#,
+		#afterFlag#,
+		#afterFunction#,
+		#dealClass#
+		) 		
+	</insert>
+	<!-- 根据taskId 查询FtpItem 信息 -->
+	<select id="queryFtpItemByTaskId" parameterType="map"
+		resultType="java.util.HashMap">
+		SELECT A.TASKID,
+		A.TASKNAME,
+		A.FILE_NAME,
+		A.U_OR_D,
+		A.RUN_STATE,
+		A.RUN_FLAG,
+		A.TNUM,
+		A.TASKCRON,
+		A.ERRPHONE,
+		A.FILESEQ,
+		A.UPNULL,
+		A.PREFLAG,
+		A.PREFUNCTION,
+		A.AFTERFLAG,
+		A.AFTERFUNCTION,
+		A.DEAL_CLASS,
+		A.CREATE_DATE
+		FROM SAOP_FTP_TASK A
+		WHERE A.STATE = 'A'
+		and A.TASKID = #taskId#
+	</select>
+	<!-- 根据任务名称搜素 -->
+	<select id="searchFtpItemByTaskName" parameterType="map"
+		resultType="java.util.HashMap">
+	<![CDATA[
+		SELECT A.TASKID,
+		A.TASKNAME,
+		A.FILE_NAME,
+		A.U_OR_D,
+		A.RUN_STATE,
+		A.RUN_FLAG,
+		A.TNUM,
+		A.TASKCRON,
+		A.ERRPHONE,
+		A.FILESEQ,
+		A.UPNULL,
+		A.PREFLAG,
+		A.PREFUNCTION,
+		A.AFTERFLAG,
+		A.AFTERFUNCTION,
+		A.DEAL_CLASS,
+		A.CREATE_DATE
+		FROM SAOP_FTP_TASK A
+		WHERE A.STATE = 'A'
+		and A.TASKNAME like '%' || #taskName# || '%'
+		and rownum < 1000
+	]]>
+	</select>
+	<!-- 修改ftp配置信息 -->
+	<update id="updateFtpItemByTaskId" parameterType="map">
+		update saop_ftp_task sft
+		set update_date = sysdate
+		<if test="taskName !=null and taskName != ''">,sft.taskname = #taskName#
+		</if>
+		<if test="fileName !=null and fileName != ''">,sft.file_name = #fileName#
+		</if>
+		<if test="uOrD !=null and uOrD != ''">,sft.u_or_d = #uOrD#</if>
+		<if test="runState !=null and runState != ''">,sft.run_state = #runState#
+		</if>
+		<if test="runFlag !=null and runFlag != ''">,sft.run_flag = #runFlag#</if>
+		<if test="tNum !=null and tNum != ''">,sft.tnum = #tNum#</if>
+		<if test="taskCron !=null and taskCron != ''">,sft.taskcron = #taskCron#
+		</if>
+		<if test="errPhone !=null and errPhone != ''">,sft.errphone = #errPhone#
+		</if>
+		<if test="fileSeq !=null and fileSeq != ''">,sft.fileseq = #fileSeq#</if>
+		<if test="upNull !=null and upNull != ''">,sft.upnull = #upNull#</if>
+		<if test="preFlag !=null and preFlag != ''">,sft.preflag = #preFlag#</if>
+		<if test="preFunction !=null and preFunction != ''">,sft.prefunction = #preFunction#
+		</if>
+		<if test="afterFlag !=null and afterFlag != ''">,sft.afterflag = #afterFlag#
+		</if>
+		<if test="afterFunction !=null and afterFunction != ''">,sft.afterfunction = #afterFunction#
+		</if>
+		<if test="dealClass !=null and dealClass != ''">,sft.deal_class = #dealClass#
+		</if>
+		where sft.state = 'A'
+		and sft.taskid = #taskId#
+	</update>
+
+	<!-- 修改ftp配置信息 -->
+	<update id="updateFtpItemRunState" parameterType="map">
+		update
+		saop_ftp_task sft
+		set update_date = sysdate,sft.run_state= #runState#
+		where sft.run_state = #oldRunState#
+	</update>
+
+	<!-- 删除ftp配置信息 -->
+	<update id="deleteFtpItemByTaskId" parameterType="map">
+		update
+		saop_ftp_task sft
+		set sft.state = 'R'
+		where sft.state = 'A'
+		and sft.taskid in 
+		<foreach collection="taskIds" open="(" close=")"
+				 separator=","  item="item">
+					#{item}
+		</foreach>
+	</update>
+	<!-- 根据taskids 获取将要操作的ftp配置信息 -->
+	<select id="queryFtpItemsByTaskIds" parameterType="map" resultType="java.util.HashMap">
+		SELECT
+		A.TASKID,
+		A.TASKNAME,
+		A.FILE_NAME,
+		A.U_OR_D,
+		A.RUN_STATE,
+		A.RUN_FLAG,
+		A.TNUM,
+		A.TASKCRON,
+		A.ERRPHONE,
+		A.FILESEQ,
+		A.UPNULL,
+		A.PREFLAG,
+		A.PREFUNCTION,
+		A.AFTERFLAG,
+		A.AFTERFUNCTION,
+		A.DEAL_CLASS
+		FROM SAOP_FTP_TASK A
+		WHERE A.STATE = 'A'
+		AND A.TASKID in 
+		<foreach open="(" close=")"
+				 separator="," collection="taskIds" item="item">
+					#{item}
+		</foreach>
+	</select>
+	<!-- 查询FTPItem的属性信息 -->
+	<select id="queryFtpItemAttrsByTaskId" parameterType="map"
+		resultType="java.util.HashMap">
+		SELECT A.TASKID, A.ITEM_SPEC_ID, A.VALUE
+		FROM SAOP_FTP_TASK_ATTR A
+		WHERE A.TASKID = #taskId#
+	</select>
+	<!-- 保存FTPItem的属性信息 -->
+	<insert id="addFtpItemAttrs" parameterType="map">
+		insert into
+		SAOP_FTP_TASK_ATTR(taskid,item_spec_id,value)
+		values(#taskId#,#itemSpecId#,#value#)
+	</insert>
+	<!-- 查询没有下载过的文件名 -->
+	<select id="queryFileNamesWithOutFtpLog" parameterType="map"
+		resultType="java.util.HashMap">
+		<![CDATA[
+		SELECT #fileNames# AS fileNames FROM DUAL
+		 where #fileNames# not in
+		       (select sfl.file_name from saop_ftp_log sfl where sfl.taskId = #taskId#)
+		]]>
+	</select>
+
+	<insert id="addDownloadFileName" parameterType="map">
+		<selectKey keyProperty="logid" resultType="long">
+	        <![CDATA[  
+	        SELECT seq_cep_taskid.NEXTVAL  AS logid from dual
+	        ]]>
+		</selectKey>
+	insert into saop_ftp_log(
+	log_id,
+	taskid,
+	file_name,
+	tfs_file_name
+	)
+	values(
+	#logid#,
+	#taskId#,
+	#fileName#,
+	#tfsFileName#
+	)
+	</insert>
+	
+
+	<select id="queryItemSpec" parameterType="map" resultType="java.util.HashMap">
+		select a.item_spec_cd, a.domain, a.name, a.describe, a.create_date
+		from saop_ftp_item_spec a
+		where a.status_cd = '0'
+		<if test="domain != null and domain !='' "> and a.domain = #domain#</if>
+		<if test="name != null and name !='' "> and a.name = #name#</if>
+		<if test="itemSpecCd != null and itemSpecCd !='' "> and a.item_spec_cd = #itemSpecCd#
+		</if>
+	</select>
+
+</mapper>

+ 7 - 2
pom.xml

@@ -33,6 +33,7 @@
         <module>CommunityService</module>
         <module>java110-code-generator</module>
         <module>java110-db</module>
+        <module>JobService</module>
     </modules>
 
     <parent>
@@ -373,13 +374,17 @@
             </dependency>
 
 
-            <dependency>
+           <!-- <dependency>
                 <groupId>org.quartz-scheduler</groupId>
                 <artifactId>quartz</artifactId>
                 <version>2.3.0</version>
+            </dependency>-->
+            <dependency>
+                <groupId>org.quartz-scheduler</groupId>
+                <artifactId>quartz</artifactId>
+                <version>2.2.3</version>
             </dependency>
 
-
             <dependency>
                 <groupId>org.springframework.session</groupId>
                 <artifactId>spring-session-data-redis</artifactId>