diff --git a/.gitignore b/.gitignore index 84adb3f..549e00a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,33 @@ -# ---> Java -# Compiled class file -*.class +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ -# Log file -*.log +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache -# BlueJ files -*.ctxt +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..a45eb6b --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,118 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..2cc7d4a Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..642d572 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..a16b543 --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven 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 keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..26abadc --- /dev/null +++ b/pom.xml @@ -0,0 +1,112 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.3.3.RELEASE + + + com.msdw + tms + 0.0.1-SNAPSHOT + tms + 测评管理系统 + + + 1.8 + + + + + org.apache.poi + poi + 4.0.1 + + + org.apache.poi + poi-ooxml + 4.0.1 + + + org.apache.poi + poi-ooxml-schemas + 4.0.1 + + + + org.springframework.boot + spring-boot-starter-web + + + + com.baomidou + mybatis-plus-boot-starter + 3.3.1 + + + org.projectlombok + lombok + 1.18.12 + + + + org.apache.httpcomponents + httpcore + 4.4.13 + + + + commons-lang + commons-lang + 2.6 + + + + + mysql + mysql-connector-java + 8.0.20 + + + + + io.springfox + springfox-swagger-ui + 2.7.0 + + + io.springfox + springfox-swagger2 + 2.7.0 + + + + com.aliyun.oss + aliyun-sdk-oss + 2.8.2 + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/com/msdw/tms/TmsApplication.java b/src/main/java/com/msdw/tms/TmsApplication.java new file mode 100644 index 0000000..33869c2 --- /dev/null +++ b/src/main/java/com/msdw/tms/TmsApplication.java @@ -0,0 +1,13 @@ +package com.msdw.tms; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class TmsApplication { + + public static void main(String[] args) { + SpringApplication.run(TmsApplication.class, args); + } + +} diff --git a/src/main/java/com/msdw/tms/api/EvaluationRulesControllerApi.java b/src/main/java/com/msdw/tms/api/EvaluationRulesControllerApi.java new file mode 100644 index 0000000..3e58609 --- /dev/null +++ b/src/main/java/com/msdw/tms/api/EvaluationRulesControllerApi.java @@ -0,0 +1,33 @@ +package com.msdw.tms.api; + +import com.msdw.tms.common.utils.R; +import com.msdw.tms.entity.EvaluationRulesEntity; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.Map; + + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Api(value = "测评规则管理", tags = "测评规则的查询和修改") +public interface EvaluationRulesControllerApi { + + /** + * 测评规则信息的展示 + */ + @ApiOperation(value = "测评规则信息的展示", notes = "测评规则信息的展示") + R info(); + /** + * 修改测评规则信息 + */ + @ApiOperation(value = "修改测评规则信息", notes = "修改测评规则信息") + R update(@RequestBody EvaluationRulesEntity evaluationRules); +} diff --git a/src/main/java/com/msdw/tms/api/QuestionsControllerApi.java b/src/main/java/com/msdw/tms/api/QuestionsControllerApi.java new file mode 100644 index 0000000..4cbfaa8 --- /dev/null +++ b/src/main/java/com/msdw/tms/api/QuestionsControllerApi.java @@ -0,0 +1,94 @@ +package com.msdw.tms.api; + +import com.msdw.tms.common.utils.R; +import com.msdw.tms.entity.request.QuestionsAddRequest; +import com.msdw.tms.entity.request.QuestionsQueryRequest; +import com.msdw.tms.entity.request.QuestionsUpdateRequest; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * 记录试题信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Api(value = "试题信息管理", tags = "提供试题信息的增删改查及导入等功能") +public interface QuestionsControllerApi { + + /** + * 列表 + */ + @ApiOperation(value = "分页加条件查询试题信息", notes = "分页加条件查询试题信息") + R list(@RequestParam Integer page, + @RequestParam Integer size, + QuestionsQueryRequest request); + + /** + * 信息 + */ + @ApiOperation(value = "根据试题id查询试题详情信息", notes = "根据试题id查询试题详情信息") + R info(@PathVariable("id") Integer id); + + /** + * 保存 + */ + @ApiOperation(value = "新增一道试题", notes = "传入新增试题所需相关参数") + R save(@RequestBody QuestionsAddRequest questions); + + /** + * 根据试题id修改试题信息 + */ + @ApiOperation(value = "根据试题id修改试题信息", notes = "根据试题id修改试题信息") + R update(@RequestBody QuestionsUpdateRequest questions); + + /** + * 是否禁用试题 + */ + @ApiOperation(value = "是否禁用试题", notes = "是否禁用试题") + R isnable(Integer id); + + /** + * 删除 + */ + @ApiOperation(value = "批量删除试题信息", notes = "批量删除试题信息") + R delete(@RequestBody Integer[] ids); + + /** + * 通过excel批量导入 + */ + @ApiOperation(value = "通过excel批量导入", notes = "通过excel批量导入") + R importQuestion(@RequestParam(name = "file") MultipartFile file) throws IOException; + + /** + * excel模板文件上传 + * + * @param file + * @return + */ + @ApiOperation(value = "excel模板文件上传", notes = "excel模板文件上传") + R uploadFiles(MultipartFile file) throws IOException; + + /** + * excel模板文件下载 + * + * @return + */ + @ApiOperation(value = "excel模板文件下载", notes = "excel模板文件下载") + R downloadFiles(HttpServletResponse response) throws IOException; + + /** + * 抽题测评 + */ + @ApiOperation(value = "抽题测评", notes = "抽题测评") + R evaluation (); +} diff --git a/src/main/java/com/msdw/tms/common/exception/CustomException.java b/src/main/java/com/msdw/tms/common/exception/CustomException.java new file mode 100644 index 0000000..d583d9c --- /dev/null +++ b/src/main/java/com/msdw/tms/common/exception/CustomException.java @@ -0,0 +1,21 @@ +package com.msdw.tms.common.exception; + +import com.msdw.tms.entity.response.ResultCode; + +/** + * @author 世杰 + * @date 2020/3/24 22:47 + */ +public class CustomException extends RuntimeException { + private ResultCode resultCode; + + public CustomException(ResultCode resultCode) { + //异常信息为错误代码+异常信息 + super("错误代码:" + resultCode.code() + "错误信息:" + resultCode.message()); + this.resultCode = resultCode; + } + + public ResultCode getResultCode() { + return this.resultCode; + } +} diff --git a/src/main/java/com/msdw/tms/common/exception/ExceptionCast.java b/src/main/java/com/msdw/tms/common/exception/ExceptionCast.java new file mode 100644 index 0000000..93405e2 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/exception/ExceptionCast.java @@ -0,0 +1,14 @@ +package com.msdw.tms.common.exception; + +import com.msdw.tms.entity.response.ResultCode; + +/** + * @author 世杰 + * @date 2020/3/24 23:04 + */ +public class ExceptionCast { + //使用此静态方法抛出自定义异常 + public static void cast(ResultCode resultCode) { + throw new CustomException(resultCode); + } +} diff --git a/src/main/java/com/msdw/tms/common/exception/ExceptionCatch.java b/src/main/java/com/msdw/tms/common/exception/ExceptionCatch.java new file mode 100644 index 0000000..0c4314c --- /dev/null +++ b/src/main/java/com/msdw/tms/common/exception/ExceptionCatch.java @@ -0,0 +1,62 @@ +package com.msdw.tms.common.exception; + +import com.google.common.collect.ImmutableMap; +import com.msdw.tms.entity.response.CommonCode; +import com.msdw.tms.entity.response.ResponseResult; +import com.msdw.tms.entity.response.ResultCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + + +/** + * @author 世杰 + * @date 2020/3/24 23:06 + */ +//使用 @ControllerAdvice和@ExceptionHandler注解来捕获指定类型的异常 +@ControllerAdvice//控制器增强 +public class ExceptionCatch { + private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionCatch.class); + + //定义Map,配置异常类型所对应的错误代码,使用 ImmutableMap 一旦写入数据,就无法更改,只读并且线程安全 + private static ImmutableMap, ResultCode> EXCEPTIONS; + //定义map的builder对象,去构建ImmutableMap + protected static ImmutableMap.Builder, ResultCode> builder = ImmutableMap.builder(); + + @ExceptionHandler(Exception.class) + @ResponseBody + public ResponseResult exception(Exception exception) { + exception.printStackTrace(); + //记录日志 + LOGGER.error("catch exception:{}", exception.getMessage()); + if (EXCEPTIONS == null) { + EXCEPTIONS = builder.build();//EXCEPTION构建成功 + } + //从EXCEPTIONS中找到异常类型所对应的错误代码,如果找到了,将错误代码相应给用户,如果找不到则给用户相应99999 + ResultCode resultCode = EXCEPTIONS.get(exception.getClass()); + if (resultCode != null) { + return new ResponseResult(resultCode); + } + //返回99999异常 + return new ResponseResult(CommonCode.SERVER_ERROR); + } + + static { + //定义异常类型所对应的错误代码 + builder.put(HttpMessageNotReadableException.class, CommonCode.INVALID_PARAM); + } + + @ExceptionHandler(CustomException.class)//捕获CustomException类型异常 + @ResponseBody + public ResponseResult customException(CustomException customException) { + customException.printStackTrace(); + //记录日志 + LOGGER.error("catch exception:{}", customException.getMessage()); + + ResultCode resultCode = customException.getResultCode(); + return new ResponseResult(resultCode); + } +} diff --git a/src/main/java/com/msdw/tms/common/exception/RRException.java b/src/main/java/com/msdw/tms/common/exception/RRException.java new file mode 100644 index 0000000..41eee66 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/exception/RRException.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.msdw.tms.common.exception; + +/** + * 自定义异常 + * + * @author Mark sunlightcs@gmail.com + */ +public class RRException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public RRException(String msg) { + super(msg); + this.msg = msg; + } + + public RRException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public RRException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public RRException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/src/main/java/com/msdw/tms/common/utils/AliyunOssUtil.java b/src/main/java/com/msdw/tms/common/utils/AliyunOssUtil.java new file mode 100644 index 0000000..05084d7 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/AliyunOssUtil.java @@ -0,0 +1,315 @@ +package com.msdw.tms.common.utils; + +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.OSSException; +import com.aliyun.oss.model.*; +import com.msdw.tms.config.AliyunOssConfig; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLEncoder; +import java.text.SimpleDateFormat; +import java.util.Date; + + +public class AliyunOssUtil { + + private static String sdf = new SimpleDateFormat("yyyyMMdd").format(new Date()); + + /** + * 创建存储空间 + * + * @param client + * @param config + */ + public static void createBucket(OSSClient client, AliyunOssConfig config) { + // 判断存储空间是否存在,不存在,则创建 + if (!client.doesBucketExist(config.getBucketName())) { + CreateBucketRequest bucketRequest = new CreateBucketRequest(null); + // 设置仓库名称 + bucketRequest.setBucketName(config.getBucketName()); + // 设置仓库权限 + bucketRequest.setCannedACL(CannedAccessControlList.PublicRead); + // 创建仓库 + client.createBucket(bucketRequest); + } + } + + /** + * 上传文件 + * + * @param file 需要上传的文件 + * @param client + * @param config + * @return + * @throws OSSException + * @throws ClientException + * @throws IOException + */ + public static FilesResult uploadFiles(MultipartFile file, OSSClient client, AliyunOssConfig config) throws OSSException, ClientException, IOException { + FilesResult result = new FilesResult(); + // 创建存储空间 + createBucket(client, config); + // 获取文件名 + String fileUrl = file.getOriginalFilename(); + // 获取文件尾缀 + String ext = fileUrl.substring(fileUrl.lastIndexOf(".")); + // 获取文件类型 + String fileType = getFileType(ext); + //创建文件 + String folderName = ext.substring(ext.indexOf(".") + 1); + String folder = createFolder(client, config.getBucketName(), folderName); + // 组合储存路径 + String fileName = folder + "/" + sdf + "/" + System.currentTimeMillis() + ext; + long fileSize = file.getSize(); + + ObjectMetadata metadata = new ObjectMetadata(); + // 指定该Object被下载时的网页的缓存行为 + metadata.setCacheControl("no-cache"); + // 指定该Object下设置Header + metadata.setHeader("Pragma", "no-cache"); + // 指定该Object被下载时的内容编码格式 + metadata.setContentEncoding("utf-8"); + // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成, + // 如果没有扩展名则填默认值application/octet-stream + metadata.setContentType(fileType); + // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称) + metadata.setContentDisposition("filename/filesize=" + file.getName() + "/" + fileSize + "Byte."); + // 上传文件 (上传文件流的形式) + client.putObject(config.getBucketName(), fileName, new ByteArrayInputStream(file.getBytes()), metadata); + result.setFileName(fileName); + result.setFileUrl(config.getSufferUrl() + fileName); + + if (null != client) + client.shutdown(); + + return result; + } + + /** + * 用户头像上传 + * + * @param file 需要上传的文件 + * @param client + * @param config + * @return + * @throws OSSException + * @throws ClientException + * @throws IOException + */ + public static FilesResult uploadUserAvatars(MultipartFile file, OSSClient client, AliyunOssConfig config) throws OSSException, ClientException, IOException { + FilesResult result = new FilesResult(); + String userAvatars = config.getUserAvatars(); + // 创建存储空间 + createBucket(client, config); + // 获取文件名 + String fileUrl = file.getOriginalFilename(); + // 获取文件尾缀 + String ext = fileUrl.substring(fileUrl.lastIndexOf(".")); + // 获取文件类型 + String fileType = getFileType(ext); + // 组合储存路径 + String fileName = userAvatars + "/" + sdf + "/" + System.currentTimeMillis() + ext; + long fileSize = file.getSize(); + + ObjectMetadata metadata = new ObjectMetadata(); + // 指定该Object被下载时的网页的缓存行为 + metadata.setCacheControl("no-cache"); + // 指定该Object下设置Header + metadata.setHeader("Pragma", "no-cache"); + // 指定该Object被下载时的内容编码格式 + metadata.setContentEncoding("utf-8"); + // 文件的MIME,定义文件的类型及网页编码,决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成, + // 如果没有扩展名则填默认值application/octet-stream + metadata.setContentType(fileType); + // 指定该Object被下载时的名称(指示MINME用户代理如何显示附加的文件,打开或下载,及文件名称) + metadata.setContentDisposition("filename/filesize=" + file.getName() + "/" + fileSize + "Byte."); + // 上传文件 (上传文件流的形式) + client.putObject(config.getBucketName(), fileName, new ByteArrayInputStream(file.getBytes()), metadata); + result.setFileName(fileName); + result.setFileUrl(config.getSufferUrl() + fileName); + + if (null != client) + client.shutdown(); + + return result; + } + + /** + * 简单上传 + * + * @param client + * @param config + * @param objectName 表示上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。 + * @param stream + * @return + */ + public static FilesResult uploadFiles(OSSClient client, AliyunOssConfig config, String objectName, ByteArrayInputStream stream) { + FilesResult result = new FilesResult(); + try { + PutObjectRequest putObjectRequest = new PutObjectRequest(config.getBucketName(), objectName, stream); + client.putObject(putObjectRequest); + result.setFileName(objectName); + result.setFileUrl(config.getSufferUrl() + objectName); + + } catch (Exception e) { + e.printStackTrace(); + throw e; + } finally { + if (null != client) + client.shutdown(); + } + return result; + } + + /** + * 文件下载 + * + * @param response + * @param client + * @param config + * @param objectName + */ + public static void downloadFiles(HttpServletResponse response, OSSClient client, AliyunOssConfig config, + String objectName) throws IOException { + + OSSObject ossObject = client.getObject(config.getBucketName(), objectName); + InputStream input = null; + OutputStream outputStream = null; + try { + // 获取文件名 + String fileName = objectName.substring(objectName.lastIndexOf("/") + 1); + //获取输入流 + input = ossObject.getObjectContent(); + // 获取OutputStream输出流 + outputStream = response.getOutputStream(); + byte[] buffer = new byte[input.available()]; + + response.setHeader("content-Type", "application/vnd.ms-excel"); + response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); + response.flushBuffer(); + + for (int length = 0; (length = input.read(buffer)) > 0; ) { + outputStream.write(buffer, 0, length); + } + } catch (IOException e) { + e.printStackTrace(); + throw e; + } finally { + if (null != outputStream) { + try { + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != input) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != client) + client.shutdown(); + } + + } + + /** + * 删除存储空间buckName + * + * @param ossClient oss对象 + * @param bucketName 存储空间 + */ + public static void deleteBucket(OSSClient ossClient, String bucketName) { + ossClient.deleteBucket(bucketName); + } + + /** + * 创建模拟文件夹 + * + * @param ossClient oss连接 + * @param bucketName 存储空间 + * @param folder 模拟文件夹名如"qj_nanjing/" + * @return + */ + public static String createFolder(OSSClient ossClient, String bucketName, String folder) { + // 文件夹名 + final String keySuffixWithSlash = folder; + // 判断文件夹是否存在,不存在则创建 + if (!ossClient.doesObjectExist(bucketName, keySuffixWithSlash)) { + // 创建文件夹 + ossClient.putObject(bucketName, keySuffixWithSlash, new ByteArrayInputStream(new byte[0])); + // 得到文件夹名 + OSSObject object = ossClient.getObject(bucketName, keySuffixWithSlash); + String fileDir = object.getKey(); + return fileDir; + } + return keySuffixWithSlash; + } + + /** + * 根据key删除OSS服务器上的文件 + * + * @param ossClient oss连接 + * @param bucketName 存储空间 + * @param fileName 模拟文件夹名 如"qj_nanjing/" + */ + public static void deleteFile(OSSClient ossClient, String bucketName, String fileName) { + ossClient.deleteObject(bucketName, fileName); + } + + /** + * 获取文件类型 + * + * @param fileExtension 文件后缀 + * @return + */ + public static String getFileType(String fileExtension) { + if (".bmp".equalsIgnoreCase(fileExtension)) { + return "image/bmp"; + } + if (".gif".equalsIgnoreCase(fileExtension)) { + return "image/gif"; + } + if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension) + || ".png".equalsIgnoreCase(fileExtension)) { + return "image/jpg"; + } + if (".html".equalsIgnoreCase(fileExtension)) { + return "text/html"; + } + if (".txt".equalsIgnoreCase(fileExtension)) { + return "text/plain"; + } + if (".vsd".equalsIgnoreCase(fileExtension)) { + return "application/vnd.visio"; + } + if (".ppt".equalsIgnoreCase(fileExtension) || ".pptx".equalsIgnoreCase(fileExtension)) { + return "application/vnd.ms-powerpoint"; + } + if (".doc".equalsIgnoreCase(fileExtension) || ".docx".equalsIgnoreCase(fileExtension)) { + return "application/msword"; + } + if (".xml".equalsIgnoreCase(fileExtension)) { + return "text/xml"; + } + if (".mp4".equalsIgnoreCase(fileExtension) || ".avi".equalsIgnoreCase(fileExtension)) { + return "video/mp4"; + } + if (".mpg".equalsIgnoreCase(fileExtension) || ".mpeg".equalsIgnoreCase(fileExtension)) { + return "video/mpeg"; + } + if ("pdf".equalsIgnoreCase(fileExtension)) { + return "application/pdf"; + } + return "application/octet-stream"; + } + +} diff --git a/src/main/java/com/msdw/tms/common/utils/Constant.java b/src/main/java/com/msdw/tms/common/utils/Constant.java new file mode 100644 index 0000000..80e4d2d --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/Constant.java @@ -0,0 +1,340 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + *

+ * https://www.renren.io + *

+ * 版权所有,侵权必究! + */ + +package com.msdw.tms.common.utils; + +/** + * 常量 + * + * @author Mark sunlightcs@gmail.com + */ +public class Constant { + /** + * 超级管理员ID + */ + public static final int SUPER_ADMIN = 1; + /** + * 当前页码 + */ + public static final String PAGE = "page"; + /** + * 每页显示记录数 + */ + public static final String LIMIT = "limit"; + /** + * 排序字段 + */ + public static final String ORDER_FIELD = "sidx"; + /** + * 排序方式 + */ + public static final String ORDER = "order"; + /** + * 升序 + */ + public static final String ASC = "asc"; + /** + * 通过excel批量导入试题数据时起始行 + */ + public static final int STARTING_ROW = 2; + /** + * 通过excel批量导入试题数据时起始列 + */ + public static final int STARTING_CELL = 0; + /** + * 试题选项A + */ + public static final String A = "A"; + /** + * 试题选项B + */ + public static final String B = "B"; + /** + * 试题选项C + */ + public static final String C = "C"; + /** + * 试题选项D + */ + public static final String D = "D"; + /** + * 试题选项E + */ + public static final String E = "E"; + /** + * 试题选项F + */ + public static final String F = "F"; + /** + * excel模板信息表id + */ + public static final int XLSX_TEMPLATE_ID = 1; + /** + * 测评规则表id + */ + public static final int EVALUATION_RULES_ID = 1; + /** + * 菜单类型 + * + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年11月15日 下午1:24:29 + */ + public enum MenuType { + /** + * 目录 + */ + CATALOG(0), + /** + * 菜单 + */ + MENU(1), + /** + * 按钮 + */ + BUTTON(2); + + private int value; + + MenuType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 定时任务状态 + * + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年12月3日 上午12:07:22 + */ + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL(0), + /** + * 暂停 + */ + PAUSE(1); + + private int value; + + ScheduleStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 云服务商 + */ + public enum CloudService { + /** + * 七牛云 + */ + QINIU(1), + /** + * 阿里云 + */ + ALIYUN(2), + /** + * 腾讯云 + */ + QCLOUD(3); + + private int value; + + CloudService(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 是否启用 + */ + public enum IsEnable { + /** + * 启用 + */ + ENABLE(1, "启用"), + /** + * 不启用 + */ + NOT_ENABLE(0, "不启用"); + + private Integer type; //类型 + private String desc; //描述 + + IsEnable(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } + + + /** + * 是否删除 + */ + public enum IsDel { + /** + * 删除 + */ + DEL(0, "删除"), + /** + * 不删除 + */ + NOT_DEL(1, "不删除"); + + private Integer type; //类型 + private String desc; //描述 + + IsDel(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } + + /** + * 评测规则类型 + */ + public enum RulesType { + /** + * 随机 + */ + RANDOM(0, "随机"), + /** + * 自定义 + */ + CUSTOMIZE(1, "自定义"); + + private Integer type; //类型 + private String desc; //描述 + + RulesType(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } + + /** + * 试题类型 + */ + public enum QuestionType { + /** + * 单选题 + */ + SINGLE_CHOICE(1, "单选题"), + /** + * 多选题 + */ + MULTIPLE_CHOICE(2, "多选题"), + /** + * 判断题 + */ + TRUE_OR_FALSE(3, "判断题"); + + private Integer type; //类型 + private String desc; //描述 + + QuestionType(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } + + +// public static void main(String[] args) { +// String answer = "A"; +//// System.out.println(answer.length());//3 +//// System.out.println(answer.charAt(2));//E +// +// String str = ""; +// for (int i = 0; i < answer.length(); i++) { +// char c = answer.charAt(i); +// str += c + ","; +// } +// str = str.substring(0, str.length() - 1); +// System.out.println(str); +// } +} \ No newline at end of file diff --git a/src/main/java/com/msdw/tms/common/utils/FilesResult.java b/src/main/java/com/msdw/tms/common/utils/FilesResult.java new file mode 100644 index 0000000..103ac4b --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/FilesResult.java @@ -0,0 +1,41 @@ +package com.msdw.tms.common.utils; + +public class FilesResult { + + // 文件名 + private String fileName; + // 文件在储存空间的路径 + private String fileUrl; + // 上传状态 + private String status; + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileUrl() { + return fileUrl; + } + + public void setFileUrl(String fileUrl) { + this.fileUrl = fileUrl; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public String toString() { + return "UploadFilesResult [fileName=" + fileName + ", fileUrl=" + fileUrl + ", status=" + status + "]"; + } + +} diff --git a/src/main/java/com/msdw/tms/common/utils/PageUtils.java b/src/main/java/com/msdw/tms/common/utils/PageUtils.java new file mode 100644 index 0000000..190589c --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/PageUtils.java @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.msdw.tms.common.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * + * @author Mark sunlightcs@gmail.com + */ +public class PageUtils implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private int totalCount; + /** + * 每页记录数 + */ + private int pageSize; + /** + * 总页数 + */ + private int totalPage; + /** + * 当前页数 + */ + private int currPage; + /** + * 列表数据 + */ + private List list; + + /** + * 分页 + * @param list 列表数据 + * @param totalCount 总记录数 + * @param pageSize 每页记录数 + * @param currPage 当前页数 + */ + public PageUtils(List list, int totalCount, int pageSize, int currPage) { + this.list = list; + this.totalCount = totalCount; + this.pageSize = pageSize; + this.currPage = currPage; + this.totalPage = (int)Math.ceil((double)totalCount/pageSize); + } + + /** + * 分页 + */ + public PageUtils(IPage page) { + this.list = page.getRecords(); + this.totalCount = (int)page.getTotal(); + this.pageSize = (int)page.getSize(); + this.currPage = (int)page.getCurrent(); + this.totalPage = (int)page.getPages(); + } + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getCurrPage() { + return currPage; + } + + public void setCurrPage(int currPage) { + this.currPage = currPage; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + +} diff --git a/src/main/java/com/msdw/tms/common/utils/Query.java b/src/main/java/com/msdw/tms/common/utils/Query.java new file mode 100644 index 0000000..f94a521 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/Query.java @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + *

+ * https://www.renren.io + *

+ * 版权所有,侵权必究! + */ + +package com.msdw.tms.common.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.msdw.tms.common.xss.SQLFilter; +import org.apache.commons.lang.StringUtils; + +import java.util.Map; + +/** + * 查询参数 + * + * @author Mark sunlightcs@gmail.com + */ +public class Query { + + public IPage getPage(Map params) { + return this.getPage(params, null, false); + } + + public IPage getPage(Map params, String defaultOrderField, boolean isAsc) { + //分页参数 + long curPage = 1; + long limit = 10; + + if (params.get(Constant.PAGE) != null) { + curPage = Long.parseLong((String) params.get(Constant.PAGE)); + } + if (params.get(Constant.LIMIT) != null) { + limit = Long.parseLong((String) params.get(Constant.LIMIT)); + } + + //分页对象 + Page page = new Page<>(curPage, limit); + + //分页参数 + params.put(Constant.PAGE, page); + + //排序字段 + //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) + String orderField = SQLFilter.sqlInject((String) params.get(Constant.ORDER_FIELD)); + String order = (String) params.get(Constant.ORDER); + + //前端字段排序 + if (StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)) { + if (Constant.ASC.equalsIgnoreCase(order)) { + return page.addOrder(OrderItem.asc(orderField)); + } else { + return page.addOrder(OrderItem.desc(orderField)); + } + } + + //没有排序字段,则不排序 + if (StringUtils.isBlank(defaultOrderField)) { + return page; + } + + //默认排序 + if (isAsc) { + page.addOrder(OrderItem.asc(defaultOrderField)); + } else { + page.addOrder(OrderItem.desc(defaultOrderField)); + } + + return page; + } + + public IPage getPage(Integer pageNo, Integer size) { + //分页参数 + long curPage = 1; + long limit = 10; + + if (pageNo != null) { + curPage = Long.parseLong(pageNo.toString()); + } + if (size != null) { + limit = Long.parseLong(size.toString()); + } + + //分页对象 + Page page = new Page<>(curPage, limit); + + return page; + } +} diff --git a/src/main/java/com/msdw/tms/common/utils/R.java b/src/main/java/com/msdw/tms/common/utils/R.java new file mode 100644 index 0000000..4fcc3a4 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/R.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.msdw.tms.common.utils; + +import org.apache.http.HttpStatus; + +import java.util.HashMap; +import java.util.Map; + +/** + * 返回数据 + * + * @author Mark sunlightcs@gmail.com + */ +public class R extends HashMap { + private static final long serialVersionUID = 1L; + + public R() { + put("code", 0); + put("msg", "success"); + } + + public static R error() { + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员"); + } + + public static R error(String msg) { + return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg); + } + + public static R error(int code, String msg) { + R r = new R(); + r.put("code", code); + r.put("msg", msg); + return r; + } + + public static R ok(String msg) { + R r = new R(); + r.put("msg", msg); + return r; + } + + public static R ok(Map map) { + R r = new R(); + r.putAll(map); + return r; + } + + public static R ok() { + return new R(); + } + + public R put(String key, Object value) { + super.put(key, value); + return this; + } +} diff --git a/src/main/java/com/msdw/tms/common/utils/poi/ExcelAttribute.java b/src/main/java/com/msdw/tms/common/utils/poi/ExcelAttribute.java new file mode 100644 index 0000000..31b70b9 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/poi/ExcelAttribute.java @@ -0,0 +1,25 @@ +package com.msdw.tms.common.utils.poi; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ExcelAttribute { + /** + * 对应的列名称 + */ + String name() default ""; + + /** + * excel列的索引 + */ + int sort(); + + /** + * 字段类型对应的格式 + */ + String format() default ""; +} diff --git a/src/main/java/com/msdw/tms/common/utils/poi/ExcelExportUtil.java b/src/main/java/com/msdw/tms/common/utils/poi/ExcelExportUtil.java new file mode 100644 index 0000000..6da79eb --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/poi/ExcelExportUtil.java @@ -0,0 +1,87 @@ +package com.msdw.tms.common.utils.poi; + +import lombok.Data; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.net.URLEncoder; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 导出Excel工具类 + * 基于模板打印的方式导出: + */ +@Data +public class ExcelExportUtil { + + private int rowIndex; //写入数据的起始行 + private int styleIndex; //需要提取的样式所在的行号 + private Class clazz; //对象的字节码 + private Field fields[]; //对象中的所有属性 + + public ExcelExportUtil(Class clazz, int rowIndex, int styleIndex) { + this.clazz = clazz; + this.rowIndex = rowIndex; + this.styleIndex = styleIndex; + fields = clazz.getDeclaredFields(); + } + + /** + * 基于注解导出 + * 参数: + * response: + * InputStream:模板的输入流 + * objs:数据 + * fileName:生成的文件名 + */ + public void export(HttpServletResponse response, InputStream is, List objs, String fileName) throws Exception { + + //1.根据模板创建工作簿 + XSSFWorkbook workbook = new XSSFWorkbook(is); + //2.读取工作表 + Sheet sheet = workbook.getSheetAt(0); + //3.提取公共的样式 + CellStyle[] styles = getTemplateStyles(sheet.getRow(styleIndex)); + //4.根据数据创建每一行和每一个单元格的数据2 + AtomicInteger datasAi = new AtomicInteger(rowIndex); //数字 + for (T t : objs) { + //datasAi.getAndIncrement() :获取数字,并++ i++ + Row row = sheet.createRow(datasAi.getAndIncrement()); + for (int i = 0; i < styles.length; i++) { + Cell cell = row.createCell(i); + cell.setCellStyle(styles[i]); + for (Field field : fields) { + if (field.isAnnotationPresent(ExcelAttribute.class)) { + field.setAccessible(true); + ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class); + if (i == ea.sort()) { + if (field.get(t) != null) { + cell.setCellValue(field.get(t).toString()); + } + } + } + } + } + } + fileName = URLEncoder.encode(fileName, "UTF-8"); + response.setContentType("application/octet-stream"); + response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes("ISO8859-1"))); + response.setHeader("filename", fileName); + workbook.write(response.getOutputStream()); + } + + public CellStyle[] getTemplateStyles(Row row) { + CellStyle[] styles = new CellStyle[row.getLastCellNum()]; + for (int i = 0; i < row.getLastCellNum(); i++) { + styles[i] = row.getCell(i).getCellStyle(); + } + return styles; + } +} diff --git a/src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java b/src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java new file mode 100644 index 0000000..57c5627 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/utils/poi/ExcelImportUtil.java @@ -0,0 +1,120 @@ +package com.msdw.tms.common.utils.poi; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import java.io.InputStream; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + + +public class ExcelImportUtil { + + private Class clazz; + private Field fields[]; + + public ExcelImportUtil(Class clazz) { + this.clazz = clazz; + fields = clazz.getDeclaredFields(); + } + + /** + * 基于注解读取excel + */ + public List readExcel(InputStream is, int rowIndex, int cellIndex) { + List list = new ArrayList(); + T entity = null; + try { + XSSFWorkbook workbook = new XSSFWorkbook(is); + Sheet sheet = workbook.getSheetAt(0); + // 不准确 + // int rowLength = sheet.getLastRowNum(); + // System.out.println(sheet.getLastRowNum()); + for (int rowNum = rowIndex; rowNum <= sheet.getLastRowNum(); rowNum++) { + Row row = sheet.getRow(rowNum); + entity = (T) clazz.newInstance(); + // System.out.println(row.getLastCellNum()); + for (int j = cellIndex; j < row.getLastCellNum(); j++) { + Cell cell = row.getCell(j); + for (Field field : fields) { + if (field.isAnnotationPresent(ExcelAttribute.class)) { + field.setAccessible(true); + ExcelAttribute ea = field.getAnnotation(ExcelAttribute.class); + if (j == ea.sort()) { + field.set(entity, covertAttrType(field, cell)); + } + } + } + } + list.add(entity); + } + } catch (Exception e) { + e.printStackTrace(); + } + return list; + } + + /** + * 类型转换 将cell 单元格格式转为 字段类型 + */ + private Object covertAttrType(Field field, Cell cell) throws Exception { + String fieldType = field.getType().getSimpleName(); + if ("String".equals(fieldType)) { + return getValue(cell); + } else if ("Date".equals(fieldType)) { + return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(getValue(cell)); + } else if ("int".equals(fieldType) || "Integer".equals(fieldType)) { + return Integer.parseInt(getValue(cell)); + } else if ("double".equals(fieldType) || "Double".equals(fieldType)) { + return Double.parseDouble(getValue(cell)); + } else { + return null; + } + } + + + /** + * 格式转为String + * + * @param cell + * @return + */ + public String getValue(Cell cell) { + if (cell == null) { + return ""; + } + switch (cell.getCellType()) { + case STRING: + return cell.getRichStringCellValue().getString().trim(); + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + Date dt = DateUtil.getJavaDate(cell.getNumericCellValue()); + return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(dt); + } else { + // 防止数值变成科学计数法 + String strCell = ""; + Double num = cell.getNumericCellValue(); + BigDecimal bd = new BigDecimal(num.toString()); + if (bd != null) { + strCell = bd.toPlainString(); + } + // 去除 浮点型 自动加的 .0 + if (strCell.endsWith(".0")) { + strCell = strCell.substring(0, strCell.indexOf(".")); + } + return strCell; + } + case BOOLEAN: + return String.valueOf(cell.getBooleanCellValue()); + default: + return ""; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/msdw/tms/common/xss/HTMLFilter.java b/src/main/java/com/msdw/tms/common/xss/HTMLFilter.java new file mode 100644 index 0000000..6f1df38 --- /dev/null +++ b/src/main/java/com/msdw/tms/common/xss/HTMLFilter.java @@ -0,0 +1,530 @@ +package com.msdw.tms.common.xss; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * HTML filtering utility for protecting against XSS (Cross Site Scripting). + * + * This code is licensed LGPLv3 + * + * This code is a Java port of the original work in PHP by Cal Hendersen. + * http://code.iamcal.com/php/lib_filter/ + * + * The trickiest part of the translation was handling the differences in regex handling + * between PHP and Java. These resources were helpful in the process: + * + * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html + * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php + * http://www.regular-expressions.info/modifiers.html + * + * A note on naming conventions: instance variables are prefixed with a "v"; global + * constants are in all caps. + * + * Sample use: + * String input = ... + * String clean = new HTMLFilter().filter( input ); + * + * The class is not thread safe. Create a new instance if in doubt. + * + * If you find bugs or have suggestions on improvement (especially regarding + * performance), please contact us. The latest version of this + * source, and our contact details, can be found at http://xss-html-filter.sf.net + * + * @author Joseph O'Connell + * @author Cal Hendersen + * @author Michael Semb Wever + */ +public final class HTMLFilter { + + /** regex flag union representing /si modifiers in php **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("<"); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap(); + + /** set of allowed html elements, along with allowed attributes for each element **/ + private final Map> vAllowed; + /** counts of open tags for each (allowable) html element **/ + private final Map vTagCounts = new HashMap(); + + /** html elements which must always be self-closing (e.g. "") **/ + private final String[] vSelfClosingTags; + /** html elements which must always have separate opening and closing tags (e.g. "") **/ + private final String[] vNeedClosingTags; + /** set of disallowed html elements **/ + private final String[] vDisallowed; + /** attributes which should be checked for valid protocols **/ + private final String[] vProtocolAtts; + /** allowed protocols **/ + private final String[] vAllowedProtocols; + /** tags which should be removed if they contain no content (e.g. "" or "") **/ + private final String[] vRemoveBlanks; + /** entities allowed within html markup **/ + private final String[] vAllowedEntities; + /** flag determining whether comments are allowed in input String. */ + private final boolean stripComment; + private final boolean encodeQuotes; + private boolean vDebug = false; + /** + * flag determining whether to try to make tags when presented with "unbalanced" + * angle brackets (e.g. "" becomes " text "). If set to false, + * unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** Default constructor. + * + */ + public HTMLFilter() { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = true; + } + + /** Set debug flag to true. Otherwise use default settings. See the default constructor. + * + * @param debug turn debug on with a true argument + */ + public HTMLFilter(final boolean debug) { + this(); + vDebug = debug; + + } + + /** Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + public HTMLFilter(final Map conf) { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() { + vTagCounts.clear(); + } + + private void debug(final String msg) { + if (vDebug) { + Logger.getAnonymousLogger().info(msg); + } + } + + //--------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + //--------------------------------------------------------------- + /** + * given a user submitted input String, filter out any invalid or restricted + * html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) { + reset(); + String s = input; + + debug("************************************************"); + debug(" INPUT: " + input); + + s = escapeComments(s); + debug(" escapeComments: " + s); + + s = balanceHTML(s); + debug(" balanceHTML: " + s); + + s = checkTags(s); + debug(" checkTags: " + s); + + s = processRemoveBlanks(s); + debug("processRemoveBlanks: " + s); + + s = validateEntities(s); + debug(" validateEntites: " + s); + + debug("************************************************\n\n"); + return s; + } + + public boolean isAlwaysMakeTags(){ + return alwaysMakeTags; + } + + public boolean isStripComments(){ + return stripComment; + } + + private String escapeComments(final String s) { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) { + final String match = m.group(1); //(.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) { + if (alwaysMakeTags) { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } else { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + s = buf.toString(); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + for (String key : vTagCounts.keySet()) { + for (int ii = 0; ii < vTagCounts.get(key); ii++) { + s += ""; + } + } + + return s; + } + + private String processRemoveBlanks(final String s) { + String result = s; + for (String tag : vRemoveBlanks) { + if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){ + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){ + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) { + if (!inArray(name, vSelfClosingTags)) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) { + String params = ""; + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList(); + final List paramValues = new ArrayList(); + while (m2.find()) { + paramNames.add(m2.group(1)); //([a-z0-9]+) + paramValues.add(m2.group(3)); //(.*?) + } + while (m3.find()) { + paramNames.add(m3.group(1)); //([a-z0-9]+) + paramValues.add(m3.group(3)); //([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + +// debug( "paramName='" + paramName + "'" ); +// debug( "paramValue='" + paramValue + "'" ); +// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) { + if (inArray(paramName, vProtocolAtts)) { + paramValue = processParamProtocol(paramValue); + } + params += " " + paramName + "=\"" + paramValue + "\""; + } + } + + if (inArray(name, vSelfClosingTags)) { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) { + ending = ""; + } + + if (ending == null || ending.length() < 1) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } else { + vTagCounts.put(name, 1); + } + } else { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } else { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1, s.length()); + if (s.startsWith("#//")) { + s = "#" + s.substring(3, s.length()); + } + } + } + + return s; + } + + private String decodeEntities(String s) { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) { + final String one = m.group(1); //([^&;]*) + final String two = m.group(2); //(?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s){ + if(encodeQuotes){ + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) { + final String one = m.group(1); //(>|^) + final String two = m.group(2); //([^<]+?) + final String three = m.group(3); //(<|$) + m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three)); + } + m.appendTail(buf); + return buf.toString(); + }else{ + return s; + } + } + + private String checkEntity(final String preamble, final String term) { + + return ";".equals(term) && isValidEntity(preamble) + ? '&' + preamble + : "&" + preamble; + } + + private boolean isValidEntity(final String entity) { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) { + for (String item : array) { + if (item != null && item.equals(s)) { + return true; + } + } + return false; + } + + private boolean allowed(final String name) { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} \ No newline at end of file diff --git a/src/main/java/com/msdw/tms/common/xss/SQLFilter.java b/src/main/java/com/msdw/tms/common/xss/SQLFilter.java new file mode 100644 index 0000000..3ea59ab --- /dev/null +++ b/src/main/java/com/msdw/tms/common/xss/SQLFilter.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.msdw.tms.common.xss; + +import com.msdw.tms.common.exception.RRException; +import org.apache.commons.lang.StringUtils; + +/** + * SQL过滤 + * + * @author Mark sunlightcs@gmail.com + */ +public class SQLFilter { + + /** + * SQL注入过滤 + * @param str 待验证的字符串 + */ + public static String sqlInject(String str){ + if(StringUtils.isBlank(str)){ + return null; + } + //去掉'|"|;|\字符 + str = StringUtils.replace(str, "'", ""); + str = StringUtils.replace(str, "\"", ""); + str = StringUtils.replace(str, ";", ""); + str = StringUtils.replace(str, "\\", ""); + + //转换成小写 + str = str.toLowerCase(); + + //非法字符 + String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; + + //判断是否包含非法字符 + for(String keyword : keywords){ + if(str.indexOf(keyword) != -1){ + throw new RRException("包含非法字符"); + } + } + + return str; + } +} diff --git a/src/main/java/com/msdw/tms/config/AliyunOssConfig.java b/src/main/java/com/msdw/tms/config/AliyunOssConfig.java new file mode 100644 index 0000000..3bc4d74 --- /dev/null +++ b/src/main/java/com/msdw/tms/config/AliyunOssConfig.java @@ -0,0 +1,59 @@ +package com.msdw.tms.config; + +import com.aliyun.oss.OSSClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Component +@PropertySource(value = "classpath:aliyun.properties") +@Configuration +public class AliyunOssConfig { + + @Value("${oss.endpoint}") + private String endpoint;// oss外网访问域名 + @Value("${oss.accessKeyId}") + private String accessKeyId;// oss中的密匙keyId + @Value("${oss.secretAccessKey}") + private String secretAccessKey;// oss中的密钥 + @Value("${oss.bucketName}") + private String bucketName;// 仓库名称 + @Value("${oss.sufferUrl}") + private String sufferUrl; + @Value("${user.userAvatars}")//用户头像 + private String userAvatars; + + @Bean + @Scope("prototype") + public OSSClient ossClient() { + return new OSSClient(endpoint, accessKeyId, secretAccessKey); + } + + public String getEndpoint() { + return endpoint; + } + + public String getAccessKeyId() { + return accessKeyId; + } + + public String getSecretAccessKey() { + return secretAccessKey; + } + + public String getBucketName() { + return bucketName; + } + + public String getSufferUrl() { + return sufferUrl; + } + + public String getUserAvatars() { + return userAvatars; + } + +} diff --git a/src/main/java/com/msdw/tms/config/SwaggerConfig.java b/src/main/java/com/msdw/tms/config/SwaggerConfig.java new file mode 100644 index 0000000..4a3fe69 --- /dev/null +++ b/src/main/java/com/msdw/tms/config/SwaggerConfig.java @@ -0,0 +1,35 @@ +package com.msdw.tms.config; + +import io.swagger.annotations.ApiOperation; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +//@Profile({"dev","test"}) +//@ConditionalOnProperty(name = "swagger.enable", havingValue = "true") +public class SwaggerConfig { + + @Bean + public Docket productApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select()//添加ApiOperiation注解的被扫描 + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("网站管理").description("网站管理") + .version("1.0").build(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/msdw/tms/controller/EvaluationRulesController.java b/src/main/java/com/msdw/tms/controller/EvaluationRulesController.java new file mode 100644 index 0000000..0efa731 --- /dev/null +++ b/src/main/java/com/msdw/tms/controller/EvaluationRulesController.java @@ -0,0 +1,49 @@ +package com.msdw.tms.controller; + +import com.msdw.tms.api.EvaluationRulesControllerApi; +import com.msdw.tms.common.utils.R; +import com.msdw.tms.entity.EvaluationRulesEntity; +import com.msdw.tms.entity.vo.EvaluationRulesVO; +import com.msdw.tms.service.EvaluationRulesService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@RestController +@RequestMapping("tms/evaluationrules") +public class EvaluationRulesController implements EvaluationRulesControllerApi { + @Autowired + private EvaluationRulesService evaluationRulesService; + + /** + * 测评规则信息的展示 + */ + @Override + @GetMapping("/info") + //@RequiresPermissions("qms:evaluationrules:info") + public R info() { + EvaluationRulesVO evaluationRulesVO = evaluationRulesService.getEvaluationRules(); + + return R.ok().put("data", evaluationRulesVO); + } + + /** + * 修改 + */ + @Override + @PutMapping("/update") + //@RequiresPermissions("qms:evaluationrules:update") + public R update(@RequestBody EvaluationRulesEntity evaluationRules) { + boolean b = evaluationRulesService.updateEvaluationRulesById(evaluationRules); + + return b ? R.ok() : R.error(); + } + +} diff --git a/src/main/java/com/msdw/tms/controller/QuestionsController.java b/src/main/java/com/msdw/tms/controller/QuestionsController.java new file mode 100644 index 0000000..bce1ca3 --- /dev/null +++ b/src/main/java/com/msdw/tms/controller/QuestionsController.java @@ -0,0 +1,160 @@ +package com.msdw.tms.controller; + +import com.msdw.tms.api.QuestionsControllerApi; +import com.msdw.tms.common.utils.FilesResult; +import com.msdw.tms.common.utils.PageUtils; +import com.msdw.tms.common.utils.R; +import com.msdw.tms.entity.request.QuestionsAddRequest; +import com.msdw.tms.entity.request.QuestionsQueryRequest; +import com.msdw.tms.entity.request.QuestionsUpdateRequest; +import com.msdw.tms.entity.vo.EvaluationVO; +import com.msdw.tms.entity.vo.QuestionsDetailVO; +import com.msdw.tms.service.AliyunOssService; +import com.msdw.tms.service.QuestionsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; + + +/** + * 记录试题信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@RestController +@RequestMapping("tms/questions") +public class QuestionsController implements QuestionsControllerApi { + @Autowired + private QuestionsService questionsService; + + @Autowired + private AliyunOssService ossService; + + /** + * 列表 + */ + @Override + @GetMapping("/list") + //@RequiresPermissions("qms:questions:list") + public R list(@RequestParam Integer page, + @RequestParam Integer size, + QuestionsQueryRequest request) { + + PageUtils questionsQueryPage = questionsService.queryQuestionsPage(page, size, request); + + return R.ok().put("page", questionsQueryPage); + } + + /** + * 信息 + */ + @Override + @GetMapping("/info/{id}") + //@RequiresPermissions("qms:questions:info") + public R info(@PathVariable("id") Integer id) { + QuestionsDetailVO questions = questionsService.getQuestionDetailById(id); + + return R.ok().put("questions", questions); + } + + /** + * 保存 + */ + @Override + @PostMapping("/save") + //@RequiresPermissions("qms:questions:save") + public R save(@RequestBody QuestionsAddRequest questions) { + boolean save = questionsService.saveQuestion(questions); + + return save ? R.ok() : R.error(); + } + + /** + * 根据试题id修改试题信息 + */ + @Override + @PutMapping("/update") + //@RequiresPermissions("qms:questions:update") + public R update(@RequestBody QuestionsUpdateRequest questions) { + boolean update = questionsService.updateQuestionById(questions); + + return update ? R.ok() : R.error(); + } + + /** + * 是否禁用试题 + */ + @Override + @PutMapping("/isnable") + //@RequiresPermissions("qms:questions:isnable") + public R isnable(Integer id) { + boolean b = questionsService.isnable(id); + + return b ? R.ok() : R.error(); + } + + /** + * 删除 + */ + @Override + @DeleteMapping("/delete") + //@RequiresPermissions("qms:questions:delete") + public R delete(@RequestBody Integer[] ids) { + boolean delete = questionsService.deleteByIds(Arrays.asList(ids)); + + return delete ? R.ok() : R.error(); + } + + /** + * 通过excel批量导入 + */ + @Override + @PostMapping("/import") + //@RequiresPermissions("qms:questions:import") + public R importQuestion(@RequestParam(name = "file") MultipartFile file) throws IOException { + boolean b = questionsService.importQuestion(file); + + return b ? R.ok() : R.error(); + } + + /** + * excel模板文件上传 + * + * @param file + * @return + */ + @Override + @PostMapping("/upload") + //@RequiresPermissions("qms:questions:upload") + public R uploadFiles(MultipartFile file) throws IOException { + FilesResult filesResult = questionsService.uploadFiles(file); + return R.ok().put("data", filesResult); + } + + /** + * excel模板文件下载 + * + * @return + */ + @Override + @GetMapping("/download") + //@RequiresPermissions("qms:questions:download") + public R downloadFiles(HttpServletResponse response) throws IOException { + questionsService.downloadFiles(response); + return R.ok(); + } + + @Override + @GetMapping("/evaluation") + public R evaluation() { + EvaluationVO evaluation = questionsService.evaluation(); + return R.ok().put("data", evaluation); + } + +} diff --git a/src/main/java/com/msdw/tms/dao/EvaluationRulesDao.java b/src/main/java/com/msdw/tms/dao/EvaluationRulesDao.java new file mode 100644 index 0000000..d1a5c22 --- /dev/null +++ b/src/main/java/com/msdw/tms/dao/EvaluationRulesDao.java @@ -0,0 +1,17 @@ +package com.msdw.tms.dao; + +import com.msdw.tms.entity.EvaluationRulesEntity; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Mapper +public interface EvaluationRulesDao extends BaseMapper { + +} diff --git a/src/main/java/com/msdw/tms/dao/QuestionsDao.java b/src/main/java/com/msdw/tms/dao/QuestionsDao.java new file mode 100644 index 0000000..6775d13 --- /dev/null +++ b/src/main/java/com/msdw/tms/dao/QuestionsDao.java @@ -0,0 +1,17 @@ +package com.msdw.tms.dao; + +import com.msdw.tms.entity.QuestionsEntity; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 记录试题信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Mapper +public interface QuestionsDao extends BaseMapper { + +} diff --git a/src/main/java/com/msdw/tms/dao/XlsxTemplateDao.java b/src/main/java/com/msdw/tms/dao/XlsxTemplateDao.java new file mode 100644 index 0000000..169e869 --- /dev/null +++ b/src/main/java/com/msdw/tms/dao/XlsxTemplateDao.java @@ -0,0 +1,17 @@ +package com.msdw.tms.dao; + +import com.msdw.tms.entity.XlsxTemplateEntity; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * 模板文件信息记录 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Mapper +public interface XlsxTemplateDao extends BaseMapper { + +} diff --git a/src/main/java/com/msdw/tms/entity/EvaluationRulesEntity.java b/src/main/java/com/msdw/tms/entity/EvaluationRulesEntity.java new file mode 100644 index 0000000..88f776e --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/EvaluationRulesEntity.java @@ -0,0 +1,64 @@ +package com.msdw.tms.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; +import java.util.Date; +import lombok.Data; + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Data +@TableName("tms_evaluation_rules") +public class EvaluationRulesEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 测评类型:1:随机类型,0:自定义类型 + */ + private Integer evaluationType; + /** + * 测评时长,单位:分钟 + */ + private Integer duration; + /** + * 测评总题数 + */ + private Integer questionNum; + /** + * 单选题数 + */ + private Integer singleNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isSingleEnable; + /** + * 多选题数 + */ + private Integer multipleNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isMultipleEnable; + /** + * 判断题数 + */ + private Integer judgmentNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isJudgmentEnable; + +} diff --git a/src/main/java/com/msdw/tms/entity/QuestionsEntity.java b/src/main/java/com/msdw/tms/entity/QuestionsEntity.java new file mode 100644 index 0000000..f6ea702 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/QuestionsEntity.java @@ -0,0 +1,100 @@ +package com.msdw.tms.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; +import java.util.Date; +import lombok.Data; + +/** + * 记录试题信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Data +@TableName("tms_questions") +public class QuestionsEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 自增主键 + */ + @TableId + private Integer id; + /** + * 题型号:用于区分是什么题型 + */ + private Integer questionTypeNo; + /** + * 题型名称 + */ + private String questionType; + /** + * 题干信息 + */ + private String questionStem; + /** + * A选项内容 + */ + private String optionA; + /** + * B选项内容 + */ + private String optionB; + /** + * C选项内容 + */ + private String optionC; + /** + * D选项内容 + */ + private String optionD; + /** + * E选项内容 + */ + private String optionE; + /** + * F选项内容 + */ + private String optionF; + /** + * 正确答案 + */ + private String answer; + /** + * 答案解析 + */ + private String answerAnalysis; + /** + * 是否禁用:1:启用,0:禁用,默认是1启用 + */ + private Integer isEnable; + /** + * 是否删除:1使用,0删除,默认1使用 + */ + private Integer isDel; + /** + * 创建人 + */ + private String createUser; + /** + * 创建时间 + */ + private Date createTime; + /** + * 修改人 + */ + private String modifyUser; + /** + * 修改时间,用于排序,创建时,修改时间等于创建时间 + */ + private Date modifyTime; + /** + * 试题科目 + */ + private String subjects; + +} diff --git a/src/main/java/com/msdw/tms/entity/XlsxTemplateEntity.java b/src/main/java/com/msdw/tms/entity/XlsxTemplateEntity.java new file mode 100644 index 0000000..cb3757a --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/XlsxTemplateEntity.java @@ -0,0 +1,40 @@ +package com.msdw.tms.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.io.Serializable; +import java.util.Date; +import lombok.Data; + +/** + * 模板文件信息记录 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Data +@TableName("tms_xlsx_template") +public class XlsxTemplateEntity implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @TableId + private Integer id; + /** + * 文件名 + */ + private String fileName; + /** + * 文件全路径 + */ + private String fileUrl; + /** + * 状态 + */ + private Integer status; + +} diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java new file mode 100644 index 0000000..3949b36 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/request/QuestionsAddRequest.java @@ -0,0 +1,61 @@ +package com.msdw.tms.entity.request; + +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * 试题的基本信息表 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-14 16:05:06 + */ +@Data +public class QuestionsAddRequest { + /** + * 题型名称 + */ + private String questionType; + /** + * 题干信息 + */ + private String questionStem; + /** + * A选项内容 + */ + private String optionA; + /** + * B选项内容 + */ + private String optionB; + /** + * C选项内容 + */ + private String optionC; + /** + * D选项内容 + */ + private String optionD; + /** + * E选项内容 + */ + private String optionE; + /** + * F选项内容 + */ + private String optionF; + /** + * 正确答案 + */ + private String answer; + /** + * 答案解析 + */ + private String answerAnalysis; + /** + * 试题科目 + */ + private String subjects; +} diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java new file mode 100644 index 0000000..6ae49e1 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/request/QuestionsImportRequest.java @@ -0,0 +1,70 @@ +package com.msdw.tms.entity.request; + +import com.msdw.tms.common.utils.poi.ExcelAttribute; +import lombok.Data; + +/** + * 试题的基本信息表 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-14 16:05:06 + */ +@Data +public class QuestionsImportRequest { + /** + * 试题科目 + */ + @ExcelAttribute(sort = 0) + private String subjects; + /** + * 题干,问题描述 + */ + @ExcelAttribute(sort = 1) + private String questionStem; + /** + * 题型 + */ + @ExcelAttribute(sort = 2) + private String questionType; + /** + * 选项A + */ + @ExcelAttribute(sort = 3) + private String optionA; + /** + * 选项B + */ + @ExcelAttribute(sort = 4) + private String optionB; + /** + * 选项C + */ + @ExcelAttribute(sort = 5) + private String optionC; + /** + * 选项D + */ + @ExcelAttribute(sort = 6) + private String optionD; + /** + * 选项E + */ + @ExcelAttribute(sort = 7) + private String optionE; + /** + * 选项F + */ + @ExcelAttribute(sort = 8) + private String optionF; + /** + * 正确答案 + */ + @ExcelAttribute(sort = 9) + private String answer; + /** + * 答案解析 + */ + @ExcelAttribute(sort = 10) + private String answerAnalysis; +} diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java new file mode 100644 index 0000000..bc7c3f0 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/request/QuestionsQueryRequest.java @@ -0,0 +1,36 @@ +package com.msdw.tms.entity.request; + +import lombok.Data; + +/** + * 试题的基本信息表 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-14 16:05:06 + */ +@Data +public class QuestionsQueryRequest { + + /** + * 题干,问题描述 + */ + private String questionStem; + + // /** + // * 题型id + // */ + // private Integer questionType; + // /** + // * 参考答案 + // */ + // private String answer; + // /** + // * 答案解析 + // */ + // private String answerAnalysis; + // /** + // * 创建时,修改时间即为创建时间,修改时间用于前端显示和排序 + // */ + // private Date modifyTime; +} diff --git a/src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java b/src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java new file mode 100644 index 0000000..d86496c --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/request/QuestionsUpdateRequest.java @@ -0,0 +1,62 @@ +package com.msdw.tms.entity.request; + +import lombok.Data; + +/** + * 试题的基本信息表 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-14 16:05:06 + */ +@Data +public class QuestionsUpdateRequest { + /** + * 主键 + */ + private Integer id; + /** + * 题型名称 + */ + private String questionType; + /** + * 题干信息 + */ + private String questionStem; + /** + * A选项内容 + */ + private String optionA; + /** + * B选项内容 + */ + private String optionB; + /** + * C选项内容 + */ + private String optionC; + /** + * D选项内容 + */ + private String optionD; + /** + * E选项内容 + */ + private String optionE; + /** + * F选项内容 + */ + private String optionF; + /** + * 正确答案 + */ + private String answer; + /** + * 答案解析 + */ + private String answerAnalysis; + /** + * 试题科目 + */ + private String subjects; +} diff --git a/src/main/java/com/msdw/tms/entity/response/CommonCode.java b/src/main/java/com/msdw/tms/entity/response/CommonCode.java new file mode 100644 index 0000000..5f33b78 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/response/CommonCode.java @@ -0,0 +1,54 @@ +package com.msdw.tms.entity.response; + +import lombok.ToString; + +/** + * @Author: mrt. + * @Description: + * @Date:Created in 2018/1/24 18:33. + * @Modified By: + */ + +@ToString +public enum CommonCode implements ResultCode { + + SUCCESS(true, 10000, "操作成功!"), + UNAUTHENTICATED(false, 10001, "此操作需要登陆系统!"), + UNAUTHORISE(false, 10002, "权限不足,无权操作!"), + INVALID_PARAM(false, 10003, "非法参数!"), + QUESTION_NUM_INVALID(false, 10004, "测评题目数量设置超出范围!"), + QUESTION_EXISTS(false, 10005, "此题目已存在!"), + QUESTIONTYPE_INVALID(false, 10005, "题型错误!"), + FAIL(false, 11111, "操作失败!"), + SERVER_ERROR(false, 99999, "抱歉,系统繁忙,请稍后重试!"); + // private static ImmutableMap codes ; + //操作是否成功 + boolean success; + //操作代码 + int code; + //提示信息 + String message; + + private CommonCode(boolean success, int code, String message) { + this.success = success; + this.code = code; + this.message = message; + } + + @Override + public boolean success() { + return success; + } + + @Override + public int code() { + return code; + } + + @Override + public String message() { + return message; + } + + +} diff --git a/src/main/java/com/msdw/tms/entity/response/Response.java b/src/main/java/com/msdw/tms/entity/response/Response.java new file mode 100644 index 0000000..9c159ea --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/response/Response.java @@ -0,0 +1,9 @@ +package com.msdw.tms.entity.response; + +/** + * Created by admin on 2018/3/5. + */ +public interface Response { + public static final boolean SUCCESS = true; + public static final int SUCCESS_CODE = 10000; +} diff --git a/src/main/java/com/msdw/tms/entity/response/ResponseResult.java b/src/main/java/com/msdw/tms/entity/response/ResponseResult.java new file mode 100644 index 0000000..0897404 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/response/ResponseResult.java @@ -0,0 +1,41 @@ +package com.msdw.tms.entity.response; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +/** + * @Author: mrt. + * @Description: + * @Date:Created in 2018/1/24 18:33. + * @Modified By: + */ +@Data +@ToString +@NoArgsConstructor +public class ResponseResult implements Response { + + //操作是否成功 + boolean success = SUCCESS; + + //操作代码 + int code = SUCCESS_CODE; + + //提示信息 + String message; + + public ResponseResult(ResultCode resultCode) { + this.success = resultCode.success(); + this.code = resultCode.code(); + this.message = resultCode.message(); + } + + public static ResponseResult SUCCESS() { + return new ResponseResult(CommonCode.SUCCESS); + } + + public static ResponseResult FAIL() { + return new ResponseResult(CommonCode.FAIL); + } + +} diff --git a/src/main/java/com/msdw/tms/entity/response/ResultCode.java b/src/main/java/com/msdw/tms/entity/response/ResultCode.java new file mode 100644 index 0000000..0c380c8 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/response/ResultCode.java @@ -0,0 +1,21 @@ +package com.msdw.tms.entity.response; + +/** + * Created by mrt on 2018/3/5. + * 10000-- 通用错误代码 + * 22000-- 媒资错误代码 + * 23000-- 用户中心错误代码 + * 24000-- cms错误代码 + * 25000-- 文件系统 + */ +public interface ResultCode { + //操作是否成功,true为成功,false操作失败 + boolean success(); + + //操作代码 + int code(); + + //提示信息 + String message(); + +} diff --git a/src/main/java/com/msdw/tms/entity/vo/EvaluationRulesVO.java b/src/main/java/com/msdw/tms/entity/vo/EvaluationRulesVO.java new file mode 100644 index 0000000..d8e375e --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/vo/EvaluationRulesVO.java @@ -0,0 +1,76 @@ +package com.msdw.tms.entity.vo; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Data +public class EvaluationRulesVO implements Serializable { + + /** + * 主键 + */ + private Integer id; + /** + * 测评类型:1:随机类型,0:自定义类型 + */ + private Integer evaluationType; + /** + * 测评时长,单位:分钟 + */ + private Integer duration; + /** + * 测评总题数 + */ + private Integer questionNum; + /** + * 题库总题数 + */ + private Integer totalQuestionNum; + /** + * 单选题数 + */ + private Integer singleNum; + /** + * 题库单选题总数 + */ + private Integer totalSingleNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isSingleEnable; + /** + * 多选题数 + */ + private Integer multipleNum; + /** + * 题库多选题总数 + */ + private Integer totalMultipleNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isMultipleEnable; + /** + * 判断题数 + */ + private Integer judgmentNum; + /** + * 题库判断题总数 + */ + private Integer totalJudgmentNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isJudgmentEnable; + +} diff --git a/src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java b/src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java new file mode 100644 index 0000000..c40b6e5 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/vo/EvaluationVO.java @@ -0,0 +1,66 @@ +package com.msdw.tms.entity.vo; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.msdw.tms.entity.QuestionsEntity; +import lombok.Data; + +import java.io.Serializable; +import java.util.Set; + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Data +@TableName("tms_evaluation_rules") +public class EvaluationVO implements Serializable { + + /** + * 主键 + */ + private Integer id; + /** + * 测评类型:1:随机类型,0:自定义类型 + */ + private Integer evaluationType; + /** + * 测评时长,单位:分钟 + */ + private Integer duration; + /** + * 测评总题数 + */ + private Integer questionNum; + /** + * 单选题数 + */ + private Integer singleNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isSingleEnable; + /** + * 多选题数 + */ + private Integer multipleNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isMultipleEnable; + /** + * 判断题数 + */ + private Integer judgmentNum; + /** + * 只在类型为自定义类型时才启用:1:启用,0:不启用,默认1启用 + */ + private Integer isJudgmentEnable; + /** + *试题列表 + */ + private Set Questions; +} diff --git a/src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java b/src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java new file mode 100644 index 0000000..182d643 --- /dev/null +++ b/src/main/java/com/msdw/tms/entity/vo/QuestionsDetailVO.java @@ -0,0 +1,121 @@ +package com.msdw.tms.entity.vo; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 记录试题信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +@Data +public class QuestionsDetailVO implements Serializable { + + /** + * 主键 + */ + private Integer id; + /** + * 题型号:用于区分是什么题型 + */ + private Integer questionTypeNo; + /** + * 题型名称 + */ + private String questionType; + /** + * 题干信息 + */ + private String questionStem; + /** + * A选项内容 + */ + private String optionA; + /** + * A选项是否为正确答案 + */ + private boolean AIsTrue = false; + /** + * B选项内容 + */ + private String optionB; + /** + * B选项是否为正确答案 + */ + private boolean BIsTrue = false; + /** + * C选项内容 + */ + private String optionC; + /** + * C选项是否为正确答案 + */ + private boolean CIsTrue = false; + /** + * D选项内容 + */ + private String optionD; + /** + * D选项是否为正确答案 + */ + private boolean DIsTrue = false; + /** + * E选项内容 + */ + private String optionE; + /** + * E选项是否为正确答案 + */ + private boolean EIsTrue = false; + /** + * F选项内容 + */ + private String optionF; + /** + * F选项是否为正确答案 + */ + private boolean FIsTrue = false; + /** + * 正确答案 + */ + private String answer; + /** + * 答案解析 + */ + private String answerAnalysis; + /** + * 是否禁用:1:启用,0:禁用,默认是1启用 + */ + private Integer isEnable; + /** + * 是否删除:1使用,0删除,默认1使用 + */ + private Integer isDel; + /** + * 创建人 + */ + private String createUser; + /** + * 创建时间 + */ + private Date createTime; + /** + * 修改人 + */ + private String modifyUser; + /** + * 修改时间,用于排序,创建时,修改时间等于创建时间 + */ + private Date modifyTime; + /** + * 试题科目 + */ + private String subjects; + +} diff --git a/src/main/java/com/msdw/tms/service/AliyunOssService.java b/src/main/java/com/msdw/tms/service/AliyunOssService.java new file mode 100644 index 0000000..5c12e80 --- /dev/null +++ b/src/main/java/com/msdw/tms/service/AliyunOssService.java @@ -0,0 +1,32 @@ +package com.msdw.tms.service; + +import com.msdw.tms.common.utils.FilesResult; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public interface AliyunOssService { + + /** + * 上传文件 + * + * @param file 上传文件 + */ + FilesResult uploadFiles(MultipartFile file) throws IOException; + + /** + * 下载文件 + * + * @param response + * @param objectName 本地路径 + */ + void downloadFiles(HttpServletResponse response, String objectName) throws IOException; + + /** + * 根据文件路径+文件名称,删除该文件 + * + * @param filename + */ + void deleteFile(String filename); +} diff --git a/src/main/java/com/msdw/tms/service/EvaluationRulesService.java b/src/main/java/com/msdw/tms/service/EvaluationRulesService.java new file mode 100644 index 0000000..a9578a3 --- /dev/null +++ b/src/main/java/com/msdw/tms/service/EvaluationRulesService.java @@ -0,0 +1,19 @@ +package com.msdw.tms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.msdw.tms.entity.EvaluationRulesEntity; +import com.msdw.tms.entity.vo.EvaluationRulesVO; + +/** + * 测评规则信息记录,只记录一条信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +public interface EvaluationRulesService extends IService { + EvaluationRulesVO getEvaluationRules(); + + boolean updateEvaluationRulesById(EvaluationRulesEntity evaluationRules); +} + diff --git a/src/main/java/com/msdw/tms/service/QuestionsService.java b/src/main/java/com/msdw/tms/service/QuestionsService.java new file mode 100644 index 0000000..f3d4544 --- /dev/null +++ b/src/main/java/com/msdw/tms/service/QuestionsService.java @@ -0,0 +1,48 @@ +package com.msdw.tms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.msdw.tms.common.utils.FilesResult; +import com.msdw.tms.common.utils.PageUtils; +import com.msdw.tms.entity.QuestionsEntity; +import com.msdw.tms.entity.request.QuestionsAddRequest; +import com.msdw.tms.entity.request.QuestionsQueryRequest; +import com.msdw.tms.entity.request.QuestionsUpdateRequest; +import com.msdw.tms.entity.vo.EvaluationVO; +import com.msdw.tms.entity.vo.QuestionsDetailVO; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +/** + * 记录试题信息 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +public interface QuestionsService extends IService { + + PageUtils queryQuestionsPage(Integer page, Integer size, QuestionsQueryRequest request); + + QuestionsDetailVO getQuestionDetailById(Integer id); + + boolean saveQuestion(QuestionsAddRequest questions); + + boolean updateQuestionById(QuestionsUpdateRequest questions); + + boolean isnable(Integer id); + + boolean deleteByIds(List asList); + + boolean importQuestion(MultipartFile file) throws IOException; + + FilesResult uploadFiles(MultipartFile file) throws IOException; + + void downloadFiles(HttpServletResponse response) throws IOException; + + EvaluationVO evaluation(); +} + diff --git a/src/main/java/com/msdw/tms/service/XlsxTemplateService.java b/src/main/java/com/msdw/tms/service/XlsxTemplateService.java new file mode 100644 index 0000000..9f36b79 --- /dev/null +++ b/src/main/java/com/msdw/tms/service/XlsxTemplateService.java @@ -0,0 +1,15 @@ +package com.msdw.tms.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.msdw.tms.entity.XlsxTemplateEntity; + +/** + * 模板文件信息记录 + * + * @author gongsj + * @email gongsj@gmail.com + * @date 2020-08-19 09:28:06 + */ +public interface XlsxTemplateService extends IService { +} + diff --git a/src/main/java/com/msdw/tms/service/impl/AliyunOssServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/AliyunOssServiceImpl.java new file mode 100644 index 0000000..e5acfc7 --- /dev/null +++ b/src/main/java/com/msdw/tms/service/impl/AliyunOssServiceImpl.java @@ -0,0 +1,58 @@ +package com.msdw.tms.service.impl; + +import com.aliyun.oss.OSSClient; +import com.msdw.tms.common.utils.AliyunOssUtil; +import com.msdw.tms.common.utils.FilesResult; +import com.msdw.tms.config.AliyunOssConfig; +import com.msdw.tms.service.AliyunOssService; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * 阿里云OSSUtil + */ +@Service +public class AliyunOssServiceImpl implements AliyunOssService { + + @Autowired + private AliyunOssConfig config; + + @Autowired + private BeanFactory beanFactory; + + /** + * 上传文件 + * + * @param file 上传文件 + */ + public FilesResult uploadFiles(MultipartFile file) throws IOException { + OSSClient client = beanFactory.getBean(OSSClient.class); + return AliyunOssUtil.uploadFiles(file, client, config); + } + + /** + * 下载文件 + * + * @param response + * @param objectName 本地路径 + */ + public void downloadFiles(HttpServletResponse response, String objectName) throws IOException { + OSSClient client = beanFactory.getBean(OSSClient.class); + AliyunOssUtil.downloadFiles(response, client, config, objectName); + } + + /** + * 根据文件路径+文件名称,删除该文件 + * + * @param filename + */ + public void deleteFile(String filename) { + OSSClient client = beanFactory.getBean(OSSClient.class); + AliyunOssUtil.deleteFile(client, config.getBucketName(), filename); + } +} diff --git a/src/main/java/com/msdw/tms/service/impl/EvaluationRulesServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/EvaluationRulesServiceImpl.java new file mode 100644 index 0000000..66afb7d --- /dev/null +++ b/src/main/java/com/msdw/tms/service/impl/EvaluationRulesServiceImpl.java @@ -0,0 +1,116 @@ +package com.msdw.tms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.msdw.tms.common.exception.ExceptionCast; +import com.msdw.tms.common.utils.Constant; +import com.msdw.tms.dao.EvaluationRulesDao; +import com.msdw.tms.entity.EvaluationRulesEntity; +import com.msdw.tms.entity.QuestionsEntity; +import com.msdw.tms.entity.response.CommonCode; +import com.msdw.tms.entity.vo.EvaluationRulesVO; +import com.msdw.tms.service.EvaluationRulesService; +import com.msdw.tms.service.QuestionsService; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + + +@Service("evaluationRulesService") +public class EvaluationRulesServiceImpl extends ServiceImpl implements EvaluationRulesService { + + @Autowired + QuestionsService questionsService; + + @Override + public EvaluationRulesVO getEvaluationRules() { + EvaluationRulesVO evaluationRulesVO = new EvaluationRulesVO(); + + EvaluationRulesEntity evaluationRules = this.getById(Constant.EVALUATION_RULES_ID); + + if (evaluationRules.getEvaluationType() == Constant.RulesType.CUSTOMIZE.getType()) {//自定义 + + int totalNum = 0; + if (evaluationRules.getIsSingleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用 + totalNum += evaluationRules.getSingleNum(); + } + if (evaluationRules.getIsMultipleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用 + totalNum += evaluationRules.getMultipleNum(); + } + if (evaluationRules.getIsJudgmentEnable() == Constant.IsEnable.ENABLE.getType()) {//启用 + totalNum += evaluationRules.getJudgmentNum(); + } + + //类型为自定义,测评试题数量是各个参与测评的试题类型数量之和 + evaluationRules.setQuestionNum(totalNum); + } + + BeanUtils.copyProperties(evaluationRules, evaluationRulesVO); + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除 + .eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用 + + evaluationRulesVO.setTotalQuestionNum(questionsService.count(queryWrapper));//总题数 + + int totalSingleNum = questionsService.count(queryWrapper.eq("question_type_no", + Constant.QuestionType.SINGLE_CHOICE.getType()));//单选题总数 + int totalMultipleNum = questionsService.count(queryWrapper.eq("question_type_no", + Constant.QuestionType.MULTIPLE_CHOICE.getType()));//多选题总数 + int totalJudgmentNum = questionsService.count(queryWrapper.eq("question_type_no", + Constant.QuestionType.TRUE_OR_FALSE.getType()));//判断题总数 + + evaluationRulesVO.setTotalSingleNum(totalSingleNum); + evaluationRulesVO.setTotalMultipleNum(totalMultipleNum); + evaluationRulesVO.setTotalJudgmentNum(totalJudgmentNum); + + return evaluationRulesVO; + } + + @Override + public boolean updateEvaluationRulesById(EvaluationRulesEntity evaluationRules) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除 + .eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用 + + //判断题目是否超出范围 + //判断类型 + Integer evaluationType = evaluationRules.getEvaluationType(); + if (evaluationType == Constant.RulesType.RANDOM.getType()) {//随机 + Integer questionNum = evaluationRules.getQuestionNum(); + + //查询总题数 + int count = questionsService.count(queryWrapper);//总题数 + numIncalid(questionNum, count); + + } else if (evaluationType == Constant.RulesType.CUSTOMIZE.getType()) {//自定义 + if (evaluationRules.getIsSingleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用 + int singleNum = evaluationRules.getSingleNum(); + int totalSingleNum = questionsService.count(queryWrapper.eq("question_type_no", + Constant.QuestionType.SINGLE_CHOICE.getType()));//单选题总数 + numIncalid(singleNum, totalSingleNum); + } + if (evaluationRules.getIsMultipleEnable() == Constant.IsEnable.ENABLE.getType()) {//启用 + int multipleNum = evaluationRules.getMultipleNum(); + int totalMultipleNum = questionsService.count(queryWrapper.eq("question_type_no", + Constant.QuestionType.MULTIPLE_CHOICE.getType()));//多选题总数 + numIncalid(multipleNum, totalMultipleNum); + } + if (evaluationRules.getIsJudgmentEnable() == Constant.IsEnable.ENABLE.getType()) {//启用 + int judgmentNum = evaluationRules.getJudgmentNum(); + int totalJudgmentNum = questionsService.count(queryWrapper.eq("question_type_no", + Constant.QuestionType.TRUE_OR_FALSE.getType()));//判断题总数 + numIncalid(judgmentNum, totalJudgmentNum); + } + + } + + return this.updateById(evaluationRules); + } + + private void numIncalid(int num, int totalNum) { + if (num < 0 || num > totalNum) { + ExceptionCast.cast(CommonCode.QUESTION_NUM_INVALID); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java new file mode 100644 index 0000000..fe5e00a --- /dev/null +++ b/src/main/java/com/msdw/tms/service/impl/QuestionsServiceImpl.java @@ -0,0 +1,404 @@ +package com.msdw.tms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.msdw.tms.common.exception.ExceptionCast; +import com.msdw.tms.common.utils.Constant; +import com.msdw.tms.common.utils.FilesResult; +import com.msdw.tms.common.utils.PageUtils; +import com.msdw.tms.common.utils.Query; +import com.msdw.tms.common.utils.poi.ExcelImportUtil; +import com.msdw.tms.dao.QuestionsDao; +import com.msdw.tms.entity.QuestionsEntity; +import com.msdw.tms.entity.XlsxTemplateEntity; +import com.msdw.tms.entity.request.QuestionsAddRequest; +import com.msdw.tms.entity.request.QuestionsImportRequest; +import com.msdw.tms.entity.request.QuestionsQueryRequest; +import com.msdw.tms.entity.request.QuestionsUpdateRequest; +import com.msdw.tms.entity.response.CommonCode; +import com.msdw.tms.entity.vo.EvaluationRulesVO; +import com.msdw.tms.entity.vo.EvaluationVO; +import com.msdw.tms.entity.vo.QuestionsDetailVO; +import com.msdw.tms.service.AliyunOssService; +import com.msdw.tms.service.EvaluationRulesService; +import com.msdw.tms.service.QuestionsService; +import com.msdw.tms.service.XlsxTemplateService; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + + +@Service("questionsService") +public class QuestionsServiceImpl extends ServiceImpl implements QuestionsService { + + @Autowired + private AliyunOssService ossService; + + @Autowired + XlsxTemplateService xlsxTemplateService; + + @Autowired + EvaluationRulesService evaluationRulesService; + + /** + * 条件加分页查询,题干模糊查询,未删除,修改时间降序 + * + * @param page + * @param size + * @param request + * @return + */ + @Override + public PageUtils queryQuestionsPage(Integer page, Integer size, QuestionsQueryRequest request) { + //请求包装类 + QueryWrapper queryWrapper = new QueryWrapper<>(); + + //只查询未被删除的试题 + queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()); + + //判断请求体是否为空 + if (request != null) { + // 题干:判断题干是否为空,不为空则加入搜索条件 + if (request.getQuestionStem() != null) { + queryWrapper.like("question_stem", request.getQuestionStem()); + } + // 题型:判断题型是否为空,不为空则加入搜索条件 + // if (questionsRequest.getQuestionType() != null) { + // queryWrapper.eq("question_type", questionsRequest.getQuestionType()); + // } + // 修改时间:判断修改时间是否为空,不为空则加入搜索条件 + // if (questionsRequest.getModifyTime() != null) { + // queryWrapper.eq("modify_time", questionsRequest.getModifyTime()); + // } + } + + //修改时间降序 + queryWrapper.orderByDesc("modify_time"); + + IPage questionsEntityIPage = this.page( + new Query().getPage(page, size), + queryWrapper + ); + + return new PageUtils(questionsEntityIPage); + } + + @Override + public QuestionsDetailVO getQuestionDetailById(Integer id) { + { + QuestionsDetailVO questionsDetailVO = new QuestionsDetailVO(); + //查询试题信息 + QuestionsEntity questionsEntity = this.getById(id); + BeanUtils.copyProperties(questionsEntity, questionsDetailVO); + //处理每个选项是否为被设置为答案 + String answer = questionsEntity.getAnswer(); + + if (answer.contains(Constant.A)) { + questionsDetailVO.setAIsTrue(true); + } + if (answer.contains(Constant.B)) { + questionsDetailVO.setBIsTrue(true); + } + if (answer.contains(Constant.C)) { + questionsDetailVO.setCIsTrue(true); + } + if (answer.contains(Constant.D)) { + questionsDetailVO.setDIsTrue(true); + } + if (answer.contains(Constant.E)) { + questionsDetailVO.setEIsTrue(true); + } + if (answer.contains(Constant.F)) { + questionsDetailVO.setFIsTrue(true); + } + return questionsDetailVO; + } + } + + /** + * 保存试题,根据题型名称得到题型号,设置创建时间和修改时间 + * + * @param questions + * @return + */ + @Override + @Transactional + public boolean saveQuestion(QuestionsAddRequest questions) { + if (questions == null || StringUtils.isEmpty(questions.getQuestionStem())) { + ExceptionCast.cast(CommonCode.INVALID_PARAM); + } + + // 判断是否题干重复。。。 + isStemRepeat(questions.getQuestionStem()); + + QuestionsEntity questionsEntity = new QuestionsEntity(); + BeanUtils.copyProperties(questions, questionsEntity); + + String questionType = questions.getQuestionType(); + //根据题型名称得到题型号 + if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) { + //单选题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType()); + } else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) { + //多选题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType()); + } else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) { + //判断题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType()); + } else {// 判断题型是否不存在。。。 + //说明题型不正确 + ExceptionCast.cast(CommonCode.QUESTIONTYPE_INVALID); + } + + questionsEntity.setCreateTime(new Date()); + questionsEntity.setModifyTime(new Date()); + //TODO 创建者和修改者。。。 + + return this.save(questionsEntity); + } + + @Override + @Transactional + public boolean updateQuestionById(QuestionsUpdateRequest questions) { + if (questions == null || questions.getId() == null || StringUtils.isEmpty(questions.getQuestionStem())) { + ExceptionCast.cast(CommonCode.INVALID_PARAM); + } + + // 判断是否题干重复 + isStemRepeat(questions.getQuestionStem()); + + // 判断id是否存在 + if (this.getById(questions.getId()) == null) { + ExceptionCast.cast(CommonCode.INVALID_PARAM); + } + + QuestionsEntity questionsEntity = new QuestionsEntity(); + BeanUtils.copyProperties(questions, questionsEntity); + + String questionType = questions.getQuestionType(); + //根据题型名称得到题型号 + if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) { + //单选题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType()); + } else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) { + //多选题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType()); + } else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) { + //判断题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType()); + } else { + //说明题型不正确 + ExceptionCast.cast(CommonCode.QUESTIONTYPE_INVALID); + } + + questionsEntity.setModifyTime(new Date()); + //TODO 设置修改者。。。 + + return this.updateById(questionsEntity); + } + + private void isStemRepeat(String stem) { + int count = this.count(new QueryWrapper().eq("question_stem", stem)); + if (count > 0) {//说明已存在 + //抛出题目已存在异常 + ExceptionCast.cast(CommonCode.QUESTION_EXISTS); + } + } + + @Override + @Transactional + public boolean isnable(Integer id) { + QuestionsEntity questionsEntity = new QuestionsEntity(); + questionsEntity.setId(id); + QuestionsEntity byId = this.getById(id); + if (byId.getIsEnable() == Constant.IsEnable.ENABLE.getType()) { + questionsEntity.setIsEnable(Constant.IsEnable.NOT_ENABLE.getType()); + } + + if (byId.getIsEnable() == Constant.IsEnable.NOT_ENABLE.getType()) { + questionsEntity.setIsEnable(Constant.IsEnable.ENABLE.getType()); + } + + return this.updateById(questionsEntity); + } + + @Override + @Transactional + public boolean deleteByIds(List asList) { + List collect = asList.stream().map(item -> { + QuestionsEntity questionsEntity = new QuestionsEntity(); + questionsEntity.setId(item); + questionsEntity.setIsDel(Constant.IsDel.DEL.getType()); + return questionsEntity; + }).collect(Collectors.toList()); + + return updateBatchById(collect); + } + + /** + * 校验题干重复和题型不对的,从列表中将该题剔除,名称相同的要去重 + * + * @param file + * @return + * @throws IOException + */ + @Override + @Transactional + public boolean importQuestion(MultipartFile file) throws IOException { + List list = new ExcelImportUtil(QuestionsImportRequest.class) + .readExcel(file.getInputStream(), Constant.STARTING_ROW, Constant.STARTING_CELL); + + if (list == null || list.size() == 0) { + ExceptionCast.cast(CommonCode.INVALID_PARAM); + } + //List unique = persons.stream().collect( + // Collectors.collectingAndThen( + // Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName))), ArrayList::new) + //); + + List collect = list.stream().map(item -> { + + int count = this.count(new QueryWrapper().eq("question_stem", item.getQuestionStem())); + if (count > 0) {//说明已存在 + return null; + } + QuestionsEntity questionsEntity = new QuestionsEntity(); + BeanUtils.copyProperties(item, questionsEntity); + String questionType = item.getQuestionType(); + //根据题型名称得到题型号 + if (questionType.equals(Constant.QuestionType.SINGLE_CHOICE.getDesc())) { + //单选题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.SINGLE_CHOICE.getType()); + } else if (questionType.equals(Constant.QuestionType.MULTIPLE_CHOICE.getDesc())) { + //多选题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.MULTIPLE_CHOICE.getType()); + } else if (questionType.equals(Constant.QuestionType.TRUE_OR_FALSE.getDesc())) { + //判断题 + questionsEntity.setQuestionTypeNo(Constant.QuestionType.TRUE_OR_FALSE.getType()); + } else { + // 题型不正确 + return null; + } + questionsEntity.setCreateTime(new Date()); + questionsEntity.setModifyTime(new Date()); + //TODO 创建者和修改者。。。 + return questionsEntity; + }).filter(question -> question != null).collect(Collectors.collectingAndThen( + Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(QuestionsEntity::getQuestionStem))), + ArrayList::new + )); + + return this.saveBatch(collect); + } + + /** + * 上传模板文件,修改模板信息表数据 + * + * @param file + * @return + */ + @Override + @Transactional + public FilesResult uploadFiles(MultipartFile file) throws IOException { + FilesResult filesResult = ossService.uploadFiles(file); + + XlsxTemplateEntity xlsxTemplateEntity = new XlsxTemplateEntity(); + BeanUtils.copyProperties(filesResult, xlsxTemplateEntity); + xlsxTemplateEntity.setId(Constant.XLSX_TEMPLATE_ID); + xlsxTemplateService.updateById(xlsxTemplateEntity); + + return filesResult; + } + + @Override + public void downloadFiles(HttpServletResponse response) throws IOException { + XlsxTemplateEntity xlsxTemplate = xlsxTemplateService.getById(Constant.XLSX_TEMPLATE_ID); + ossService.downloadFiles(response, xlsxTemplate.getFileName()); + } + + @Override + public EvaluationVO evaluation() { + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("is_del", Constant.IsDel.NOT_DEL.getType()) //未删除 + .eq("is_enable", Constant.IsEnable.ENABLE.getType()); //启用 + + Set set = new HashSet<>(); + + // 查询测评规则类型 + EvaluationRulesVO evaluationRules = evaluationRulesService.getEvaluationRules(); + + EvaluationVO evaluation = new EvaluationVO(); + + BeanUtils.copyProperties(evaluationRules, evaluation); + + Integer evaluationType = evaluationRules.getEvaluationType(); + if (evaluationType == Constant.RulesType.RANDOM.getType()) {//随机 + // 类型为随机,直接用题目数量 + Integer questionNum = evaluationRules.getQuestionNum(); + // 查询题库所有未删除,未禁用的题目id + List questions = this.list(queryWrapper); + + set = getRandomList(questionNum, questions); + + } else if (evaluationType == Constant.RulesType.CUSTOMIZE.getType()) {//自定义 + + int singleNum = 0; + int multipleNum = 0; + int judgmentNum = 0; + + //判断各条目的题型是否启用 + if (evaluationRules.getIsSingleEnable() == Constant.IsEnable.ENABLE.getType()) { + singleNum = evaluationRules.getSingleNum(); + + List singleChoice = this.list(queryWrapper.eq("question_type_no", + Constant.QuestionType.SINGLE_CHOICE.getType())); + set.addAll(getRandomList(singleNum, singleChoice)); + } + if (evaluationRules.getIsMultipleEnable() == Constant.IsEnable.ENABLE.getType()) { + multipleNum = evaluationRules.getMultipleNum(); + + List multipleChoice = this.list(queryWrapper.eq("question_type_no", + Constant.QuestionType.MULTIPLE_CHOICE.getType())); + + set.addAll(getRandomList(multipleNum, multipleChoice)); + } + if (evaluationRules.getIsJudgmentEnable() == Constant.IsEnable.ENABLE.getType()) { + judgmentNum = evaluationRules.getJudgmentNum(); + List judgments = this.list(queryWrapper.eq("question_type_no", + Constant.QuestionType.TRUE_OR_FALSE.getType())); + + set.addAll(getRandomList(judgmentNum, judgments)); + } + + evaluation.setQuestionNum(singleNum + multipleNum + judgmentNum); + + } + evaluation.setQuestions(set); + + return evaluation; + } + + private Set getRandomList(int len, List list) { + Set set = new HashSet<>(); + Random random = new Random(); + int i = 0; + while (true) { + i = random.nextInt(list.size()); + set.add(list.get(i)); + if (set.size() >= len) { + break; + } + } + return set; + } +} \ No newline at end of file diff --git a/src/main/java/com/msdw/tms/service/impl/XlsxTemplateServiceImpl.java b/src/main/java/com/msdw/tms/service/impl/XlsxTemplateServiceImpl.java new file mode 100644 index 0000000..8d5738d --- /dev/null +++ b/src/main/java/com/msdw/tms/service/impl/XlsxTemplateServiceImpl.java @@ -0,0 +1,12 @@ +package com.msdw.tms.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.msdw.tms.dao.XlsxTemplateDao; +import com.msdw.tms.entity.XlsxTemplateEntity; +import com.msdw.tms.service.XlsxTemplateService; +import org.springframework.stereotype.Service; + + +@Service("xlsxTemplateService") +public class XlsxTemplateServiceImpl extends ServiceImpl implements XlsxTemplateService { +} \ No newline at end of file diff --git a/src/main/resources/aliyun.properties b/src/main/resources/aliyun.properties new file mode 100644 index 0000000..acb5672 --- /dev/null +++ b/src/main/resources/aliyun.properties @@ -0,0 +1,6 @@ +oss.endpoint=oss-cn-shenzhen.aliyuncs.com +oss.accessKeyId=LTAIHIkGqaILObBm +oss.secretAccessKey=QDTxKMrfDPeJ3bsr3AqjYHwnlL6PdM +oss.bucketName=liuwanr +oss.sufferUrl=http://liuwanr.oss-cn-shenzhen.aliyuncs.com/ +user.userAvatars=userAvatars \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..8a03b75 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,15 @@ +spring: + datasource: + url: jdbc:mysql://www.liuwanr.cn:3306/msdw_tms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai + username: super + password: huoran888 + driver-class-name: com.mysql.jdbc.Driver +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用 + mapper-locations: classpath:/mapper/**/*.xml + global-config: + db-config: + id-type: auto +server: + port: 7000 \ No newline at end of file diff --git a/src/main/resources/excel-template/试题导入模板.xlsx b/src/main/resources/excel-template/试题导入模板.xlsx new file mode 100644 index 0000000..4c064f0 Binary files /dev/null and b/src/main/resources/excel-template/试题导入模板.xlsx differ diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..d09983d --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + utf8 + + + + + + + + ${LOG_HOME}/tms.%d{yyyy-MM-dd}.log + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + 0 + + 512 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/tms/EvaluationRulesDao.xml b/src/main/resources/mapper/tms/EvaluationRulesDao.xml new file mode 100644 index 0000000..edf0605 --- /dev/null +++ b/src/main/resources/mapper/tms/EvaluationRulesDao.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/tms/QuestionsDao.xml b/src/main/resources/mapper/tms/QuestionsDao.xml new file mode 100644 index 0000000..30a3679 --- /dev/null +++ b/src/main/resources/mapper/tms/QuestionsDao.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/tms/XlsxTemplateDao.xml b/src/main/resources/mapper/tms/XlsxTemplateDao.xml new file mode 100644 index 0000000..9994315 --- /dev/null +++ b/src/main/resources/mapper/tms/XlsxTemplateDao.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/msdw/tms/TmsApplicationTests.java b/src/test/java/com/msdw/tms/TmsApplicationTests.java new file mode 100644 index 0000000..c8e9a17 --- /dev/null +++ b/src/test/java/com/msdw/tms/TmsApplicationTests.java @@ -0,0 +1,13 @@ +package com.msdw.tms; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class TmsApplicationTests { + + @Test + void contextLoads() { + } + +}