first commit

pull/1/head
mfay 4 years ago
parent b89efa1db2
commit 2bc3d8b1cb
  1. 33
      IOReportSysBE/.gitignore
  2. 118
      IOReportSysBE/.mvn/wrapper/MavenWrapperDownloader.java
  3. BIN
      IOReportSysBE/.mvn/wrapper/maven-wrapper.jar
  4. 2
      IOReportSysBE/.mvn/wrapper/maven-wrapper.properties
  5. 310
      IOReportSysBE/mvnw
  6. 182
      IOReportSysBE/mvnw.cmd
  7. 172
      IOReportSysBE/pom.xml
  8. 211
      IOReportSysBE/src/generator/CodeGenerator.java
  9. 25
      IOReportSysBE/src/generator/ModuleInfo.java
  10. 19
      IOReportSysBE/src/generator/ProjectInfo.java
  11. 25
      IOReportSysBE/src/generator/TableMetaInfo.java
  12. 73
      IOReportSysBE/src/generator/converter/CustomTypeConvert.java
  13. 17
      IOReportSysBE/src/generator/converter/JSONColumnType.java
  14. 79
      IOReportSysBE/src/generator/project.json
  15. 97
      IOReportSysBE/src/generator/templates/controller.java.vm
  16. 17
      IOReportSysBE/src/generator/templates/mapper.java.vm
  17. 39
      IOReportSysBE/src/generator/templates/mapper.xml.vm
  18. 161
      IOReportSysBE/src/generator/templates/model.java.vm
  19. 31
      IOReportSysBE/src/generator/templates/service.java.vm
  20. 106
      IOReportSysBE/src/generator/templates/serviceImpl.java.vm
  21. 33
      IOReportSysBE/src/main/java/edu/ncst/ioreport/IOReprotApplication.java
  22. 34
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/CustomAccessDeniedHandler.java
  23. 47
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/JsonConfig.java
  24. 208
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/SecurityConfig.java
  25. 15
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/exception/NotBindUserException.java
  26. 109
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/DataBaseUrlVoter.java
  27. 104
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/filter/AuthCheckFilter.java
  28. 208
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/filter/LoginFilter.java
  29. 60
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/provider/WechatIdLoginProvider.java
  30. 39
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/token/JwtAuthenticationToken.java
  31. 39
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/token/MobileCaptchaAuthenticationToken.java
  32. 51
      IOReportSysBE/src/main/java/edu/ncst/ioreport/config/security/token/WechatIdAuthenticationToken.java
  33. 132
      IOReportSysBE/src/main/java/edu/ncst/ioreport/controller/TestController.java
  34. 56
      IOReportSysBE/src/main/java/edu/ncst/ioreport/controller/UserController.java
  35. 41
      IOReportSysBE/src/main/java/edu/ncst/ioreport/exception/BusinessException.java
  36. 63
      IOReportSysBE/src/main/java/edu/ncst/ioreport/exception/CodeMsg.java
  37. 54
      IOReportSysBE/src/main/java/edu/ncst/ioreport/exception/handler/InterfaceExceptionHandler.java
  38. 34
      IOReportSysBE/src/main/java/edu/ncst/ioreport/mapper/BaseMapperPlus.java
  39. 9
      IOReportSysBE/src/main/java/edu/ncst/ioreport/mapper/ResourceMapper.java
  40. 25
      IOReportSysBE/src/main/java/edu/ncst/ioreport/mapper/RoleMapper.java
  41. 26
      IOReportSysBE/src/main/java/edu/ncst/ioreport/mapper/UserMapper.java
  42. 40
      IOReportSysBE/src/main/java/edu/ncst/ioreport/model/BaseEntity.java
  43. 49
      IOReportSysBE/src/main/java/edu/ncst/ioreport/model/LoginLog.java
  44. 55
      IOReportSysBE/src/main/java/edu/ncst/ioreport/model/Resource.java
  45. 58
      IOReportSysBE/src/main/java/edu/ncst/ioreport/model/Role.java
  46. 93
      IOReportSysBE/src/main/java/edu/ncst/ioreport/model/User.java
  47. 18
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/ILoginLogService.java
  48. 22
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/IResourceService.java
  49. 26
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/IRoleService.java
  50. 19
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/IUserService.java
  51. 27
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/impl/LoginLogServiceImpl.java
  52. 62
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/impl/ResourceServiceImpl.java
  53. 55
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/impl/RoleServiceImpl.java
  54. 78
      IOReportSysBE/src/main/java/edu/ncst/ioreport/service/impl/UserServiceImpl.java
  55. 79
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/CaptchaUtil.java
  56. 29
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/CookieUtils.java
  57. 91
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/ResponseUtils.java
  58. 55
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/ResultUtils.java
  59. 55
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/SessionUtils.java
  60. 25
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/SpringUtils.java
  61. 27
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/URLUtils.java
  62. 49
      IOReportSysBE/src/main/java/edu/ncst/ioreport/utils/WeChatUtils.java
  63. 18
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/AccessToken.java
  64. 30
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/ListResultVO.java
  65. 61
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/Query.java
  66. 19
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/ResultVO.java
  67. 22
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/SessionKey.java
  68. 20
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/Sorter.java
  69. 41
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/param/CurrentUserVO.java
  70. 29
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/param/QLoginLog.java
  71. 14
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/param/QUser.java
  72. 20
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/param/UserLoginVO.java
  73. 29
      IOReportSysBE/src/main/java/edu/ncst/ioreport/vo/result/UserInfoVO.java
  74. 61
      IOReportSysBE/src/main/resources/application.yml
  75. 57
      IOReportSysBE/src/main/resources/logback.xml
  76. 13
      IOReportSysBE/src/test/java/edu/ncst/ioreport/IOReportApplicationTests.java
  77. 31
      IOReportSysMP/.eslintrc.js
  78. 3
      IOReportSysMP/.vscode/settings.json
  79. 13
      IOReportSysMP/miniprogram/api/index.d.ts
  80. 50
      IOReportSysMP/miniprogram/api/orderApi/index.d.ts
  81. 113
      IOReportSysMP/miniprogram/api/orderApi/orderApi.js
  82. 36
      IOReportSysMP/miniprogram/api/orderApi/orderApi.ts
  83. 10
      IOReportSysMP/miniprogram/api/userApi/index.d.ts
  84. 89
      IOReportSysMP/miniprogram/api/userApi/userApi.js
  85. 40
      IOReportSysMP/miniprogram/api/userApi/userApi.ts
  86. 67
      IOReportSysMP/miniprogram/app.js
  87. 43
      IOReportSysMP/miniprogram/app.json
  88. 65
      IOReportSysMP/miniprogram/app.ts
  89. 88
      IOReportSysMP/miniprogram/app.wxss
  90. BIN
      IOReportSysMP/miniprogram/asset/banenr.png
  91. BIN
      IOReportSysMP/miniprogram/asset/qrcode.png
  92. BIN
      IOReportSysMP/miniprogram/asset/qrcode_mini.png
  93. 30
      IOReportSysMP/miniprogram/components/navigationBar/navigationBar.js
  94. 6
      IOReportSysMP/miniprogram/components/navigationBar/navigationBar.json
  95. 23
      IOReportSysMP/miniprogram/components/navigationBar/navigationBar.scss
  96. 31
      IOReportSysMP/miniprogram/components/navigationBar/navigationBar.ts
  97. 10
      IOReportSysMP/miniprogram/components/navigationBar/navigationBar.wxml
  98. 6
      IOReportSysMP/miniprogram/components/sysCard/index.d.ts
  99. 20
      IOReportSysMP/miniprogram/components/sysCard/sysCard.js
  100. 4
      IOReportSysMP/miniprogram/components/sysCard/sysCard.json
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,33 @@
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/
*.DS_Store

@ -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();
}
}

Binary file not shown.

@ -0,0 +1,2 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

310
IOReportSysBE/mvnw vendored

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

@ -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%

@ -0,0 +1,172 @@
<?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.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>edu.ncst</groupId>
<artifactId>ioreport</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ioreport</name>
<description>ioreport project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</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>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.35</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- MyBatis Plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<!-- 数据校验 -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<!-- DevTools -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- swagger -->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-swagger2</artifactId>-->
<!-- <version>2.9.2</version>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-swagger-ui</artifactId>-->
<!-- <version>2.9.2</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-boot-starter</artifactId>-->
<!-- <version>3.0.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,211 @@
package edu.ncst.ioreport.utils.generator;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.ioreport.model.BaseEntity;
import edu.ncst.ioreport.utils.generator.converter.CustomTypeConvert;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
public class CodeGenerator extends AutoGenerator {
// 项目信息
private final ProjectInfo projectInfo = null;
// 项目路径
String projectPath = System.getProperty("user.dir");
// 包名
private final String basePackage = "edu.ncst.ioreport";
// 策略配置
private final StrategyConfig strategy = new StrategyConfig();
// 包配置
private final PackageConfig packageConfig = new PackageConfig();
// 表格元数据
private final HashMap<String, TableMetaInfo> tableMetaInfoMap = new HashMap<>();
public CodeGenerator() {
this.loadGlobalConfig();
this.loadDatasourceConfig();
this.loadCustomConfig();
this.loadTemplateConfig();
this.loadPackageConfig();
this.loadStrategyConfig();
}
// 加载全局配置
private void loadGlobalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(projectPath + "/src/main/java");
globalConfig.setOpen(false);
globalConfig.setSwagger2(true);
setGlobalConfig(globalConfig);
}
// 数据源配置
private void loadDatasourceConfig() {
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/award_sys?useUnicode=true&useSSL=false&characterEncoding=utf8&allowPublicKeyRetrieval=True");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("smart");
dsc.setPassword("hblgjg@2020");
// 自定义类型转换
CustomTypeConvert customTypeConvert = new CustomTypeConvert();
dsc.setTypeConvert(customTypeConvert);
setDataSource(dsc);
}
// 自定义配置
private void loadCustomConfig() {
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
Map<String, Object> map = new HashMap<>();
map.put("string", StringUtils.class);
setMap(map);
}
public void initTableMap(TableInfo tableInfo) {
Map<String, Object> map = getMap();
log.info(tableMetaInfoMap.get(tableInfo.getName()).toString());
map.put("tableMetaInfo", tableMetaInfoMap.get(tableInfo.getName()));
setMap(map);
}
};
// 如果模板引擎是 velocity
String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapping/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
cfg.setFileOutConfigList(focList);
setCfg(cfg);
}
// 配置模板
private void loadTemplateConfig() {
TemplateConfig templateConfig = new TemplateConfig();
templateConfig.setController("templates/controller.java");
templateConfig.setXml(null);
setTemplate(templateConfig);
}
// 包配置
private void loadPackageConfig() {
packageConfig.setParent(basePackage);
setPackageInfo(packageConfig);
}
// 策略配置
private void loadStrategyConfig() {
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 填充字段
TableFill createTimeFill = new TableFill("create_time", FieldFill.INSERT);
TableFill createUserIdFill = new TableFill("create_user_id", FieldFill.INSERT);
TableFill updateTimeFill = new TableFill("update_time", FieldFill.INSERT_UPDATE);
TableFill updateUserIdFill = new TableFill("update_user_id", FieldFill.INSERT_UPDATE);
List<TableFill> tableFillList = new ArrayList<>();
tableFillList.add(createTimeFill);
tableFillList.add(createUserIdFill);
tableFillList.add(updateTimeFill);
tableFillList.add(updateUserIdFill);
strategy.setTableFillList(tableFillList);
strategy.setLogicDeleteFieldName("delete_time");
strategy.setControllerMappingHyphenStyle(true);
}
// 加载模块信息
public void loadModuleInfo(ModuleInfo moduleInfo) {
// 获取数据库表名称
List<TableMetaInfo> tables = moduleInfo.getTables();
List<String> tableNameList = new ArrayList<>();
for (TableMetaInfo tableMetaInfo : tables) {
tableNameList.add(tableMetaInfo.getTableName());
tableMetaInfoMap.put(tableMetaInfo.getTableName(), tableMetaInfo);
}
String[] tableNames = new String[tableNameList.size()];
tableNameList.toArray(tableNames);
// 根据配置加载策略
strategy.setInclude(tableNames);
strategy.setTablePrefix(moduleInfo.getTablePrefix() + "_");
if (moduleInfo.getExtendBaseEntity()) {
strategy.setSuperEntityClass(BaseEntity.class);
strategy.setSuperEntityColumns("create_time", "create_user_id", "update_time", "update_user_id", "delete_time", "delete_user_id");
}
setStrategy(strategy);
// 设置包
String moduleName = moduleInfo.getModuleName();
if (moduleName != null && !moduleName.equals("")) {
packageConfig.setEntity("model." + moduleName);
packageConfig.setController("controller." + moduleName);
packageConfig.setMapper("mapper." + moduleName);
packageConfig.setServiceImpl("service.impl." + moduleName);
setPackageInfo(packageConfig);
}
}
// 生成代码
public void generateCode() {
execute();
}
// public static void main(String[] args) throws IOException {
// ObjectMapper mapper = new ObjectMapper();
// URL configFileURL = CodeGenerator.class.getClassLoader().getResource("project.json");
//
// assert configFileURL != null;
// File configFile = new File(configFileURL.getFile());
// ProjectInfo projectInfo = mapper.readValue(configFile, ProjectInfo.class);
// log.info(projectInfo.toString());
// List<ModuleInfo> modules = projectInfo.getModules();
// for (ModuleInfo moduleInfo : modules) {
// CodeGenerator codeGenerator = new CodeGenerator();
// codeGenerator.loadModuleInfo(moduleInfo);
// codeGenerator.generateCode();
// }
// }
}

@ -0,0 +1,25 @@
package edu.ncst.ioreport.utils.generator;
import lombok.Data;
import java.util.List;
@Data
public class ModuleInfo {
// 模块显示文本
private String moduleLabel;
// 模块名称
private String moduleName;
// 表格前缀
private String tablePrefix;
// 表格信息列表
private List<TableMetaInfo> tables;
// 是否继承自基类
private Boolean extendBaseEntity = false;
}

@ -0,0 +1,19 @@
package edu.ncst.ioreport.utils.generator;
import lombok.Data;
import java.util.List;
@Data
public class ProjectInfo {
// 项目显示文本
private String projectLabel;
// 项目名称
private String projectName;
// 模块列表
private List<ModuleInfo> modules;
}

@ -0,0 +1,25 @@
package edu.ncst.ioreport.utils.generator;
import lombok.Data;
import java.util.List;
@Data
public class TableMetaInfo {
// 表格显示文本
private String tableLabel;
// 表格名称
private String tableName;
// 是否继承自基类
private Boolean extendBaseEntity = false;
// 是否为关系表
private Boolean relationTable = false;
// 主键列表
private List<String> primaryKeys;
}

@ -0,0 +1,73 @@
package edu.ncst.ioreport.utils.generator.converter;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.ITypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
public class CustomTypeConvert implements ITypeConvert {
@Override
public IColumnType processTypeConvert(GlobalConfig globalConfig, String fieldType) {
String t = fieldType.toLowerCase();
if (t.contains("char")) {
return DbColumnType.STRING;
} else if (t.contains("bigint")) {
return DbColumnType.LONG;
} else if (t.contains("tinyint(1)")) {
return DbColumnType.BOOLEAN;
} else if (t.contains("int")) {
return DbColumnType.INTEGER;
} else if (t.contains("text")) {
return DbColumnType.STRING;
} else if (t.contains("bit")) {
return DbColumnType.BOOLEAN;
} else if (t.contains("decimal")) {
return DbColumnType.BIG_DECIMAL;
} else if (t.contains("clob")) {
return DbColumnType.CLOB;
} else if (t.contains("blob")) {
return DbColumnType.BLOB;
} else if (t.contains("binary")) {
return DbColumnType.BYTE_ARRAY;
} else if (t.contains("float")) {
return DbColumnType.FLOAT;
} else if (t.contains("double")) {
return DbColumnType.DOUBLE;
} else if (t.contains("enum")) {
return DbColumnType.STRING;
} else if (t.contains("json")) {
return new JSONColumnType();
} else if (t.contains("date") || t.contains("time") || t.contains("year")) {
switch (globalConfig.getDateType()) {
case ONLY_DATE:
return DbColumnType.DATE;
case SQL_PACK:
switch (t) {
case "date":
return DbColumnType.DATE_SQL;
case "time":
return DbColumnType.TIME;
case "year":
return DbColumnType.DATE_SQL;
default:
return DbColumnType.TIMESTAMP;
}
case TIME_PACK:
switch (t) {
case "date":
return DbColumnType.LOCAL_DATE;
case "time":
return DbColumnType.LOCAL_TIME;
case "year":
return DbColumnType.YEAR;
default:
return DbColumnType.LOCAL_DATE_TIME;
}
}
}
return DbColumnType.STRING;
}
}

@ -0,0 +1,17 @@
package edu.ncst.ioreport.utils.generator.converter;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
public class JSONColumnType implements IColumnType {
@Override
public String getType() {
return "HashMap<String, Object>";
}
@Override
public String getPkg() {
return "java.util.HashMap";
}
}

@ -0,0 +1,79 @@
{
"projectLabel": "出入校报备系统",
"projectName": "ioreport-mgt",
"modules": [
{
"moduleLabel": "系统管理",
"moduleName": "system",
"tablePrefix": "sys",
"tables": [
{
"tableLabel": "用户",
"tableName": "sys_user"
},
{
"tableLabel": "角色",
"tableName": "sys_role"
},
{
"tableLabel": "用户角色",
"tableName": "sys_user_role",
"relationTable": true
},
{
"tableLabel": "角色菜单",
"tableName": "sys_role_menu",
"relationTable": true
},
{
"tableLabel": "角色单位",
"tableName": "sys_role_dept",
"relationTable": true
},
{
"tableLabel": "菜单",
"tableName": "sys_menu"
},
{
"tableLabel": "字典",
"tableName": "sys_dict"
},
{
"tableLabel": "字典类型",
"tableName": "sys_dict_type"
},
{
"tableLabel": "操作日志",
"tableName": "sys_operation_log"
},
{
"tableLabel": "登录日志",
"tableName": "sys_login_log"
},
{
"tableLabel": "系统配置",
"tableName": "sys_config"
}
]
},
{
"moduleLabel": "设备管理",
"moduleName": "equipment",
"extendBaseEntity": true,
"tables": [
{
"tableLabel": "设备",
"tableName": "equipment"
},
{
"tableLabel": "设备分类",
"tableName": "equipment_category"
},
{
"tableLabel": "设备制造商",
"tableName": "manufacturer"
}
]
}
]
}

@ -0,0 +1,97 @@
package ${package.Controller};
import ${package.Entity}.${entity};;
import edu.ncst.equmanager.qo.Query;
import ${package.Service}.I${entity}Service;
import edu.ncst.equmanager.utils.ResponseUtils;
import edu.ncst.equmanager.utils.ResultUtils;
import edu.ncst.equmanager.vo.ListResultVO;
import edu.ncst.equmanager.vo.ResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import lombok.extern.slf4j.Slf4j;
#if(${restControllerStyle})
import org.springframework.web.bind.annotation.RestController;
#else
import org.springframework.stereotype.Controller;
#end
#if(${superControllerClassPackage})
import ${superControllerClassPackage};
#end
/**
* $!{table.comment} 控制器
*/
@Api(description = "$!{table.comment} 控制器", tags = "$!{table.controllerName}")
@Slf4j
#if(${restControllerStyle})
@RestController
#else
@Controller
#end
@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
#if(${kotlin})
class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
#else
#if(${superControllerClass})
public class ${table.controllerName} extends ${superControllerClass} {
#else
public class ${table.controllerName} {
#end
private final I${entity}Service ${cfg.string.firstToLowerCase(${entity})}Service;
public ${entity}Controller(I${entity}Service ${cfg.string.firstToLowerCase(${entity})}Service) {
this.${cfg.string.firstToLowerCase(${entity})}Service = ${cfg.string.firstToLowerCase(${entity})}Service;
}
@ApiOperation("获取$!{table.comment}列表")
@GetMapping("/list")
public ResultVO<ListResultVO<${entity}>> get${entity}List(Query query) {
ListResultVO<${entity}> ${cfg.string.firstToLowerCase(${entity})}List = ${cfg.string.firstToLowerCase(${entity})}Service.get${entity}List(query);
return ResultUtils.success("ok", ${cfg.string.firstToLowerCase(${entity})}List);
}
#if(!${cfg.tableMetaInfo.relationTable})
@ApiOperation("获取$!{table.comment}详情")
@PostMapping("/detail")
public ResultVO<${entity}> get${entity}Detail(@RequestParam Integer id) {
${entity} ${cfg.string.firstToLowerCase(${entity})}Detail = ${cfg.string.firstToLowerCase(${entity})}Service.get${entity}Detail(id);
return ResultUtils.success("ok", ${cfg.string.firstToLowerCase(${entity})}Detail);
}
#end
@ApiOperation("添加$!{table.comment}")
@PostMapping("/add")
public ResultVO<${entity}> add${entity}(@RequestBody ${entity} ${cfg.string.firstToLowerCase(${entity})}) {
${entity} result = ${cfg.string.firstToLowerCase(${entity})}Service.add${entity}(${cfg.string.firstToLowerCase(${entity})});
return ResultUtils.success("ok", result);
}
#if(!${cfg.tableMetaInfo.relationTable})
@ApiOperation("修改$!{table.comment}")
@PutMapping("/modify")
public ResultVO<${entity}> modify${entity}(@RequestBody ${entity} ${cfg.string.firstToLowerCase(${entity})}) {
${entity} result = ${cfg.string.firstToLowerCase(${entity})}Service.modify${entity}(${cfg.string.firstToLowerCase(${entity})});
return ResultUtils.success("ok", result);
}
#end
@ApiOperation("删除$!{table.comment}")
@DeleteMapping("/delete")
public ResponseEntity<?> delete${entity}(@RequestParam Integer id) {
${cfg.string.firstToLowerCase(${entity})}Service.delete${entity}(id);
return ResponseUtils.success("删除成功");
}
}
#end

@ -0,0 +1,17 @@
package ${package.Mapper};
import ${package.Entity}.${entity};
import ${superMapperClassPackage};
import org.springframework.stereotype.Repository;
/**
* $!{table.comment} Mapper 接口
*/
@Repository
#if(${kotlin})
interface ${table.mapperName} : ${superMapperClass}<${entity}>
#else
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
}
#end

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${package.Mapper}.${table.mapperName}">
#if(${enableCache})
<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
#end
#if(${baseResultMap})
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
#foreach($field in ${table.fields})
#if(${field.keyFlag})##生成主键排在第一位
<id column="${field.name}" property="${field.propertyName}" />
#end
#end
#foreach($field in ${table.commonFields})##生成公共字段
<result column="${field.name}" property="${field.propertyName}" />
#end
#foreach($field in ${table.fields})
#if(!${field.keyFlag})##生成普通字段
<result column="${field.name}" property="${field.propertyName}" />
#end
#end
</resultMap>
#end
#if(${baseColumnList})
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
#foreach($field in ${table.commonFields})
${field.columnName},
#end
${table.fieldNames}
</sql>
#end
</mapper>

@ -0,0 +1,161 @@
package ${package.Entity};
#foreach($pkg in ${table.importPackages})
import ${pkg};
#end
#if(${swagger2})
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
#end
#if(${entityLombokModel})
import lombok.Data;
import lombok.EqualsAndHashCode;
#if(${chainModel})
import lombok.experimental.Accessors;
#end
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import com.baomidou.mybatisplus.annotation.*;
#end
/**
* $!{table.comment}
*/
#if(${swagger2})
@ApiModel(value="${entity}", description="$!{table.comment}")
#end
#if(${entityLombokModel})
@Data
#if(${superEntityClass})
@EqualsAndHashCode(callSuper = true)
#else
@EqualsAndHashCode(callSuper = false)
#end
#if(${chainModel})
@Accessors(chain = true)
#end
#end
#if(${table.convert})
@TableName("${table.name}")
#end
#if(${superEntityClass})
@TableName(autoResultMap = true)
public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
#elseif(${activeRecord})
public class ${entity} extends Model<${entity}> {
#else
public class ${entity} implements Serializable {
#end
#if(${entitySerialVersionUID})
private static final long serialVersionUID=1L;
#end
## ---------- BEGIN 字段循环遍历 ----------
#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if("$!field.comment" != "")
#if(${swagger2})
@ApiModelProperty(value = "${field.comment}")
#else
/**
* ${field.comment}
*/
#end
#end
#if(${field.keyFlag})
## 主键
#if(${field.keyIdentityFlag})
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
#elseif(!$null.isNull(${idType}) && "$!idType" != "")
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
#elseif(${field.convert})
@TableId("${field.annotationColumnName}")
#end
## 普通字段
#elseif(${field.fill})
## ----- 存在字段填充设置 -----
#if(${field.convert})
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
#else
@TableField(fill = FieldFill.${field.fill})
#end
#elseif(${field.convert})
@TableField("${field.annotationColumnName}")
#end
## 乐观锁注解
#if(${versionFieldName}==${field.name})
@Version
#end
## JSON 类型处理器
#if(${field.type} == "json")
@TableField(typeHandler = JacksonTypeHandler.class)
#end
## 逻辑删除注解
#if(${logicDeleteFieldName}==${field.name})
@TableLogic
#end
private ${field.propertyType} ${field.propertyName};
#end
## ---------- END 字段循环遍历 ----------
#if(!${entityLombokModel})
#foreach($field in ${table.fields})
#if(${field.propertyType.equals("boolean")})
#set($getprefix="is")
#else
#set($getprefix="get")
#end
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
#if(${chainModel})
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#else
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#end
this.${field.propertyName} = ${field.propertyName};
#if(${chainModel})
return this;
#end
}
#end
## --foreach end---
#end
## --end of #if(!${entityLombokModel})--
#if(${entityColumnConstant})
#foreach($field in ${table.fields})
public static final String ${field.name.toUpperCase()} = "${field.name}";
#end
#end
#if(${activeRecord})
@Override
protected Serializable pkVal() {
#if(${keyPropertyName})
return this.${keyPropertyName};
#else
return null;
#end
}
#end
#if(!${entityLombokModel})
@Override
public String toString() {
return "${entity}{" +
#foreach($field in ${table.fields})
#if($!{foreach.index}==0)
"${field.propertyName}=" + ${field.propertyName} +
#else
", ${field.propertyName}=" + ${field.propertyName} +
#end
#end
"}";
}
#end
}

@ -0,0 +1,31 @@
package ${package.Service};
import ${package.Entity}.${entity};
import ${superServiceClassPackage};
import edu.ncst.equmanager.vo.ListResultVO;
import edu.ncst.equmanager.qo.Query;
/**
* $!{table.comment} 服务类
*/
#if(${kotlin})
interface ${table.serviceName} : ${superServiceClass}<${entity}>
#else
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
ListResultVO<${entity}> get${entity}List(Query query);
#if(!${cfg.tableMetaInfo.relationTable})
${entity} get${entity}Detail(Integer id);
#end
${entity} add${entity}(${entity} ${cfg.string.firstToLowerCase(${entity})});
#if(!${cfg.tableMetaInfo.relationTable})
${entity} modify${entity}(${entity} ${cfg.string.firstToLowerCase(${entity})});
#end
boolean delete${entity}(Integer id);
}
#end

@ -0,0 +1,106 @@
package ${package.ServiceImpl};
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import edu.ncst.equmanager.qo.Query;
import edu.ncst.equmanager.exception.BusinessException;
import edu.ncst.equmanager.exception.CodeMsg;
import edu.ncst.equmanager.vo.ListResultVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* $!{table.comment} 服务实现类
*/
@Service
#if(${kotlin})
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
}
#else
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
private final ${entity}Mapper ${cfg.string.firstToLowerCase(${entity})}Mapper;
public ${entity}ServiceImpl(${entity}Mapper ${cfg.string.firstToLowerCase(${entity})}Mapper) {
this.${cfg.string.firstToLowerCase(${entity})}Mapper = ${cfg.string.firstToLowerCase(${entity})}Mapper;
}
// 获取$!{table.comment}列表
@Override
public ListResultVO<${entity}> get${entity}List(Query query) {
QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
Page<${entity}> pageRequest = query.toPageRequest();
Page<${entity}> page = ${cfg.string.firstToLowerCase(${entity})}Mapper.selectPage(pageRequest, queryWrapper);
// 封装返回结果
ListResultVO<${entity}> listResultVO = new ListResultVO<>();
listResultVO.setList(page.getRecords());
listResultVO.setTotal(page.getTotal());
listResultVO.setCurrent(page.getCurrent());
return listResultVO;
}
#if(!${cfg.tableMetaInfo.relationTable})
// 获取$!{table.comment}详情
@Override
public ${entity} get${entity}Detail(Integer id) {
${entity} ${cfg.string.firstToLowerCase(${entity})} = ${cfg.string.firstToLowerCase(${entity})}Mapper.selectById(id);
return ${cfg.string.firstToLowerCase(${entity})};
}
#end
// 添加$!{table.comment}
@Transactional
@Override
public ${entity} add${entity}(${entity} ${cfg.string.firstToLowerCase(${entity})}) {
int insert = ${cfg.string.firstToLowerCase(${entity})}Mapper.insert(${cfg.string.firstToLowerCase(${entity})});
#if(!${cfg.tableMetaInfo.relationTable})
${entity} result = get${entity}Detail(${cfg.string.firstToLowerCase(${entity})}.getId());
#end
if (insert == 1) {
#if(${cfg.tableMetaInfo.relationTable})
return ${cfg.string.firstToLowerCase(${entity})};
#else
return result;
#end
} else {
throw new BusinessException(CodeMsg.ADD_ERROR);
}
}
#if(!${cfg.tableMetaInfo.relationTable})
// 修改$!{table.comment}
@Transactional
@Override
public ${entity} modify${entity}(${entity} ${cfg.string.firstToLowerCase(${entity})}) {
int update = ${cfg.string.firstToLowerCase(${entity})}Mapper.updateById(${cfg.string.firstToLowerCase(${entity})});
${entity} result = get${entity}Detail(${cfg.string.firstToLowerCase(${entity})}.getId());
if (update == 1) {
return result;
} else {
throw new BusinessException(CodeMsg.MODIFY_ERROR);
}
}
#end
// 删除$!{table.comment}
@Transactional
@Override
public boolean delete${entity}(Integer id) {
int delete = ${cfg.string.firstToLowerCase(${entity})}Mapper.deleteById(id);
if (delete == 1) {
return true;
} else {
throw new BusinessException(CodeMsg.DELETE_ERROR);
}
}
}
#end

@ -0,0 +1,33 @@
package edu.ncst.ioreport;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.spring4all.swagger.EnableSwagger2Doc;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableSwagger2Doc
@SpringBootApplication
@MapperScan(basePackages = {"edu.ncst.ioreport.mapper"})
@EnableTransactionManagement
@EnableCaching
@EnableAspectJAutoProxy(exposeProxy=true)
public class IOReprotApplication {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
public static void main(String[] args) {
SpringApplication.run(IOReprotApplication.class, args);
}
}

@ -0,0 +1,34 @@
package edu.ncst.ioreport.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Service;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Service
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
Map map = new HashMap();
map.put("code",403);
map.put("msg", "无访问权限");
map.put("data","");
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().write(objectMapper.writeValueAsString(map));
}
}

@ -0,0 +1,47 @@
package edu.ncst.ioreport.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class JsonConfig {
@Bean
public HttpMessageConverter configureMessageConverters() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
// 保留map空的字段
SerializerFeature.WriteMapNullValue,
// 将String类型的null转成""
SerializerFeature.WriteNullStringAsEmpty,
// 将Number类型的null转成0
SerializerFeature.WriteNullNumberAsZero,
// 将List类型的null转成[]
SerializerFeature.WriteNullListAsEmpty,
// 将Boolean类型的null转成false
SerializerFeature.WriteNullBooleanAsFalse,
// 避免循环引用
SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
List<MediaType> mediaTypeList = new ArrayList<>();
// 解决中文乱码问题,相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
mediaTypeList.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypeList);
return converter;
}
}

@ -0,0 +1,208 @@
package edu.ncst.ioreport.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.ioreport.config.security.DataBaseUrlVoter;
import edu.ncst.ioreport.config.security.filter.AuthCheckFilter;
import edu.ncst.ioreport.config.security.filter.LoginFilter;
import edu.ncst.ioreport.config.security.provider.WechatIdLoginProvider;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.service.ILoginLogService;
import edu.ncst.ioreport.service.impl.UserServiceImpl;
import edu.ncst.ioreport.utils.ResultUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.access.vote.UnanimousBased;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
/**
* 安全配置
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserServiceImpl userService;
@Autowired
private ILoginLogService loginLogService;
@Autowired
private DataBaseUrlVoter dataBaseUrlVoter;
@Autowired
private RedisTemplate<String, String> redisCacheTemplate;
@Autowired
private WechatIdLoginProvider wechatIdLoginProvider;
/**
* 认证失败处理类
*/
@Autowired
CustomAccessDeniedHandler accessDeniedHandler;
//org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126)
/**
* 解决 无法直接注入 AuthenticationManager
*
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
/**
* 权限白名单
* 注意该名单下匹配的 URL 不会经过鉴权因此也无法获取当前用户的信息
*/
private final String[] WHITE_LIST = {
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/**",
"/swagger-ui.html",
"/webjars/**",
"/api/captcha.jpg",
"/websocket/**",
"/api/image/get/**",
"/common/download/**",
"/test/**",
"/*.html",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/error*"
};
/**
* 密码加密器
*/
@Bean
public PasswordEncoder passwordEncoderBean() {
return new BCryptPasswordEncoder();
}
/**
* 权限投票访问决策管理器
*/
@Bean
public AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters
= Arrays.asList(
new WebExpressionVoter(),
new RoleVoter(),//主要用来判断当前请求是否具备该接口所需要的角色
dataBaseUrlVoter,
new AuthenticatedVoter());
return new UnanimousBased(decisionVoters);//要求所有 AccessDecisionVoter 均返回肯定的结果时,才代表授予权限。
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
auth.authenticationProvider(wechatIdLoginProvider);
}
/**
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问非remember-me下自动登录
* hasAnyAuthority | 如果有参数参数表示权限则其中任何一个权限可以访问
* hasAnyRole | 如果有参数参数表示角色则其中任何一个角色可以访问
* hasAuthority | 如果有参数参数表示权限则其权限可以访问
* hasIpAddress | 如果有参数参数表示IP地址如果用户IP和参数匹配则可以访问
* hasRole | 如果有参数参数表示角色则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
//权限验证 基于资源配置
// HttpSecurity 及WebSecurity 作用是不一样的:
// WebSecurity 主要针对的全局的忽略规则,
// HttpSecurity主要是权限控制规则。
@Override
protected void configure(HttpSecurity http) throws Exception {
//允许跨域
http.cors().and().anonymous().and()
// CRSF禁用,因为不使用session
.csrf().disable()
.formLogin().disable().httpBasic().disable()
.authorizeRequests()
.accessDecisionManager(accessDecisionManager())//访问决策管理器
.antMatchers("/api/login").permitAll()
.antMatchers("/system/init").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(accessDeniedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterAfter(new AuthCheckFilter(redisCacheTemplate), UsernamePasswordAuthenticationFilter.class)
.addFilterAt(
new LoginFilter(authenticationManager(), loginLogService, redisCacheTemplate), UsernamePasswordAuthenticationFilter.class
)
.exceptionHandling()//登录认证失败
.authenticationEntryPoint(((request, response, authException) -> {
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(ResultUtils.error(CodeMsg.USER_NEED_LOGIN)));
out.flush();
out.close();
}));
// 退出登录
http.logout()
.logoutUrl("/logout")
.deleteCookies("JSESSIONID")
.logoutSuccessHandler(((request, response, authentication) -> {
PrintWriter out = response.getWriter();
response.setContentType("application/json");
out.write(new ObjectMapper().writeValueAsString(ResultUtils.success("注销成功")));
out.flush();
out.close();
}));
}
// @Override
// protected void configure(HttpSecurity httpSecurity) throws Exception{
// //调试阶段
// httpSecurity.csrf().disable().authorizeRequests();
// httpSecurity.authorizeRequests().anyRequest()
// .permitAll().and().logout().permitAll();
// }
//用于配置全局的某些通用事物,例如静态资源等
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(WHITE_LIST);
}
}

@ -0,0 +1,15 @@
package edu.ncst.ioreport.config.exception;
import org.springframework.security.core.AuthenticationException;
public class NotBindUserException extends AuthenticationException {
public NotBindUserException(String msg, Throwable t) {
super(msg, t);
}
public NotBindUserException(String msg) {
super(msg);
}
}

@ -0,0 +1,109 @@
package edu.ncst.ioreport.config.security;
import edu.ncst.ioreport.model.Role;
import edu.ncst.ioreport.service.IResourceService;
import edu.ncst.ioreport.utils.URLUtils;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* URL 鉴权投票器
*/
@Component
public class DataBaseUrlVoter implements AccessDecisionVoter<FilterInvocation> {
@Autowired
private IResourceService resourceService;
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
@Override
public int vote(Authentication authentication, FilterInvocation fi, Collection<ConfigAttribute> attributes) {
if (authentication == null) {
return ACCESS_DENIED; // 反对票
}
String url = fi.getRequestUrl(); // 当前请求的URL
String urlWithoutQueryString = URLUtils.removeQueryString(url);
// Current User Info
Object details = authentication.getDetails();
if (details instanceof UserInfoVO) {
UserInfoVO userInfoVO = (UserInfoVO) details;
AntPathMatcher antPathMatcher = new AntPathMatcher();
//获取不限用户角色的资源
List<String> permitAllResourceURLs = resourceService.getPermitAllResourceURLs();
// Permit All Resource
for (String permitUrl : permitAllResourceURLs) {
boolean match = antPathMatcher.match(permitUrl, urlWithoutQueryString);
if (match) {
return ACCESS_GRANTED; // 赞同票
}
}
// 判断用户角色信息
// 反对票:1、没有角色信息 2、角色未绑定该资源
// 赞成票:用户是超级管理员
List<String> roles = userInfoVO.getRoles();
if (roles == null || roles.isEmpty()) {
return ACCESS_DENIED; // 反对票
}
List<String> roleNames = roles.stream().map(String::toString).collect(Collectors.toList());
// Super Admin User Always Pass
if (roleNames.contains("SUPER_ADMIN")) {
return ACCESS_GRANTED; // 赞同票
}
List<String> rolesResourceList = resourceService.getRolesResourceList(roleNames);//获取目标角色绑定的资源
// Role Resource
if (rolesResourceList == null) {
return ACCESS_DENIED; // 反对票
}
for (String allowUrl : rolesResourceList) {
boolean match = antPathMatcher.match(allowUrl, urlWithoutQueryString);
if (match) {
return ACCESS_GRANTED; // 赞同票
}
}
}
return ACCESS_DENIED;
}
Collection<? extends GrantedAuthority> extractAuthorities(
Authentication authentication) {
return authentication.getAuthorities();
}
}

@ -0,0 +1,104 @@
package edu.ncst.ioreport.config.security.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.ioreport.config.security.token.JwtAuthenticationToken;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.model.Role;
import edu.ncst.ioreport.utils.ResponseUtils;
import edu.ncst.ioreport.utils.ResultUtils;
import edu.ncst.ioreport.vo.ResultVO;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
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.ArrayList;
import java.util.List;
/**
* 用户凭证检查过滤器
* 并不是所有的container都像我们期望的只过滤一次servlet版本不同表现也不同
* OncePerRequestFilter可以保证一次请求只通过一次过滤器推荐自定义的授权过滤器继承OncePerRequestFilter
*/
@Slf4j
public class AuthCheckFilter extends OncePerRequestFilter {
private final RedisTemplate<String, String> stringRedisTemplate;
public AuthCheckFilter(RedisTemplate<String, String> stringRedisTemplate) {
super();
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String jwtToken = null;
String authorization = request.getHeader("Authorization");
log.info("开始鉴权====header Authorization====" +authorization);
if (authorization != null && authorization.startsWith("Bearer ")) {
jwtToken = authorization.replace("Bearer ", "");
log.info("获取到token====header====");
} else {
log.info("header中无token,进入过滤器链");
filterChain.doFilter(request, response);
return;
}
if (jwtToken == null || "".equals(jwtToken)) {
log.error("鉴权TOKEN:未获取,用户需要登录");
ResultVO<Object> resultVO = ResultUtils.error(CodeMsg.USER_NEED_LOGIN);
ResponseUtils.output(response, resultVO);
} else {
log.info("鉴权TOKEN:" +"Bearer " + jwtToken);
}
try {
// 解析TOKEN
Jws<Claims> jws = Jwts.parser().setSigningKey("ncst20221003")
.parseClaimsJws(jwtToken);
Claims claims = jws.getBody();
String userName = claims.getSubject();
//可以通过控制redis数据从服务端强制下线用户
if(!stringRedisTemplate.hasKey("jwt_token:"+userName)){
throw new ExpiredJwtException(null,jws.getBody(),"登录失效");
}
// 获取用户信息
String userInfoJSON = (String) claims.get("userInfo");
ObjectMapper objectMapper = new ObjectMapper();
UserInfoVO userInfoVO = objectMapper.readValue(userInfoJSON, UserInfoVO.class);
// 获取角色列表
List<String> roles = userInfoVO.getRoles();
List<GrantedAuthority> authorities = new ArrayList<>();
if (roles != null && !roles.isEmpty()) {
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
}
// 将 TOKEN 存到 CONTEXT 当中
JwtAuthenticationToken token = new JwtAuthenticationToken(userName, authorities, userInfoVO);
SecurityContextHolder.getContext().setAuthentication(token);
} catch (ExpiredJwtException e) {
ResultVO<Object> resultVO = ResultUtils.error(CodeMsg.USER_TOKEN_EXPIRED);// 用户凭证过期
ResponseUtils.output(response, resultVO);
} finally {
filterChain.doFilter(request, response);
}
}
}

@ -0,0 +1,208 @@
package edu.ncst.ioreport.config.security.filter;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.ioreport.config.security.token.WechatIdAuthenticationToken;
import edu.ncst.ioreport.exception.BusinessException;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.model.Role;
import edu.ncst.ioreport.model.User;
import edu.ncst.ioreport.service.ILoginLogService;
import edu.ncst.ioreport.utils.ResultUtils;
import edu.ncst.ioreport.vo.ResultVO;
import edu.ncst.ioreport.vo.param.UserLoginVO;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
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.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 统一登录入口
*/
@Slf4j
public class LoginFilter extends AbstractAuthenticationProcessingFilter {//OncePerRequestFilter
private static final String loginUrl = "/api/login";
private final ILoginLogService loginLogService;
private final RedisTemplate<String, String> stringRedisTemplate;
private String tempToken="";
private final int MAX_ATTEMPT = 20;
public LoginFilter(AuthenticationManager authenticationManager, ILoginLogService loginLogService, RedisTemplate<String, String> stringRedisTemplate) {
super(new AntPathRequestMatcher(loginUrl, HttpMethod.POST.name()));
setAuthenticationManager(authenticationManager);
this.loginLogService = loginLogService;
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* 尝试登录
* 根据登录表单的类型type将登录凭证分发给对应的 AuthenticationProvider
* 当前filter的认证逻辑
*/
@Override
public Authentication attemptAuthentication(
HttpServletRequest request, HttpServletResponse response
) throws AuthenticationException, IOException, ServletException {
UserLoginVO paramUserLoginVO = new ObjectMapper().readValue(request.getInputStream(), UserLoginVO.class);
AuthenticationManager authenticationManager = getAuthenticationManager();
request.setAttribute("userLoginVO", paramUserLoginVO);
log.info("尝试登录===="+ paramUserLoginVO);
// if(paramUserLoginVO!=null&&paramUserLoginVO.getWeChatCode()!=null&&paramUserLoginVO.getWeChatCode().trim().length()>0){
// AccessTokenDTO getAccessTokenDTO = WeChatUtils.code2session(paramUserLoginVO.getWeChatCode());
// String weChatId = getAccessTokenDTO.getWeChatId();
// if (weChatId != null && !"".equals(weChatId)) {
// stringRedisTemplate.opsForValue().set("wechat_id"+weChatId,getAccessTokenDTO.getSessionKey());
// }
// }
WechatIdAuthenticationToken token = new WechatIdAuthenticationToken(paramUserLoginVO.getWeChatCode());
request.setAttribute("token", token);
return authenticationManager.authenticate(token);
}
/**
* 登录成功
* 无论以何种方式登录登录成功后都向客户端返回 JWT前端将该 JWT 临时存储到 localStorage 当中以便后续的请求在请求头中携带 JWT
*/
@Override
protected void successfulAuthentication(
HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult
) throws IOException {
Object principal = authResult.getPrincipal();
UserInfoVO userInfoVO = new UserInfoVO();
if (principal instanceof User) {
User user = (User) principal;
BeanUtils.copyProperties(user, userInfoVO);
}
ObjectMapper objectMapper = new ObjectMapper();
String userInfoJSON = objectMapper.writeValueAsString(userInfoVO);
UUID uuid = UUID.randomUUID();
String jwtTokenId = uuid.toString();
// 生成 jwt
String jwt = Jwts.builder()
.claim("userInfo", userInfoJSON)
.setSubject(authResult.getName())
.setExpiration(new Date(System.currentTimeMillis() + 10 * 24 * 60 * 60 * 1000)) // 10天有效
.signWith(SignatureAlgorithm.HS512, "ncst20221003")
.setId(jwtTokenId)
.compact();
stringRedisTemplate.opsForValue().set("jwt_token:"+authResult.getName(),jwt,10, TimeUnit.DAYS);
// stringRedisTemplate.delete("user_attempts:"+request.getRemoteAddr());
// 记录登录日志
loginLogService.addLoginLog(userInfoVO.getId(), true);
// 返回结果
ResultVO<String> result = ResultUtils.success("登录成功", jwt);
response.setContentType("application/json;charset=utf-8");
Cookie cookieToken = new Cookie("SYS_TOKEN", jwt);
cookieToken.setHttpOnly(true);
response.addCookie(cookieToken);
log.info("登录成功");
PrintWriter out = response.getWriter();
out.print(new ObjectMapper().writeValueAsString(result));
out.flush();
out.close();
}
// 将权限列表转换成逗号分隔的字符串
private String convertRoleToString(List<Role> roleList) {
StringBuilder roleStrings = new StringBuilder();
if (roleList == null) {
return "";
}
for (Role role : roleList) {
roleStrings.append(role.getName()).append(",");
}
if (roleStrings.length() > 0) {
roleStrings.deleteCharAt(roleStrings.length() - 1);
}
return roleStrings.toString();
}
// 将权限列表转换成逗号分隔的字符串
private String convertAuthorityToString(Collection<? extends GrantedAuthority> authorities) {
StringBuilder authorityString = new StringBuilder();
for (GrantedAuthority authority : authorities) {
authorityString.append(authority.getAuthority()).append(",");
}
if (authorityString.length() > 0) {
authorityString.deleteCharAt(authorityString.length() - 1);
}
return authorityString.toString();
}
/**
* 登录失败
* 向前端返回登录失败的错误信息
*/
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
ResultVO<?> resultVO;
log.debug("登录失败:"+failed);
if (failed instanceof LockedException) {
resultVO = ResultUtils.error(CodeMsg.USER_IS_LOCKED);
} else if (failed instanceof CredentialsExpiredException) {
resultVO = ResultUtils.error(CodeMsg.USER_CREDENTIALS_EXPIRED);
} else if (failed instanceof AccountExpiredException) {
resultVO = ResultUtils.error(CodeMsg.USER_ACCOUNT_EXPIRED);
} else if (failed instanceof DisabledException) {
resultVO = ResultUtils.error(CodeMsg.USER_IS_DISABLED);
} else if (failed instanceof AuthenticationException) {
Throwable cause = failed.getCause();
if (cause instanceof BusinessException) {
BusinessException businessException = (BusinessException) cause;
resultVO = ResultUtils.error(businessException.getError());
} else {
resultVO = ResultUtils.error(CodeMsg.USER_BAD_CREDENTIALS);
}
} else {
resultVO = ResultUtils.error(CodeMsg.LOGIN_FAIL);
}
// 拦截后直接将错误信息反馈给前端,不经过全局异常处理器(GlobalExceptionHandler)处理
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(new ObjectMapper().writeValueAsString(resultVO));
out.flush();
out.close();
}
}

@ -0,0 +1,60 @@
package edu.ncst.ioreport.config.security.provider;
import edu.ncst.ioreport.config.exception.NotBindUserException;
import edu.ncst.ioreport.config.security.token.WechatIdAuthenticationToken;
import edu.ncst.ioreport.service.IUserService;
import edu.ncst.ioreport.utils.WeChatUtils;
import edu.ncst.ioreport.vo.SessionKey;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class WechatIdLoginProvider implements AuthenticationProvider {
@Autowired
private IUserService userService;
@SneakyThrows
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
log.info("进入到微信登录接口");
// 获取 Code
if (!(authentication instanceof WechatIdAuthenticationToken)) {
return null;
}
WechatIdAuthenticationToken token = (WechatIdAuthenticationToken) authentication;
String code = token.getWechatCode();
SessionKey sessionKeyDTO = WeChatUtils.code2session(code);
if (sessionKeyDTO == null) {
return null;
}
String wechatId = sessionKeyDTO.getWeChatId();
String sessionKey = sessionKeyDTO.getSessionKey();
log.info("小程序登录成功:"+wechatId);
// 查找该 wechatID 已经绑定用户
UserDetails userDetails = userService.loadUserByWechatId(wechatId);
if (userDetails == null) {
throw new NotBindUserException("账号不存在");
} else {
return new WechatIdAuthenticationToken(userDetails);
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(WechatIdAuthenticationToken.class);
}
}

@ -0,0 +1,39 @@
package edu.ncst.ioreport.config.security.token;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.List;
/**
* JWT认证凭证Security Context
*/
public class JwtAuthenticationToken extends AbstractAuthenticationToken {
private final Object principal;
private final Object details;
public JwtAuthenticationToken(Object principal, List<GrantedAuthority> authorities, UserInfoVO userInfoVO) {
super(authorities);
this.principal = principal;
this.details = userInfoVO;
this.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public Object getDetails() {
return this.details;
}
}

@ -0,0 +1,39 @@
package edu.ncst.ioreport.config.security.token;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* 手机验证码方式登录凭证
*/
public class MobileCaptchaAuthenticationToken extends AbstractAuthenticationToken {
// 手机号码
private String phoneNumber;
// 验证码
private String captchaCode;
public MobileCaptchaAuthenticationToken(String phoneNumber, String captchaCode) {
super(null);
this.phoneNumber = phoneNumber;
this.captchaCode = captchaCode;
}
public MobileCaptchaAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
super(authorities);
}
@Override
public Object getCredentials() {
return this.phoneNumber;
}
@Override
public Object getPrincipal() {
return this.captchaCode;
}
}

@ -0,0 +1,51 @@
package edu.ncst.ioreport.config.security.token;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* OpenId 登录
*/
public class WechatIdAuthenticationToken extends AbstractAuthenticationToken {
private String wechatCode;
private final Object principal;
public WechatIdAuthenticationToken(String wechatCode) {
super(null);
this.principal = wechatCode;
this.wechatCode = wechatCode;
}
public WechatIdAuthenticationToken(Object principal) {
super(null);
this.principal = principal;
super.setAuthenticated(true);
}
public WechatIdAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = null;
}
@Override
public Object getCredentials() {
return this.wechatCode;
}
@Override
public Object getPrincipal() {
return this.principal;
}
public String getWechatCode() {
return wechatCode;
}
public void setWechatCode(String wechatCode) {
this.wechatCode = wechatCode;
}
}

@ -0,0 +1,132 @@
package edu.ncst.ioreport.controller;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.model.Resource;
import edu.ncst.ioreport.service.IUserService;
import edu.ncst.ioreport.utils.ResponseUtils;
import edu.ncst.ioreport.utils.ResultUtils;
import edu.ncst.ioreport.vo.ResultVO;
import edu.ncst.ioreport.vo.param.QUser;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/test")
@Api(tags = "TestController")
@Slf4j
public class TestController {
@Autowired
private IUserService userService;
@ApiOperation("get传参,简单类型,requestParam注解")
@GetMapping("/user/detail")
@ResponseBody
public ResponseEntity getUserInfo(@RequestParam(name = "phone", required = false) String param, @RequestParam String name){
if(param==null){
return ResponseUtils.error(CodeMsg.PARAM_ERROR);
}
QUser queryVO = new QUser();
queryVO.setPhone(param);
UserInfoVO user = userService.getUserInfo(queryVO);
return ResponseUtils.success(user);
}
@ApiOperation("post传参,简单类型,requestParam注解")
@PostMapping("/user/detail00")
@ResponseBody
public ResponseEntity getUserInfo00(@RequestParam(name = "param", required = false) String param,@RequestParam String name){
if(param==null){
return ResponseUtils.error(CodeMsg.PARAM_ERROR);
}
QUser queryVO = new QUser();
queryVO.setPhone(param);
UserInfoVO user = userService.getUserInfo(queryVO);
return ResponseUtils.success(user);
}
@ApiOperation("get方法传参,类接收,无注解")
@GetMapping("/user/detail1")
@ResponseBody
public UserInfoVO getUserInfo1(QUser param){
if(param.getPhone()==null){
String s = param.getPhone().toString();
}
UserInfoVO user = userService.getUserInfo(param);
user.setFullName("getUserInfo1");
return user;
}
@ApiOperation("post方法传参,类接收,无注解")
@PostMapping("/user/detail11")
@ResponseBody
public UserInfoVO getUserInfo11(QUser param){
if(param.getPhone()==null){
String s = param.getPhone().toString();
}
UserInfoVO user = userService.getUserInfo(param);
user.setFullName("getUserInfo1");
return user;
}
@ApiOperation("get方法传参,类接收,requestparam注解")
@GetMapping("/user/detail2")
@ResponseBody
public UserInfoVO getUserInfo2(@RequestParam QUser param){
if(param.getPhone()==null){
String s = param.getPhone().toString();
}
UserInfoVO user = userService.getUserInfo(param);
user.setFullName("getUserInfo2");
return user;
}
@ApiOperation("post方法传参,类接收,requestparam注解")
@PostMapping("/user/detail22")
@ResponseBody
public UserInfoVO getUserInfo22(@RequestParam QUser param){
if(param.getPhone()==null){
String s = param.getPhone().toString();
}
UserInfoVO user = userService.getUserInfo(param);
user.setFullName("getUserInfo22");
return user;
}
@ApiOperation("get方法传参,类接收,requestbody注解")
@GetMapping("/user/detail3")
@ResponseBody
public UserInfoVO getUserInfo3(@RequestBody QUser param){
if(param.getPhone()==null){
String s = param.getPhone().toString();
}
UserInfoVO user = userService.getUserInfo(param);
user.setFullName("getUserInfo3");
return user;
}
@ApiOperation("post方法传参,类接收,requestbody注解")
@PostMapping("/user/detail4")
@ResponseBody
public UserInfoVO getUserInfo4(@RequestBody QUser param){
if(param.getPhone()==null){
String s = param.getPhone().toString();
}
UserInfoVO user = userService.getUserInfo(param);
user.setFullName("getUserInfo3");
return user;
}
@ApiOperation("post方法传参,类接收,requestbody注解")
@PostMapping("/user/detailResource")
@ResponseBody
public ResultVO<Resource> getUserInfoResource(@RequestBody Resource param){
return ResultUtils.success(param);
}
}

@ -0,0 +1,56 @@
package edu.ncst.ioreport.controller;
import edu.ncst.ioreport.model.User;
import edu.ncst.ioreport.service.IRoleService;
import edu.ncst.ioreport.service.IUserService;
import edu.ncst.ioreport.utils.ResponseUtils;
import edu.ncst.ioreport.utils.ResultUtils;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.ResultVO;
import edu.ncst.ioreport.vo.param.CurrentUserVO;
import edu.ncst.ioreport.vo.param.QUser;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
;
/**
* 用户 控制器
*/
@Api(description = "用户管理", tags = "UserController")
@Slf4j
@RestController
@RequestMapping("/api/user")
public class UserController {
private final IUserService userService;
private final IRoleService roleService;
public UserController(IUserService userService, IRoleService roleService) {
this.userService = userService;
this.roleService = roleService;
}
@ApiOperation("获取用户列表")
@GetMapping("/list")
public ResultVO<ListResultVO<User>> getUserList(QUser query) {
ListResultVO<User> userList = userService.getUserList(query);
return ResultUtils.success("ok", userList);
}
@ApiOperation("获取当前用户信息")
@GetMapping("/current")
public ResultVO<UserInfoVO> getCurrentUser() {
UserInfoVO currentUserDTO = userService.getCurrentUser();
// roleService.selectRoleAll();
return ResultUtils.success(currentUserDTO);
}
}

@ -0,0 +1,41 @@
package edu.ncst.ioreport.exception;
import org.springframework.security.core.AuthenticationException;
public class BusinessException extends AuthenticationException {
private CodeMsg codeMsg;
public BusinessException(String msg){
super(msg);
codeMsg = CodeMsg.BUSINESS_ERROR.fillArgs(msg);
}
public BusinessException(CodeMsg msg){
super(msg.getMsg());
if(msg==null){
msg=CodeMsg.BUSINESS_ERROR.fillArgs("未知错误");
}
this.codeMsg = msg;
}
public CodeMsg getError() {
if(codeMsg==null){
codeMsg=CodeMsg.BUSINESS_ERROR.fillArgs("未知错误");
}
return codeMsg;
}
@Override
public String getMessage() {
if(codeMsg==null){
String msg = super.getMessage();
if(msg==null){
return CodeMsg.BUSINESS_ERROR.fillArgs("未知错误").getMsg();
} else{
return msg;
}
}
return codeMsg.getMsg();
}
}

@ -0,0 +1,63 @@
package edu.ncst.ioreport.exception;
import lombok.Data;
@Data
public class CodeMsg {
public static final CodeMsg SUCCESS = new CodeMsg(0, "成功");
public static final CodeMsg SUCCESS_MSG = new CodeMsg(0, "%s");
public final static CodeMsg SERVER_ERROR = new CodeMsg(500, "服务器错误:%s");
public static final CodeMsg PARAM_ERROR = new CodeMsg(501, "参数错误:%s");
public static final CodeMsg GLOBAL_ERROR = new CodeMsg(502, "全局错误:%s");
public static final CodeMsg BUSINESS_ERROR = new CodeMsg(503, "业务错误:%s");;
public final static CodeMsg USER_NEED_LOGIN = new CodeMsg(10000, "尚未登录,请登录。");
public final static CodeMsg USERNAME_REQUIRE_NOT_NULL = new CodeMsg(10001, "用户名不能为空");
public final static CodeMsg PASSWORD_REQUIRE_NOT_NULL = new CodeMsg(10002, "用户密码不能为空");
public final static CodeMsg USER_NOT_FOUND = new CodeMsg(10003, "该用户不存在。");
public final static CodeMsg USERNAME_OR_PASSWORD_ERROR = new CodeMsg(10004, "用户名或密码错误");
public final static CodeMsg USER_IS_LOCKED = new CodeMsg(10005, "当前IP已被锁定,请1小时后再试。");
public final static CodeMsg USER_CREDENTIALS_EXPIRED = new CodeMsg(10006, "用户登录凭证过期,请重新登录。");
public final static CodeMsg USER_ACCOUNT_EXPIRED = new CodeMsg(10007, "用户账号过期,请联系管理员。");
public final static CodeMsg USER_IS_DISABLED = new CodeMsg(10008, "该用户已被禁用,请联系管理员。");
public final static CodeMsg USER_BAD_CREDENTIALS = new CodeMsg(10009, "无效的登录凭证,请尝试重新登录");
public final static CodeMsg USER_TOKEN_EXPIRED = new CodeMsg(10010, "用户凭证已过期,请联系管理员。");
public final static CodeMsg NOT_GET_CURRENT_USER_INFO = new CodeMsg(10011, "无法获取当前用户信息。");
public final static CodeMsg CAN_NOT_DATA_ACCESS = new CodeMsg(10012, "当前用户没有访问相关数据的权限。");
public final static CodeMsg LOGIN_FAIL = new CodeMsg(10015, "登录失败,未知原因。");
public final static CodeMsg CAPTCHA_IS_NOT_RIGHT = new CodeMsg(10018, "验证码错误。");
public final static CodeMsg CAPTCHA_IS_EMPTY = new CodeMsg(10019, "验证码不能为空。");
public final static CodeMsg CAPTCHA_IS_EXPIRED = new CodeMsg(10020, "验证码已过期。");
public static final CodeMsg TEMP_TOKEN_NOT_FOUND = new CodeMsg(10021,"无法获取临时授权");
public static final CodeMsg TEMP_TOKEN_EXPIRED = new CodeMsg(10022,"临时授权已过期");
/**
* 基本操作 101XX
*/
public final static CodeMsg FETCH_ERROR = new CodeMsg(10100, "获取数据失败");
public final static CodeMsg ADD_ERROR = new CodeMsg(10101, "添加失败%s");
public final static CodeMsg MODIFY_ERROR = new CodeMsg(10102, "修改失败");
public final static CodeMsg DELETE_ERROR = new CodeMsg(10103, "删除失败");
public final static CodeMsg DELETE_ERROR_RELATION_DATA = new CodeMsg(101031, "存在关联业务数据,删除或禁用失败");
public final static CodeMsg REPEAT_RECORD = new CodeMsg(10104, "字段与已有记录重复");
public final static CodeMsg ENABLE_OR_DISABLE_ERROR = new CodeMsg(10105, "启用或禁用出错。");
public final static CodeMsg CAN_FOUND_DICT = new CodeMsg(10106, "找不到字典。");
public final static CodeMsg FORM_ERROR = new CodeMsg(10107, "表单参数错误");
public static final CodeMsg MORE_THAN_ONE_ITEM = new CodeMsg(10108, "多余一条数据被查出");
public static final CodeMsg ALREADY_EXIST_ITEM = new CodeMsg(10109, "数据重复");
private int code;
private String msg;
public CodeMsg(int i, String s) {
this.code=i;
this.msg=s;
}
public CodeMsg fillArgs(Object... args) {
String message = String.format(msg, args);
return new CodeMsg(code, message);
}
}

@ -0,0 +1,54 @@
package edu.ncst.ioreport.exception.handler;
import edu.ncst.ioreport.exception.BusinessException;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.utils.ResponseUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import lombok.extern.slf4j.Slf4j;
/**
* 自定义异常处理器
*
* @author ieflex
*/
@RestControllerAdvice
@Slf4j
public class InterfaceExceptionHandler {
/**
* 接口 业务异常
*/
@ResponseBody
@ExceptionHandler(BusinessException.class)
public ResponseEntity businessInterfaceException(BusinessException e) {
log.error(e.getMessage(), e);
return ResponseUtils.error(CodeMsg.BUSINESS_ERROR.fillArgs(e.getError()));
}
/**
* 拦截所有运行时的全局异常
*/
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public ResponseEntity runtimeException(RuntimeException e) {
log.error(e.getMessage(), e);
// 返回 JOSN
return ResponseUtils.error(CodeMsg.GLOBAL_ERROR.fillArgs(e.toString()));
}
/**
* 系统异常捕获处理
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public ResponseEntity exception(Exception e) {
log.error(e.getMessage(), e);
return ResponseUtils.error(CodeMsg.SERVER_ERROR.fillArgs(e.toString()));
}
}

@ -0,0 +1,34 @@
package edu.ncst.ioreport.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import java.util.List;
/**
* 自定义 Mapper 接口, 实现 自定义扩展
*
* @param <M> mapper 泛型
* @param <T> table 泛型
* @param <V> vo 泛型
* @author Lion Li
* @since 2021-05-13
*/
@SuppressWarnings("unchecked")
public interface BaseMapperPlus<M, T, V> extends BaseMapper<T> {
Log log = LogFactory.getLog(BaseMapperPlus.class);
int DEFAULT_BATCH_SIZE = 1000;
default List<T> selectList() {
return this.selectList(new QueryWrapper<>());
}
}

@ -0,0 +1,9 @@
package edu.ncst.ioreport.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import edu.ncst.ioreport.model.Resource;
import org.springframework.stereotype.Repository;
@Repository
public interface ResourceMapper extends BaseMapper<Resource> {
}

@ -0,0 +1,25 @@
package edu.ncst.ioreport.mapper;
import edu.ncst.ioreport.model.Role;
import java.util.List;
/**
* 角色表 数据层
*
* @author Lion Li
*/
public interface RoleMapper extends BaseMapperPlus<RoleMapper, Role, Role> {
/**
* 根据条件分页查询角色数据
*
* @param role 角色信息
* @return 角色数据集合信息
*/
List<Role> selectRoleList(Role role);
}

@ -0,0 +1,26 @@
package edu.ncst.ioreport.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import edu.ncst.ioreport.model.User;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 用户 Mapper 接口
*/
@Repository
public interface UserMapper extends BaseMapper<User> {
List<User> getUserList( @Param(Constants.WRAPPER) QueryWrapper queryWrapper);
User getUserDetail(Integer userId);
User getUserByWechatId(String wechatId);
}

@ -0,0 +1,40 @@
package edu.ncst.ioreport.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public abstract class BaseEntity implements Serializable {
@ApiModelProperty(value = "创建时间")
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;
@ApiModelProperty(value = "创建人")
@TableField(value = "create_user_id", fill = FieldFill.INSERT)
private Integer createUserId;
@ApiModelProperty(value = "最后更新时间")
@TableField(value = "last_modify_time", fill = FieldFill.INSERT_UPDATE)
private Date lastModifyTime;
@ApiModelProperty(value = "最后更新者")
@TableField(value = "last_modify_user_id", fill = FieldFill.INSERT_UPDATE)
private Integer lastModifyUserId;
@ApiModelProperty(value = "删除时间")
@TableField("delete_time")
@TableLogic
private Date deleteTime;
@ApiModelProperty(value = "删除者")
@TableField("delete_user_id")
private Integer deleteUserId;
}

@ -0,0 +1,49 @@
package edu.ncst.ioreport.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* 登录日志
*/
@ApiModel(value="LoginLog", description="登录日志")
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("log_login_log")
public class LoginLog implements Serializable {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "登录方式")
private String type;
@ApiModelProperty(value = "用户ID")
private Integer userId;
@ApiModelProperty(value = "登錄用户")
@TableField(exist = false)
private User user;
@ApiModelProperty(value = "登录凭证", notes = "用户名、手机号、电子邮箱或微信登录凭证code")
private String principal;
@ApiModelProperty(value = "IP地址")
private String ipAddress;
@ApiModelProperty(value = "登录时间")
private Date loginTime;
}

@ -0,0 +1,55 @@
package edu.ncst.ioreport.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
@ApiModel(value="Resource", description="资源")
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_resource")
public class Resource implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "资源ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "显示文本")
private String label;
@ApiModelProperty(value = "资源名称(方法签名)")
private String name;
@ApiModelProperty(value = "请求方法类型")
private String method;
@ApiModelProperty(value = "链接")
private String url;
@ApiModelProperty(value = "允许所有访问", notes = "不需要用户登录")
private Boolean permitAll = false;
@ApiModelProperty(value = "上级菜单ID")
private Integer parentId;
@ApiModelProperty(value = "上级菜单ID")
@TableField(exist = false)
private List<Resource> children;
@ApiModelProperty(value = "排序")
private Integer sort;
@ApiModelProperty(value = "是否對所有角色開放",notes = "需要用户登录")
private Boolean isForAll = true;
}

@ -0,0 +1,58 @@
package edu.ncst.ioreport.model;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.util.Objects;
/**
* 角色
*/
@ApiModel(value="Role", description="角色")
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_role")
public class Role {
private static final long serialVersionUID=1L;
@ApiModelProperty(value = "角色ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@ApiModelProperty(value = "角色名称")
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Role role = (Role) o;
return Objects.equals(name, role.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
public static Role forName(String name) {
Role role = new Role();
role.setName(name);
return role;
}
}

@ -0,0 +1,93 @@
package edu.ncst.ioreport.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@ApiModel(value="User", description="用户")
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("user")
public class User extends BaseEntity implements Serializable, UserDetails {
@ApiModelProperty(value = "用户id")
private Integer id;
@ApiModelProperty(value = "教师工号")
private String teacherID;
@ApiModelProperty(value = "用户真实名")
private String fullName;
@ApiModelProperty(value = "地址信息")
private String address;
@ApiModelProperty(value = "手机号")
private String phone;
@ApiModelProperty(value = "所属单位")
private Integer unitId;
@ApiModelProperty(value = "微信小程序id")
private Integer wechatId;
@ApiModelProperty(value = "角色列表")
@TableField(exist = false)
private List<String> roles;
@ApiModelProperty(value = "是否启用 1:启用 0:禁用")
private Boolean enable;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
if (this.roles != null && this.roles.size() > 0) {
List<GrantedAuthority> roleAuthority = roles.stream()
.map((role) -> new SimpleGrantedAuthority("ROLE_" + role))
.collect(Collectors.toList());
grantedAuthorities.addAll(roleAuthority);
}
return grantedAuthorities;
}
@Override
public String getPassword() {
return "";
}
@Override
public String getUsername() {
return teacherID;
}
@JsonIgnore
public boolean isAccountNonExpired() {
return true;
}//用户是否未过期
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}//用户是否未锁定
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}//凭证是否未过期
@Override
public boolean isEnabled() {
return this.enable;
}//是否启用
}

@ -0,0 +1,18 @@
package edu.ncst.ioreport.service;
import edu.ncst.ioreport.model.LoginLog;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.param.QLoginLog;
/**
* 登录日志 服务类
*/
public interface ILoginLogService {
// 查询登录日志列表
ListResultVO<LoginLog> getLoginLogList(QLoginLog query);
// 添加登录日志
void addLoginLog(Integer userId, Boolean success);
}

@ -0,0 +1,22 @@
package edu.ncst.ioreport.service;
import edu.ncst.ioreport.model.Resource;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.Query;
import java.util.List;
public interface IResourceService {
List<Resource> getResourceList(Query query);
List<Integer> getRoleResourceIds(Integer roleId);
List<String> getRolesResourceList(List<String> roleNames);
List<Resource> getPermitAllResourceList();
List<String> getPermitAllResourceURLs();
}

@ -0,0 +1,26 @@
package edu.ncst.ioreport.service;
import edu.ncst.ioreport.model.Role;
import java.util.List;
/**
* 角色业务层
*
*/
public interface IRoleService {
List<Role> insertRole() ;
List<Role> selectRoleList(Role role);
/**
* 查询所有角色
*
* @return 角色列表
*/
List<Role> selectRoleAll();
}

@ -0,0 +1,19 @@
package edu.ncst.ioreport.service;
import edu.ncst.ioreport.model.User;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.param.CurrentUserVO;
import edu.ncst.ioreport.vo.param.QUser;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import org.springframework.security.core.userdetails.UserDetails;
public interface IUserService {
UserInfoVO getUserInfo(QUser query);
ListResultVO<User> getUserList(QUser query);
UserInfoVO getCurrentUser();
UserDetails loadUserByWechatId(String wechatId);
}

@ -0,0 +1,27 @@
package edu.ncst.ioreport.service.impl;
import edu.ncst.ioreport.model.LoginLog;
import edu.ncst.ioreport.service.ILoginLogService;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.param.QLoginLog;
import org.springframework.stereotype.Service;
/**
* 登录日志 服务实现类
*/
@Service
public class LoginLogServiceImpl implements ILoginLogService {
@Override
public ListResultVO<LoginLog> getLoginLogList(QLoginLog query) {
return null;
}
@Override
public void addLoginLog(Integer userId, Boolean success) {
}
//project/declarationAdd
}

@ -0,0 +1,62 @@
package edu.ncst.ioreport.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import edu.ncst.ioreport.mapper.ResourceMapper;
import edu.ncst.ioreport.model.Resource;
import edu.ncst.ioreport.service.IResourceService;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.*;
import java.lang.reflect.Method;
import java.util.*;
@Service
public class ResourceServiceImpl implements IResourceService {
@Autowired
private ResourceMapper resourceMapper;
// 欲扫描的包路径
private static final String SCAN_PACKAGE = "edu.ncst.ioreport.controller";
/**
* 获取资源列表
*/
@Override
public List<Resource> getResourceList(Query query) {
QueryWrapper<Resource> queryWrapper = new QueryWrapper<>();
List<Resource> resources = resourceMapper.selectList(queryWrapper);
return resources;
}
@Override
public List<Integer> getRoleResourceIds(Integer roleId) {
List<Integer> urls = new ArrayList<>();
urls.add(1);
return urls;
}
@Override
public List<String> getRolesResourceList(List<String> roleNames) {
return null;
}
@Override
public List<Resource> getPermitAllResourceList() {
return null;
}
//允许所有登录用户访问的接口列表
@Override
public List<String> getPermitAllResourceURLs() {
List<String> urls = new ArrayList<>();
urls.add("/api/user/current");
urls.add("/api/records/detail");
urls.add("/api/records/list");
return urls;
}
}

@ -0,0 +1,55 @@
package edu.ncst.ioreport.service.impl;
import edu.ncst.ioreport.mapper.RoleMapper;
import edu.ncst.ioreport.model.Role;
import edu.ncst.ioreport.service.IRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
/**
* 角色 业务层处理
*
* @author Lion Li
*/
@RequiredArgsConstructor
@Service
public class RoleServiceImpl implements IRoleService {
private final RoleMapper baseMapper;
/**
* 根据条件分页查询角色数据
*
* @param role 角色信息
* @return 角色数据集合信息
*/
@Override
public List<Role> selectRoleList(Role role) {
return baseMapper.selectRoleList(role);
}
/**
* 查询所有角色
*
* @return 角色列表
*/
@Override
public List<Role> selectRoleAll() {
RoleServiceImpl x = (RoleServiceImpl) AopContext.currentProxy();
return x.selectRoleList(new Role());
}
@Override
@Transactional
public List<Role> insertRole() {
RoleServiceImpl x = (RoleServiceImpl) AopContext.currentProxy();
return x.selectRoleList(new Role());
}
}

@ -0,0 +1,78 @@
package edu.ncst.ioreport.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.ncst.ioreport.mapper.UserMapper;
import edu.ncst.ioreport.model.Role;
import edu.ncst.ioreport.model.User;
import edu.ncst.ioreport.service.IUserService;
import edu.ncst.ioreport.utils.SessionUtils;
import edu.ncst.ioreport.vo.ListResultVO;
import edu.ncst.ioreport.vo.param.CurrentUserVO;
import edu.ncst.ioreport.vo.param.QUser;
import edu.ncst.ioreport.vo.result.UserInfoVO;
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.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService, UserDetailsService {
@Override
public UserInfoVO getUserInfo(QUser query) {
UserInfoVO vo = new UserInfoVO();
vo.setTeacherID("1001");
vo.setAddress("address 1111111");
vo.setFullName("zhangsan");
vo.setFullName("张三");
return vo;
}
@Override
public ListResultVO<User> getUserList(QUser query) {
User user = new User();
user.setAddress("address 1111111");
user.setTeacherID("1001");
user.setFullName("张三");
user.setEnable(true);
ListResultVO listResultVO = new ListResultVO();
List list = new ArrayList<>();
list.add(user);
listResultVO.setList(list);
return listResultVO;
}
@Override
public UserInfoVO getCurrentUser() {
UserInfoVO user = SessionUtils.getCurrentUser();
return user;
}
@Override
public UserDetails loadUserByWechatId(String wechatId) {
User user = new User();
user.setAddress("address 1111111");
user.setTeacherID("1001");
user.setFullName("张三");
List<String> roles = new ArrayList<>();
roles.add("Admin");//Teacher;Doorman
user.setRoles(roles);
user.setEnable(true);
return user;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = new User();
user.setAddress("address 1111111");
user.setTeacherID("1001");
user.setFullName("张三");
List<String> roles = new ArrayList<>();
roles.add("Admin");
user.setEnable(true);
return user;
}
}

@ -0,0 +1,79 @@
package edu.ncst.ioreport.utils;
import lombok.experimental.UtilityClass;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
@UtilityClass
public class CaptchaUtil {
private int width = 200;
private int height = 50;
public BufferedImage createImage() {
return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
public String drawRandomText(BufferedImage verifyImg) {
Graphics2D graphics = (Graphics2D) verifyImg.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
Font font = new Font("Bitmap", Font.PLAIN, 54);
graphics.setFont(font);
String baseNumLetter = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
StringBuilder stringBuffer = new StringBuilder();
int x = 10;
String ch = "";
Random random = new Random();
for (int i = 0; i < 4; i++) {
graphics.setColor(getRandomColor());
// 设置字体旋转角度(控制小于30度)
int degree = random.nextInt() % 30;
int dot = random.nextInt(baseNumLetter.length());
ch = baseNumLetter.charAt(dot) + "";
stringBuffer.append(ch);
// 正向旋转
graphics.rotate(degree * Math.PI / 180, x, 45);
graphics.drawString(ch, x, 45);
// 反向旋转
graphics.rotate(-degree * Math.PI / 180, x, 45);
x += 48;
}
// 绘制干扰线
for (int i = 0; i < 6; i++) {
graphics.setColor(getRandomColor());
graphics.drawLine(random.nextInt(width), random.nextInt(height), random.nextInt(width), random.nextInt(height));
}
// 绘制噪点
for (int i = 0; i < 30; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
graphics.setColor(getRandomColor());
graphics.fillRect(x1, y1, 2, 1);
}
return stringBuffer.toString();
}
/***
* 取随机颜色
*/
private Color getRandomColor() {
Random random = new Random();
return new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
}

@ -0,0 +1,29 @@
package edu.ncst.ioreport.utils;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
public class CookieUtils {
/**
* 获取指定的 Cookie
*/
public static Cookie getCookie(HttpServletRequest request, String name) {
if (name == null || "".equalsIgnoreCase(name)) {
return null;
}
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName() != null && name.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
}

@ -0,0 +1,91 @@
package edu.ncst.ioreport.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.vo.ResultVO;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;
/**
* 消息类响应工具类
*/
public class ResponseUtils {
// 成功
// 成功
public static <T> ResponseEntity<?> success(String msg, T data) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(0);
resultVO.setMsg(msg);
resultVO.setData(data);
return ResponseEntity.ok(resultVO);
}
public static ResponseEntity<?> success(Object data) {
return success("success", data);
}
public static ResponseEntity<?> success(String msg) {
return success(msg, null);
}
public static ResponseEntity<?> success() {
return success("success", null);
}
// 失败
public static <T> ResponseEntity<?> error(Integer code, String msg) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(code);
resultVO.setMsg(msg);
return ResponseEntity.ok().body(resultVO);
}
public static ResponseEntity<?> error(CodeMsg codeMsg) {
return error(codeMsg.getCode(), codeMsg.getMsg());
}
// 输出字段错误信息
public static <T> ResponseEntity<?> fieldError(BindingResult bindingResult) {
ResultVO<T> resultVO = new ResultVO<>();
String msg = "未知字段错误";
if (bindingResult.hasFieldErrors()) {
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
int count = bindingResult.getFieldErrorCount();
if (count > 0) {
msg = fieldErrors.get(0).getDefaultMessage();
}
}
resultVO.setMsg(msg);
return ResponseEntity.ok().body(resultVO);
}
// 调用
public static void output(HttpServletResponse response, Object data) {
try(OutputStream out = response.getOutputStream()) {
response.setContentType("application/json;charset=utf-8");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(data);
PrintWriter writer = new PrintWriter(out);
writer.print(s);
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

@ -0,0 +1,55 @@
package edu.ncst.ioreport.utils;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.vo.ResultVO;
public class ResultUtils {
// 成功
public static <T> ResultVO<T> success(String msg, T data) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(0);
resultVO.setMsg(msg);
resultVO.setData(data);
return resultVO;
}
public static <T> ResultVO<T> success(String msg) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(0);
resultVO.setMsg(msg);
resultVO.setData(null);
return resultVO;
}
// 成功
public static <T> ResultVO<T> success(T data) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(0);
resultVO.setMsg("success");
resultVO.setData(data);
return resultVO;
}
// 错误
public static <T> ResultVO<T> error(CodeMsg codeMsg) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(codeMsg.getCode());
resultVO.setMsg(codeMsg.getMsg());
resultVO.setData(null);
return resultVO;
}
// 错误
public static <T> ResultVO<T> error(String codeMsg) {
ResultVO<T> resultVO = new ResultVO<>();
resultVO.setCode(500);
resultVO.setMsg(codeMsg);
resultVO.setData(null);
return resultVO;
}
}

@ -0,0 +1,55 @@
package edu.ncst.ioreport.utils;
import edu.ncst.ioreport.exception.BusinessException;
import edu.ncst.ioreport.exception.CodeMsg;
import edu.ncst.ioreport.service.IUserService;
import edu.ncst.ioreport.vo.result.UserInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
/**
* 会话工具类
*/
@Component
public class SessionUtils {
@Autowired
private IUserService userService;
// 获取当前用户
public static UserInfoVO getCurrentUser() {
SecurityContext context = SecurityContextHolder.getContext();
if (context == null || context.getAuthentication() == null || context.getAuthentication().getDetails() == null) {
throw new BusinessException(CodeMsg.NOT_GET_CURRENT_USER_INFO);
}
return (UserInfoVO) context.getAuthentication().getDetails();
}
// 获取当前用户标识
public static Object getCurrentPrincipal() {
SecurityContext context = SecurityContextHolder.getContext();
return context.getAuthentication().getPrincipal();
}
// 获取当前 Request
public static HttpServletRequest getRequest() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
}
// 获取当前 Response
public static HttpServletResponse getResponse() {
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
}
}

@ -0,0 +1,25 @@
package edu.ncst.ioreport.utils;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;
/**
* spring工具类
*
* @author Lion Li
*/
@Component
public final class SpringUtils{
/**
* 获取aop代理对象
*
* @param invoker
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T getAopProxy(T invoker) {
return (T) AopContext.currentProxy();
}
}

@ -0,0 +1,27 @@
package edu.ncst.ioreport.utils;
public class URLUtils {
public static String removeQueryString(String url) {
int a = url.indexOf("?");
int b = url.indexOf("#");
int deleteStart = 0;
if (a == -1 && b == -1) {
deleteStart = -1;
} else if (a != -1 && b != -1) {
deleteStart = Math.min(a, b);
} else if (a == -1) {
deleteStart = b;
} else {
deleteStart = a;
}
if (deleteStart != -1) {
return url.substring(0, deleteStart);
} else {
return url;
}
}
}

@ -0,0 +1,49 @@
package edu.ncst.ioreport.utils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.ncst.ioreport.vo.AccessToken;
import edu.ncst.ioreport.vo.SessionKey;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
@Component
public class WeChatUtils {
private static final RestTemplate restTemplate;
private static final String corpId = "ww17f8d10783494584";
private static final String corpsecret = "i5t-rh8bXeNCgihcYPrG9ZPpWkivzPJ69sv570osk6I";
// private static final String corpId = "wwcb1e222a0708b4fc";
// private static final String corpsecret = "uWh34kbYvxR7txvICe97mrGIuooLRfhsWi5YBPWLuAg";
//
static {
restTemplate = new RestTemplate();
}
// 根据 Code 获取 Session
public static SessionKey code2session(String code) {
// 获取 accesstoken
String gettoken = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + corpId + "&corpsecret=" + corpsecret + "&js_code=" +
code + "&grant_type=authorization_code";
//获取Sessionid和userid
String jscode2session = "https://qyapi.weixin.qq.com/cgi-bin/miniprogram/jscode2session?access_token=%s&js_code=%s&grant_type=authorization_code";
ResponseEntity<String> response = restTemplate.getForEntity(gettoken, String.class);
ObjectMapper objectMapper = new ObjectMapper();
SessionKey session = null;
try {
AccessToken accessToken = objectMapper.readValue(response.getBody(), AccessToken.class);
response = restTemplate.getForEntity(String.format(jscode2session, accessToken.getAccessToken(), code), String.class);
session = objectMapper.readValue(response.getBody(), SessionKey.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return session;
}
}

@ -0,0 +1,18 @@
package edu.ncst.ioreport.vo;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.Data;
@Data
public class AccessToken {
@JsonAlias("access_token")
private String accessToken;
@JsonAlias("expires_in")
private String expiresIn;
private String errcode;
private String errmsg;
}

@ -0,0 +1,30 @@
package edu.ncst.ioreport.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
@ApiModel(value = "ListResultVO", description = "分页列表数据")
@Data
@EqualsAndHashCode(callSuper = false)
public class ListResultVO<T> implements Serializable {
private static final long serialVersionUID = -8896090499552990782L;
@ApiModelProperty(value = "列表数据")
private List<T> list;
@ApiModelProperty(value = "记录总数")
private Long total;
@ApiModelProperty(value = "每页记录数")
private Long pageSize;
@ApiModelProperty(value = "当前页码")
private Long current;
}

@ -0,0 +1,61 @@
package edu.ncst.ioreport.vo;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.io.Serializable;
@ApiModel(description = "查询参数")
@Data
public class Query implements Serializable {
private static final long serialVersionUID = 4617734867110140874L;
// 排序方式
private String sorter;
// 页码
private Integer current = 1;
// 每页记录数
private Integer pageSize = 10;
// 转换为 Pageable
public <T> Page<T> toPageRequest() {
return new Page<>(current, pageSize);
}
// 转换为 Sorter 对象
public Sorter toSorter() {
if (sorter == null) {
return null;
}
if (sorter.endsWith("_ascend")) {
String key = sorter.replace("_ascend", "");
String column = StringUtils.camelToUnderline(key);
Sorter _sorter = new Sorter();
_sorter.setColumn(column);
_sorter.setKey(key);
_sorter.setIsAsc(true);
return _sorter;
} else if (sorter.endsWith("_descend")){
String key = sorter.replace("_descend", "");
String column = StringUtils.camelToUnderline(key);
Sorter _sorter = new Sorter();
_sorter.setColumn(column);
_sorter.setKey(key);
_sorter.setIsAsc(false);
return _sorter;
}
return null;
}
}

@ -0,0 +1,19 @@
package edu.ncst.ioreport.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 统一的接口返回数据格式
*/
@ApiModel(value = "ResultVO", description = "返回信息")
@Data
public class ResultVO<T> {
private Integer code=0;
private String msg="success";
// 数据
@ApiModelProperty(value = "数据", dataType = "Object",name = "data")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private T data;
}

@ -0,0 +1,22 @@
package edu.ncst.ioreport.vo;
import com.fasterxml.jackson.annotation.JsonAlias;
import lombok.Data;
@Data
public class SessionKey {
@JsonAlias("userid")
private String weChatId;
@JsonAlias("session_key")
private String sessionKey;
private String corpid;
private String deviceid;
private String errcode;
private String errmsg;
}

@ -0,0 +1,20 @@
package edu.ncst.ioreport.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(description = "排序器")
@Data
public class Sorter {
@ApiModelProperty(value = "排序关键字")
private String key;
@ApiModelProperty(value = "是否为升序")
private Boolean isAsc = true;
@ApiModelProperty(value = "排序列名", notes = "根据该列进行排序")
private String column;
}

@ -0,0 +1,41 @@
package edu.ncst.ioreport.vo.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(description = "当前用户信息")
@Data
public class CurrentUserVO {
@ApiModelProperty("头像链接")
private String avatar;
@ApiModelProperty("姓名")
private String username;
@ApiModelProperty("昵称")
private String nickname;
@ApiModelProperty("全名")
private String fullname;
@ApiModelProperty("角色")
private String role;
@ApiModelProperty("头衔")
private String title;
@ApiModelProperty("用户组")
private String group;
@ApiModelProperty("用户ID")
private Integer userId;
@ApiModelProperty("所在单位ID")
private Integer unitId;
@ApiModelProperty("所在单位名称")
private Integer unitName;
}

@ -0,0 +1,29 @@
package edu.ncst.ioreport.vo.param;
import edu.ncst.ioreport.vo.Query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@ApiModel(description = "登录日志查询对象")
@Data
public class QLoginLog extends Query {
@ApiModelProperty(value = "关键字", notes = "用于对用户名、用户ID、用户姓名进行模糊查询")
private String keyword;
@ApiModelProperty(value = "登录类型")
private String type;
@ApiModelProperty(value = "开始日期")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startTime;
@ApiModelProperty(value = "结束日期")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}

@ -0,0 +1,14 @@
package edu.ncst.ioreport.vo.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description = "用户信息查询")
public class QUser {
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("姓名")
private String name;
}

@ -0,0 +1,20 @@
package edu.ncst.ioreport.vo.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(description = "用户登录表单")
@Data
public class UserLoginVO {
@ApiModelProperty("微信小程序Code")
private String weChatCode;
@ApiModelProperty("手机号")
private String phoneNumber;
@ApiModelProperty("临时TOKEN")
private String tempToken;
}

@ -0,0 +1,29 @@
package edu.ncst.ioreport.vo.result;
import edu.ncst.ioreport.model.Role;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel(description = "用户信息")
public class UserInfoVO {
@ApiModelProperty(value = "用户id")
private Integer id;
@ApiModelProperty(value = "教师工号")
private String teacherID;
@ApiModelProperty(value = "真实名")
private String fullName;
@ApiModelProperty(value = "地址信息")
private String address;
@ApiModelProperty(value = "手机号")
private String phone;
@ApiModelProperty(value = "所属单位")
private Integer unitId;
@ApiModelProperty(value = "微信id")
private String wechatID;
@ApiModelProperty(value = "角色列表")
private List<String> roles;
}

@ -0,0 +1,61 @@
spring:
datasource:
url: jdbc:mysql://localhost:3306/iorecordsys?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username: smart
password: hblgjg@2020
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
max-lifetime: 300000
devtools:
restart:
enabled: true #设置开启热部署
additional-paths: src/main/java #重启目录
exclude: WEB-INF/**
application:
name: springfox-swagger
mvc:
pathmatch:
matching-strategy: ant_path_matcher
async:
request-timeout: 120000 #设置restful的api超时时间为60秒
server:
port: 8085
tomcat:
connection-timeout: 300000
servlet:
encoding:
charset: utf-8
#mybatis:
# mapper-locations: classpath:mapping/*.xml
# type-aliases-package: edu.ncst.ioreport.model
swagger:
enable: true
title: API文档
description: 出入校报备系统API文档
base-package: edu.ncst.ioreport.controller
exclude-path: /error/**
termsOfServiceUrl: https://meander.net.cn
contact:
name: sage
url: www.meander.net.cn
email: sage@meander.net.cn
logging:
config: classpath:logback.xml
level:
edu.ncst.equmanager: DEBUG
org.springframework: DEBUG
java.sql: DEBUG
#
## MyBatis Plus
mybatis-plus:
# global-config:
# db-config:
# logic-delete-field: deleteAt
# logic-delete-value: now()
# logic-not-delete-value: null
# banner: false # 关闭控制台的 LOGO
# mapper-locations: classpath*:/mapping/**/*.xml
configuration:
map-underscore-to-camel-case: false

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_PATH" value="D:/log"/>
<!-- 定义日志格式 -->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS,CTT} [%-5level] [%thread] [%-30.30logger{30}] %msg%n"/>
<property name="MAX_FILE_SIZE" value="10MB"/>
<property name="MAX_HISTORY" value="30"/>
<property name="CONTEXT_NAME" value="sbgl"/>
<contextName>${CONTEXT_NAME}</contextName>
<!-- 彩色日志 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 控制台输出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS,CTT} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<!-- 控制台日志样式 -->
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS,CTT}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%15.15t]){faint} [%X{requestId}] %clr(%-40.40logger{39}){cyan} [%L] %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 文件日志样式 -->
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS,CTT}} ${LOG_LEVEL_PATTERN:-%5p} [%t] [%X{requestId}] %-40.40logger{39} %L : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 禁用logback自身日志输出 -->
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<!-- 控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 运行日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<file>${LOG_PATH}/sbgl.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/sbgl-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>${MAX_FILE_SIZE}</maxFileSize>
<maxHistory>${MAX_HISTORY}</maxHistory>
</rollingPolicy>
</appender>
<!--
日志输出级别 debug info error
-->
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>

@ -0,0 +1,13 @@
package edu.ncst.ioreport;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class IOReportApplicationTests {
@Test
void contextLoads() {
}
}

@ -0,0 +1,31 @@
/*
* Eslint config file
* Documentation: https://eslint.org/docs/user-guide/configuring/
* Install the Eslint extension before using this feature.
*/
module.exports = {
env: {
es6: true,
browser: true,
node: true,
},
ecmaFeatures: {
modules: true,
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
globals: {
wx: true,
App: true,
Page: true,
getCurrentPages: true,
getApp: true,
Component: true,
requirePlugin: true,
requireMiniProgram: true,
},
// extends: 'eslint:recommended',
rules: {},
}

@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

@ -0,0 +1,13 @@
// declare namespace API {
// interface TableInfo<T> {
// total: number
// rows: Array<T>
// code: number
// msg: string
// }
// interface Result<T> {
// msg: string,
// data: T,
// code: number,
// }
// }

@ -0,0 +1,50 @@
declare namespace Order {
interface submitEventDetail {
ID: string;
depart: string;
enterDate: string;
enterTime: string;
innerLocation: string;
name: string;
outerLocation: string;
phone: string;
reason: string;
orderType: string;
}
interface submitDetail {
ID: string;
depart: string;
reportDateTime: string;
innerLocation: string;
name: string;
outerLocation: string;
phone: string;
reason: string;
orderType: string;
}
interface OrderInfo {
orderType: "0" | "1"
reportDateTime: string
reportID: string
reportStatus: "0" | "1" | "2" | "3"
reviewer: string
}
interface OrderDetail extends Record<string, any> {
reportType: "0" | "1"
reportDateTime: string
reportID: string
reportStatus: "0" | "1" | "2" | "3"
reviewer: string
ID: string // 工号
depart: string
innerLocation: string
name: string
outerLocation: string
phone: string
reason: string
auditor?: string // 审核人
auditorDateTime?: string // 审核时间
qrCode: string
}
}

@ -0,0 +1,113 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var request_1 = require("../../utils/request");
var BASE_URL = 'http://localhost:8080/';
var submitOrder = function (detail) {
wx.showLoading({ title: "提交中" });
request_1.request({ url: BASE_URL + 'api/genOrder', method: 'POST', data: detail });
};
var getOrderInfo = function () { return __awaiter(void 0, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
wx.showLoading({ title: "加载中" });
return [4 /*yield*/, request_1.request({ url: BASE_URL + 'api/order/list' })];
case 1:
res = _a.sent();
return [2 /*return*/, res.data.rows];
}
});
}); };
var getOrderDetailByOrderID = function (orderID) { return __awaiter(void 0, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, request_1.request({ url: BASE_URL + 'api/order', method: "POST", data: { orderID: orderID, } })];
case 1:
res = _a.sent();
return [2 /*return*/, res.data];
}
});
}); };
var getOrderDetailByQrCode = function (qrCode) { return __awaiter(void 0, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, request_1.request({ url: BASE_URL + ("api/order/" + qrCode) })];
case 1:
res = _a.sent();
return [2 /*return*/, res.data];
}
});
}); };
var getOrderDetailFilter = function (reportType, reportStatus) { return __awaiter(void 0, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, request_1.request({ url: BASE_URL + 'api/order/list/filter' + ("?reportType=" + (reportType || '') + "&reportStatus=" + (reportStatus || '')) })];
case 1:
res = _a.sent();
return [2 /*return*/, res.data.rows];
}
});
}); };
var passOrder = function (orderId) { return __awaiter(void 0, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, request_1.request({ url: BASE_URL + 'api/order/pass' + ("?orderId=" + (orderId || '')) }, { successMsg: '通过成功' })];
case 1:
res = _a.sent();
return [2 /*return*/, res.msg];
}
});
}); };
var denyOrder = function (orderId) { return __awaiter(void 0, void 0, void 0, function () {
var res;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, request_1.request({ url: BASE_URL + 'api/order/deny' + ("?orderId=" + (orderId || '')) }, { successMsg: '退回成功' })];
case 1:
res = _a.sent();
return [2 /*return*/, res.msg];
}
});
}); };
exports.default = { submitOrder: submitOrder, getOrderInfo: getOrderInfo, getOrderDetailByOrderID: getOrderDetailByOrderID, getOrderDetailFilter: getOrderDetailFilter, passOrder: passOrder, denyOrder: denyOrder, getOrderDetailByQrCode: getOrderDetailByQrCode };

@ -0,0 +1,36 @@
import { request } from "../../utils/request"
const BASE_URL = 'http://localhost:8080/'
const submitOrder = (detail: Order.submitDetail) => {
wx.showLoading({ title: "提交中" })
request({ url: BASE_URL + 'api/genOrder', method: 'POST', data: detail })
}
const getOrderInfo = async () => {
wx.showLoading({ title: "加载中" })
const res = await request<API.Result<API.TableInfo<Order.OrderInfo>>>({ url: BASE_URL + 'api/order/list' })
return res.data.rows;
}
const getOrderDetailByOrderID = async (orderID: string) => {
const res = await request<API.Result<Order.OrderDetail>>({ url: BASE_URL + 'api/order', method: "POST", data: { orderID, } })
return res.data;
}
const getOrderDetailByQrCode = async (qrCode: string) => {
const res = await request<API.Result<Order.OrderDetail>>({ url: BASE_URL + `api/order/${qrCode}` })
return res.data;
}
const getOrderDetailFilter = async (reportType?: string, reportStatus?: string) => {
const res = await request<API.Result<API.TableInfo<API.Result<Order.OrderDetail>>>>({ url: BASE_URL + 'api/order/list/filter' + `?reportType=${reportType || ''}&reportStatus=${reportStatus || ''}` })
return res.data.rows;
}
const passOrder = async (orderId: string) => {
const res = await request<API.Result<never>>({ url: BASE_URL + 'api/order/pass' + `?orderId=${orderId || ''}` }, { successMsg: '通过成功' })
return res.msg;
}
const denyOrder = async (orderId: string) => {
const res = await request<API.Result<never>>({ url: BASE_URL + 'api/order/deny' + `?orderId=${orderId || ''}` }, { successMsg: '退回成功' })
return res.msg;
}
export default { submitOrder, getOrderInfo, getOrderDetailByOrderID, getOrderDetailFilter, passOrder, denyOrder, getOrderDetailByQrCode }

@ -0,0 +1,10 @@
declare namespace User{
interface userInfo{
roles:Array<string>;
ID:string;// 工号
name: string;
phone: string;// 联系方式
department: string; // 学院
}
}

@ -0,0 +1,89 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var constant_1 = __importDefault(require("../../utils/constant"));
var request_1 = require("../../utils/request");
var BASE_URL = 'http://localhost:8080/';
var qyLogin = function () { return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve, reject) {
return;
wx.qy.login({
success: function (loginRes) {
resolve(loginRes);
},
fail: function () {
wx.hideLoading();
// 登录失败
reject({ code: undefined });
}
});
})];
});
}); };
var login = function () { return __awaiter(void 0, void 0, void 0, function () {
var code, token, data;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
code = '';
if (typeof code == "undefined") {
// 登录失败
return [2 /*return*/];
}
return [4 /*yield*/, request_1.request({
url: BASE_URL + 'api/login',
data: { code: code, },
method: "POST"
})];
case 1:
token = (_a.sent()).data.token;
wx.setStorageSync(constant_1.default.SYS_TOKEN, token);
return [4 /*yield*/, request_1.request({ url: BASE_URL + 'api/userInfo', data: token, method: "POST" })];
case 2:
data = (_a.sent()).data;
wx.setStorageSync(constant_1.default.ROLE_LIST, data.roles);
wx.setStorageSync(constant_1.default.USER_INFO, data);
return [2 /*return*/, data];
}
});
}); };
exports.default = { login: login };

@ -0,0 +1,40 @@
import constant from "../../utils/constant";
import { request } from "../../utils/request";
const BASE_URL = 'http://localhost:8080/';
interface IqyLoginRes {
code: string,
errMsg: string,
}
const qyLogin = async () => {
return new Promise<IqyLoginRes>((resolve, reject) => {
return;
(wx as any).qy.login({
success: (loginRes: IqyLoginRes) => {
resolve(loginRes);
},
fail: () => {
wx.hideLoading();
// 登录失败
reject({ code: undefined })
}
});
})
}
const login = async () => {
// const { code } = await qyLogin()
const code = ''
if (typeof code == "undefined") {
// 登录失败
return;
}
const { data: { token } } = await request<API.Result<{ token: string }>>({
url: BASE_URL + 'api/login', data: { code, }, method: "POST"
})
wx.setStorageSync(constant.SYS_TOKEN, token);
const { data } = await request<API.Result<User.userInfo>>({ url: BASE_URL + 'api/userInfo', data: token, method: "POST" })
wx.setStorageSync(constant.ROLE_LIST, data.roles)
wx.setStorageSync(constant.USER_INFO, data)
return data;
}
export default { login }

@ -0,0 +1,67 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
//TODO 门卫扫码的页面 没做
//TODO 一堆接口
var constant_1 = __importDefault(require("./utils/constant"));
var util_1 = require("./utils/util");
// 路由守卫 next() 放行
var routerBeforeEach = function (next) {
var token = wx.getStorageSync('SYS_TOKEN');
// TODO 获取用户信息 存储
if (token) {
// 登录成功
next();
return;
}
// 登录失败 的操作
next();
};
var OldPage = Page;
Page = function (options) {
var oldLoad = options.onLoad;
var oldShow = options.onShow;
options.onLoad = function () {
var _this = this;
routerBeforeEach(function () {
oldLoad === null || oldLoad === void 0 ? void 0 : oldLoad.apply(_this, arguments);
});
};
options.onShow = function () {
var _this = this;
routerBeforeEach(function () {
oldShow === null || oldShow === void 0 ? void 0 : oldShow.apply(_this, arguments);
});
};
OldPage(options);
};
// app.ts
App({
globalData: {
navBarHeight: 0,
menuRight: 0,
menuTop: 0,
menuHeight: 0,
},
onLaunch: function () {
// 展示本地存储能力
var that = this;
// 获取系统信息
var systemInfo = wx.getSystemInfoSync();
// 胶囊按钮位置信息
var menuButtonInfo = wx.getMenuButtonBoundingClientRect();
// 导航栏高度 = 状态栏高度 + 44
that.globalData.navBarHeight = systemInfo.statusBarHeight + 44;
that.globalData.menuRight = systemInfo.screenWidth - menuButtonInfo.right;
that.globalData.menuTop = menuButtonInfo.top;
that.globalData.menuHeight = menuButtonInfo.height;
// 登录
console.log("app.ts============");
var userinfo = wx.getStorageSync(constant_1.default.USER_INFO);
if (!userinfo) {
util_1.wxLogin();
}
},
});

@ -0,0 +1,43 @@
{
"pages": [
"pages/index/index",
"pages/report/list/myReport",
"pages/report/detail/reportDetail",
"pages/logs/logs",
"pages/report/enter/enterReport",
"pages/report/out/outerReport",
"pages/audit/list/auditList",
"pages/audit/detail/index",
"pages/verfy/index",
"pages/user/info"
],
"darkmode": false,
"themeLocation": "theme.json",
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationStyle": "custom",
"navigationBarTitleText": "出入校报备助手",
"navigationBarTextStyle": "black"
},
"style": "v2",
"useExtendedLib": {
"kbone": true,
"weui": true
},
"sitemapLocation": "sitemap.json",
"usingComponents": {
"yform": "components/yform/yform",
"yinput": "components/yinput/yinput",
"yselect": "components/yselect/yselect",
"ytimePicker": "components/ypicker/timePicker/timePicker",
"ysinglePicker": "components/ypicker/singlePicker/singlePicker",
"ybutton": "components/ybutton/ybutton",
"sysFilterBar":"components/sysFilterBar/sysFilterBar",
"navigationBar": "components/navigationBar/navigationBar",
"sysCard": "./components/sysCard/sysCard",
"sysInput": "components/sysInput/sysInput",
"sysTextarea": "components/sysTextarea/sysTextarea",
"ydatePicker":"components/ypicker/datePicker/datePicker"
}
}

@ -0,0 +1,65 @@
//TODO 门卫扫码的页面 没做
//TODO 一堆接口
import constant from './utils/constant';
import {wxLogin} from './utils/util';
// 路由守卫 next() 放行
const routerBeforeEach = (next: Function) => {
const token = wx.getStorageSync('SYS_TOKEN');
// TODO 获取用户信息 存储
if (token) {
// 登录成功
next()
return;
}
// 登录失败 的操作
next()
}
const OldPage = Page;
Page = function (options) {
const oldLoad = options.onLoad
const oldShow = options.onShow
options.onLoad = function () {
routerBeforeEach(() => {
oldLoad?.apply(this, arguments as any)
})
}
options.onShow = function () {
routerBeforeEach(() => {
oldShow?.apply(this, arguments as any)
})
}
OldPage(options)
}
// app.ts
App<IAppOption>({
globalData: {
navBarHeight: 0, // 导航栏高度
menuRight: 0, // 胶囊距右方间距(方保持左、右间距一致)
menuTop: 0, // 胶囊距底部间距(保持底部间距一致)
menuHeight: 0, // 胶囊高度(自定义内容可与胶囊高度保证一致)
},
onLaunch() {
// 展示本地存储能力
const that = this;
// 获取系统信息
const systemInfo = wx.getSystemInfoSync();
// 胶囊按钮位置信息
const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
// 导航栏高度 = 状态栏高度 + 44
that.globalData.navBarHeight = systemInfo.statusBarHeight + 44;
that.globalData.menuRight = systemInfo.screenWidth - menuButtonInfo.right;
that.globalData.menuTop = menuButtonInfo.top;
that.globalData.menuHeight = menuButtonInfo.height;
// 登录
console.log("app.ts============")
let userinfo = wx.getStorageSync(constant.USER_INFO);
if(!userinfo){
wxLogin();
}
},
})

@ -0,0 +1,88 @@
page {
font-family:"PingFangSC-Thin";
font-size:small; /*微信小程序中,使用rpx做单位*/
--color-primary: #0078D4;
--navigation-bar-color: var(--color-primary);
--color-gray-0: rgba(196, 196, 196, 0.28);
--color-border-gray-0: rgba(196, 196, 196, 0.28);
--el-color-primary-light-3: #79bbff;
--el-color-primary-light-5: #a0cfff;
--el-color-primary-light-7: #c6e2ff;
--el-color-primary-light-8: #d9ecff;
--el-color-primary-light-9: #ecf5ff;
--el-color-primary-dark-2: #337ecc;
--el-color-success: #67c23a;
--el-color-success-light-3: #95d475;
--el-color-success-light-5: #b3e19d;
--el-color-success-light-7: #d1edc4;
--el-color-success-light-8: #e1f3d8;
--el-color-success-light-9: #f0f9eb;
--el-color-success-dark-2: #529b2e;
--el-color-warning: #e6a23c;
--el-color-warning-light-3: #eebe77;
--el-color-warning-light-5: #f3d19e;
--el-color-warning-light-7: #f8e3c5;
--el-color-warning-light-8: #faecd8;
--el-color-warning-light-9: #fdf6ec;
--el-color-warning-dark-2: #b88230;
--el-color-danger: #f56c6c;
--el-color-danger-light-3: #f89898;
--el-color-danger-light-5: #fab6b6;
--el-color-danger-light-7: #fcd3d3;
--el-color-danger-light-8: #fde2e2;
--el-color-danger-light-9: #fef0f0;
--el-color-danger-dark-2: #c45656;
--el-color-error: #f56c6c;
--el-color-error-light-3: #f89898;
--el-color-error-light-5: #fab6b6;
--el-color-error-light-7: #fcd3d3;
--el-color-error-light-8: #fde2e2;
--el-color-error-light-9: #fef0f0;
--el-color-error-dark-2: #c45656;
--el-color-info: #909399;
--el-color-info-light-3: #b1b3b8;
--el-color-info-light-5: #c8c9cc;
--el-color-info-light-7: #dedfe0;
--el-color-info-light-8: #e9e9eb;
--el-color-info-light-9: #f4f4f5;
--el-color-info-dark-2: #73767a;
--el-bg-color: #ffffff;
--el-bg-color-page: #f2f3f5;
--el-bg-color-overlay: #ffffff;
--el-text-color-primary: #303133;
--el-text-color-regular: #606266;
--el-text-color-secondary: #909399;
--el-text-color-placeholder: #a8abb2;
--el-text-color-disabled: #c0c4cc;
--el-border-color: #dcdfe6;
--el-border-color-light: #e4e7ed;
--el-border-color-lighter: #ebeef5;
--el-border-color-extra-light: #f2f6fc;
--el-border-color-dark: #d4d7de;
--el-border-color-darker: #cdd0d6;
--el-fill-color: #f0f2f5;
--el-fill-color-light: #f5f7fa;
--el-fill-color-lighter: #fafafa;
--el-fill-color-extra-light: #fafcff;
--el-fill-color-dark: #ebedf0;
--el-fill-color-darker: #e6e8eb;
--el-fill-color-blank: #ffffff;
--el-box-shadow: 0px 12px 32px 4px rgba(0, 0, 0, .04), 0px 8px 20px rgba(0, 0, 0, .08);
--el-box-shadow-light: 0px 0px 12px rgba(0, 0, 0, .12);
--el-box-shadow-lighter: 0px 0px 6px rgba(0, 0, 0, .12);
--el-box-shadow-dark: 0px 16px 48px 16px rgba(0, 0, 0, .08), 0px 12px 32px rgba(0, 0, 0, .12), 0px 8px 16px -8px rgba(0, 0, 0, .16);
--el-disabled-bg-color: var(--el-fill-color-light);
--el-disabled-text-color: var(--el-text-color-placeholder);
--el-disabled-border-color: var(--el-border-color-light);
--el-overlay-color: rgba(0, 0, 0, .8);
--el-overlay-color-light: rgba(0, 0, 0, .7);
--el-overlay-color-lighter: rgba(0, 0, 0, .5);
--el-mask-color: rgba(255, 255, 255, .9);
--el-mask-color-extra-light: rgba(255, 255, 255, .3);
--el-border-width: 1px;
--el-border-style: solid;
--el-border-color-hover: var(--el-text-color-disabled);
--el-border: var(--el-border-width) var(--el-border-style) var(--el-border-color);
--el-svg-monochrome-grey: var(--el-border-color);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

@ -0,0 +1,30 @@
"use strict";
var app = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
title: String,
searchInput: Boolean,
onlyStations: Boolean,
},
/**
* 组件的初始数据
*/
data: {
navBarHeight: app.globalData.navBarHeight,
menuRight: app.globalData.menuRight,
menuTop: app.globalData.menuTop - 5,
menuHeight: app.globalData.menuHeight + 10,
searchInput: false,
},
/**
* 组件的方法列表
*/
methods: {
onBack: function () {
wx.navigateBack();
}
}
});

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"mp-icon": "weui-miniprogram/icon/icon"
}
}

@ -0,0 +1,23 @@
.nav-bar {
position: fixed;
width: 100%;
color: #fff;
background: var(--navigation-bar-color);
display: flex;
align-items: center;
.icon {
margin: 0 4px;
line-height: 16px;
text-align: center;
}
}
.nav-barindex{
position: fixed;
width: 100%;
}
.navigation-title{
font-size: 35rpx;
text-align: left;
font-weight: 900;
padding-left: 20rpx;
}

@ -0,0 +1,31 @@
const app = getApp()
Component({
/**
*
*/
properties: {
title: String,
searchInput: Boolean,
onlyStations: Boolean,
},
/**
*
*/
data: {
navBarHeight: app.globalData.navBarHeight,
menuRight: app.globalData.menuRight,
menuTop: app.globalData.menuTop - 5,
menuHeight: app.globalData.menuHeight + 10,
searchInput: false,
},
/**
*
*/
methods: {
onBack(){
wx.navigateBack()
}
}
})

@ -0,0 +1,10 @@
<!-- 自定义顶部栏 -->
<view wx:if="{{!onlyStations}}" class="nav-bar" style="top:{{menuTop}}px;height:{{menuHeight}}px; min-height:{{menuHeight}}px;line-height:{{menuHeight}}px;">
<mp-icon bindtap="onBack" class="icon" type="field" icon="back" color="white" size="{{10}}"></mp-icon>
<text class="navigation-title">{{title}}</text>
</view>
<view wx:if="{{onlyStations}}" class="nav-barindex" style="top:{{menuTop}}px;height:{{menuHeight}}px; min-height:{{menuHeight}}px;line-height:{{menuHeight}}px;">
<text class="navigation-title">{{title}}</text>
</view>
<!-- 占位,高度与顶部栏一样 -->
<view style="height:{{navBarHeight}}px;background-color: white;"></view>

@ -0,0 +1,6 @@
interface ISysCardClickDetail{
reportStatus: '0' | '1' | '2' | '3',
reportType: string,
reportDateTime: string,
reviewer: string,
}

@ -0,0 +1,20 @@
"use strict";
var colors = { 'SCHOOL_PASS': '#DAFFA5', 'SUBMIT': '#7CE4ED', 'DEPT_PASS': '#7CE4ED', 'DENY': '#E9F0E0' };
Component({
// reportType: "入校报备",
// reportDateTime: "2022-10-4 18:18:30",
// reviewer: "张三",
properties: {
reportStatus: String,
reportType: String,
reportDateTime: String,
reviewer: String,
},
data: {
colors: colors,
},
/**
* 组件的方法列表
*/
methods: {}
});

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save