Add
This commit is contained in:
parent
9908f7f7a0
commit
b66b478dd4
32
.gitignore
vendored
Normal file
32
.gitignore
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
HELP.md
|
||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**
|
||||||
|
!**/src/test/**
|
||||||
|
|
||||||
|
### STS ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
/epaper.iml
|
118
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
118
.mvn/wrapper/MavenWrapperDownloader.java
vendored
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Normal file
Binary file not shown.
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
2
.mvn/wrapper/maven-wrapper.properties
vendored
Normal file
@ -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
|
322
mvnw
vendored
Normal file
322
mvnw
vendored
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
# or more contributor license agreements. See the NOTICE file
|
||||||
|
# distributed with this work for additional information
|
||||||
|
# regarding copyright ownership. The ASF licenses this file
|
||||||
|
# to you under the Apache License, Version 2.0 (the
|
||||||
|
# "License"); you may not use this file except in compliance
|
||||||
|
# with the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing,
|
||||||
|
# software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
# KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# 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 "$@"
|
182
mvnw.cmd
vendored
Normal file
182
mvnw.cmd
vendored
Normal file
@ -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%
|
226
pom.xml
Normal file
226
pom.xml
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.2.6.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
<groupId>org.codedream</groupId>
|
||||||
|
<artifactId>epaper</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<name>epaper</name>
|
||||||
|
<description>ePaper For CodeDream</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.junit.vintage</groupId>
|
||||||
|
<artifactId>junit-vintage-engine</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mariadb.jdbc</groupId>
|
||||||
|
<artifactId>mariadb-java-client</artifactId>
|
||||||
|
<version>2.5.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.2.61</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>fastjson</artifactId>
|
||||||
|
<version>1.1.71.android</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.java-json-tools</groupId>
|
||||||
|
<artifactId>json-patch</artifactId>
|
||||||
|
<version>1.12</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
<version>1.11</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Restful API 文档可视化支持 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
|
<version>2.9.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-swagger-ui</artifactId>
|
||||||
|
<version>2.9.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baidu.aip</groupId>
|
||||||
|
<artifactId>java-sdk</artifactId>
|
||||||
|
<version>4.12.0</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-simple</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-scratchpad</artifactId>
|
||||||
|
<version>4.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>4.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>4.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- 缓存依赖 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.python</groupId>
|
||||||
|
<artifactId>jython-standalone</artifactId>
|
||||||
|
<version>2.7.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.pdfbox</groupId>
|
||||||
|
<artifactId>pdfbox</artifactId>
|
||||||
|
<version>2.0.19</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.docx4j/docx4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>args4j</groupId>
|
||||||
|
<artifactId>args4j</artifactId>
|
||||||
|
<version>2.32</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.docx4j</groupId>
|
||||||
|
<artifactId>docx4j</artifactId>
|
||||||
|
<version>3.2.1</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>fr.opensagres.xdocreport</groupId>
|
||||||
|
<artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
|
||||||
|
<version>1.0.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>fr.opensagres.xdocreport</groupId>
|
||||||
|
<artifactId>org.odftoolkit.odfdom.converter.pdf</artifactId>
|
||||||
|
<version>1.0.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.jaxb-namespaceprefixmapper-interfaces</groupId>
|
||||||
|
<artifactId>JAXBNamespacePrefixMapper</artifactId>
|
||||||
|
<version>2.2.4</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-impl</artifactId>
|
||||||
|
<version>2.2.11</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-core</artifactId>
|
||||||
|
<version>2.2.11</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.freemarker</groupId>
|
||||||
|
<artifactId>freemarker</artifactId>
|
||||||
|
<version>2.3.30</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<version>1.2.17</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>AlibabaMaven</id>
|
||||||
|
<name>Maven Aliyun Mirror</name>
|
||||||
|
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
</project>
|
21
src/main/java/org/codedream/epaper/EpaperApplication.java
Normal file
21
src/main/java/org/codedream/epaper/EpaperApplication.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package org.codedream.epaper;
|
||||||
|
|
||||||
|
import org.codedream.epaper.configure.EPApplicationContextInitializer;
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableScheduling
|
||||||
|
@EnableAsync
|
||||||
|
public class EpaperApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication application = new SpringApplication(EpaperApplication.class);
|
||||||
|
// 添加启动检查
|
||||||
|
application.addInitializers(new EPApplicationContextInitializer());
|
||||||
|
application.run(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.codedream.epaper.component;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动获得Bean的工具类
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class EPSpringUtil {
|
||||||
|
@Resource
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public <T> T getBean(Class<T> tClass){
|
||||||
|
return applicationContext.getBean(tClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,218 @@
|
|||||||
|
package org.codedream.epaper.component.api;
|
||||||
|
|
||||||
|
import org.codedream.epaper.component.datamanager.JSONParameter;
|
||||||
|
import org.codedream.epaper.component.json.respond.JSONBaseRespondObject;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON返回快速构造组件类(主要用于异常处理机制)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class QuickJSONRespond {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONParameter jsonParameter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据对象构造获得标准的JSON响应字符串
|
||||||
|
* @param status 状态码
|
||||||
|
* @param msg 信息
|
||||||
|
* @param info 附加信息
|
||||||
|
* @param dataObject 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONStandardRespond(Integer status, String msg, String info, Object dataObject){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(status, msg);
|
||||||
|
if(info != null) respondObject.setInfo(info);
|
||||||
|
else respondObject.setInfo(null);
|
||||||
|
|
||||||
|
respondObject.setData(dataObject);
|
||||||
|
return jsonParameter.getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据对象构造获得标准的JSON响应字符串
|
||||||
|
* @param status 状态码
|
||||||
|
* @param dataObject 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONStandardRespond(HttpStatus status, Object dataObject){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(status.value(), status.getReasonPhrase());
|
||||||
|
|
||||||
|
respondObject.setData(dataObject);
|
||||||
|
return jsonParameter.getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据对象构造获得标准的JSON响应字符串
|
||||||
|
* @param status 状态码
|
||||||
|
* @param info 附加信息
|
||||||
|
* @param dataObject 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONStandardRespond(HttpStatus status, String info, Object dataObject){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(status.value(), status.getReasonPhrase());
|
||||||
|
if(info != null) respondObject.setInfo(info);
|
||||||
|
else respondObject.setInfo(null);
|
||||||
|
|
||||||
|
respondObject.setData(dataObject);
|
||||||
|
return jsonParameter.getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据对象构造获得标准的JSON响应字符串
|
||||||
|
* @param status 状态码
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONStandardRespond(HttpStatus status, String info){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(status.value(), status.getReasonPhrase());
|
||||||
|
if(info != null) respondObject.setInfo(info);
|
||||||
|
else respondObject.setInfo(null);
|
||||||
|
|
||||||
|
return jsonParameter.getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回特定状态码的和解释息
|
||||||
|
* @param code 状态码
|
||||||
|
* @param msg 信息
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONStandardRespond(Integer code, String msg, String info){
|
||||||
|
JSONBaseRespondObject respondObject = new JSONBaseRespondObject(code, msg);
|
||||||
|
if(info != null) respondObject.setInfo(info);
|
||||||
|
else respondObject.setInfo(null);
|
||||||
|
respondObject.setData(null);
|
||||||
|
return jsonParameter.getJSONString(respondObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(404状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond404(String info){
|
||||||
|
return getJSONStandardRespond(HttpStatus.NOT_FOUND, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(404状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @param object 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond404(String info, Object object){
|
||||||
|
return getJSONStandardRespond(HttpStatus.NOT_FOUND, info, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(500状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond500(String info){
|
||||||
|
return getJSONStandardRespond(HttpStatus.INTERNAL_SERVER_ERROR, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(200状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond200(String info){
|
||||||
|
return getJSONStandardRespond(HttpStatus.OK, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(200状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @param object 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond200(String info, Object object){
|
||||||
|
return getJSONStandardRespond(HttpStatus.OK, info, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(403状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond403(String info){
|
||||||
|
return getJSONStandardRespond(HttpStatus.FORBIDDEN, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(406状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond406(String info){
|
||||||
|
return getJSONStandardRespond(HttpStatus.NOT_ACCEPTABLE, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(406状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @param object 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond406(String info, Object object){
|
||||||
|
return getJSONStandardRespond(HttpStatus.NOT_ACCEPTABLE, info, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(501状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond501(String info){
|
||||||
|
return getJSONStandardRespond(501, "Not Implemented", info) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(401状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond401(String info){
|
||||||
|
return getJSONStandardRespond(401, "Unauthorized", info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(400状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond400(String info){
|
||||||
|
return getJSONStandardRespond(400, "Bad Request", info);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(404状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @param object 附带对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond400(String info, Object object){
|
||||||
|
return getJSONStandardRespond(400, "Bad Request", info, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得标准的JSON响应字符串返回(400状态)
|
||||||
|
* @param info 附加信息
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getRespond409(String info){
|
||||||
|
return getJSONStandardRespond(409, "Conflict", info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package org.codedream.epaper.component.article;
|
||||||
|
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTN;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得章结构的句列表
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class GetSentenceFromArticle {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得章结构的句列表
|
||||||
|
* @param article 章结构
|
||||||
|
* @return 句结构列表
|
||||||
|
*/
|
||||||
|
public List<Sentence> get(Article article){
|
||||||
|
List<Sentence> sentences = new ArrayList<>();
|
||||||
|
for(Paragraph paragraph : article.getParagraphs()){
|
||||||
|
sentences.addAll(paragraph.getSentences());
|
||||||
|
}
|
||||||
|
return sentences;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查请求是否为Ajax的方式发起
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class AJAXRequestChecker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查请求是否为Ajax的方式发起
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean checkAjaxPOSTRequest(HttpServletRequest request){
|
||||||
|
return Optional.ofNullable(request.getHeader("X-Requested-With")).isPresent();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token生成器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class AuthTokenGenerator {
|
||||||
|
@Resource
|
||||||
|
private SHA1Encoder encoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成Token
|
||||||
|
* @param username 用户名
|
||||||
|
* @return token字符串
|
||||||
|
*/
|
||||||
|
public String generateAuthToken(String username){
|
||||||
|
Date dateNow = new Date();
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
return encoder.encode(String.format("Token [%s][%d][%s]",username,dateNow.getTime(), uuid.toString()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
|
import org.springframework.security.authentication.InsufficientAuthenticationException;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 权限管理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class EPAccessDecisionManager implements AccessDecisionManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确定用户的权限
|
||||||
|
* @param authentication 认证柄
|
||||||
|
* @param object 传入对象
|
||||||
|
* @param configAttributes 角色信息对象
|
||||||
|
* @throws AccessDeniedException 访问禁止异常
|
||||||
|
* @throws InsufficientAuthenticationException 会话认证异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
|
||||||
|
if(null == configAttributes || configAttributes.size() <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ConfigAttribute c : configAttributes) {
|
||||||
|
String needRole = c.getAttribute();
|
||||||
|
for (GrantedAuthority ga : authentication.getAuthorities()) {
|
||||||
|
if (needRole.trim().equals(ga.getAuthority())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new AccessDeniedException("Access Denied");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持该角色信息对象
|
||||||
|
* @param attribute 角色信息对象
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supports(ConfigAttribute attribute) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否支持该认证柄
|
||||||
|
* @param clazz 认证柄对象信息
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> clazz) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.api.QuickJSONRespond;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已认证用户访问无权限资源状态处理
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class EPAccessDeniedHandler implements AccessDeniedHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QuickJSONRespond quickJSONRespond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理函数
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param response HTTP返回
|
||||||
|
* @param accessDeniedException 无权限访问异常
|
||||||
|
* @throws IOException I/O异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
log.info("ASEAccessDeniedHandler Found!");
|
||||||
|
|
||||||
|
// 对无权限操作返回403
|
||||||
|
response.getWriter().print(quickJSONRespond.getRespond403(null));
|
||||||
|
response.setStatus(403);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.api.QuickJSONRespond;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匿名用户访问无权限资源(未得到认证的用户视为匿名用户)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class EPAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
@Resource
|
||||||
|
private QuickJSONRespond quickJSONRespond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理函数
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param response HTTP返回
|
||||||
|
* @param authException 认证异常
|
||||||
|
* @throws IOException I/O异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
// 对匿名用户返回401
|
||||||
|
response.getWriter().print(quickJSONRespond.getRespond401(null));
|
||||||
|
response.setStatus(401);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.api.QuickJSONRespond;
|
||||||
|
import org.codedream.epaper.component.json.respond.ErrorInfoJSONRespond;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证失败处理
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class EPAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QuickJSONRespond quickJSONRespond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param response HTTP返回
|
||||||
|
* @param exception 异常类型
|
||||||
|
* @throws IOException I/O异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
log.info("ASEAuthenticationFailureHandler Login Fail!");
|
||||||
|
|
||||||
|
// 填写异常信息存储对象
|
||||||
|
ErrorInfoJSONRespond errorInfoJSONRespond = new ErrorInfoJSONRespond();
|
||||||
|
errorInfoJSONRespond.setDate(new Date());
|
||||||
|
errorInfoJSONRespond.setExceptionMessage(exception.getMessage());
|
||||||
|
errorInfoJSONRespond.setException(exception.getClass().getSimpleName());
|
||||||
|
|
||||||
|
// 认证失败返回406
|
||||||
|
response.getWriter().write(quickJSONRespond.getJSONStandardRespond(
|
||||||
|
406,
|
||||||
|
"Not Acceptable",
|
||||||
|
"Authentication Failure",
|
||||||
|
errorInfoJSONRespond));
|
||||||
|
response.setStatus(406);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.api.QuickJSONRespond;
|
||||||
|
import org.codedream.epaper.component.json.respond.UserLoginCheckerJSONRespond;
|
||||||
|
import org.codedream.epaper.model.user.User;
|
||||||
|
import org.codedream.epaper.service.IAuthService;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
// 认证成功返回
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class EPAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QuickJSONRespond quickJSONRespond;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IAuthService authService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param response HTTP返回
|
||||||
|
* @param authentication 认证柄
|
||||||
|
* @throws IOException I/O异常
|
||||||
|
* @throws ServletException Servlet异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
||||||
|
throws IOException, ServletException
|
||||||
|
{
|
||||||
|
|
||||||
|
UserLoginCheckerJSONRespond respond = new UserLoginCheckerJSONRespond();
|
||||||
|
respond.setUserExist(authentication.isAuthenticated());
|
||||||
|
respond.setLoginStatus(authentication.isAuthenticated());
|
||||||
|
respond.setPvc(authService.preValidationCodeGetter());
|
||||||
|
|
||||||
|
// 获得 JSONTokenAuthenticationToken
|
||||||
|
JSONTokenAuthenticationToken authenticationToken = (JSONTokenAuthenticationToken) authentication;
|
||||||
|
|
||||||
|
User user = (User) authenticationToken.getPrincipal();
|
||||||
|
|
||||||
|
Optional<String> tokenOptional = authService.userNewTokenGetter(
|
||||||
|
user.getUsername(), authenticationToken.getClientCode());
|
||||||
|
|
||||||
|
if(tokenOptional.isPresent()){
|
||||||
|
respond.setToken(tokenOptional.get());
|
||||||
|
}
|
||||||
|
else respond.setToken("");
|
||||||
|
|
||||||
|
// 认证成功返回200
|
||||||
|
response.getWriter().write(quickJSONRespond.getRespond200("Authentication Success", respond));
|
||||||
|
response.setStatus(200);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.model.auth.JSONToken;
|
||||||
|
import org.codedream.epaper.service.AuthService;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API请求验证服务
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class EPJSONTokenAuthenticationFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONRandomCodeGenerator randomCodeGenerator;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AuthService authService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONSignedGenerator signedGenerator;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param response HTTP返回
|
||||||
|
* @param filterChain 过滤器链
|
||||||
|
* @throws ServletException Servlet异常
|
||||||
|
* @throws IOException I/O异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
|
||||||
|
// 用户名
|
||||||
|
String openid = request.getHeader( "openid");
|
||||||
|
// 客户端签名
|
||||||
|
String signed = request.getHeader("signed");
|
||||||
|
// 时间戳
|
||||||
|
String timestamp = request.getHeader("timestamp");
|
||||||
|
|
||||||
|
// 服务端API测试豁免签名
|
||||||
|
if(signed != null && signed.equals("6d4923fca4dcb51f67b85e54a23a8d763d9e02af")){
|
||||||
|
//执行授权
|
||||||
|
doAuthentication("test", request);
|
||||||
|
}
|
||||||
|
// 正常认证
|
||||||
|
else if (signed != null && openid != null && timestamp != null) {
|
||||||
|
// 获得具体时间
|
||||||
|
Date date = new Date(Long.parseLong(timestamp));
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
// 限制时间戳有效区间为60s
|
||||||
|
long dtTime = 60*1000;
|
||||||
|
Date maxDate = new Date(now.getTime() + dtTime);
|
||||||
|
|
||||||
|
// 检查时间戳是否合理
|
||||||
|
if(maxDate.after(date)) {
|
||||||
|
// 从服务器中查找token
|
||||||
|
Optional<JSONToken> optionalJSONToken = authService.findTokenByUserName(openid);
|
||||||
|
if (optionalJSONToken.isPresent()) {
|
||||||
|
JSONToken token = optionalJSONToken.get();
|
||||||
|
|
||||||
|
// 检查token是否过期
|
||||||
|
if (!authService.checkTokenIfExpired(token)) {
|
||||||
|
// 生成特征随机代码
|
||||||
|
String randomCode = randomCodeGenerator.generateRandomCode(openid,
|
||||||
|
date, token.getClientCode());
|
||||||
|
|
||||||
|
log.info(String.format("Determined Signed: %s",
|
||||||
|
signedGenerator.generateSigned(openid, randomCode, token.getToken())));
|
||||||
|
log.info(String.format("Get Signed: %s", signed));
|
||||||
|
|
||||||
|
// 检查签名是否正确
|
||||||
|
if (signed.equals(signedGenerator.generateSigned(openid, randomCode, token.getToken()))) {
|
||||||
|
// 执行授权操作
|
||||||
|
doAuthentication(openid, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行授权
|
||||||
|
private void doAuthentication(String username, HttpServletRequest request){
|
||||||
|
// 查询用户的相关信息
|
||||||
|
UserDetails user = userDetailsService.loadUserByUsername(username);
|
||||||
|
|
||||||
|
// 生成用户权限列表
|
||||||
|
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
|
||||||
|
|
||||||
|
// 生成授权柄 (储存上下文信息)
|
||||||
|
JSONTokenAuthenticationToken authentication =
|
||||||
|
new JSONTokenAuthenticationToken(user, null, authorities);
|
||||||
|
|
||||||
|
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
|
||||||
|
// 执行授权
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码编码器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class EPPasswordEncoder implements PasswordEncoder {
|
||||||
|
/**
|
||||||
|
* 密码编码
|
||||||
|
* @param charSequence
|
||||||
|
* @return 密文
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String encode(CharSequence charSequence) {
|
||||||
|
return DigestUtils.sha256Hex(charSequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码验证
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @param s 密文
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean matches(CharSequence charSequence, String s) {
|
||||||
|
return s.equals(DigestUtils.sha256Hex(charSequence.toString()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.authentication.*;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
// 普通用户名密码验证, 用户获得Token
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class EPSecurityAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
@Resource
|
||||||
|
UserDetailsService userDetailsService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPPasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
JSONTokenUsernamePasswordAuthenticationToken authenticationToken =
|
||||||
|
(JSONTokenUsernamePasswordAuthenticationToken) authentication;
|
||||||
|
|
||||||
|
// 获得JSON中的学号
|
||||||
|
String username = (String) authenticationToken.getPrincipal();
|
||||||
|
// 获得JSON中的加密密码
|
||||||
|
String encrypted_password = passwordEncoder.encode((String) authenticationToken.getCredentials());
|
||||||
|
// 获得客户端代码
|
||||||
|
String clientCode = authenticationToken.getClientCode();
|
||||||
|
// 判断用户是否存在并获取用户信息
|
||||||
|
UserDetails userInfo = userDetailsService.loadUserByUsername(username);
|
||||||
|
|
||||||
|
if (userInfo == null) {
|
||||||
|
throw new UsernameNotFoundException("User Not Exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断密码是否正确
|
||||||
|
if(!userInfo.getPassword().equals(encrypted_password)){
|
||||||
|
throw new BadCredentialsException("Password IS INCORRECT");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断账号是否停用/删除
|
||||||
|
if (!userInfo.isEnabled()) {
|
||||||
|
throw new DisabledException("User IS Disabled");
|
||||||
|
}
|
||||||
|
else if(!userInfo.isAccountNonLocked()) {
|
||||||
|
throw new LockedException("User IS Locked");
|
||||||
|
}
|
||||||
|
else if(!userInfo.isAccountNonExpired()) {
|
||||||
|
throw new AccountExpiredException("User IS Expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成权限列表
|
||||||
|
Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
|
||||||
|
|
||||||
|
return new JSONTokenAuthenticationToken(userInfo, clientCode, authorities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> aClass) {
|
||||||
|
return aClass.equals(JSONTokenUsernamePasswordAuthenticationToken.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户名编码器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class EPUsernameEncoder {
|
||||||
|
/**
|
||||||
|
* 编码
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @return 密文
|
||||||
|
*/
|
||||||
|
public String encode(CharSequence charSequence){
|
||||||
|
return "openid_" + DigestUtils.sha256Hex(charSequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @param s 密文
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean matches(CharSequence charSequence, String s){
|
||||||
|
return s.equals(encode(charSequence.toString()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.datamanager.JSONParameter;
|
||||||
|
import org.codedream.epaper.component.json.request.UserLoginChecker;
|
||||||
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账号认证过滤器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class EPUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JSONParameter jsonParameter;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AJAXRequestChecker ajaxRequestChecker;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TimestampExpiredChecker timestampExpiredChecker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证函数
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param response HTTP返回
|
||||||
|
* @return 认证柄
|
||||||
|
* @throws AuthenticationException 认证异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws AuthenticationException {
|
||||||
|
|
||||||
|
String timestamp = request.getHeader("timestamp");
|
||||||
|
|
||||||
|
// 检查时间戳是否合理(60秒内)
|
||||||
|
if(timestamp == null || !timestampExpiredChecker.checkTimestampBeforeMaxTime(timestamp, 60)){
|
||||||
|
throw new AuthenticationServiceException("Timestamp Expired.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为AJAX请求格式的数据
|
||||||
|
if(!ajaxRequestChecker.checkAjaxPOSTRequest(request)) {
|
||||||
|
throw new AuthenticationServiceException("Authentication method not supported: NOT Ajax Method.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<UserLoginChecker> checkerOptional = jsonParameter.getJavaObjectByRequest(request, UserLoginChecker.class);
|
||||||
|
if(!checkerOptional.isPresent()) throw new BadCredentialsException("Invalid AJAX JSON Request");
|
||||||
|
|
||||||
|
UserLoginChecker checker = checkerOptional.get();
|
||||||
|
|
||||||
|
if(checker.getOpenid() == null
|
||||||
|
|| checker.getPassword() == null
|
||||||
|
|| checker.getClientCode() == null)
|
||||||
|
throw new AuthenticationServiceException("Request Data IS Incomplete");
|
||||||
|
|
||||||
|
// 获得相应的用户名密码
|
||||||
|
String openid = checker.getOpenid();
|
||||||
|
// 得到加密密码
|
||||||
|
String password = checker.getPassword();
|
||||||
|
String clientCode = checker.getClientCode();
|
||||||
|
|
||||||
|
if (openid == null) openid = "";
|
||||||
|
if (password == null) password = "";
|
||||||
|
|
||||||
|
// 去除首尾两端的空白字符
|
||||||
|
openid = openid.trim();
|
||||||
|
password = password.trim();
|
||||||
|
|
||||||
|
|
||||||
|
JSONTokenUsernamePasswordAuthenticationToken authRequest =
|
||||||
|
new JSONTokenUsernamePasswordAuthenticationToken(openid, password, clientCode);
|
||||||
|
|
||||||
|
authRequest.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
|
||||||
|
return this.getAuthenticationManager().authenticate(authRequest);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机特征值生成器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JSONRandomCodeGenerator {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA1Encoder encoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机特征值
|
||||||
|
* @param username 用户名
|
||||||
|
* @param date 时间
|
||||||
|
* @param clientCode 客户端代码
|
||||||
|
* @return 随机特征值字符串
|
||||||
|
*/
|
||||||
|
public String generateRandomCode(String username, Date date, String clientCode){
|
||||||
|
return encoder.encode(String.format("RandomCode [%s][%s][%s]",
|
||||||
|
username, Long.toString(date.getTime()), clientCode));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端签名生成器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JSONSignedGenerator {
|
||||||
|
@Resource
|
||||||
|
SHA1Encoder encoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成签名
|
||||||
|
* @param username 用户名
|
||||||
|
* @param randomCode 随机特征值
|
||||||
|
* @param token Token
|
||||||
|
* @return 客户端签名
|
||||||
|
*/
|
||||||
|
public String generateSigned(String username, String randomCode, String token){
|
||||||
|
return encoder.encode(String.format("SIGN [%s][%s][%s]",username, randomCode, token));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联Token与其他用户的相关数据的认证柄
|
||||||
|
*/
|
||||||
|
public class JSONTokenAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
|
||||||
|
// 客户端签名
|
||||||
|
private String signed = null;
|
||||||
|
// 用户名
|
||||||
|
private Object principal = null;
|
||||||
|
// 客户端代码
|
||||||
|
private String clientCode = null;
|
||||||
|
|
||||||
|
|
||||||
|
public JSONTokenAuthenticationToken(UserDetails principal,
|
||||||
|
String clientCode,
|
||||||
|
Collection<? extends GrantedAuthority> authorities)
|
||||||
|
{
|
||||||
|
super(authorities);
|
||||||
|
this.principal = principal;
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
this.signed = null;
|
||||||
|
setAuthenticated(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONTokenAuthenticationToken(String principal, String clientCode, String signed) {
|
||||||
|
super(null);
|
||||||
|
this.principal = principal;
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
this.signed = signed;
|
||||||
|
setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCredentials() {
|
||||||
|
return signed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientCode() {
|
||||||
|
return clientCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientCode(String clientCode) {
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 明文用户名密码验证认证柄
|
||||||
|
*/
|
||||||
|
public class JSONTokenUsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
|
// 用户名
|
||||||
|
private String username = null;
|
||||||
|
// 明文密码
|
||||||
|
private String password = null;
|
||||||
|
// 授权柄
|
||||||
|
private String clientCode = null;
|
||||||
|
|
||||||
|
|
||||||
|
public JSONTokenUsernamePasswordAuthenticationToken(String username, String password, String clientCode) {
|
||||||
|
super(null);
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.clientCode = clientCode;
|
||||||
|
setAuthenticated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getCredentials() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getPrincipal() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扩展接口 获得客户端代码
|
||||||
|
* @return 客户端代码
|
||||||
|
*/
|
||||||
|
public String getClientCode() {
|
||||||
|
return clientCode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA1编码器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SHA1Encoder {
|
||||||
|
/**
|
||||||
|
* 编码
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @return 密文
|
||||||
|
*/
|
||||||
|
public String encode(CharSequence charSequence){
|
||||||
|
return DigestUtils.sha1Hex(charSequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @param s 密文
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean match (CharSequence charSequence, String s){
|
||||||
|
return s.equals(encode(charSequence));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package org.codedream.epaper.component.auth;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证时间戳验证器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class TimestampExpiredChecker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查时间戳是否在某个最大有效时间前
|
||||||
|
* @param timestamp 时间戳字符串
|
||||||
|
* @param seconds 最大有效时间
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean checkTimestampBeforeMaxTime(String timestamp, int seconds){
|
||||||
|
Date timestampDate = new Date(Long.parseLong(timestamp));
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Date maxDate = new Date(currentTime + seconds * 1000);
|
||||||
|
return timestampDate.before(maxDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查时间戳是否在某个最大有效时间前
|
||||||
|
* @param date 时间对象
|
||||||
|
* @param seconds 最大做大有效时间
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean checkDateBeforeMaxTime(Date date, int seconds){
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Date maxDate = new Date(currentTime + seconds * 1000);
|
||||||
|
return date.before(maxDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查时间戳是否在某个设置的时间前
|
||||||
|
* @param date 时间对象
|
||||||
|
* @param seconds 设置时间
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean checkDateBeforeDeterminedTime(Date date, int seconds){
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
Date maxDate = new Date(currentTime - seconds * 1000);
|
||||||
|
return date.before(maxDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package org.codedream.epaper.component.batchthread;
|
||||||
|
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.FutureTask;
|
||||||
|
|
||||||
|
public class ComparableFutureTask extends FutureTask implements Comparable<ComparableFutureTask> {
|
||||||
|
|
||||||
|
private BatchProcessingTask taskToAppoint = new BatchProcessingTask();
|
||||||
|
|
||||||
|
public ComparableFutureTask(Callable callable) {
|
||||||
|
super(callable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ComparableFutureTask o) {
|
||||||
|
|
||||||
|
if (this.getTaskToAppoint().getPriority() > o.getTaskToAppoint().getPriority()) {
|
||||||
|
return 1;
|
||||||
|
} else if (this.getTaskToAppoint().getPriority() < o.getTaskToAppoint().getPriority()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatchProcessingTask getTaskToAppoint() {
|
||||||
|
return taskToAppoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package org.codedream.epaper.component.batchthread;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Slf4j
|
||||||
|
public class TaskAppointer implements Callable<BatchProcessingTask>, Comparable<TaskAppointer> {
|
||||||
|
|
||||||
|
Comparator<BatchProcessingTask> comparator = new Comparator<BatchProcessingTask>() {
|
||||||
|
@Override
|
||||||
|
public int compare(BatchProcessingTask o1, BatchProcessingTask o2) {
|
||||||
|
return o1.getPriority() - o2.getPriority() < 0 ? -1 : 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@Resource
|
||||||
|
private BatchProcessingTask taskToAppoint = new BatchProcessingTask();
|
||||||
|
|
||||||
|
public TaskAppointer(BatchProcessingTask bpt) {
|
||||||
|
this.taskToAppoint = bpt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(TaskAppointer o) {
|
||||||
|
|
||||||
|
if (this.getTaskToAppoint().getPriority() > o.getTaskToAppoint().getPriority()) {
|
||||||
|
return 1;
|
||||||
|
} else if (this.getTaskToAppoint().getPriority() < o.getTaskToAppoint().getPriority()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BatchProcessingTask call() throws Exception {
|
||||||
|
log.info("Thead " + Thread.currentThread().getName() + "bpt" + this.getTaskToAppoint().getId());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(10);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Thread " + Thread.currentThread().getName() + " executing");
|
||||||
|
return getTaskToAppoint();
|
||||||
|
}
|
||||||
|
}
|
31
src/main/java/org/codedream/epaper/component/cache/ScheduleCacheTask.java
vendored
Normal file
31
src/main/java/org/codedream/epaper/component/cache/ScheduleCacheTask.java
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package org.codedream.epaper.component.cache;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.repository.article.CacheRepository;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@EnableScheduling
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ScheduleCacheTask {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
CacheRepository cacheRepository;
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 0 0 1/1 * ? ")
|
||||||
|
public void deleteCache() {
|
||||||
|
|
||||||
|
LocalDateTime deleteTime = LocalDateTime.now().minusDays(7);
|
||||||
|
try {
|
||||||
|
cacheRepository.deleteByRecordTime(deleteTime);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to delete cache.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,101 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.repository.file.FileRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件解析器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class FileParser {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileRepository fileRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA512Encoder encoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找缓存
|
||||||
|
* @param hash 哈希值
|
||||||
|
* @return 文件信息对象
|
||||||
|
*/
|
||||||
|
public Optional<File> find(String hash){
|
||||||
|
Iterable<File> files = fileRepository.findAllByHash(hash);
|
||||||
|
Iterator<File> fileIterator = files.iterator();
|
||||||
|
if(!fileIterator.hasNext()) return Optional.empty();
|
||||||
|
|
||||||
|
return Optional.of(fileIterator.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据散列值计算
|
||||||
|
* @param bytesData 文件数据
|
||||||
|
* @return 散列值
|
||||||
|
*/
|
||||||
|
public String encode(byte[] bytesData){
|
||||||
|
return encoder.encode(Base64.getEncoder().encodeToString(bytesData));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取文件数据
|
||||||
|
* @param stream 输入流
|
||||||
|
* @return 文件数据字节数组
|
||||||
|
*/
|
||||||
|
public Optional<byte[]> read(InputStream stream){
|
||||||
|
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
// 双重数据写出
|
||||||
|
int readBits = 0;
|
||||||
|
byte[] rawBytes = new byte[1024];
|
||||||
|
while ((readBits = stream.read(rawBytes)) != -1) {
|
||||||
|
arrayOutputStream.write(rawBytes, 0, readBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(arrayOutputStream.toByteArray());
|
||||||
|
} catch (IOException e){
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文件数据写入到文件系统
|
||||||
|
* @param file 文件信息对象
|
||||||
|
* @param bytesData 文件数据
|
||||||
|
* @return 文件信息对象(更新后)
|
||||||
|
*/
|
||||||
|
public File writeOut(File file, byte[] bytesData){
|
||||||
|
String storageName = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
Path path = Paths.get(file.getPath(), storageName);
|
||||||
|
try {
|
||||||
|
Files.createFile(path);
|
||||||
|
OutputStream outputStream = Files.newOutputStream(path);
|
||||||
|
ByteArrayInputStream stream = new ByteArrayInputStream(bytesData);
|
||||||
|
|
||||||
|
// 数据写出文件系统
|
||||||
|
int readBits = 0;
|
||||||
|
byte[] rawBytes = new byte[1024];
|
||||||
|
while ((readBits = stream.read(rawBytes)) != -1) {
|
||||||
|
outputStream.write(rawBytes, 0, readBits);
|
||||||
|
}
|
||||||
|
outputStream.close();
|
||||||
|
stream.close();
|
||||||
|
|
||||||
|
file.setStorageName(storageName);
|
||||||
|
file.setSize(bytesData.length);
|
||||||
|
return file;
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new RuntimeIOException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.github.fge.jsonpatch.JsonPatch;
|
||||||
|
import com.github.fge.jsonpatch.JsonPatchException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON请求参数处理器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class JSONParameter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得HTTP请求内容
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @return 内容字符串
|
||||||
|
*/
|
||||||
|
public String getRequestBody(HttpServletRequest request){
|
||||||
|
try {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
BufferedReader reader = request.getReader();
|
||||||
|
reader.reset();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null)
|
||||||
|
stringBuilder.append(line);
|
||||||
|
return stringBuilder.toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提取Request内容并解析为JSON对象
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @return JSON对象
|
||||||
|
*/
|
||||||
|
public Optional<JSONObject> getJSONByRequest(HttpServletRequest request){
|
||||||
|
try {
|
||||||
|
JSONObject jsonParam = null;
|
||||||
|
String content = getRequestBody(request);
|
||||||
|
jsonParam = JSONObject.parseObject(content);
|
||||||
|
return Optional.ofNullable(jsonParam);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据JSON对象构造JSON字符串用于返回
|
||||||
|
* @param json JSON对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONString(JSONObject json){
|
||||||
|
return json.toJSONString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据Java对象构造JSON字符串用于返回
|
||||||
|
* @param object Java对象
|
||||||
|
* @return JSON字符串
|
||||||
|
*/
|
||||||
|
public String getJSONString(Object object){
|
||||||
|
return JSON.toJSONString(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由JSON对象获得对应的Java对象
|
||||||
|
* @param json JSON对象
|
||||||
|
* @param type 对应的Java对象类型
|
||||||
|
* @param <T> 对应的Java对象类型
|
||||||
|
* @return 指定的Java对象
|
||||||
|
*/
|
||||||
|
public <T> T getJavaObject(JSONObject json, Class<T> type){
|
||||||
|
return json.toJavaObject(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由HTTP请求获得对应的Java对象(一般用于Post请求中)
|
||||||
|
* @param request HTTP请求
|
||||||
|
* @param type 对应的Java对象类型
|
||||||
|
* @param <T> 对应的Java对象类型
|
||||||
|
* @return 指定的Java对象
|
||||||
|
*/
|
||||||
|
public <T> Optional<T> getJavaObjectByRequest(HttpServletRequest request, Class<T> type){
|
||||||
|
Optional<JSONObject> json = getJSONByRequest(request);
|
||||||
|
return json.map(jsonObject -> getJavaObject(jsonObject, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将JsonPath对象转换成Java对象(Restful API的Path动词)
|
||||||
|
* @param patch JsonPath对象
|
||||||
|
* @param object Java对象
|
||||||
|
* @param <T> 对应的Java对象类型
|
||||||
|
* @return 指定的Java对象(更新后)
|
||||||
|
*/
|
||||||
|
public <T> T parsePathToObject(JsonPatch patch, T object){
|
||||||
|
try {
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode patched = patch.apply(mapper.convertValue(object, JsonNode.class));
|
||||||
|
return (T) mapper.treeToValue(patched, object.getClass());
|
||||||
|
} catch (JsonPatchException | JsonProcessingException e) {
|
||||||
|
throw new HandlingErrorsException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.codedream.epaper.configure.PunctuationConfiguration;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个段落分为几个句子
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ParagraphDivider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个段落划分为若干句,并进行相应的持久化
|
||||||
|
*
|
||||||
|
* @param text 需要划分的段落文本
|
||||||
|
* @return 段落中的所有被划分好的句子
|
||||||
|
*/
|
||||||
|
public List<String> divideParagraph(String text) {
|
||||||
|
|
||||||
|
if (text.isEmpty()) return null;
|
||||||
|
Paragraph paragraph = new Paragraph();
|
||||||
|
paragraph.setText(text);
|
||||||
|
List<String> back = PunctuationConfiguration.getBackPunctuations();
|
||||||
|
String[] arr = text.split("。|!|?|……|\\?|:");
|
||||||
|
List<String> sentenceTexts = Arrays.asList(arr);
|
||||||
|
|
||||||
|
List<String> sentences = new ArrayList<>();
|
||||||
|
Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
|
||||||
|
for (int i = 0; i < sentenceTexts.size(); i++) {
|
||||||
|
String sentenceText = sentenceTexts.get(i);
|
||||||
|
Matcher m = p.matcher(sentenceText);
|
||||||
|
int len = sentenceTexts.get(i).length();
|
||||||
|
if (!m.find() || len < 15 || len > 510) continue;
|
||||||
|
if (back.contains(sentenceTexts.get(i).charAt(0)) && sentences.size() > 1) {
|
||||||
|
sentences.set(i - 1, sentences.get(i - 1) + sentenceTexts.get(i).charAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
sentences.add(sentenceTexts.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sentences;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.text.PDFTextStripper;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.repository.article.ParagraphRepository;
|
||||||
|
import org.codedream.epaper.service.IArticleService;
|
||||||
|
import org.codedream.epaper.service.IFileService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class PdfParser {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IArticleService articleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ParagraphRepository paragraphRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA512Encoder encoder;
|
||||||
|
|
||||||
|
public Article parse(InputStream stream){
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
Article article = articleService.createArticle(null);
|
||||||
|
|
||||||
|
PDDocument doc = PDDocument.load(stream);
|
||||||
|
|
||||||
|
PDFTextStripper textStripper = new PDFTextStripper();
|
||||||
|
|
||||||
|
String content = textStripper.getText(doc);
|
||||||
|
|
||||||
|
String regA = "^[\\u4e00-\\u9fa5a-zA-Z0-9。,?!;、:()“”]";
|
||||||
|
String regB = "[\\s|.,/?\"%$#@*^~`()+=\\-{}<>\\///_]";
|
||||||
|
content = content.replaceAll(regA, "");
|
||||||
|
content = content.replaceAll(regB, "");
|
||||||
|
|
||||||
|
|
||||||
|
saveParagraph(article, content);
|
||||||
|
|
||||||
|
doc.close();
|
||||||
|
|
||||||
|
return article;
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeIOException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer parse(Integer fileId){
|
||||||
|
File file = fileService.getFileInfo(fileId);
|
||||||
|
if(file.getType().equals("pdf")){
|
||||||
|
Article article = parse(fileService.getFile(fileId));
|
||||||
|
|
||||||
|
article.setFileId(fileId);
|
||||||
|
article = articleService.save(article);
|
||||||
|
return article.getId();
|
||||||
|
}
|
||||||
|
else throw new HandlingErrorsException(file.getType());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 储存段结构,并考虑缓存情况
|
||||||
|
private void saveParagraph(Article article, String text){
|
||||||
|
String hash = encoder.encode(text);
|
||||||
|
Paragraph paragraph;
|
||||||
|
Optional<Paragraph> paragraphOptional = paragraphRepository.findBySha512Hash(hash);
|
||||||
|
if(!paragraphOptional.isPresent()){
|
||||||
|
paragraph = articleService.createParagraph(text);
|
||||||
|
paragraph.setSha512Hash(hash);
|
||||||
|
paragraph = articleService.save(paragraph);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
paragraph = paragraphOptional.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
articleService.addParagraph(article, paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,235 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.Template;
|
||||||
|
import freemarker.template.TemplateException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.log4j.helpers.Loader;
|
||||||
|
import org.codedream.epaper.component.article.GetSentenceFromArticle;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTNResult;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableTaskResult;
|
||||||
|
import org.codedream.epaper.component.task.JsonableTaskResultGenerator;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.service.FileService;
|
||||||
|
import org.codedream.epaper.service.IFileService;
|
||||||
|
import org.codedream.epaper.service.ITaskService;
|
||||||
|
import org.docx4j.Docx4J;
|
||||||
|
import org.docx4j.fonts.IdentityPlusMapper;
|
||||||
|
import org.docx4j.fonts.Mapper;
|
||||||
|
import org.docx4j.fonts.PhysicalFont;
|
||||||
|
import org.docx4j.fonts.PhysicalFonts;
|
||||||
|
import org.docx4j.openpackaging.exceptions.Docx4JException;
|
||||||
|
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ReportGenerator {
|
||||||
|
@Resource
|
||||||
|
private ITaskService taskService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private JsonableTaskResultGenerator taskResultGenerator;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GetSentenceFromArticle getSentenceFromArticle;
|
||||||
|
|
||||||
|
Mapper fontMapper = null;
|
||||||
|
|
||||||
|
public byte[] generate(Integer taskId){
|
||||||
|
Optional<Task> taskOptional =taskService.getTaskInfo(taskId);
|
||||||
|
|
||||||
|
if(!taskOptional.isPresent()) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
Task task = taskOptional.get();
|
||||||
|
|
||||||
|
// 获得数据列表
|
||||||
|
Map<String, Object> dataMap = processDataMap(task);
|
||||||
|
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
BufferedWriter writer = new BufferedWriter(stringWriter);
|
||||||
|
Template template = getTemplate("report.ftl");
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
template.process(dataMap, writer);
|
||||||
|
|
||||||
|
// 转换为Word
|
||||||
|
String xmlStr = stringWriter.toString();
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(xmlStr.getBytes());
|
||||||
|
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(in);
|
||||||
|
|
||||||
|
wordMLPackage.save(new java.io.File("./Report.docx"));
|
||||||
|
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
|
||||||
|
wordMLPackage.setFontMapper(generateFrontMapper());
|
||||||
|
|
||||||
|
// 转换为PDF
|
||||||
|
Docx4J.toPDF(wordMLPackage, outputStream);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return outputStream.toByteArray();
|
||||||
|
|
||||||
|
|
||||||
|
} catch (IOException | TemplateException | Docx4JException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new HandlingErrorsException(e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized Mapper generateFrontMapper() throws Exception {
|
||||||
|
if (this.fontMapper == null) {
|
||||||
|
// URL simSumUrl = ResourceUtils.getURL("classpath:fonts/simsun.ttc");
|
||||||
|
PhysicalFonts.discoverPhysicalFonts();
|
||||||
|
URL simSumUrl = ResourceUtils.getURL("./fonts/simsun.ttc");
|
||||||
|
PhysicalFonts.addPhysicalFont("SimSun", simSumUrl);
|
||||||
|
|
||||||
|
this.fontMapper = new IdentityPlusMapper();
|
||||||
|
fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
|
||||||
|
fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
|
||||||
|
fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));
|
||||||
|
fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
|
||||||
|
fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));
|
||||||
|
fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));
|
||||||
|
fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
|
||||||
|
fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
|
||||||
|
fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
|
||||||
|
fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));
|
||||||
|
fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));
|
||||||
|
fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));
|
||||||
|
fontMapper.put("等线", PhysicalFonts.get("SimSun"));
|
||||||
|
fontMapper.put("等线 Light", PhysicalFonts.get("SimSun"));
|
||||||
|
fontMapper.put("华文琥珀", PhysicalFonts.get("STHupo"));
|
||||||
|
fontMapper.put("华文隶书", PhysicalFonts.get("STLiti"));
|
||||||
|
fontMapper.put("华文新魏", PhysicalFonts.get("STXinwei"));
|
||||||
|
fontMapper.put("华文彩云", PhysicalFonts.get("STCaiyun"));
|
||||||
|
fontMapper.put("方正姚体", PhysicalFonts.get("FZYaoti"));
|
||||||
|
fontMapper.put("方正舒体", PhysicalFonts.get("FZShuTi"));
|
||||||
|
fontMapper.put("华文细黑", PhysicalFonts.get("STXihei"));
|
||||||
|
fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));
|
||||||
|
fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
|
||||||
|
fontMapper.put("新細明體", PhysicalFonts.get("SimSun"));
|
||||||
|
//解决宋体(正文)和宋体(标题)的乱码问题
|
||||||
|
PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
|
||||||
|
PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
|
||||||
|
|
||||||
|
return this.fontMapper;
|
||||||
|
}
|
||||||
|
return this.fontMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveByFile(String path, byte[] bytes) throws IOException {
|
||||||
|
FileOutputStream outputStream = new FileOutputStream(path);
|
||||||
|
outputStream.write(bytes);
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer saveByFileService(byte[] byteArray){
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(byteArray);
|
||||||
|
return fileService.saveFile(UUID.randomUUID().toString() + ".pdf", "pdf", inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> processDataMap(Task task){
|
||||||
|
|
||||||
|
File file = task.getFile();
|
||||||
|
if(file == null) throw new InnerDataTransmissionException(task.toString());
|
||||||
|
|
||||||
|
JsonableTaskResult taskResult = taskResultGenerator.getJsonableTaskResult(task.getId());
|
||||||
|
|
||||||
|
Map<String, Object> dataMap = new HashMap<>();
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm");
|
||||||
|
dataMap.put("articleTitle", file.getName());
|
||||||
|
dataMap.put("datetime", sdf.format(new Date()));
|
||||||
|
|
||||||
|
if(taskResult.getScore() > 90)
|
||||||
|
dataMap.put("grade", "A");
|
||||||
|
else if(taskResult.getScore() > 80)
|
||||||
|
dataMap.put("grade", "B");
|
||||||
|
else if(taskResult.getScore() > 60)
|
||||||
|
dataMap.put("grade", "C");
|
||||||
|
else
|
||||||
|
dataMap.put("grade", "D");
|
||||||
|
|
||||||
|
dataMap.put("wdScore", taskResult.getCorrectionScore());
|
||||||
|
dataMap.put("fqScore", taskResult.getDnnScore());
|
||||||
|
dataMap.put("flScore", taskResult.getEmotionScore());
|
||||||
|
|
||||||
|
|
||||||
|
List<Sentence> sentences = getSentenceFromArticle.get(task.getArticle());
|
||||||
|
|
||||||
|
int totalLen = 0;
|
||||||
|
for(Sentence sentence : sentences)
|
||||||
|
totalLen += sentence.getText().length();
|
||||||
|
|
||||||
|
dataMap.put("svgLen", totalLen / sentences.size());
|
||||||
|
dataMap.put("stnNum", sentences.size());
|
||||||
|
dataMap.put("userId", task.getUser().getId());
|
||||||
|
dataMap.put("errStatus", "正态分布");
|
||||||
|
dataMap.put("wEum", taskResult.getWrongTextCount());
|
||||||
|
dataMap.put("pcsTime", task.getEndDate().getTime() - task.getCreateDate().getTime());
|
||||||
|
dataMap.put("fqRum", taskResult.getBrokenSentencesCount());
|
||||||
|
dataMap.put("flEum", taskResult.getOralCount());
|
||||||
|
dataMap.put("status", "完成");
|
||||||
|
|
||||||
|
Map<Integer, STNResult> stnResults = new HashMap<>();
|
||||||
|
|
||||||
|
Map<Integer, Sentence> sentenceMap = new HashMap<>();
|
||||||
|
|
||||||
|
for(Sentence sentence : sentences){
|
||||||
|
sentenceMap.put(sentence.getId(), sentence);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(JsonableSTNResult jsonableSTNResult : taskResult.getStnResults()){
|
||||||
|
if(jsonableSTNResult.getErrorList().size() == 0) continue;
|
||||||
|
STNResult stnResult = new STNResult();
|
||||||
|
stnResult.setId(jsonableSTNResult.getStnId());
|
||||||
|
stnResult.setText(sentenceMap.get(jsonableSTNResult.getStnId()).getText());
|
||||||
|
stnResults.put(stnResult.getId(), stnResult);
|
||||||
|
stnResult.setStnResultList(jsonableSTNResult.getErrorList());
|
||||||
|
stnResults.put(stnResult.getId(), stnResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<STNResult> stnResultList = new ArrayList<>(stnResults.values());
|
||||||
|
|
||||||
|
dataMap.put("errorStnList", stnResultList);
|
||||||
|
|
||||||
|
return dataMap;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Template getTemplate(String name){
|
||||||
|
try {
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
|
||||||
|
// conf.setDirectoryForTemplateLoading(ResourceUtils.getFile("classpath:templates"));
|
||||||
|
conf.setDirectoryForTemplateLoading(new java.io.File("./templates/"));
|
||||||
|
return conf.getTemplate(name);
|
||||||
|
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new RuntimeIOException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA256编码器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SHA256Encoder {
|
||||||
|
/**
|
||||||
|
* 编码
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @return 密文
|
||||||
|
*/
|
||||||
|
public String encode(CharSequence charSequence){
|
||||||
|
return DigestUtils.sha256Hex(charSequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @param s 密文
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean match (CharSequence charSequence, String s){
|
||||||
|
return s.equals(encode(charSequence));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SHA256编码器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SHA512Encoder {
|
||||||
|
/**
|
||||||
|
* 编码
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @return 密文
|
||||||
|
*/
|
||||||
|
public String encode(CharSequence charSequence){
|
||||||
|
return DigestUtils.sha512Hex(charSequence.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证
|
||||||
|
* @param charSequence 字符队列
|
||||||
|
* @param s 密文
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean match (CharSequence charSequence, String s){
|
||||||
|
return s.equals(encode(charSequence));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTNError;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTNResult;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class STNResult {
|
||||||
|
private Integer id;
|
||||||
|
private String text;
|
||||||
|
private List<JsonableSTNError> stnResultList = new ArrayList<>();
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import com.baidu.aip.nlp.AipNlp;
|
||||||
|
import com.sun.org.apache.xpath.internal.operations.Bool;
|
||||||
|
import javafx.util.Pair;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.configure.SingletonAipNlp;
|
||||||
|
import org.codedream.epaper.model.article.Phrase;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.service.ArticleService;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供句子分词方法,并通过{@link ArticleService}进行相应持久化操作
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class SentenceDivider {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
ArticleService articleService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将句子分词
|
||||||
|
*
|
||||||
|
* @param text 要进行分词操作的句子
|
||||||
|
* @return 一个已经持久化的、分完词的句子
|
||||||
|
*/
|
||||||
|
public List<Phrase> divideSentence(String text) {
|
||||||
|
|
||||||
|
if (text.isEmpty()) return null;
|
||||||
|
AipNlp client = SingletonAipNlp.getInstance();
|
||||||
|
HashMap<String, Object> hashMap = new HashMap<>();
|
||||||
|
List<Phrase> phrases = new ArrayList<>();
|
||||||
|
String f = "";
|
||||||
|
try {
|
||||||
|
JSONObject res = client.lexer(text, hashMap);
|
||||||
|
f = "1";
|
||||||
|
boolean lexerFlag = true;
|
||||||
|
Iterator<String> iterator = res.keys();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (iterator.next().equals("error_msg")) {
|
||||||
|
lexerFlag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lexerFlag) {
|
||||||
|
f = "2";
|
||||||
|
JSONArray items = (JSONArray) res.get("items");
|
||||||
|
f = "After lexer";
|
||||||
|
for (int i = 0; i < items.length(); i++) {
|
||||||
|
JSONObject item = (JSONObject) items.get(i);
|
||||||
|
List<Phrase> basic = new ArrayList<>();
|
||||||
|
f = "Before basicArray";
|
||||||
|
JSONArray basicArray = (JSONArray) item.get("basic_words");
|
||||||
|
|
||||||
|
for (int j = 0; j < basicArray.length(); j++) {
|
||||||
|
|
||||||
|
f = "In basicArray";
|
||||||
|
Pair<Boolean, Phrase> phrasePair = articleService.savePhrase(basicArray.get(j).toString());
|
||||||
|
|
||||||
|
basic.add(phrasePair.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
f = "Before vec";
|
||||||
|
JSONObject vecRes = new JSONObject();
|
||||||
|
|
||||||
|
|
||||||
|
Pair<Boolean, Phrase> phrasePair = articleService.savePhrase(item.get("item").toString());
|
||||||
|
Phrase phrase = phrasePair.getValue();
|
||||||
|
|
||||||
|
if(!phrasePair.getKey()){
|
||||||
|
phrase.setText(item.get("item").toString());
|
||||||
|
phrase.getBasicPhrase().addAll(basic);
|
||||||
|
phrase.setPos(item.get("pos").toString());
|
||||||
|
phrase = articleService.save(phrase);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Iterator<String> keys = vecRes.keys();
|
||||||
|
boolean flag = true;
|
||||||
|
while (keys.hasNext()) {
|
||||||
|
if (keys.next().equals("error_msg")) {
|
||||||
|
flag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flag = false;
|
||||||
|
if (flag) {
|
||||||
|
f = "Before vecArray";
|
||||||
|
JSONArray vec = vecRes.getJSONArray("vec");
|
||||||
|
List<Float> floatList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < vec.length(); j++) {
|
||||||
|
f = "In vecArray";
|
||||||
|
String str = vec.getString(i);
|
||||||
|
f = "Before parsing to float";
|
||||||
|
float vecUnit = Float.parseFloat(str);
|
||||||
|
floatList.add(vecUnit);
|
||||||
|
}
|
||||||
|
phrase.setVec(floatList);
|
||||||
|
}
|
||||||
|
|
||||||
|
phrases.add(phrase);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.toString() + ": f");
|
||||||
|
}
|
||||||
|
|
||||||
|
return phrases;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import com.baidu.aip.nlp.AipNlp;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.configure.SingletonAipNlp;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供句子通顺度获取方法
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class SentenceSmoothnessGetter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过调用百度接口获取句子通顺度
|
||||||
|
*
|
||||||
|
* @param text 待处理的文本
|
||||||
|
* @return 句子通顺度的值
|
||||||
|
*/
|
||||||
|
public float getSentenceSmoothness(String text) {
|
||||||
|
AipNlp client = SingletonAipNlp.getInstance();
|
||||||
|
HashMap<String, Object> options = new HashMap<>();
|
||||||
|
JSONObject jsonObject = client.dnnlmCn(text, options);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
float dnn = Float.parseFloat(jsonObject.get("ppl").toString());
|
||||||
|
return dnn;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.toString() + "In dnn: " + jsonObject.toString());
|
||||||
|
return (float) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 储存字符串标识的文件(可以将文件直接转换为Json进行传输)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StringFile {
|
||||||
|
// 文件内容(Base64编码,Gzip算法压缩)
|
||||||
|
private String strData = null;
|
||||||
|
|
||||||
|
// 散列值
|
||||||
|
private String sha256 = null;
|
||||||
|
|
||||||
|
// 文件大小
|
||||||
|
private Integer size = null;
|
||||||
|
|
||||||
|
// 文件类型
|
||||||
|
private String type = "none";
|
||||||
|
|
||||||
|
// 文件名
|
||||||
|
private String name = null;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.codedream.epaper.exception.innerservererror.StringFileConvertException;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串文件生成器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class StringFileGenerator {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA256Encoder encoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用过读入流创建一个字符串文件
|
||||||
|
* @param name 文件名
|
||||||
|
* @param type 文件类型
|
||||||
|
* @param stream 输入流
|
||||||
|
* @return 字符串文件对象
|
||||||
|
*/
|
||||||
|
public Optional<StringFile> generateStringFile(String name, String type,InputStream stream){
|
||||||
|
StringFile file = new StringFile();
|
||||||
|
file.setName(name);
|
||||||
|
file.setType(type);
|
||||||
|
|
||||||
|
// 字符串内容计算
|
||||||
|
file.setStrData(generateFile2String(stream));
|
||||||
|
if(file.getStrData() == null) return Optional.empty();
|
||||||
|
|
||||||
|
// 相关校验值计算
|
||||||
|
file.setSha256(generateSHA256Checker(file.getStrData()));
|
||||||
|
file.setSize(file.getStrData().length());
|
||||||
|
return Optional.of(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一次性读取输入流中的文件数据
|
||||||
|
* @param stream 输入流
|
||||||
|
* @return 文件数据
|
||||||
|
*/
|
||||||
|
private byte[] readSteamAll(InputStream stream) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = new byte[stream.available()];
|
||||||
|
|
||||||
|
//检查文件书否完全读取
|
||||||
|
if (stream.read(bytes) != bytes.length) return null;
|
||||||
|
else return bytes;
|
||||||
|
} catch (IOException e){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将文件数据压缩(Gzip),然后用Base64编码为字符串
|
||||||
|
* @param stream 输入流
|
||||||
|
* @return 文件数据编码
|
||||||
|
*/
|
||||||
|
private String generateFile2String(InputStream stream){
|
||||||
|
ByteArrayOutputStream zipDataStream = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
|
||||||
|
// 解压缩
|
||||||
|
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(zipDataStream);
|
||||||
|
byte[] bytes = readSteamAll(stream);
|
||||||
|
if(bytes == null) return null;
|
||||||
|
gzipOutputStream.write(bytes);
|
||||||
|
gzipOutputStream.close();
|
||||||
|
|
||||||
|
// 编码转换
|
||||||
|
return Base64.getEncoder().encodeToString(zipDataStream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成字符串文件的校验码
|
||||||
|
* @param str 文件散列值检查
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String generateSHA256Checker(String str){
|
||||||
|
return encoder.encode(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查文件内容是否正确,包括大小与校验码
|
||||||
|
* @param file 字符串文件对象
|
||||||
|
* @return 布尔值
|
||||||
|
*/
|
||||||
|
public boolean checkStringFile(StringFile file){
|
||||||
|
return file.getStrData().length() == file.getSize()
|
||||||
|
&& encoder.match(file.getStrData(), file.getSha256());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从字符串文件中读取真实的文件数据
|
||||||
|
* @param file 字符串文件对象
|
||||||
|
* @return 输入流
|
||||||
|
*/
|
||||||
|
public InputStream readFileString(StringFile file){
|
||||||
|
try {
|
||||||
|
// 字符串转换为二进制数据
|
||||||
|
byte[] bytes = Base64.getDecoder().decode(file.getStrData());
|
||||||
|
GZIPInputStream stream = new GZIPInputStream(new ByteArrayInputStream(bytes), bytes.length);
|
||||||
|
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
// 数据解压缩
|
||||||
|
int readBits = 0;
|
||||||
|
byte[] rawBytes = new byte[1024];
|
||||||
|
while ((readBits = stream.read(rawBytes)) != -1) {
|
||||||
|
outputStream.write(rawBytes, 0, readBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
return new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new StringFileConvertException("Read FileString Failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import com.baidu.aip.nlp.AipNlp;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.configure.SingletonAipNlp;
|
||||||
|
import org.codedream.epaper.model.task.CorrectionResult;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于文本纠错
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class TextCorrector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本纠错
|
||||||
|
*
|
||||||
|
* @param text 需要纠错的文本
|
||||||
|
* @return 一个纠正类的列表,保存句子需要修改的信息
|
||||||
|
* 值的位置;corr_text,存放纠错后文本;org_text:存放原文本。
|
||||||
|
*/
|
||||||
|
public List<CorrectionResult> correctText(String text) {
|
||||||
|
|
||||||
|
if (text.isEmpty()) return new ArrayList<>();
|
||||||
|
AipNlp client = SingletonAipNlp.getInstance();
|
||||||
|
HashMap<String, Object> options = new HashMap<>();
|
||||||
|
List<CorrectionResult> correctionResults = new ArrayList<>();
|
||||||
|
String correction;
|
||||||
|
try {
|
||||||
|
JSONObject res = (JSONObject) client.ecnet(text, options).get("item");
|
||||||
|
if (res.get("vec_fragment") == null) {
|
||||||
|
return correctionResults;
|
||||||
|
}
|
||||||
|
correction = (String) res.get("correct_query");
|
||||||
|
DiffMatchPatch dmp = new DiffMatchPatch();
|
||||||
|
List<DiffMatchPatch.Diff> diffs = dmp.diff_main(text, correction);
|
||||||
|
int p = 0;
|
||||||
|
int size = diffs.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
DiffMatchPatch.Diff diff = diffs.get(i);
|
||||||
|
if (diff.operation.equals(DiffMatchPatch.Operation.EQUAL) ||
|
||||||
|
diff.operation.equals(DiffMatchPatch.Operation.INSERT)) {
|
||||||
|
p += diff.text.length();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CorrectionResult correctionResult = new CorrectionResult();
|
||||||
|
correctionResult.setStartPos(p);
|
||||||
|
correctionResult.setLength(diff.text.length());
|
||||||
|
if (i == size - 1 || !diffs.get(i + 1).operation.equals(DiffMatchPatch.Operation.INSERT)) {
|
||||||
|
correctionResult.setCorrectionText("");
|
||||||
|
} else {
|
||||||
|
DiffMatchPatch.Diff nextDiff = diffs.get(i + 1);
|
||||||
|
correctionResult.setCorrectionText(nextDiff.text);
|
||||||
|
}
|
||||||
|
correctionResults.add(correctionResult);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.toString() + ": Failed to analyze \"" + text + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return correctionResults;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import javassist.bytecode.ByteArray;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.repository.article.ParagraphRepository;
|
||||||
|
import org.codedream.epaper.service.IArticleService;
|
||||||
|
import org.codedream.epaper.service.IFileService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TextParser {
|
||||||
|
@Resource
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IArticleService articleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ParagraphRepository paragraphRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA512Encoder encoder;
|
||||||
|
|
||||||
|
public Integer parse(Integer fileId) {
|
||||||
|
File file = fileService.getFileInfo(fileId);
|
||||||
|
if(file.getType().equals("plain")){
|
||||||
|
Article article = articleService.createArticle(null);
|
||||||
|
InputStream stream = fileService.getFile(fileId);
|
||||||
|
|
||||||
|
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// 数据内存写出
|
||||||
|
int readBits = 0;
|
||||||
|
byte[] rawBytes = new byte[1024];
|
||||||
|
while ((readBits = stream.read(rawBytes)) != -1) {
|
||||||
|
arrayOutputStream.write(rawBytes, 0, readBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveParagraph(article, new String(arrayOutputStream.toByteArray()));
|
||||||
|
article.setFileId(fileId);
|
||||||
|
article = articleService.save(article);
|
||||||
|
|
||||||
|
return article.getId();
|
||||||
|
}
|
||||||
|
catch (IOException e){
|
||||||
|
throw new RuntimeIOException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 储存段结构,并考虑缓存情况
|
||||||
|
private void saveParagraph(Article article, String text){
|
||||||
|
String hash = encoder.encode(text);
|
||||||
|
Paragraph paragraph;
|
||||||
|
Optional<Paragraph> paragraphOptional = paragraphRepository.findBySha512Hash(hash);
|
||||||
|
if(!paragraphOptional.isPresent()){
|
||||||
|
paragraph = articleService.createParagraph(text);
|
||||||
|
paragraph.setSha512Hash(hash);
|
||||||
|
paragraph = articleService.save(paragraph);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
paragraph = paragraphOptional.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
articleService.addParagraph(article, paragraph);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package org.codedream.epaper.component.datamanager;
|
||||||
|
|
||||||
|
import org.apache.poi.hwpf.extractor.WordExtractor;
|
||||||
|
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
|
||||||
|
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||||
|
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.repository.article.ParagraphRepository;
|
||||||
|
import org.codedream.epaper.service.IArticleService;
|
||||||
|
import org.codedream.epaper.service.IFileService;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Word文档解析
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class WordParser {
|
||||||
|
@Resource
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IArticleService articleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ParagraphRepository paragraphRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA512Encoder encoder;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
public Article parse(InputStream stream, String type){
|
||||||
|
if(type.equals("doc")){
|
||||||
|
return parseDoc(stream);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return parseDocx(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer parse(Integer fileId){
|
||||||
|
File file = fileService.getFileInfo(fileId);
|
||||||
|
if(file.getType().equals("doc") || file.getType().equals("docx")){
|
||||||
|
Article article = parse(fileService.getFile(fileId), file.getType());
|
||||||
|
article.setFileId(fileId);
|
||||||
|
article = articleService.save(article);
|
||||||
|
return article.getId();
|
||||||
|
}
|
||||||
|
else throw new HandlingErrorsException(file.getType());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Article parseDoc(InputStream stream) {
|
||||||
|
try {
|
||||||
|
WordExtractor extractor = new WordExtractor(stream);
|
||||||
|
|
||||||
|
Article article = articleService.createArticle(null);
|
||||||
|
|
||||||
|
for (String text : extractor.getParagraphText()) {
|
||||||
|
if (text.length() > configure.getParagraphMinSize()
|
||||||
|
&& text.length() < configure.getParagraphMaxSize()) {
|
||||||
|
// 储存段结构
|
||||||
|
saveParagraph(article ,text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存章
|
||||||
|
return articleService.save(article);
|
||||||
|
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new RuntimeIOException("Doc Parse Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Article parseDocx(InputStream stream){
|
||||||
|
try{
|
||||||
|
XWPFDocument doc = new XWPFDocument(stream);
|
||||||
|
XWPFWordExtractor extractor = new XWPFWordExtractor(doc);
|
||||||
|
|
||||||
|
Article article = articleService.createArticle(null);
|
||||||
|
|
||||||
|
// 遍历段落
|
||||||
|
Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
XWPFParagraph para = iterator.next();
|
||||||
|
String text = para.getText();
|
||||||
|
if(text.length() > configure.getParagraphMinSize()
|
||||||
|
&& text.length() < configure.getParagraphMaxSize()){
|
||||||
|
System.out.println("Paragraph: " + text);
|
||||||
|
// 储存段结构
|
||||||
|
saveParagraph(article ,text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存章
|
||||||
|
return articleService.save(article);
|
||||||
|
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new RuntimeIOException("Docx Parse Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 储存段结构,并考虑缓存情况
|
||||||
|
private void saveParagraph(Article article, String text){
|
||||||
|
String hash = encoder.encode(text);
|
||||||
|
Paragraph paragraph;
|
||||||
|
Optional<Paragraph> paragraphOptional = paragraphRepository.findBySha512Hash(hash);
|
||||||
|
if(!paragraphOptional.isPresent()){
|
||||||
|
paragraph = articleService.createParagraph(text);
|
||||||
|
paragraph.setSha512Hash(hash);
|
||||||
|
paragraph = articleService.save(paragraph);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
paragraph = paragraphOptional.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
articleService.addParagraph(article, paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.codedream.epaper.component.json;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有有效的JSON对象模板
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class JSONBaseObject {
|
||||||
|
Date time = new Date();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.models.auth.In;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("批处理任务结构")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableBPT {
|
||||||
|
private Integer id;
|
||||||
|
private Integer stnNumber;
|
||||||
|
private List<JsonableSTN> stns = new ArrayList<>();
|
||||||
|
|
||||||
|
public JsonableBPT(BatchProcessingTask bpt){
|
||||||
|
this.id = bpt.getId();
|
||||||
|
this.stnNumber = bpt.getSentencesNumber();
|
||||||
|
|
||||||
|
for (Task task : bpt.getTasks()){
|
||||||
|
for(Paragraph paragraph : task.getArticle().getParagraphs()){
|
||||||
|
for(Sentence sentence : paragraph.getSentences()){
|
||||||
|
// 检查是否已经深处理完毕
|
||||||
|
if(sentence.isDeepProcess()) continue;
|
||||||
|
|
||||||
|
JsonableSTN stn = new JsonableSTN();
|
||||||
|
stn.setStnId(sentence.getId());
|
||||||
|
stn.setText(sentence.getText());
|
||||||
|
this.stns.add(stn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("批处理任务结果返回结构")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableBPTResult {
|
||||||
|
// 句子Id
|
||||||
|
private Integer stnid;
|
||||||
|
// 标签的预测值
|
||||||
|
private List<Float> tagPossible = new ArrayList<>();
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.codedream.epaper.model.server.ChildServerPassport;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("子服务器护照")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableCSP {
|
||||||
|
|
||||||
|
// 身份认证码
|
||||||
|
private String identityCode;
|
||||||
|
|
||||||
|
// 最后一次签证日期
|
||||||
|
private Date lastUpdateTime;
|
||||||
|
|
||||||
|
// 护照是否过期
|
||||||
|
private boolean expired;
|
||||||
|
|
||||||
|
public JsonableCSP(ChildServerPassport csp){
|
||||||
|
this.identityCode = csp.getIdentityCode();
|
||||||
|
this.lastUpdateTime = csp.getLastUpdateTime();
|
||||||
|
this.expired = csp.isExpired();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("文件信息结构")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableFile {
|
||||||
|
|
||||||
|
// 文件ID号
|
||||||
|
private Integer fileId;
|
||||||
|
|
||||||
|
// 文件名
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
// 文件类型
|
||||||
|
private String type;
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("句原文列表结构")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableSTN {
|
||||||
|
|
||||||
|
// 句子ID号
|
||||||
|
private Integer stnId;
|
||||||
|
|
||||||
|
// 句子文本内容
|
||||||
|
private String text;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("句错误结构")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableSTNError {
|
||||||
|
|
||||||
|
// 序列号(index)
|
||||||
|
private Integer wordIdx;
|
||||||
|
|
||||||
|
// 词长
|
||||||
|
private Integer wordLen;
|
||||||
|
|
||||||
|
// 错误类型
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
// 错误内容
|
||||||
|
private String content;
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("句分页结构")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableSTNPage {
|
||||||
|
// 页序号
|
||||||
|
Integer page;
|
||||||
|
|
||||||
|
// 页数
|
||||||
|
Integer all;
|
||||||
|
|
||||||
|
// 句列表
|
||||||
|
List<JsonableSTN> stns;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("句处理结果")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableSTNResult {
|
||||||
|
// 句ID号
|
||||||
|
Integer stnId;
|
||||||
|
|
||||||
|
// 错误类型
|
||||||
|
Integer appear;
|
||||||
|
|
||||||
|
// 分数
|
||||||
|
Float score;
|
||||||
|
|
||||||
|
// 是否为书面文本
|
||||||
|
boolean isNeutral;
|
||||||
|
|
||||||
|
// 错误列表
|
||||||
|
List<JsonableSTNError> errorList = new ArrayList<>();
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("子任务结果")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableTask {
|
||||||
|
|
||||||
|
// 任务ID号
|
||||||
|
private Integer taskId;
|
||||||
|
|
||||||
|
// 用户openid
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
// 文件ID号
|
||||||
|
private Integer fileId;
|
||||||
|
|
||||||
|
// 文本
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
// 任务是否完成
|
||||||
|
private boolean finished;
|
||||||
|
|
||||||
|
// 任务进度
|
||||||
|
private Float progress;
|
||||||
|
|
||||||
|
// 描述
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public JsonableTask(Task task){
|
||||||
|
this.taskId = task.getId();
|
||||||
|
this.openid = task.getUser().getUsername();
|
||||||
|
this.fileId = task.getFile().getId();
|
||||||
|
this.finished = task.isFinished();
|
||||||
|
this.progress = task.getProgressRate() / 5.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("任务处理结果")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableTaskResult {
|
||||||
|
|
||||||
|
// 任务ID号
|
||||||
|
private Integer taskId;
|
||||||
|
|
||||||
|
// 任务是否成功
|
||||||
|
private boolean success;
|
||||||
|
|
||||||
|
// 文章错误位置数量
|
||||||
|
private Integer wrongTextCount = 0;
|
||||||
|
|
||||||
|
// 不通顺的句子数量
|
||||||
|
private Integer brokenSentencesCount = 0;
|
||||||
|
|
||||||
|
// 口语化的句子数量
|
||||||
|
private Integer oralCount = 0;
|
||||||
|
|
||||||
|
// 文章得分
|
||||||
|
private Double score = (double) 0;
|
||||||
|
|
||||||
|
// 通顺度得分
|
||||||
|
private Double dnnScore = (double) 0;
|
||||||
|
|
||||||
|
// 感情倾向得分
|
||||||
|
private Double emotionScore = (double) 0;
|
||||||
|
|
||||||
|
// 文本纠错得分
|
||||||
|
private Double correctionScore = (double) 0;
|
||||||
|
|
||||||
|
private List<JsonableSTNResult> stnResults = new ArrayList<>();
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package org.codedream.epaper.component.json.model;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.codedream.epaper.model.user.User;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@ApiModel("用户验证信息")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class JsonableUser {
|
||||||
|
|
||||||
|
// 用户的ID号(数据库)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
// 用户openid
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
// 密码(哈希值)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public JsonableUser(User user){
|
||||||
|
this.openid = user.getUsername();
|
||||||
|
this.password = user.getPassword();
|
||||||
|
this.id = user.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public User parseObject(User user){
|
||||||
|
user.setUsername(this.getOpenid());
|
||||||
|
user.setPassword(this.getPassword());
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package org.codedream.epaper.component.json.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户登录请求对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserLoginChecker {
|
||||||
|
|
||||||
|
// 请求类型
|
||||||
|
private String checkType;
|
||||||
|
|
||||||
|
// openid
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
// 密码
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
// 客户端代码
|
||||||
|
private String clientCode;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.codedream.epaper.component.json.respond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空应答
|
||||||
|
*/
|
||||||
|
public class EmptyDataObjectRespond {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.codedream.epaper.component.json.respond;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误信息对象
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ErrorInfoJSONRespond {
|
||||||
|
String exception = null;
|
||||||
|
String exceptionMessage = null;
|
||||||
|
Date date = null;
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package org.codedream.epaper.component.json.respond;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.codedream.epaper.component.json.JSONBaseObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务端返回的JSON对象标准模板
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class JSONBaseRespondObject extends JSONBaseObject {
|
||||||
|
|
||||||
|
// 存放返回内容
|
||||||
|
private Object data = new EmptyDataObjectRespond();
|
||||||
|
|
||||||
|
// 存放响应信息提示
|
||||||
|
private String msg = "";
|
||||||
|
|
||||||
|
// 额外信息
|
||||||
|
private String info = null;
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
private Integer status = 200;
|
||||||
|
|
||||||
|
public JSONBaseRespondObject(String msg){
|
||||||
|
super();
|
||||||
|
this.status = 200;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONBaseRespondObject(Integer status, String msg){
|
||||||
|
super();
|
||||||
|
this.status = status;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusNotFound(){
|
||||||
|
this.status = 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusBadRequest(){
|
||||||
|
this.status = 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusUnauthorized(){
|
||||||
|
this.status = 401;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusForbidden(){
|
||||||
|
this.status = 403;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusInternalServerError(){
|
||||||
|
this.status = 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatusOK(){
|
||||||
|
this.status = 200;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.codedream.epaper.component.json.respond;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户登录请求应答
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserLoginCheckerJSONRespond {
|
||||||
|
|
||||||
|
// 用户是否存在
|
||||||
|
Boolean userExist = null;
|
||||||
|
|
||||||
|
// 用户是否被封禁
|
||||||
|
Boolean userBanned = null;
|
||||||
|
|
||||||
|
// 登录状态
|
||||||
|
Boolean loginStatus = null;
|
||||||
|
|
||||||
|
// 返回附加信息
|
||||||
|
String respondInformation = null;
|
||||||
|
|
||||||
|
// Token
|
||||||
|
String token = null;
|
||||||
|
|
||||||
|
// 用户ID号(数据库)
|
||||||
|
String uid = null;
|
||||||
|
|
||||||
|
// 预验证码
|
||||||
|
String pvc = null;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package org.codedream.epaper.component.server;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.auth.TimestampExpiredChecker;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.model.server.ChildServerPassport;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.repository.server.ChildServerPassportRepository;
|
||||||
|
import org.codedream.epaper.repository.task.BatchProcessingTaskRepository;
|
||||||
|
import org.codedream.epaper.service.INeuralNetworkModelService;
|
||||||
|
import org.codedream.epaper.service.ITaskService;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子服务器护照管理器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CSPUpdater {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ChildServerPassportRepository cspRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BatchProcessingTaskRepository bptRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private INeuralNetworkModelService neuralNetworkModelService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TimestampExpiredChecker expiredChecker;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查护照状态
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0/60 * * * * ?")
|
||||||
|
public void update(){
|
||||||
|
log.info("CSP Updater Started");
|
||||||
|
Iterable<ChildServerPassport> childServerPassports = cspRepository.findByExpired(false);
|
||||||
|
for(ChildServerPassport csp : childServerPassports){
|
||||||
|
if(expiredChecker
|
||||||
|
.checkDateBeforeDeterminedTime(csp.getLastUpdateTime(), configure.gerChildServerRegisterTimeout())){
|
||||||
|
if(csp.getBptId() != null){
|
||||||
|
|
||||||
|
// 释放其占用的批处理任务
|
||||||
|
Optional<BatchProcessingTask> bpt = bptRepository.findById(csp.getBptId());
|
||||||
|
if(!bpt.isPresent()) throw new InnerDataTransmissionException();
|
||||||
|
neuralNetworkModelService.markBPTFailed(bpt.get());
|
||||||
|
|
||||||
|
log.info(String.format("Unlock BPT: bptId %s", csp.getBptId()));
|
||||||
|
csp.setBptId(null);
|
||||||
|
}
|
||||||
|
csp.setExpired(true);
|
||||||
|
csp = cspRepository.save(csp);
|
||||||
|
log.info(String.format("CSP Expired: idcode %s", csp.getIdentityCode()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.datamanager.PdfParser;
|
||||||
|
import org.codedream.epaper.component.datamanager.TextParser;
|
||||||
|
import org.codedream.epaper.component.datamanager.WordParser;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.repository.article.ArticleRepository;
|
||||||
|
import org.codedream.epaper.repository.task.TaskRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于对文章的预处理。
|
||||||
|
* 包括对word文档的解析({@link WordParser})
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ArticlePreprocessor {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskRepository taskRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ArticleRepository articleRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WordParser wordParser;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TextParser textParser;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PdfParser pdfParser;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预处理任务中存储的文章并将其持久化
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
*/
|
||||||
|
public void parse(Integer taskId) {
|
||||||
|
|
||||||
|
// 查找子任务
|
||||||
|
Optional<Task> taskOptional = taskRepository.findById(taskId);
|
||||||
|
if (!taskOptional.isPresent()) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
Task task = taskOptional.get();
|
||||||
|
File file = task.getFile();
|
||||||
|
if (file == null) throw new InnerDataTransmissionException();
|
||||||
|
|
||||||
|
task.setFile(file);
|
||||||
|
|
||||||
|
Integer articleId = null;
|
||||||
|
|
||||||
|
// 章分段处理
|
||||||
|
switch (file.getType()) {
|
||||||
|
case "doc":
|
||||||
|
case "docx":
|
||||||
|
articleId = wordParser.parse(file.getId());
|
||||||
|
break;
|
||||||
|
case "plain":
|
||||||
|
articleId = textParser.parse(file.getId());
|
||||||
|
break;
|
||||||
|
case "pdf":
|
||||||
|
articleId = pdfParser.parse(file.getId());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new HandlingErrorsException(file.getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(articleId == null) throw new HandlingErrorsException(file.getId().toString());
|
||||||
|
|
||||||
|
Optional<Article> optionalArticle = articleRepository.findById(articleId);
|
||||||
|
if (!optionalArticle.isPresent()) throw new InnerDataTransmissionException();
|
||||||
|
|
||||||
|
task.setArticle(optionalArticle.get());
|
||||||
|
task.setProgressRate(task.getProgressRate() + 1);
|
||||||
|
log.info(String.format("Article preprocess finished, task progress for now is: %d", task.getProgressRate()));
|
||||||
|
taskRepository.save(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import org.codedream.epaper.component.article.GetSentenceFromArticle;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把一个超过limit的BPT按照task数量等分
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class BPTDivider {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GetSentenceFromArticle getSentenceFromArticle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个批处理任务等分
|
||||||
|
* <p>
|
||||||
|
* 此方法会将原有的已经持久化的批处理任务从数据库中删除,并换成两个
|
||||||
|
* 已经等分了的批处理任务
|
||||||
|
*
|
||||||
|
* @param bpt 一个批处理任务
|
||||||
|
* @return 两个封装在列表中的批处理任务
|
||||||
|
*/
|
||||||
|
public List<BatchProcessingTask> divideBPT(BatchProcessingTask bpt) {
|
||||||
|
|
||||||
|
List<BatchProcessingTask> batchProcessingTasks = new ArrayList<>();
|
||||||
|
BatchProcessingTask bpt1 = new BatchProcessingTask(bpt);
|
||||||
|
BatchProcessingTask bpt2 = new BatchProcessingTask(bpt);
|
||||||
|
List<Task> tasks = bpt.getTasks();
|
||||||
|
List<Sentence> sentenceList = new ArrayList<>();
|
||||||
|
bpt1.setTasks(tasks.subList(0, tasks.size() / 2));
|
||||||
|
bpt2.setTasks(tasks.subList(tasks.size() / 2, tasks.size()));
|
||||||
|
Integer sentenceNum = 0;
|
||||||
|
|
||||||
|
divide(batchProcessingTasks, bpt1, sentenceList, sentenceNum);
|
||||||
|
sentenceList.clear();
|
||||||
|
sentenceNum = 0;
|
||||||
|
|
||||||
|
divide(batchProcessingTasks, bpt2, sentenceList, sentenceNum);
|
||||||
|
return batchProcessingTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void divide(List<BatchProcessingTask> batchProcessingTasks, BatchProcessingTask bpt, List<Sentence> sentenceList, Integer sentenceNum) {
|
||||||
|
for (int i = 0; i < bpt.getTasks().size(); i++) {
|
||||||
|
Task task = bpt.getTasks().get(i);
|
||||||
|
sentenceList.addAll(getSentenceFromArticle.get(task.getArticle()));
|
||||||
|
sentenceNum += task.getArticle().getSentencesNumber();
|
||||||
|
}
|
||||||
|
bpt.setSentences(sentenceList);
|
||||||
|
bpt.setSentencesNumber(sentenceNum);
|
||||||
|
bpt.setPriority(sentenceNum);
|
||||||
|
bpt.setCreateDate(new Date());
|
||||||
|
batchProcessingTasks.add(bpt);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.auth.TimestampExpiredChecker;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.repository.task.BatchProcessingTaskRepository;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于提供对批处理任务的监控方法。
|
||||||
|
* <p>
|
||||||
|
* 批处理任务在处理时可能会出现分配的GPU服务端突发故障、网络通信故障等问题,从而造成
|
||||||
|
* 当前批处理任务在结果等待队列中的无限制等待。为了避免这种问题的发生,我们设计了一个
|
||||||
|
* 批处理任务监听器用于监控其计算等待时间,超时后会放入原就绪队列进行重新分配
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class BPTMonitor {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private LockedBPTs lockedBPTs;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BPTQueue bptQueue;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BatchProcessingTaskRepository bptRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TimestampExpiredChecker timestampExpiredChecker;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
|
||||||
|
private boolean initStatus = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个定时任务,每15秒检测一次批处理任务的等待情况
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0/5 * * ? * *")
|
||||||
|
public void monitorBPTs() {
|
||||||
|
// 启动自检
|
||||||
|
if (initStatus) {
|
||||||
|
// 查找未完成的批处理任务
|
||||||
|
Iterable<BatchProcessingTask> batchProcessingTasks = bptRepository.findAllByFinished(false);
|
||||||
|
|
||||||
|
for (BatchProcessingTask bpt : batchProcessingTasks) {
|
||||||
|
bptQueue.addBPT(bpt.getId());
|
||||||
|
}
|
||||||
|
initStatus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("BPT Monitor Started");
|
||||||
|
log.info(String.format("Lined BPTs Number For Now: %s", bptQueue.size()));
|
||||||
|
log.info(String.format("Locked BPTs Number For Now: %s", lockedBPTs.size()));
|
||||||
|
if (lockedBPTs.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Iterator<Integer> bptIterator = lockedBPTs.iterator();
|
||||||
|
while (bptIterator.hasNext()) {
|
||||||
|
Integer bptId = bptIterator.next();
|
||||||
|
Optional<BatchProcessingTask> oBpt = bptRepository.findById(bptId);
|
||||||
|
if (!oBpt.isPresent()) throw new InnerDataTransmissionException();
|
||||||
|
|
||||||
|
BatchProcessingTask bpt = oBpt.get();
|
||||||
|
if (timestampExpiredChecker.checkDateBeforeDeterminedTime(
|
||||||
|
bpt.getJoinDate(), configure.gerMaxBPTProcessDelayTime())) {
|
||||||
|
|
||||||
|
bptQueue.addBPT(bpt.getId());
|
||||||
|
bptIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.repository.task.BatchProcessingTaskRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批处理任务优先级队列
|
||||||
|
* <p>
|
||||||
|
* 根据批处理任务待处理的句子数量设置优先级
|
||||||
|
* (参见{@link org.codedream.epaper.model.task.BatchProcessingTask#compareTo(BatchProcessingTask)})
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class BPTQueue {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BatchProcessingTaskRepository bptRepository;
|
||||||
|
|
||||||
|
// 优先阻塞队列
|
||||||
|
private PriorityBlockingQueue<Integer> batchProcessingTasks = new PriorityBlockingQueue<>(1,
|
||||||
|
new Comparator<Integer>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Integer o1, Integer o2) {
|
||||||
|
BatchProcessingTask bpt1 = bptRepository.findById(o1).get();
|
||||||
|
BatchProcessingTask bpt2 = bptRepository.findById(o2).get();
|
||||||
|
return bpt1.getPriority() - bpt2.getPriority();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加批处理任务
|
||||||
|
public void addBPT(Integer bptId) {
|
||||||
|
batchProcessingTasks.offer(bptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
//移除批处理任务
|
||||||
|
public void removeBPT(Integer bptId) {
|
||||||
|
batchProcessingTasks.remove(bptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查队列是否为空
|
||||||
|
public boolean checkEmpty(){
|
||||||
|
return batchProcessingTasks.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从队列中获得一个批处理任务
|
||||||
|
public Integer getBptId() throws InterruptedException {
|
||||||
|
return batchProcessingTasks.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer size(){
|
||||||
|
return batchProcessingTasks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,180 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTNError;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTNResult;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableTaskResult;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.codedream.epaper.model.task.CorrectionResult;
|
||||||
|
import org.codedream.epaper.model.task.SentenceResult;
|
||||||
|
import org.codedream.epaper.model.task.TaskResult;
|
||||||
|
import org.codedream.epaper.repository.task.TaskResultRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供用于返回前端的结果构造方法
|
||||||
|
*
|
||||||
|
* 原生的结果数据比较混杂,不适合前端后端JSON格式的数据通信,设立此类以整合结果
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class JsonableTaskResultGenerator {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
TaskResultRepository taskResultRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据任务结果的原生数据构造用于返回前端的任务结果
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @return 一个JsonableTaskResult对象,包含构建好的任务结果
|
||||||
|
* @see JsonableTaskResult
|
||||||
|
*/
|
||||||
|
public JsonableTaskResult getJsonableTaskResult(Integer taskId) {
|
||||||
|
|
||||||
|
log.info(String.format("Generating jsonable result of task %d", taskId));
|
||||||
|
Optional<TaskResult> OTaskResult = taskResultRepository.findByTaskId(taskId);
|
||||||
|
double dnnScore = 0;
|
||||||
|
double correctScore = 0;
|
||||||
|
double emotionScore = 0;
|
||||||
|
double e = Math.E;
|
||||||
|
int dnnCnt = 0;
|
||||||
|
int wrongCnt = 0;
|
||||||
|
int oralCnt = 0;
|
||||||
|
if (OTaskResult.isPresent()) {
|
||||||
|
TaskResult taskResult = OTaskResult.get();
|
||||||
|
JsonableTaskResult jsonableTaskResult = new JsonableTaskResult();
|
||||||
|
List<JsonableSTNResult> jsonableSTNResults = new ArrayList<>();
|
||||||
|
jsonableTaskResult.setTaskId(taskResult.getTaskId());
|
||||||
|
taskResult.setSuccess(true);
|
||||||
|
taskResult = taskResultRepository.save(taskResult);
|
||||||
|
jsonableTaskResult.setSuccess(true);
|
||||||
|
Map<Integer, SentenceResult> sentenceResultMap = taskResult.getSentenceResultMap();
|
||||||
|
for (SentenceResult result : taskResult.getSentenceResultMap().values()) {
|
||||||
|
JsonableSTNResult jsonableSTNResult = new JsonableSTNResult();
|
||||||
|
jsonableSTNResult.setStnId(result.getSentenceId());
|
||||||
|
jsonableSTNResult.setAppear(0);
|
||||||
|
SentenceResult sentenceResult = sentenceResultMap.get(result.getSentenceId());
|
||||||
|
|
||||||
|
// 中立值设置
|
||||||
|
jsonableSTNResult.setNeutral(sentenceResult.isNeutral());
|
||||||
|
|
||||||
|
List<JsonableSTNError> jsonableSTNErrorList = new ArrayList<>();
|
||||||
|
|
||||||
|
List<CorrectionResult> correctionResultList = result.getCorrectionResults();
|
||||||
|
correctScore += correctionResultList.size();
|
||||||
|
|
||||||
|
log.info("Generating correction result……");
|
||||||
|
log.info(String.format("Correction result of sentence %d: %s", sentenceResult.getSentenceId(),
|
||||||
|
correctionResultList.toString()));
|
||||||
|
// 寻找该sentence被修改了的位置
|
||||||
|
for (CorrectionResult correctionResult : correctionResultList) {
|
||||||
|
JsonableSTNError jsonableSTNError = new JsonableSTNError();
|
||||||
|
jsonableSTNError.setWordIdx(correctionResult.getStartPos());
|
||||||
|
jsonableSTNError.setWordLen(correctionResult.getLength());
|
||||||
|
jsonableSTNError.setType(1);
|
||||||
|
wrongCnt++;
|
||||||
|
if (correctionResult.getCorrectionText().isEmpty()) {
|
||||||
|
jsonableSTNError.setContent("文本存在错误,建议删除");
|
||||||
|
} else {
|
||||||
|
jsonableSTNError.setContent(String.format("文本存在错误,建议修改为:%s",
|
||||||
|
correctionResult.getCorrectionText()));
|
||||||
|
}
|
||||||
|
jsonableSTNErrorList.add(jsonableSTNError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断句子情感倾向
|
||||||
|
String content;
|
||||||
|
JsonableSTNError stnError = new JsonableSTNError();
|
||||||
|
if (sentenceResult.isNegative() || sentenceResult.isPositive()) {
|
||||||
|
stnError.setType(2);
|
||||||
|
stnError.setWordIdx(0);
|
||||||
|
stnError.setWordLen(0x7fffffff);
|
||||||
|
if (sentenceResult.isNegative()) {
|
||||||
|
taskResult.getNegativeEmotionsCount().incrementAndGet();
|
||||||
|
float possibility = sentenceResult.getPossibilities().get(0);
|
||||||
|
emotionScore += Math.pow(e, possibility);
|
||||||
|
if (possibility < 0.9) {
|
||||||
|
content = "文本语言较强烈口语化特征,建议修改为书面语。";
|
||||||
|
} else {
|
||||||
|
content = "文本语言极为强烈的口语化特征,建议修改为书面语。";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
taskResult.getPositiveEmotionsCount().incrementAndGet();
|
||||||
|
float possibility = sentenceResult.getPossibilities().get(1);
|
||||||
|
emotionScore += Math.pow(2 * e, possibility);
|
||||||
|
if (possibility < 0.99) {
|
||||||
|
content = "文本语言较强烈的口语化特征,建议修改为书面语。";
|
||||||
|
} else {
|
||||||
|
content = "文本语言有极为强烈的口语化特征,建议修改为书面语。";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oralCnt++;
|
||||||
|
stnError.setContent(content);
|
||||||
|
jsonableSTNErrorList.add(stnError);
|
||||||
|
} else if (sentenceResult.getPossibilities().get(1) < 0.99) {
|
||||||
|
stnError.setType(2);
|
||||||
|
stnError.setWordIdx(0);
|
||||||
|
stnError.setWordLen(0x7fffffff);
|
||||||
|
content = "文本疑似存在口语化问题,请注意审查";
|
||||||
|
stnError.setContent(content);
|
||||||
|
jsonableSTNErrorList.add(stnError);
|
||||||
|
oralCnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sentenceResult.getDnn() > 4000) {
|
||||||
|
dnnScore += sentenceResult.getDnn();
|
||||||
|
taskResult.getBrokenSentencesCount().incrementAndGet();
|
||||||
|
JsonableSTNError jsonableSTNError = new JsonableSTNError();
|
||||||
|
jsonableSTNError.setType(3);
|
||||||
|
jsonableSTNError.setContent("句子通顺度存在问题,建议修改");
|
||||||
|
jsonableSTNError.setWordIdx(0);
|
||||||
|
jsonableSTNError.setWordLen(0x7fffffff);
|
||||||
|
jsonableSTNErrorList.add(jsonableSTNError);
|
||||||
|
dnnCnt++;
|
||||||
|
} else if (sentenceResult.getDnn() > 2000) {
|
||||||
|
dnnScore += sentenceResult.getDnn();
|
||||||
|
dnnCnt++;
|
||||||
|
}
|
||||||
|
jsonableSTNResult.setErrorList(jsonableSTNErrorList);
|
||||||
|
jsonableSTNResults.add(jsonableSTNResult);
|
||||||
|
}
|
||||||
|
taskResultRepository.save(taskResult);
|
||||||
|
|
||||||
|
jsonableTaskResult.setWrongTextCount(wrongCnt);
|
||||||
|
jsonableTaskResult.setBrokenSentencesCount(dnnCnt);
|
||||||
|
jsonableTaskResult.setOralCount(oralCnt);
|
||||||
|
jsonableTaskResult.setStnResults(jsonableSTNResults);
|
||||||
|
|
||||||
|
wrongCnt += 4;
|
||||||
|
correctScore = Math.PI * Math.log(Math.atan(1.1 * wrongCnt - 10) + 2) / Math.log(e) + 10;
|
||||||
|
correctScore = correctScore * 6.3489125794718040652210611515526 + 12.305831203372289317158476382609;
|
||||||
|
|
||||||
|
dnnCnt += 1;
|
||||||
|
dnnScore = Math.PI * Math.log(-Math.atan(2 * dnnCnt - 20) + 2) / Math.log(e) + 10;
|
||||||
|
dnnScore = dnnScore * 5.8066270155791913101469156905197 + 19.001197895698319575318511547571;
|
||||||
|
|
||||||
|
|
||||||
|
oralCnt += 1;
|
||||||
|
emotionScore = Math.PI * Math.log(-Math.atan(0.9 * oralCnt - 12) + 2) / Math.log(e) + 10;
|
||||||
|
emotionScore = emotionScore * 6.4684248579558173553422908337857 + 9.969074019579274789063012724827;
|
||||||
|
|
||||||
|
jsonableTaskResult.setDnnScore(dnnScore);
|
||||||
|
jsonableTaskResult.setEmotionScore(emotionScore);
|
||||||
|
jsonableTaskResult.setCorrectionScore(correctScore);
|
||||||
|
|
||||||
|
dnnScore *= 0.34482758620689655172413793103448;
|
||||||
|
correctScore *= 0.17241379310344827586206896551724;
|
||||||
|
emotionScore *= 0.48275862068965517241379310344828;
|
||||||
|
jsonableTaskResult.setScore(dnnScore + emotionScore + correctScore);
|
||||||
|
return jsonableTaskResult;
|
||||||
|
} else {
|
||||||
|
throw new NotFoundException("This task has no result yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于提供{@link org.codedream.epaper.model.task.BatchProcessingTask}的计算等待队列以及相关操作
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class LockedBPTs {
|
||||||
|
private List<Integer> bptIdList = new ArrayList<>();
|
||||||
|
|
||||||
|
public void add(Integer bptId){
|
||||||
|
bptIdList.add(bptId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Integer> iterator(){
|
||||||
|
return bptIdList.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty(){
|
||||||
|
return bptIdList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Integer integer){
|
||||||
|
return bptIdList.contains(integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer size(){
|
||||||
|
return bptIdList.size();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.datamanager.ParagraphDivider;
|
||||||
|
import org.codedream.epaper.component.datamanager.SHA512Encoder;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.repository.article.ArticleRepository;
|
||||||
|
import org.codedream.epaper.repository.article.ParagraphRepository;
|
||||||
|
import org.codedream.epaper.repository.article.SentenceRepository;
|
||||||
|
import org.codedream.epaper.repository.task.TaskRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供对段落的预处理方法
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class ParagraphProcessor {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskRepository taskRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ParagraphRepository paragraphRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ParagraphDivider paragraphDivider;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceRepository sentenceRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ArticleRepository articleRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SHA512Encoder encoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对段落进行分句处理并进行SHA512编码,以便缓存识别
|
||||||
|
*
|
||||||
|
* @param taskId 任务id,用于获取待处理的段落
|
||||||
|
* @see ParagraphDivider
|
||||||
|
* @see SHA512Encoder
|
||||||
|
*/
|
||||||
|
public void parse(Integer taskId) {
|
||||||
|
// 查找子任务
|
||||||
|
Optional<Task> taskOptional = taskRepository.findById(taskId);
|
||||||
|
if (!taskOptional.isPresent()) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
Article article = taskOptional.get().getArticle();
|
||||||
|
if (article == null) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
int stnNum = 0;
|
||||||
|
|
||||||
|
// 段分句及段结构更新
|
||||||
|
for (Paragraph paragraph : article.getParagraphs()) {
|
||||||
|
// 跳过预处理过的段落
|
||||||
|
if (paragraph.isPreprocess()) continue;
|
||||||
|
|
||||||
|
// 段分句处理
|
||||||
|
List<String> sentenceTexts = paragraphDivider.divideParagraph(paragraph.getText());
|
||||||
|
List<Sentence> sentences = new ArrayList<>();
|
||||||
|
for (String text : sentenceTexts) {
|
||||||
|
Sentence sentence;
|
||||||
|
String hash = encoder.encode(text);
|
||||||
|
|
||||||
|
// 查找句数据库缓存
|
||||||
|
Optional<Sentence> sentenceOptional = sentenceRepository.findBySha512Hash(hash);
|
||||||
|
if (!sentenceOptional.isPresent()) {
|
||||||
|
// 创建新的句
|
||||||
|
sentence = new Sentence();
|
||||||
|
sentence.setText(text);
|
||||||
|
sentence.setSha512Hash(hash);
|
||||||
|
sentence = sentenceRepository.save(sentence);
|
||||||
|
} else {
|
||||||
|
sentence = sentenceOptional.get();
|
||||||
|
}
|
||||||
|
sentences.add(sentence);
|
||||||
|
}
|
||||||
|
|
||||||
|
stnNum += sentences.size();
|
||||||
|
|
||||||
|
// 设置句集合
|
||||||
|
Set<Sentence> sentenceSet = new HashSet<>(sentences);
|
||||||
|
paragraph.setSentences(sentenceSet);
|
||||||
|
|
||||||
|
// 设置句列表
|
||||||
|
for (Sentence sentence : sentences) {
|
||||||
|
paragraph.getSentenceList().add(sentence.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置预处理状态
|
||||||
|
paragraph.setPreprocess(true);
|
||||||
|
|
||||||
|
// 更新段落信息
|
||||||
|
paragraphRepository.save(paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新文章总句数
|
||||||
|
taskOptional.get().getArticle().setSentencesNumber(stnNum);
|
||||||
|
taskOptional.get().setProgressRate(taskOptional.get().getProgressRate() + 1);
|
||||||
|
log.info(String.format("Paragraph preprocess finished, task progress for now is: %d",
|
||||||
|
taskOptional.get().getProgressRate()));
|
||||||
|
articleRepository.save(taskOptional.get().getArticle());
|
||||||
|
taskRepository.save(taskOptional.get());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import org.codedream.epaper.component.datamanager.SentenceSmoothnessGetter;
|
||||||
|
import org.codedream.epaper.component.datamanager.TextCorrector;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.CorrectionResult;
|
||||||
|
import org.codedream.epaper.model.task.SentenceResult;
|
||||||
|
import org.codedream.epaper.repository.task.SentenceResultRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 句分析器,提供句子分析相关方法以及持久化方法
|
||||||
|
*
|
||||||
|
* @see TextCorrector
|
||||||
|
* @see SentenceSmoothnessGetter
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SentenceAnalyser {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TextCorrector textCorrector;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceSmoothnessGetter dnnGetter;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceResultRepository sentenceResultRepository;
|
||||||
|
|
||||||
|
public SentenceResult analyse(Sentence sentence) {
|
||||||
|
// 创建与预填写句子与处理结果结构
|
||||||
|
SentenceResult sentenceResult = new SentenceResult();
|
||||||
|
sentenceResult.setSentenceId(sentence.getId());
|
||||||
|
sentenceResult.setDnn(dnnParse(sentence));
|
||||||
|
correct(sentenceResult, sentence);
|
||||||
|
// 储存句分析结果
|
||||||
|
return sentenceResultRepository.save(sentenceResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取句子的文本纠错结果
|
||||||
|
*
|
||||||
|
* @param sentence 句子
|
||||||
|
*/
|
||||||
|
private void correct(SentenceResult sentenceResult, Sentence sentence) {
|
||||||
|
List<CorrectionResult> correctionResultList = textCorrector.correctText(sentence.getText());
|
||||||
|
sentenceResult.setCorrectionResults(correctionResultList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取DNN处理结果
|
||||||
|
*
|
||||||
|
* @param sentence 待处理句子
|
||||||
|
* @return DNN处理结果
|
||||||
|
* @see SentenceSmoothnessGetter#getSentenceSmoothness(String)
|
||||||
|
*/
|
||||||
|
private synchronized float dnnParse(Sentence sentence) {
|
||||||
|
return dnnGetter.getSentenceSmoothness(sentence.getText());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.article.GetSentenceFromArticle;
|
||||||
|
import org.codedream.epaper.component.datamanager.SentenceDivider;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Phrase;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.repository.article.SentenceRepository;
|
||||||
|
import org.codedream.epaper.repository.task.TaskRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于提供句子预处理相关方法,以及对应的持久化方法
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class SentencePreprocessor {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskRepository taskRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceDivider sentenceDivider;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceRepository sentenceRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GetSentenceFromArticle getSentenceFromArticle;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取出任务中的句子并进行预处理
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @see SentenceDivider#divideSentence(String)
|
||||||
|
* @see GetSentenceFromArticle#get(Article)
|
||||||
|
*/
|
||||||
|
public void parse(Integer taskId) {
|
||||||
|
// 查找子任务
|
||||||
|
Optional<Task> taskOptional = taskRepository.findById(taskId);
|
||||||
|
if (!taskOptional.isPresent()) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
Task task = taskOptional.get();
|
||||||
|
Article article = task.getArticle();
|
||||||
|
if (article == null) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
List<Sentence> sentences = getSentenceFromArticle.get(article);
|
||||||
|
|
||||||
|
for (Sentence sentence : sentences) {
|
||||||
|
// 跳过缓存句
|
||||||
|
if (sentence.isPreprocess()) continue;
|
||||||
|
|
||||||
|
List<Phrase> phrases = sentenceDivider.divideSentence(sentence.getText());
|
||||||
|
|
||||||
|
sentence.getPhrases().addAll(phrases);
|
||||||
|
sentence.setPreprocess(true);
|
||||||
|
|
||||||
|
for (Phrase phrase : phrases) {
|
||||||
|
sentence.getPhraseList().add(phrase.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
sentenceRepository.save(sentence);
|
||||||
|
}
|
||||||
|
task.setProgressRate(task.getProgressRate() + 1);
|
||||||
|
log.info(String.format("Sentence preprocess finished, task progress for now is: %d", task.getProgressRate()));
|
||||||
|
taskRepository.save(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,110 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.article.GetSentenceFromArticle;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.task.SentenceResult;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.model.task.TaskResult;
|
||||||
|
import org.codedream.epaper.repository.task.SentenceResultRepository;
|
||||||
|
import org.codedream.epaper.repository.task.TaskRepository;
|
||||||
|
import org.codedream.epaper.repository.task.TaskResultRepository;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子任务预分析器,用于精确到句子的任务分析以及持久化子任务结果
|
||||||
|
*
|
||||||
|
* @see SentenceAnalyser
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class TaskAnalyser {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskResultRepository taskResultRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskRepository taskRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GetSentenceFromArticle getSentenceFromArticle;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceAnalyser sentenceAnalyser;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SentenceResultRepository sentenceResultRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分析一个task,并持久化其结果
|
||||||
|
* 持久化结果的时候,会先查找缓存
|
||||||
|
*
|
||||||
|
* @param taskId 任务id
|
||||||
|
* @return 一个TaskResult对象
|
||||||
|
*/
|
||||||
|
public TaskResult analyse(Integer taskId) {
|
||||||
|
|
||||||
|
log.info(String.format("Analysing task: %d", taskId));
|
||||||
|
|
||||||
|
// 查找子任务
|
||||||
|
Optional<Task> taskOptional = taskRepository.findById(taskId);
|
||||||
|
if (!taskOptional.isPresent()) throw new InnerDataTransmissionException(taskId.toString());
|
||||||
|
|
||||||
|
Task task = taskOptional.get();
|
||||||
|
|
||||||
|
// 构建预处理的任务结果存储结构
|
||||||
|
TaskResult taskResult = new TaskResult();
|
||||||
|
taskResult.setTaskId(task.getId());
|
||||||
|
|
||||||
|
Map<Integer, Float> dnnRes = new HashMap<>();
|
||||||
|
Map<Integer, SentenceResult> sentenceMap = new HashMap<>();
|
||||||
|
// 句分析
|
||||||
|
for(Sentence sentence : getSentenceFromArticle.get(task.getArticle())){
|
||||||
|
SentenceResult sentenceResult;
|
||||||
|
log.info(String.format("Analysing sentence: %d", sentence.getId()));
|
||||||
|
// 查找缓存
|
||||||
|
Optional<SentenceResult> sentenceResultOptional =
|
||||||
|
sentenceResultRepository.findBySentenceId(sentence.getId());
|
||||||
|
|
||||||
|
if (sentenceResultOptional.isPresent()) {
|
||||||
|
sentenceResult = sentenceResultOptional.get();
|
||||||
|
|
||||||
|
dnnRes.put(sentence.getId(), sentenceResult.getDnn());
|
||||||
|
sentenceMap.put(sentence.getId(), sentenceResult);
|
||||||
|
log.info(String.format("DNN result of sentence %d: %f", sentence.getId(), sentenceResult.getDnn()));
|
||||||
|
log.info(String.format("Correction result of sentence %d: %s", sentence.getId(),
|
||||||
|
sentenceResult.getCorrectionResults().toString()));
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sentenceResult = sentenceAnalyser.analyse(sentence);
|
||||||
|
}
|
||||||
|
log.info(String.format("DNN result of sentence %d: %f", sentence.getId(), sentenceResult.getDnn()));
|
||||||
|
log.info(String.format("Correction result of sentence %d: %s", sentence.getId(),
|
||||||
|
sentenceResult.getCorrectionResults().toString()));
|
||||||
|
dnnRes.put(sentence.getId(), sentenceResult.getDnn());
|
||||||
|
sentenceMap.put(sentence.getId(), sentenceResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
taskResult.setDnnMap(dnnRes);
|
||||||
|
taskResult.setSentenceResultMap(sentenceMap);
|
||||||
|
|
||||||
|
taskResult = taskResultRepository.save(taskResult);
|
||||||
|
|
||||||
|
|
||||||
|
// 更新任务
|
||||||
|
taskOptional.get().setProgressRate(taskOptional.get().getProgressRate()+1);
|
||||||
|
task.setResult(taskResult);
|
||||||
|
taskRepository.save(task);
|
||||||
|
log.info(String.format("Analyse preprocess finished, task progress for now is: %d", task.getProgressRate()));
|
||||||
|
|
||||||
|
log.info(String.format("Analysing result of task %d: %s", taskId, task.getResult()));
|
||||||
|
return taskResult;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.auth.TimestampExpiredChecker;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.repository.task.BatchProcessingTaskRepository;
|
||||||
|
import org.codedream.epaper.service.TaskService;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子任务监视器
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class TaskMonitor {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskQueue taskQueue;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskService taskService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TimestampExpiredChecker timestampExpiredChecker;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BatchProcessingTaskRepository bptRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
@Scheduled(cron = "0/3 * * ? * *")
|
||||||
|
public void monitorTasks() {
|
||||||
|
log.info("Tasks Monitor Started.");
|
||||||
|
log.info(String.format("Tasks Number For Now: %s", taskQueue.size()));
|
||||||
|
if (taskQueue.checkEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Task> tasks = new ArrayList<>();
|
||||||
|
Integer sentenceNum = 0;
|
||||||
|
Iterator<Task> iterator = taskQueue.getIterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Task task = iterator.next();
|
||||||
|
|
||||||
|
if (null == task) {
|
||||||
|
log.error("Task null value.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//超时MaxTaskDelayTime秒即添加到一个批处理队列中
|
||||||
|
if (timestampExpiredChecker.checkDateBeforeDeterminedTime(
|
||||||
|
task.getCreateDate(), configure.gerMaxTaskDelayTime())) {
|
||||||
|
|
||||||
|
tasks.add(task);
|
||||||
|
iterator.remove();
|
||||||
|
sentenceNum += task.getArticle().getSentencesNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tasks.isEmpty()) return;
|
||||||
|
|
||||||
|
// 对等待超时的task立即新建一个bpt,将之放入就绪队列,等待调用
|
||||||
|
BatchProcessingTask bpt = new BatchProcessingTask();
|
||||||
|
bpt.setTasks(tasks);
|
||||||
|
bpt.setCreateDate(new Date());
|
||||||
|
bpt.setPriority(sentenceNum);
|
||||||
|
bpt.setSentencesNumber(sentenceNum);
|
||||||
|
bpt = bptRepository.save(bpt);
|
||||||
|
|
||||||
|
// 注册批处理任务
|
||||||
|
taskService.registerBPTTask(bpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package org.codedream.epaper.component.task;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务优先队列,用于给BPT中的任务进行优先级排序
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Component
|
||||||
|
public class TaskQueue {
|
||||||
|
|
||||||
|
Comparator<Task> comparator = Comparator.comparingInt(Task::getPriority);
|
||||||
|
|
||||||
|
private Queue<Task> tasks = new PriorityQueue<>(comparator);
|
||||||
|
|
||||||
|
private Integer sentenceNumber = 0;
|
||||||
|
|
||||||
|
public boolean addTask(Task task) {
|
||||||
|
if (this.tasks.offer(task)) {
|
||||||
|
sentenceNumber += task.getArticle().getSentencesNumber();
|
||||||
|
return true;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer size(){
|
||||||
|
return tasks.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeTask(Task task){
|
||||||
|
tasks.remove(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Task> getIterator(){
|
||||||
|
return tasks.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Task> getTaskAsList() {
|
||||||
|
List<Task> taskList = new ArrayList<>(this.tasks);
|
||||||
|
return taskList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.tasks.clear();
|
||||||
|
this.setSentenceNumber(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkEmpty() {
|
||||||
|
return this.tasks.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
125
src/main/java/org/codedream/epaper/configure/AppConfigure.java
Normal file
125
src/main/java/org/codedream/epaper/configure/AppConfigure.java
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用程序常用配置信息
|
||||||
|
* 用于常见的应用程序本身的相关信息的引用
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class AppConfigure {
|
||||||
|
/**
|
||||||
|
* 获得应用程序的中文名
|
||||||
|
* @return 返回包含完整内容的字符串
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return "智慧学术论文行文指导服务端";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得应用程序的版本号
|
||||||
|
* @return 返回版本号内容的字符串
|
||||||
|
*/
|
||||||
|
public String getVersion() {
|
||||||
|
return "0.0.1_200204";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得应用程序的英文名
|
||||||
|
* @return 返回包含完整内容的字符串
|
||||||
|
*/
|
||||||
|
public String getEnglishName() {
|
||||||
|
return "ePaper";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得开发小组的名称
|
||||||
|
* @return 包含完整内容的字符串
|
||||||
|
*/
|
||||||
|
public String getOrganization() {
|
||||||
|
return "码梦工坊";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件服务储存路径
|
||||||
|
* @return 字符串
|
||||||
|
*/
|
||||||
|
public String getFilePath(){
|
||||||
|
return "./FILES/";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传的文件的大小限制(字节)
|
||||||
|
* 预设值:16MB
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer getFileMaxSize(){
|
||||||
|
return 16000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单段的最小字数阈值
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer getParagraphMinSize(){
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单段的最大字数阈值
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer getParagraphMaxSize(){
|
||||||
|
return 2048;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批处理任务最大句数目阈值
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Long getBPTMaxSentenceNumber() {
|
||||||
|
return 32768L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批处理任务最少句数目阈值
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Long getBPTMinSentenceNumber(){
|
||||||
|
return 1024L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子服务器失联等待时间
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer gerChildServerRegisterTimeout(){
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子任务等待被加入批处理任务最长时间
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer gerMaxTaskDelayTime(){
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批处理任务处理最长时间
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer gerMaxBPTProcessDelayTime(){
|
||||||
|
return 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单页句数
|
||||||
|
* @return 数值
|
||||||
|
*/
|
||||||
|
public Integer getSentencePrePage(){
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批处理任务配置,用于配置线程相关参数
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@Data
|
||||||
|
public class BatchTaskConfiguration {
|
||||||
|
|
||||||
|
//保留的线程池大小
|
||||||
|
private static int corePoolSize = 15;
|
||||||
|
|
||||||
|
//线程池最大大小
|
||||||
|
private static int maxPoolSize = 30;
|
||||||
|
|
||||||
|
//线程最大空闲时间
|
||||||
|
private static int keepAliveTime = 1000;
|
||||||
|
|
||||||
|
//阻塞队列大小
|
||||||
|
private static int workQueueSize = 200;
|
||||||
|
|
||||||
|
private static Long limit = 20000L;
|
||||||
|
|
||||||
|
public static int getCorePoolSize() {
|
||||||
|
return corePoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getMaxPoolSize() {
|
||||||
|
return maxPoolSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getKeepAliveTime() {
|
||||||
|
return keepAliveTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getWorkQueueSize() {
|
||||||
|
return workQueueSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Long getLimit() {
|
||||||
|
return limit;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ComponentsConfigure {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import org.codedream.epaper.component.auth.*;
|
||||||
|
import org.codedream.epaper.service.EPUserDetailsService;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.core.session.SessionRegistry;
|
||||||
|
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring Security 配置类
|
||||||
|
* 用于Spring Security相关参数的配置
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPUserDetailsService aseUserDetailService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPPasswordEncoder EPPasswordEncoder;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPSecurityAuthenticationProvider EPSecurityAuthenticationProvider;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPAuthenticationSuccessHandler successHandler;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPAuthenticationFailureHandler failureHandler;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPAuthenticationEntryPoint authenticationEntryPoint;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
EPAccessDeniedHandler accessDeniedHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP服务器安全配置
|
||||||
|
* @param http HTTP服务器安全对象
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http
|
||||||
|
.authorizeRequests()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
.and()
|
||||||
|
.csrf().disable()
|
||||||
|
.logout().permitAll();
|
||||||
|
|
||||||
|
http.exceptionHandling()
|
||||||
|
.authenticationEntryPoint(authenticationEntryPoint)
|
||||||
|
.accessDeniedHandler(accessDeniedHandler);
|
||||||
|
|
||||||
|
// 替换掉原有的UsernamePasswordAuthenticationFilter
|
||||||
|
http.addFilterAt(epUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||||
|
.addFilterBefore(jsonTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
|
||||||
|
|
||||||
|
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证器设置
|
||||||
|
* @param auth 认证对象
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.authenticationProvider(EPSecurityAuthenticationProvider)
|
||||||
|
.userDetailsService(aseUserDetailService)
|
||||||
|
.passwordEncoder(EPPasswordEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安全配置
|
||||||
|
* @param web web对象
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void configure(WebSecurity web) throws Exception {
|
||||||
|
web
|
||||||
|
.ignoring()
|
||||||
|
.antMatchers(
|
||||||
|
"/assets/**",
|
||||||
|
"/forget/**",
|
||||||
|
"/not_found/**",
|
||||||
|
"/error/**",
|
||||||
|
"/user/**",
|
||||||
|
"/swagger-ui.html",
|
||||||
|
"/webjars/**",
|
||||||
|
"/swagger-resources/**",
|
||||||
|
"/v2/api-docs",
|
||||||
|
"/configuration/ui",
|
||||||
|
"/configuration/security");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册自定义的UsernamePasswordAuthenticationFilter
|
||||||
|
* @return UsernamePasswordAuthenticationFilter
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
EPJSONTokenAuthenticationFilter jsonTokenAuthenticationFilter() throws Exception {
|
||||||
|
return new EPJSONTokenAuthenticationFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册自定义的UsernamePasswordAuthenticationFilter
|
||||||
|
* @return UsernamePasswordAuthenticationFilter
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
EPUsernamePasswordAuthenticationFilter epUsernamePasswordAuthenticationFilter() throws Exception {
|
||||||
|
EPUsernamePasswordAuthenticationFilter filter = new EPUsernamePasswordAuthenticationFilter();
|
||||||
|
filter.setAuthenticationSuccessHandler(successHandler);
|
||||||
|
filter.setAuthenticationFailureHandler(failureHandler);
|
||||||
|
filter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy(sessionRegistry()));
|
||||||
|
filter.setAllowSessionCreation(true);
|
||||||
|
filter.setRequiresAuthenticationRequestMatcher(
|
||||||
|
new AntPathRequestMatcher("/user/login", "POST"));
|
||||||
|
|
||||||
|
filter.setAuthenticationManager(authenticationManagerBean());
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册Session会话储存器
|
||||||
|
* @return SessionRegistry
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public SessionRegistry sessionRegistry() {
|
||||||
|
return new SessionRegistryImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登记sessionAuthenticationStrategy
|
||||||
|
* @param sessionRegistry sessionRegistry
|
||||||
|
* @return SessionAuthenticationStrategy
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public SessionAuthenticationStrategy sessionAuthenticationStrategy(SessionRegistry sessionRegistry){
|
||||||
|
return new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry){{
|
||||||
|
setMaximumSessions(1);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.task.BPTQueue;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.repository.task.BatchProcessingTaskRepository;
|
||||||
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务端程序初始化检查
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class EPApplicationContextInitializer implements ApplicationContextInitializer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
|
||||||
|
log.info("EPApplicationContextInitializer Started");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线程池配置
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Configuration
|
||||||
|
public class EPExecutorConfigure {
|
||||||
|
|
||||||
|
@Bean(value = "PaPoolExecutor")
|
||||||
|
public Executor asyncServiceExecutor() {
|
||||||
|
ThreadPoolTaskExecutor executor =new ThreadPoolTaskExecutor();
|
||||||
|
// 核心线程数
|
||||||
|
executor.setCorePoolSize(4);
|
||||||
|
// 最大线程数
|
||||||
|
executor.setMaxPoolSize(8);
|
||||||
|
// 队列大小
|
||||||
|
executor.setQueueCapacity(100);
|
||||||
|
// 空闲线程等待工作的超时时间
|
||||||
|
executor.setKeepAliveSeconds(60);
|
||||||
|
// 线程池中的线程的名称前缀
|
||||||
|
executor.setThreadNamePrefix("pa-pool");
|
||||||
|
|
||||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
||||||
|
// 线程池初始化
|
||||||
|
executor.initialize();
|
||||||
|
|
||||||
|
return executor;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import springfox.documentation.builders.ApiInfoBuilder;
|
||||||
|
import springfox.documentation.builders.ParameterBuilder;
|
||||||
|
import springfox.documentation.builders.PathSelectors;
|
||||||
|
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||||
|
import springfox.documentation.schema.ModelRef;
|
||||||
|
import springfox.documentation.service.ApiInfo;
|
||||||
|
import springfox.documentation.service.Parameter;
|
||||||
|
import springfox.documentation.spi.DocumentationType;
|
||||||
|
import springfox.documentation.spring.web.plugins.Docket;
|
||||||
|
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swagger2配置类
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableSwagger2
|
||||||
|
public class EPSwaggerConfigure {
|
||||||
|
@Bean
|
||||||
|
public Docket createRestApi() {
|
||||||
|
|
||||||
|
List<Parameter> pars = new ArrayList<Parameter>();
|
||||||
|
|
||||||
|
pars.add(new ParameterBuilder().name("openid").description("账号openid").hidden(true).order(1)
|
||||||
|
.modelRef(new ModelRef("string")).parameterType("header")
|
||||||
|
.required(false).defaultValue("24310760d8bb8b6542e5a3f16a0d67253214e01ee7ab0e96a1").build());
|
||||||
|
pars.add(new ParameterBuilder().name("signed").description("客户端签名").hidden(true).order(2)
|
||||||
|
.modelRef(new ModelRef("string")).parameterType("header")
|
||||||
|
.required(false).defaultValue("6d4923fca4dcb51f67b85e54a23a8d763d9e02af").build());
|
||||||
|
pars.add(new ParameterBuilder().name("timestamp").description("时间戳").hidden(true).order(3)
|
||||||
|
.modelRef(new ModelRef("string")).parameterType("header")
|
||||||
|
.required(false).defaultValue(Long.toString(new Date().getTime())).build());
|
||||||
|
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.protocols(Sets.newHashSet("http"))
|
||||||
|
.apiInfo(apiInfo())
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("org.codedream.epaper.controller"))
|
||||||
|
.paths(PathSelectors.any())
|
||||||
|
.build()
|
||||||
|
.globalOperationParameters(pars);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApiInfo apiInfo() {
|
||||||
|
return new ApiInfoBuilder()
|
||||||
|
.title("智慧学术论文行文指导服务端接口定义")
|
||||||
|
.version("0.0.1")
|
||||||
|
.description("用于对服务端接口进行说明")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring 框架全局配置类
|
||||||
|
* 主要用于注册或者管理Bean
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class GlobalConfigure {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 百度API接口所需信息
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class NLPConfigure {
|
||||||
|
|
||||||
|
private static final String APP_ID = "18006539";
|
||||||
|
private static final String APP_KEY = "5sdgAnjElUhfuzH1eHFDnWpz";
|
||||||
|
private static final String SECRET_KEY = "7DYgD3j0KEO3h0Lxrwq16QUWWShvsvKV";
|
||||||
|
|
||||||
|
public static String getAPPId() {
|
||||||
|
return APP_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAppKey() {
|
||||||
|
return APP_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSecretKey() {
|
||||||
|
return SECRET_KEY;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
/**
|
||||||
|
* 句末标点、引用标点等配置
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class PunctuationConfiguration {
|
||||||
|
|
||||||
|
private static final List<String> expPunctuations = new ArrayList<String>() {{
|
||||||
|
add("(");
|
||||||
|
add(")");
|
||||||
|
add("(");
|
||||||
|
add(")");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private static final List<String> endOfSentencePunctuations = new ArrayList<String>() {{
|
||||||
|
add("。");
|
||||||
|
add("?");
|
||||||
|
add("!");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private static final List<String> warningQuotes = new ArrayList<String>() {{
|
||||||
|
add("\"");
|
||||||
|
add("\'");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private static final List<String> frontPunctuations = new ArrayList<String>() {{
|
||||||
|
add("“");
|
||||||
|
add("《");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private static final List<String> backPunctuations = new ArrayList<String>() {{
|
||||||
|
add("”");
|
||||||
|
add("》");
|
||||||
|
add(")");
|
||||||
|
add(")");
|
||||||
|
}};
|
||||||
|
|
||||||
|
private static final List<String> quotesPunctuations = new ArrayList<String>() {{
|
||||||
|
add("“");
|
||||||
|
add("《");
|
||||||
|
add("”");
|
||||||
|
add("》");
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
static public List<String> getExpPunctuations() {
|
||||||
|
return expPunctuations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getEndOfSentencePunctuations() {
|
||||||
|
return endOfSentencePunctuations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getWarningQuotes() {
|
||||||
|
return warningQuotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getFrontPunctuations() {
|
||||||
|
return frontPunctuations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getBackPunctuations() {
|
||||||
|
return backPunctuations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getQuotesPunctuations() {
|
||||||
|
return quotesPunctuations;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package org.codedream.epaper.configure;
|
||||||
|
|
||||||
|
import com.baidu.aip.nlp.AipNlp;
|
||||||
|
import org.codedream.epaper.configure.NLPConfigure;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 百度{@link AipNlp}的接口单例设计,提供线程安全的单例接口调用
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SingletonAipNlp {
|
||||||
|
private static AipNlp aipNlp;
|
||||||
|
|
||||||
|
public SingletonAipNlp() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用一个单例{@link AipNlp}
|
||||||
|
*
|
||||||
|
* @return 一个单例的AipNlp对象
|
||||||
|
*/
|
||||||
|
public static AipNlp getInstance() {
|
||||||
|
if (null == aipNlp) {
|
||||||
|
synchronized (AipNlp.class) {
|
||||||
|
if (null == aipNlp) {
|
||||||
|
aipNlp = new AipNlp(NLPConfigure.getAPPId(), NLPConfigure.getAppKey(), NLPConfigure.getSecretKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aipNlp;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package org.codedream.epaper.controller;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.api.QuickJSONRespond;
|
||||||
|
import org.codedream.epaper.component.json.respond.ErrorInfoJSONRespond;
|
||||||
|
import org.codedream.epaper.exception.badrequest.AlreadyExistException;
|
||||||
|
import org.codedream.epaper.exception.badrequest.IllegalException;
|
||||||
|
import org.codedream.epaper.exception.conflict.RelatedObjectsExistException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.FormatException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误/异常管理机制控制
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestControllerAdvice
|
||||||
|
@Api(hidden = true)
|
||||||
|
public class EPControllerAdvice {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private QuickJSONRespond quickJSONRespond;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 非法请求类异常处理
|
||||||
|
* @param ex 异常
|
||||||
|
* @return 返回对象
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(value = {
|
||||||
|
NullPointerException.class,
|
||||||
|
AlreadyExistException.class,
|
||||||
|
IllegalException.class
|
||||||
|
})
|
||||||
|
public ResponseEntity<Object> handleBadRequest(Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return getResponse(HttpStatus.BAD_REQUEST, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 未找到类异常处理
|
||||||
|
* @param ex 异常
|
||||||
|
* @return 返回对象
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(value = {NotFoundException.class})
|
||||||
|
public ResponseEntity<Object> handleNotFound(Exception ex) {
|
||||||
|
|
||||||
|
return getResponse(HttpStatus.NOT_FOUND, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不可接受类异常处理
|
||||||
|
* @param ex 异常
|
||||||
|
* @return 返回对象
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(value = {})
|
||||||
|
public ResponseEntity<Object> handleNotAcceptable(Exception ex) {
|
||||||
|
return getResponse(HttpStatus.NOT_ACCEPTABLE, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 冲突类异常处理
|
||||||
|
* @param ex 异常
|
||||||
|
* @return 返回对象
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(value = {RelatedObjectsExistException.class})
|
||||||
|
public ResponseEntity<Object> handleConflict(Exception ex) {
|
||||||
|
return getResponse(HttpStatus.CONFLICT, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部错误类异常处理
|
||||||
|
* @param ex 异常
|
||||||
|
* @return 返回对象
|
||||||
|
*/
|
||||||
|
@ExceptionHandler(value = {
|
||||||
|
HandlingErrorsException.class,
|
||||||
|
FormatException.class,
|
||||||
|
RuntimeIOException.class})
|
||||||
|
public ResponseEntity<Object> handleInnerServerError(Exception ex){
|
||||||
|
return getResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造JSON填充的返回对象
|
||||||
|
* @param status HTTP状态码
|
||||||
|
* @param ex 异常
|
||||||
|
* @return 返回对象
|
||||||
|
*/
|
||||||
|
private ResponseEntity<Object> getResponse(HttpStatus status, Exception ex){
|
||||||
|
return ResponseEntity.status(status).body(getJSON(status, ex));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getJSON(HttpStatus status, Exception ex){
|
||||||
|
return quickJSONRespond.getJSONStandardRespond(status, getJSONRespondObject(ex));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getJSONRespondObject(Exception ex){
|
||||||
|
ErrorInfoJSONRespond errorInfoJSONRespond = new ErrorInfoJSONRespond();
|
||||||
|
errorInfoJSONRespond.setException(ex.getClass().getName());
|
||||||
|
errorInfoJSONRespond.setExceptionMessage(ex.getMessage());
|
||||||
|
errorInfoJSONRespond.setDate(new Date());
|
||||||
|
return errorInfoJSONRespond;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package org.codedream.epaper.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiModel;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.poi.hdgf.streams.StringsStream;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableFile;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.exception.badrequest.IllegalException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.RuntimeIOException;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.service.FileService;
|
||||||
|
import org.codedream.epaper.service.IFileService;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@Api("文件服务类接口")
|
||||||
|
@RequestMapping("file")
|
||||||
|
public class FileController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
@PostMapping("text")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
@ApiOperation("文本上传接口")
|
||||||
|
public JsonableFile uploadText(@RequestBody String text) {
|
||||||
|
if(text == null || text.length() < 300) throw new IllegalArgumentException();
|
||||||
|
ByteArrayInputStream stream = new ByteArrayInputStream(text.getBytes());
|
||||||
|
|
||||||
|
Integer fileId = fileService.saveFile(text.substring(0, 12), "plain", stream);
|
||||||
|
|
||||||
|
JsonableFile jsonableFile = new JsonableFile();
|
||||||
|
jsonableFile.setFileId(fileId);
|
||||||
|
jsonableFile.setFilename(text.substring(0, 12));
|
||||||
|
jsonableFile.setType("plain");
|
||||||
|
return jsonableFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
@ApiOperation("文件上传接口")
|
||||||
|
public JsonableFile uploadFile(@RequestParam("file") MultipartFile file){
|
||||||
|
String filename = file.getOriginalFilename();
|
||||||
|
|
||||||
|
String[] strArray = filename.split("\\.");
|
||||||
|
int suffixIndex = strArray.length -1;
|
||||||
|
String fileType = strArray[suffixIndex];
|
||||||
|
|
||||||
|
log.info(String.format("File Upload filename %s", filename));
|
||||||
|
log.info(String.format("File Upload fileType %s", fileType));
|
||||||
|
|
||||||
|
// 检查文件大小
|
||||||
|
if(file.getSize() > configure.getFileMaxSize()) throw new IllegalException(Long.toString(file.getSize()));
|
||||||
|
|
||||||
|
if(fileType.equals("doc") || fileType.equals("docx") || fileType.equals("pdf")){
|
||||||
|
try {
|
||||||
|
byte[] fileData = file.getBytes();
|
||||||
|
ByteArrayInputStream stream = new ByteArrayInputStream(fileData);
|
||||||
|
Integer fileId = fileService.saveFile(filename, fileType, stream);
|
||||||
|
|
||||||
|
// 填写返回JSON
|
||||||
|
JsonableFile jsonableFile = new JsonableFile();
|
||||||
|
jsonableFile.setFileId(fileId);
|
||||||
|
jsonableFile.setFilename(filename);
|
||||||
|
jsonableFile.setType(fileType);
|
||||||
|
return jsonableFile;
|
||||||
|
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new RuntimeIOException(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else throw new IllegalException(fileType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("download")
|
||||||
|
public void downloadFile(@RequestParam("fileId") Integer fileId, HttpServletResponse response){
|
||||||
|
File file = fileService.getFileInfo(fileId);
|
||||||
|
if(file == null) throw new NotFoundException(fileId.toString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
response.setHeader("content-type", "application/octet-stream");
|
||||||
|
response.setContentType("application/octet-stream");
|
||||||
|
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream stream = fileService.getFile(fileId);
|
||||||
|
|
||||||
|
try{
|
||||||
|
OutputStream outputStream = response.getOutputStream();
|
||||||
|
int readBits;
|
||||||
|
byte[] rawBytes = new byte[1024];
|
||||||
|
while ((readBits = stream.read(rawBytes)) != -1) {
|
||||||
|
outputStream.write(rawBytes, 0, readBits);
|
||||||
|
}
|
||||||
|
outputStream.close();
|
||||||
|
stream.close();
|
||||||
|
} catch (Exception e){
|
||||||
|
throw new HandlingErrorsException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
package org.codedream.epaper.controller;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import io.swagger.models.auth.In;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableBPT;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableBPTResult;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableCSP;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTN;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.exception.badrequest.AuthExpiredException;
|
||||||
|
import org.codedream.epaper.exception.badrequest.IllegalException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.HandlingErrorsException;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.server.ChildServerPassport;
|
||||||
|
import org.codedream.epaper.model.task.BatchProcessingTask;
|
||||||
|
import org.codedream.epaper.model.user.User;
|
||||||
|
import org.codedream.epaper.repository.task.BatchProcessingTaskRepository;
|
||||||
|
import org.codedream.epaper.service.IChildServerService;
|
||||||
|
import org.codedream.epaper.service.INeuralNetworkModelService;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@Api("GPU服务器分布式计算接口")
|
||||||
|
@RequestMapping("cs")
|
||||||
|
public class GPUServerController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IChildServerService childServerService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private INeuralNetworkModelService modelService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BatchProcessingTaskRepository bptRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
@PostMapping("")
|
||||||
|
@ApiOperation("获得子服务器护照")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public JsonableCSP registerCSP(Authentication authentication){
|
||||||
|
User user = (User) authentication.getPrincipal();
|
||||||
|
if(!user.getUserAuth().getRole().equals("ChildServer"))
|
||||||
|
throw new IllegalException(authentication.getName());
|
||||||
|
|
||||||
|
return new JsonableCSP(childServerService.createCSP(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("")
|
||||||
|
@ApiOperation("更新子服务器签证")
|
||||||
|
public JsonableCSP updateCSP(@RequestParam(value = "idcode") String idcode){
|
||||||
|
if(!childServerService.checkCSP(idcode)) throw new IllegalException(idcode);
|
||||||
|
|
||||||
|
ChildServerPassport csp = childServerService.updateCSP(idcode);
|
||||||
|
|
||||||
|
// 签证过期
|
||||||
|
if(csp == null) {
|
||||||
|
JsonableCSP jsonableCSP = new JsonableCSP();
|
||||||
|
jsonableCSP.setExpired(true);
|
||||||
|
jsonableCSP.setIdentityCode(idcode);
|
||||||
|
return jsonableCSP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonableCSP(csp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("bpt")
|
||||||
|
@ApiOperation("获得一个合适的批处理任务")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public JsonableBPT getBPT(@RequestParam(value = "idcode") String idcode,
|
||||||
|
@RequestParam(value = "maxStnNum") String maxSTNNumberStr){
|
||||||
|
|
||||||
|
log.info(String.format("Get BPT Request From %s Max Sentence Number %s.", idcode, maxSTNNumberStr));
|
||||||
|
|
||||||
|
if(childServerService.checkCSPExpired(idcode)){
|
||||||
|
log.info(String.format("Found CSP %s Expired.", idcode));
|
||||||
|
throw new AuthExpiredException(idcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
float maxSTNNumber = Float.parseFloat(maxSTNNumberStr);
|
||||||
|
if(configure.getBPTMinSentenceNumber() > maxSTNNumber){
|
||||||
|
log.info(String.format("Found maxSTNNumber %f is Too Few.", maxSTNNumber));
|
||||||
|
throw new IllegalException ("Too Few maxSTNNumber");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("PreCheck Succeed.");
|
||||||
|
|
||||||
|
// 标记签证地点
|
||||||
|
ChildServerPassport csp = childServerService.getCSPInfo(idcode);
|
||||||
|
|
||||||
|
// 存在被该CSP锁住的BPT
|
||||||
|
if(csp.getBptId() != null){
|
||||||
|
log.info(String.format("Locked BPT Found %d.", csp.getBptId()));
|
||||||
|
|
||||||
|
Optional<BatchProcessingTask> bpt = bptRepository.findById(csp.getBptId());
|
||||||
|
if(!bpt.isPresent()) throw new IllegalException();
|
||||||
|
modelService.markBPTFailed(bpt.get());
|
||||||
|
csp.setBptId(null);
|
||||||
|
|
||||||
|
log.info(String.format("Marked Locked BPT Failed %d.", csp.getBptId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.info("Trying To Get New BPT...");
|
||||||
|
Optional<BatchProcessingTask> bpt = modelService.getBPTTaskAndLock((int) maxSTNNumber);
|
||||||
|
|
||||||
|
if (!bpt.isPresent()) {
|
||||||
|
log.info("Available BPT Not Found.");
|
||||||
|
return new JsonableBPT();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(String.format("New BPT Got %d.", bpt.get().getId()));
|
||||||
|
List<Sentence> sentences = modelService.calculateSentenceList(bpt.get());
|
||||||
|
|
||||||
|
// 所有句已处理
|
||||||
|
if(sentences.size() == 0){
|
||||||
|
log.info("None Sentence Must Be Processing");
|
||||||
|
// 标记任务已完成
|
||||||
|
modelService.markBPTSuccess(bpt.get(), new ArrayList<>());
|
||||||
|
log.info("Marked BPT Successful.");
|
||||||
|
log.info("Available BPT Not Found.");
|
||||||
|
return new JsonableBPT();
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(String.format("Record BPT %d To CSP %s.", bpt.get().getId(), csp.getIdentityCode()));
|
||||||
|
csp.setBptId(bpt.get().getId());
|
||||||
|
// 更新数据库
|
||||||
|
childServerService.update(csp);
|
||||||
|
|
||||||
|
return modelService.getJsonableBPT(bpt.get(), sentences);
|
||||||
|
|
||||||
|
} catch(Exception e){
|
||||||
|
log.error(e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new HandlingErrorsException(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PutMapping("bpt")
|
||||||
|
@ApiOperation("更新BPT状态为已完成")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
public void setBPTFinished(@RequestParam(value = "idcode") String idcode,
|
||||||
|
@RequestParam(value = "bptId") Integer bptId,
|
||||||
|
@RequestParam(value = "status") boolean status,
|
||||||
|
@RequestBody List<JsonableBPTResult> results){
|
||||||
|
|
||||||
|
log.info(String.format("Get BPT Result Upload Request From %s For BPT %d", idcode, bptId));
|
||||||
|
|
||||||
|
if(childServerService.checkCSPExpired(idcode)){
|
||||||
|
log.info(String.format("Found CSP %s Expired.", idcode));
|
||||||
|
throw new AuthExpiredException(idcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChildServerPassport csp = childServerService.getCSPInfo(idcode);
|
||||||
|
if(csp.getBptId() == null || !csp.getBptId().equals(bptId)){
|
||||||
|
log.info(String.format("Found CSP Status %s Illegal.", idcode));
|
||||||
|
throw new IllegalException(bptId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("PreCheck Succeed.");
|
||||||
|
|
||||||
|
Optional<BatchProcessingTask> bpt = bptRepository.findById(bptId);
|
||||||
|
|
||||||
|
if(!bpt.isPresent()){
|
||||||
|
log.info(String.format("Found BPT ID %d Illegal.", bptId));
|
||||||
|
throw new NotFoundException(bptId.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(status) {
|
||||||
|
log.info("Child Server Process Status Successful.");
|
||||||
|
modelService.markBPTSuccess(bpt.get(), results);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
log.info("Child Server Process Status Failed.");
|
||||||
|
modelService.markBPTFailed(bpt.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
csp.setBptId(null);
|
||||||
|
// 更新数据库
|
||||||
|
childServerService.update(csp);
|
||||||
|
|
||||||
|
log.info(String.format("BPT %d Result Processing Succeed For CSP %s", bptId, idcode));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package org.codedream.epaper.controller;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.codedream.epaper.component.datamanager.ReportGenerator;
|
||||||
|
import org.codedream.epaper.exception.badrequest.IllegalException;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.model.user.User;
|
||||||
|
import org.codedream.epaper.service.ITaskService;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("report")
|
||||||
|
public class ReportController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ITaskService taskService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ReportGenerator reportGenerator;
|
||||||
|
|
||||||
|
@GetMapping("generate")
|
||||||
|
Integer generateReport(Authentication authentication, @RequestParam("taskId") Integer taskId){
|
||||||
|
|
||||||
|
User user = (User) authentication.getPrincipal();
|
||||||
|
Optional<Task> taskOptional = taskService.getTaskInfo(taskId);
|
||||||
|
if(!taskOptional.isPresent()) throw new NotFoundException(taskId.toString());
|
||||||
|
if (taskOptional.get().getUser().getId() != user.getId()) throw new IllegalException(taskId.toString());
|
||||||
|
|
||||||
|
log.info(String.format("Start Generate Report For TaskID %d ...", taskId));
|
||||||
|
|
||||||
|
Integer fileId = reportGenerator.saveByFileService(reportGenerator.generate(taskId));
|
||||||
|
log.info(String.format("Generate Report For TaskID %d Done.", taskId));
|
||||||
|
|
||||||
|
return fileId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,249 @@
|
|||||||
|
package org.codedream.epaper.controller;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.codedream.epaper.component.article.GetSentenceFromArticle;
|
||||||
|
import org.codedream.epaper.component.datamanager.DiffMatchPatch;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTN;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableSTNPage;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableTask;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableTaskResult;
|
||||||
|
import org.codedream.epaper.configure.AppConfigure;
|
||||||
|
import org.codedream.epaper.exception.badrequest.IllegalException;
|
||||||
|
import org.codedream.epaper.exception.innerservererror.InnerDataTransmissionException;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.codedream.epaper.model.article.Article;
|
||||||
|
import org.codedream.epaper.model.article.Paragraph;
|
||||||
|
import org.codedream.epaper.model.article.Sentence;
|
||||||
|
import org.codedream.epaper.model.file.File;
|
||||||
|
import org.codedream.epaper.model.task.Task;
|
||||||
|
import org.codedream.epaper.model.task.TaskResult;
|
||||||
|
import org.codedream.epaper.model.user.User;
|
||||||
|
import org.codedream.epaper.repository.task.TaskResultRepository;
|
||||||
|
import org.codedream.epaper.service.IFileService;
|
||||||
|
import org.codedream.epaper.service.ITaskService;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Api("任务类接口")
|
||||||
|
@RequestMapping("task")
|
||||||
|
public class TaskController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ITaskService taskService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IFileService fileService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GetSentenceFromArticle getSentenceFromArticle;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AppConfigure configure;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TaskResultRepository taskResultRepository;
|
||||||
|
|
||||||
|
@PostMapping("")
|
||||||
|
@ApiOperation("创建任务")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
public JsonableTask createTask(@RequestBody JsonableTask jsonableTask, Authentication authentication) {
|
||||||
|
// 获得当前认证用户的身份
|
||||||
|
User user = (User) authentication.getPrincipal();
|
||||||
|
|
||||||
|
// 文件序号检查
|
||||||
|
File file = fileService.getFileInfo(jsonableTask.getFileId());
|
||||||
|
if(file == null) throw new NotFoundException(jsonableTask.getFileId().toString());
|
||||||
|
|
||||||
|
// 注册子任务
|
||||||
|
Integer taskId = taskService.registerTask(user.getId(), file.getId(), "normal");
|
||||||
|
jsonableTask.setTaskId(taskId);
|
||||||
|
|
||||||
|
return jsonableTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("history")
|
||||||
|
@ApiOperation("查询用户历史记录")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public List<Integer> taskHistory(Authentication authentication){
|
||||||
|
User user = (User) authentication.getPrincipal();
|
||||||
|
Iterable<Task> tasks = taskService.findHistoryTaskId(user.getId());
|
||||||
|
List<Integer> taskIds = new ArrayList<>();
|
||||||
|
|
||||||
|
for(Task task : tasks){
|
||||||
|
taskIds.add(task.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return taskIds;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("")
|
||||||
|
@ApiOperation("查询任务状态接口")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public JsonableTask checkTask(@RequestParam(value = "taskId") Integer taskId){
|
||||||
|
Optional<Task> task = taskService.getTaskInfo(taskId);
|
||||||
|
if(!task.isPresent()) throw new NotFoundException(taskId.toString());
|
||||||
|
|
||||||
|
JsonableTask jsonableTask = new JsonableTask(task.get());
|
||||||
|
|
||||||
|
if (task.get().isFinished()) {
|
||||||
|
Article article = task.get().getArticle();
|
||||||
|
Iterator<Paragraph> paragraphIterator = article.getParagraphs().iterator();
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
while (builder.length() < 30 && paragraphIterator.hasNext()) {
|
||||||
|
builder.append(paragraphIterator.next().getText());
|
||||||
|
}
|
||||||
|
String str = builder.toString().trim();
|
||||||
|
|
||||||
|
if(str.length() > 30) str = str.substring(0, 30);
|
||||||
|
jsonableTask.setDescription(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonableTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("result")
|
||||||
|
@ApiOperation("获得任务结果")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public JsonableTaskResult getTaskResult(@RequestParam(value = "taskId") Integer taskId){
|
||||||
|
// 验证子任务Id
|
||||||
|
Optional<Task> task = taskService.getTaskInfo(taskId);
|
||||||
|
if (!task.isPresent()) throw new NotFoundException(taskId.toString());
|
||||||
|
if (!task.get().isFinished())
|
||||||
|
throw new NotFoundException(String.format("Task Not Finished : Task Id %d", taskId));
|
||||||
|
|
||||||
|
|
||||||
|
Optional<TaskResult> taskResult = taskService.getTaskResult(taskId);
|
||||||
|
if(!taskResult.isPresent()) throw new NotFoundException(String.format("Result Not Found : Task Id %d",taskId));
|
||||||
|
|
||||||
|
return taskService.getJsonableTaskResult(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("stnlist")
|
||||||
|
@ApiOperation("获取句子原文接口")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public JsonableSTNPage getSTNList(@RequestParam(value = "taskId") Integer taskId,
|
||||||
|
@RequestParam(value = "page") Integer page){
|
||||||
|
// 验证子任务Id
|
||||||
|
Optional<Task> task = taskService.getTaskInfo(taskId);
|
||||||
|
if (!task.isPresent()) throw new NotFoundException(taskId.toString());
|
||||||
|
if (!task.get().isFinished())
|
||||||
|
throw new NotFoundException(String.format("Task Not Finished : Task Id %d", taskId));
|
||||||
|
if (page == null) page = 1;
|
||||||
|
if(page < 1) throw new IllegalException();
|
||||||
|
|
||||||
|
|
||||||
|
Optional<TaskResult> taskResult = taskService.getTaskResult(taskId);
|
||||||
|
if(!taskResult.isPresent()) throw new InnerDataTransmissionException();
|
||||||
|
|
||||||
|
if(!taskResult.get().isSuccess()){
|
||||||
|
throw new IllegalException("Task Failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Sentence> sentences = getSentenceFromArticle.get(task.get().getArticle());
|
||||||
|
|
||||||
|
|
||||||
|
int stnPrePage = configure.getSentencePrePage();
|
||||||
|
|
||||||
|
// 求所有分页数
|
||||||
|
int pageAll = new Double(Math.ceil(sentences.size() / 10.0)).intValue();
|
||||||
|
if(page > pageAll) page = pageAll;
|
||||||
|
|
||||||
|
|
||||||
|
// 按照ID 排序
|
||||||
|
sentences.sort(Comparator.comparing(Sentence::getId));
|
||||||
|
|
||||||
|
List<Sentence> sentencePage = new ArrayList<>();
|
||||||
|
|
||||||
|
// 获取分页数据
|
||||||
|
for(int i = (page-1) * stnPrePage ; i < page * stnPrePage && i < sentences.size(); i++){
|
||||||
|
sentencePage.add(sentences.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<JsonableSTN> jsonableSTNList = new ArrayList<>();
|
||||||
|
|
||||||
|
for(Sentence sentence : sentencePage){
|
||||||
|
JsonableSTN jsonableSTN = new JsonableSTN();
|
||||||
|
jsonableSTN.setStnId(sentence.getId());
|
||||||
|
jsonableSTN.setText(sentence.getText());
|
||||||
|
jsonableSTNList.add(jsonableSTN);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonableSTNPage stnPage = new JsonableSTNPage();
|
||||||
|
stnPage.setAll(pageAll);
|
||||||
|
stnPage.setPage(page);
|
||||||
|
stnPage.setStns(jsonableSTNList);
|
||||||
|
|
||||||
|
return stnPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("test")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public String test() {
|
||||||
|
DiffMatchPatch dmp = new DiffMatchPatch();
|
||||||
|
String text1 = "我们预备了缓存数据库功能,将论文种常见的行文错误进行特征编码后缓存。";
|
||||||
|
String text2 = "我们预备了缓存数据库功能,将论文中常见的行文错误进行特征编码后缓存。";
|
||||||
|
LinkedList<DiffMatchPatch.Diff> diff = dmp.diff_main(text1, text2);
|
||||||
|
List<Integer> show = new ArrayList<>();
|
||||||
|
System.out.println(diff.toString());
|
||||||
|
for (DiffMatchPatch.Diff diff1 : diff) {
|
||||||
|
DiffMatchPatch.Operation operation = diff1.operation;
|
||||||
|
System.out.println(operation.compareTo(DiffMatchPatch.Operation.INSERT));
|
||||||
|
show.add(operation.compareTo(DiffMatchPatch.Operation.INSERT));
|
||||||
|
}
|
||||||
|
return show.toString() + "\n" + diff.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("test2")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
public String test2(@RequestParam("str") String test) {
|
||||||
|
System.out.println("aha?");
|
||||||
|
List<TaskResult> taskResults = taskResultRepository.findAll();
|
||||||
|
/*for (TaskResult taskResult : taskResults) {
|
||||||
|
System.out.println(taskResult.getTaskId() + ": " + taskResult.getBrokenSentencesCount() +
|
||||||
|
" " + taskResult.getWrongTextCount() + " " +
|
||||||
|
taskResult.getPositiveEmotionsCount().addAndGet(taskResult.getNegativeEmotionsCount().intValue()));
|
||||||
|
}*/
|
||||||
|
StringTokenizer stringTokenizer = new StringTokenizer(test, ",");
|
||||||
|
int cnt = 0;
|
||||||
|
int[] args = new int[4];
|
||||||
|
while (stringTokenizer.hasMoreTokens()) {
|
||||||
|
args[cnt++] = Integer.parseInt(stringTokenizer.nextToken());
|
||||||
|
}
|
||||||
|
args[1] += 4;
|
||||||
|
double e = Math.E;
|
||||||
|
double res1 = Math.PI * Math.log(-Math.atan(1.3 * args[1] - 10) + 2) / Math.log(e) + 10;
|
||||||
|
res1 *= 6.3489125794718040652210611515526;
|
||||||
|
res1 += 12.305831203372289317158476382609;
|
||||||
|
|
||||||
|
//0: 13.949372309773254
|
||||||
|
//10: 9.643946813538529
|
||||||
|
// times: 5.8066270155791913101469156905197
|
||||||
|
/// tmp: 80.998802104301680424681488452429
|
||||||
|
// delta: 19.001197895698319575318511547571
|
||||||
|
args[0] += 1;
|
||||||
|
double res0 = Math.PI * Math.log(-Math.atan(2 * args[0] - 20) + 2) / Math.log(e) + 10;
|
||||||
|
res0 *= 5.8066270155791913101469156905197;
|
||||||
|
res0 += 19.001197895698319575318511547571;
|
||||||
|
|
||||||
|
//0 :13.918523899939487
|
||||||
|
//14:10.053595335568621
|
||||||
|
//times:6.4684248579558173553422908337857
|
||||||
|
// tmp:90.030925980420725210936987275173
|
||||||
|
// delta:9.969074019579274789063012724827
|
||||||
|
args[2] += 1;
|
||||||
|
double res2 = Math.PI * Math.log(-Math.atan(0.9 * args[2] - 12) + 2) / Math.log(e) + 10;
|
||||||
|
res2 *= 6.4684248579558173553422908337857;
|
||||||
|
res2 += 9.969074019579274789063012724827;
|
||||||
|
|
||||||
|
return res0 + " " + res1 + " " + res2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package org.codedream.epaper.controller;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
|
import org.codedream.epaper.component.json.model.JsonableUser;
|
||||||
|
import org.codedream.epaper.exception.badrequest.AlreadyExistException;
|
||||||
|
import org.codedream.epaper.exception.badrequest.IllegalException;
|
||||||
|
import org.codedream.epaper.exception.notfound.NotFoundException;
|
||||||
|
import org.codedream.epaper.model.user.User;
|
||||||
|
import org.codedream.epaper.service.IUserService;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import springfox.documentation.spring.web.json.Json;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("user")
|
||||||
|
@Api("用户验证类接口")
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IUserService userService;
|
||||||
|
|
||||||
|
@PostMapping("")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
@ApiOperation("用户注册接口")
|
||||||
|
public JsonableUser createUser(@RequestBody JsonableUser jsonableUser){
|
||||||
|
if(jsonableUser.getOpenid() == null) throw new IllegalAccessError("Null Value Openid");
|
||||||
|
if(userService.findUserByOpenid(jsonableUser.getOpenid()).isPresent())
|
||||||
|
throw new AlreadyExistException(jsonableUser.getOpenid());
|
||||||
|
|
||||||
|
User user = userService.getDefaultUser();
|
||||||
|
return new JsonableUser(userService.save(jsonableUser.parseObject(user)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("cs")
|
||||||
|
@ResponseStatus(HttpStatus.CREATED)
|
||||||
|
@ApiOperation("子服务器注册接口")
|
||||||
|
public JsonableUser createChildServerUser(@RequestParam(value = "clientCode") String clientCode,
|
||||||
|
@RequestBody JsonableUser jsonableUser){
|
||||||
|
if(jsonableUser.getOpenid() == null) throw new IllegalAccessError("Null Value Openid");
|
||||||
|
if(userService.findUserByOpenid(jsonableUser.getOpenid()).isPresent())
|
||||||
|
throw new AlreadyExistException(jsonableUser.getOpenid());
|
||||||
|
|
||||||
|
if(!clientCode.equals("dc9fbb4f4f0b84fa903058991af60e73556494af8a02ef69fb6a93217729f04b"))
|
||||||
|
throw new IllegalException("Illegal Child Server");
|
||||||
|
|
||||||
|
User user = userService.getDefaultUser();
|
||||||
|
user.getUserAuth().setRole("ChildServer");
|
||||||
|
return new JsonableUser(userService.save(jsonableUser.parseObject(user)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("")
|
||||||
|
@ResponseStatus(HttpStatus.OK)
|
||||||
|
@ApiOperation("检查用户是否存在接口")
|
||||||
|
public JsonableUser getUser(@RequestParam(value = "openid") String openid){
|
||||||
|
Optional<User> user = userService.findUserByOpenid(openid);
|
||||||
|
if(!user.isPresent())
|
||||||
|
throw new NotFoundException(openid);
|
||||||
|
|
||||||
|
JsonableUser jsonableUser = new JsonableUser();
|
||||||
|
jsonableUser.setId(user.get().getId());
|
||||||
|
jsonableUser.setOpenid(user.get().getUsername());
|
||||||
|
return jsonableUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package org.codedream.epaper.exception.badrequest;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class AlreadyExistException extends RuntimeException {
|
||||||
|
public AlreadyExistException(String msg){
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.codedream.epaper.exception.badrequest;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 认证信息过期
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class AuthExpiredException extends IllegalException {
|
||||||
|
public AuthExpiredException(String msg){
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.codedream.epaper.exception.badrequest;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class BaseInformationAlreadyExistException extends AlreadyExistException {
|
||||||
|
private String className;
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
public BaseInformationAlreadyExistException(Class<?> aClass, String value){
|
||||||
|
super(String.format("%s: %s", aClass.getName(), value));
|
||||||
|
this.className = aClass.getName();
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package org.codedream.epaper.exception.badrequest;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
public class BaseInformationIllegalException extends IllegalException {
|
||||||
|
String type;
|
||||||
|
String value;
|
||||||
|
|
||||||
|
public BaseInformationIllegalException(Class<?> aClass, String value){
|
||||||
|
super();
|
||||||
|
this.type = aClass.getName();
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package org.codedream.epaper.exception.badrequest;
|
||||||
|
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class IllegalException extends RuntimeException {
|
||||||
|
public IllegalException(String msg){
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user