修复保存client_id时除了判断github_id存在,还需要判断client_id

This commit is contained in:
APLS 2020-03-05 11:42:05 +08:00
commit 34ddc4d656
85 changed files with 6638 additions and 0 deletions

310
mvnw vendored Normal file
View File

@ -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 "$@"

182
mvnw.cmd vendored Normal file
View File

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

174
pom.xml Normal file
View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.qyi</groupId>
<artifactId>e5</artifactId>
<version>1.0.0</version>
<name>e5</name>
<description>Demo 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.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<!-- freemarker 模板引擎-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!--权限管理插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--thymeleaf-->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<!--<version>4.12</version>-->
<!--<scope>test</scope>-->
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<!-- commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!--Mybatis plus代码生成器-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.2.0</version>
</dependency>
<!--添加redis缓存依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis依赖commons-pool 这个依赖一定要添加 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--OKHTTP-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!--<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
&lt;!&ndash; <version>4.3.9.RELEASE</version>&ndash;&gt;
</dependency>-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<!-- <version>1.8.9</version>-->
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<!-- <version>1.8.9</version>-->
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!--quartz 定时任务-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<!--因为quartz 需要有Spring context 所有引入mail包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,147 @@
package io.qyi.e5;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
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.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @program: demo
* @description:
* @author: 落叶随风
* @create: 2019-10-23 01:15
**/
public class AutoGenerator_ {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + "");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("落叶");
gc.setOpen(false);
// 是否覆盖
gc.setFileOverride(true);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/e5?charset=utf8mb4&useSSL=false");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
// pc.setModuleName("demo");
pc.setParent("io.qyi.e5");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 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/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录");
return false;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
// templateConfig.setController(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// strategy.setSuperEntityClass("com.baomidou.ant.common.BaseEntity");
strategy.setEntityLombokModel(true);
// 是否生成Controller
strategy.setRestControllerStyle(true);
// 公共父类
// strategy.setSuperControllerClass("com.baomidou.ant.common.BaseController");
// 写于父类中的公共字段
// strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
// strategy.setInclude(new String[]{"t_user","t_role","t_permission"});
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}

View File

@ -0,0 +1,13 @@
package io.qyi.e5;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class E5Application {
public static void main(String[] args) {
SpringApplication.run(E5Application.class, args);
}
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.bean;
import lombok.Data;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 16:20
**/
@Data
public class AppQuartz {
private Integer quartzId; //id 主键
private String jobName; //任务名称
private String jobGroup; //任务分组
private String startTime; //任务开始时间
private String cronExpression; //corn表达式
private String invokeParam;//需要传递的参数
}

View File

@ -0,0 +1,84 @@
package io.qyi.e5.bean.core;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.qyi.e5.util.ResultUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-16 01:11
**/
@Aspect
@Component
public class WebExceptionAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* io.qyi.e5..*.*(..))")
private void bountyHunterPointcut() {
}
/**
* 拦截web层异常记录异常日志并返回友好信息到前端
*
* @param e
* 异常对象
*/
@AfterThrowing(pointcut = "bountyHunterPointcut()", throwing = "e")
public void handleThrowing(JoinPoint joinPoint, Exception e) {
//e.printStackTrace();
/*if (null != user){
log.error("发现异常!操作用户手机号:"+user.getMobile());
}*/
logger.error("发现异常!方法:"+ joinPoint.getSignature().getName()+"--->异常",e);
//这里输入友好性信息
if (!StringUtils.isEmpty(e.getMessage())){
logger.error("异常",e.getMessage());
writeContent(500,e.getMessage());
}else {
writeContent(500,"十分抱歉,出现异常!程序猿小哥正在紧急抢修...");
}
}
/**
* 将内容输出到浏览器
*
* @param content
* 输出内容
*/
public static void writeContent(Integer code,String content) {
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getResponse();
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "text/json;charset=UTF-8");
response.setHeader("icop-content-type", "exception");
PrintWriter writer = null;
JsonGenerator jsonGenerator = null;
try {
writer = response.getWriter();
jsonGenerator = (new ObjectMapper()).getFactory().createGenerator(writer);
jsonGenerator.writeObject(ResultUtil.error(code,content));
} catch (IOException e1) {
e1.printStackTrace();
}finally {
writer.flush();
writer.close();
}
}
}

View File

@ -0,0 +1,21 @@
package io.qyi.e5.bean.result;
import lombok.Data;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2019-12-26 15:21
**/
@Data
public class Result<T> {
/** 错误码. */
private Integer code;
/** 提示信息. */
private String msg;
/** 具体的内容. */
private T data;
}

View File

@ -0,0 +1,45 @@
package io.qyi.e5.bean.result;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-06 00:24
**/
public enum ResultEnum {
SUCCESS(0, "ok"),
UNKNOWN_ERROR(-1, "unknown error"),
INVALID_TOKEN(-10000,"Invalid token"),
TOKEN_IS_NOT_FOUND(-10001,"This token was not found"),
INVALID_TYPE(-10002,"Invalid type"),
INVALID_FROM(-10003,"Invalid from"),
TITLE_OR_MSG_IS_NULL(-10004,"title or msg is null"),
INVALID_TOKEN_(-10005,"Invalid token"),
NO_ROBOT_FOUND(-10006,"No QQ robot corresponding to this token was found"),
NO_ROBOT_FOUND_(-10007,"No QQ robot corresponding to this token was found"),
STATE_HAS_EXPIRED(-10008,"state has expired, please re-authorize."),
INVALID_EMAIL(-10009,"Invalid Email!");
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

View File

@ -0,0 +1,26 @@
package io.qyi.e5.config;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @program: demo
* @description:
* @author: 落叶随风
* @create: 2019-10-22 04:06
**/
@Configuration
@MapperScan(basePackages = {"io.qyi.e5.*.mapper"})
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}

View File

@ -0,0 +1,28 @@
package io.qyi.e5.config.quartz;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 16:14
**/
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}

View File

@ -0,0 +1,63 @@
package io.qyi.e5.config.quartz;
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.io.IOException;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 16:16
**/
public class SchedulerConfig implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private JobFactory jobFactory;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
System.out.println("任务已经启动..." + contextRefreshedEvent.getSource());
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
//获取配置属性
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
//创建SchedulerFactoryBean
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setQuartzProperties(propertiesFactoryBean.getObject());
//使用数据源自定义数据源
// factory.setDataSource(this.primaryDataSource);
factory.setJobFactory(jobFactory);
factory.setWaitForJobsToCompleteOnShutdown(true);//这样当spring关闭时会等待所有已经启动的quartz job结束后spring才能完全shutdown
factory.setOverwriteExistingJobs(false);
factory.setStartupDelay(1);
return factory;
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name="scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
}

View File

@ -0,0 +1,120 @@
package io.qyi.e5.config.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
/**
* @author JiaweiWu
* @description: redis配置
*/
@Configuration
//@AutoConfigureAfter(RedisAutoConfiguration.class)
//@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 自定义生成key的规则
*/
/* @Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
//格式化缓存key字符串
StringBuilder sb = new StringBuilder();
//追加类名
sb.append(o.getClass().getName());
//追加方法名
sb.append(method.getName());
//遍历参数并且追加
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println("调用Redis缓存Key : " + sb.toString());
return sb.toString();
}
};
}
*/
/**
* 采用RedisCacheManager作为缓存管理器
*
* @param connectionFactory
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.create(connectionFactory);
//设置缓存过期时间
//rcm.setDefaultExpiration(60);//
return redisCacheManager;
}
/**
* 配置自定义redisTemplate
* @return
*/
/*@Bean
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}*/
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

View File

@ -0,0 +1,46 @@
package io.qyi.e5.config.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2019-12-27 08:57
**/
@Component
public class SecurityAuthenticationHandler implements AuthenticationSuccessHandler, AuthenticationFailureHandler , LogoutSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setStatus(302);
httpServletResponse.setHeader("Location", "/user/home");
}
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write("Failure");
writer.flush();
}
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
writer.write("logout success");
writer.flush();
}
}

View File

@ -0,0 +1,94 @@
package io.qyi.e5.config.security;
import io.qyi.e5.service.security.SecurityUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2019-12-26 14:15
**/
@Configuration
@EnableWebSecurity //开启wen安全功能
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SecurityAuthenticationHandler securityAuthenticationHandler;
@Autowired
private SecurityUserService securityUserService;
@Autowired
UsernamePasswordAuthenticationConfig usernamePasswordAuthenticationConfig;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("AuthenticationManagerBuilder auth");
// auth.userDetailsService(securityUserService).passwordEncoder(new BCryptPasswordEncoder());
// auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
// .withUser("user").password(new BCryptPasswordEncoder().encode("123")).roles("user").and()
// .withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("USER", "ADMIN");
}
// 通过重载该方法可配置如何通过拦截器保护请求
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("HttpSecurity http");
/*http.authorizeRequests().antMatchers("/").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.logout().permitAll();
http.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login1")
.successHandler(securityAuthenticationHandler)
.failureHandler(securityAuthenticationHandler)
// .loginProcessingUrl("api/getInfo")
.permitAll()
.and()
.logout()
.logoutUrl("logout")
.logoutSuccessHandler( securityAuthenticationHandler);*/
http.csrf().disable()
.apply(usernamePasswordAuthenticationConfig);
http.formLogin()
.loginPage("/user/login")// 登陆页面
.loginProcessingUrl("/user/loginFrom")// 登陆表单提交请求
.and()
.authorizeRequests().antMatchers("/user/login", "/user/loginFrom", "/auth2/getGithubUrl").permitAll()// 指定相应的请求 不需要验证
.and()
.authorizeRequests().antMatchers("/quartz/**").permitAll()//测试
.anyRequest()// 任何请求
.authenticated();// 都需要身份认证
// http.exceptionHandling().accessDeniedHandler();
// http.formLogin().loginProcessingUrl("api/getInfo");
// http.formLogin().usernameParameter("username");
// http.formLogin().passwordParameter("password");
}
/*@Bean
public AccessDeniedHandler getAccessDeniedHandler() {
return new RestAuthenticationAccessDeniedHandler();
}*/
/* @Override
public void configure(WebSecurity web) {
System.out.println("WebSecurity web");
String antPatterns = "/pdfjs-2.1.266/**,/favicon.ico,/css/**,/js/**,/ico/**,/images/**,/jquery-1.12.4/**,/uuid-1.4/**,/layui-2.4.5/**,/jquery-easyui-1.6.11/**,/zTree-3.5.33/**,/select2-4.0.5/**,/greensock-js-1.20.5/**";
web.ignoring().antMatchers(antPatterns.split(","));
}*/
}

View File

@ -0,0 +1,47 @@
package io.qyi.e5.config.security;
import io.qyi.e5.config.security.filter.LoginAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-28 16:24
**/
@Component
public class UsernamePasswordAuthenticationConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
UsernamePasswordAuthenticationProvider usernamePasswordAuthenticationProvider;
@Autowired
SecurityAuthenticationHandler securityAuthenticationHandler;
@Override
public void configure(HttpSecurity http) throws Exception {
LoginAuthenticationFilter authenticationFilter = new LoginAuthenticationFilter();
logger.info("自定义用户认证处理逻辑");
// 自定义用户认证处理逻辑时需要指定AuthenticationManager否则无法认证
authenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
// 指定自定义的认证成功和失败的处理器
authenticationFilter.setAuthenticationSuccessHandler(securityAuthenticationHandler);
authenticationFilter.setAuthenticationFailureHandler(securityAuthenticationHandler);
// 把自定义的用户名密码认证过滤器和处理器添加到UsernamePasswordAuthenticationFilter过滤器之前
http.authenticationProvider(usernamePasswordAuthenticationProvider)
.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}

View File

@ -0,0 +1,113 @@
package io.qyi.e5.config.security;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.qyi.e5.bean.result.ResultEnum;
import io.qyi.e5.github.entity.Github;
import io.qyi.e5.github.entity.UserInfo;
import io.qyi.e5.github.mapper.GithubMapper;
import io.qyi.e5.service.github.GithubService;
import io.qyi.e5.util.ResultUtil;
import io.qyi.e5.util.redis.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-28 15:48
**/
//自定义的用户名密码认证实现类
@Component
public class UsernamePasswordAuthenticationProvider implements AuthenticationProvider {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${redis.auth2.github}")
String states;
@Value("${isdebug}")
boolean isDebug;
@Autowired
RedisUtil redisUtil;
@Autowired
GithubMapper githubMapper;
@Autowired
GithubService githubService;
// 验证
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 将未认证的Authentication转换成自定义的用户认证Token
UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken) authentication;
// 根据用户Token中的用户名查找用户信息如果有该用户信息则验证用户密码是否正确
String code = authenticationToken.getCode();
String state = authenticationToken.getState();
logger.info("Github 认证: code{} state{} Token", code, state);
if (isDebug) {
UsernamePasswordAuthenticationToken authenticationToken1 = new UsernamePasswordAuthenticationToken("debugName",
"DebugAvatar",19658189, AuthorityUtils.createAuthorityList("user"));
authenticationToken1.setDetails(authenticationToken);
return authenticationToken1;
}
if (!redisUtil.hasKey(states + state)) {
throw new UsernameNotFoundException("status不存在");
// return ResultUtil.error(ResultEnum.STATE_HAS_EXPIRED);
}
redisUtil.del(states + state);
String accessToken = githubService.getAccessToken(code);
if (accessToken == null) {
logger.error("accessToken 为空!");
throw new BadCredentialsException("accessToken 为空!");
}
UserInfo userInfo = githubService.getUserInfo(accessToken);
if (userInfo == null) {
logger.error("获取github用户信息失败!");
throw new BadCredentialsException("获取github用户信息失败!");
}
QueryWrapper<Github> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("github_id", userInfo.getGithub_id());
Github github = githubMapper.selectOne(queryWrapper);
// 未注册就进行注册
if (github == null) {
github = new Github();
github.setAccessToken(accessToken)
.setAvatarUrl(userInfo.getAvatar_url())
.setGithubId(userInfo.getGithub_id())
.setName(userInfo.getName())
.setLogin(userInfo.getLogin());
githubMapper.insert(github);
} else {
// 已注册就进行更新 AccessToken
github.setAccessToken(accessToken);
githubMapper.update(github, queryWrapper);
}
// 创建一个已认证的token
UsernamePasswordAuthenticationToken authenticationToken1 = new UsernamePasswordAuthenticationToken(github.getName(),
github.getAvatarUrl(),github.getGithubId(), AuthorityUtils.createAuthorityList("user"));
// 设置一些详细信息
authenticationToken1.setDetails(authenticationToken);
return authenticationToken1;
}
@Override
public boolean supports(Class<?> authentication) {
// 指定该认证处理器能对 UsernamePasswordAuthenticationToken 对象进行认证
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@ -0,0 +1,109 @@
package io.qyi.e5.config.security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-28 15:23
* setAuthenticated()判断是否已认证 生成登录session同用户不用再校验
**/
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* token
*/
private String code;
private String state;
private String name;
private String avatar_url;
private int github_id;
// 创建未认证的用户名密码认证对象
public UsernamePasswordAuthenticationToken(String code) {
super(null);
this.code = code;
super.setAuthenticated(false);
logger.info("MobileLoginAuthenticationToken setAuthenticated ->false loading ...");
}
// 创建未认证的用户名密码认证对象
public UsernamePasswordAuthenticationToken(String code, String state) {
super(null);
this.code = code;
this.state = state;
super.setAuthenticated(false);
logger.info("MobileLoginAuthenticationToken setAuthenticated ->false loading ...");
}
// 创建已认证的用户密码认证对象
public UsernamePasswordAuthenticationToken( String name, String avatar_url, int github_id,Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.name = name;
this.avatar_url = avatar_url;
this.github_id = github_id;
super.setAuthenticated(true);
}
@Override
public String getCredentials() {
return null;
}
@Override
public String getPrincipal() {
return this.code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAvatar_url() {
return avatar_url;
}
public void setAvatar_url(String avatar_url) {
this.avatar_url = avatar_url;
}
public int getGithub_id() {
return github_id;
}
public void setGithub_id(int github_id) {
this.github_id = github_id;
}
}

View File

@ -0,0 +1,74 @@
package io.qyi.e5.config.security.filter;
import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-28 11:56
**/
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
protected LoginAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
}
protected LoginAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
}
public LoginAuthenticationFilter() {
super(new AntPathRequestMatcher("/auth2/receive", "GET"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
/*if (!httpServletRequest.getMethod().equals(HttpMethod.POST.name())) {
throw new AuthenticationServiceException("不支持该验证方法: " + httpServletRequest.getMethod());
} else {
}*/
/**
* 从http请求中获取用户输入的用户名和密码信息
* 这里接收的是form形式的参数如果要接收json形式的参数修改这里即可
*/
String code = httpServletRequest.getParameter("code");
String state = httpServletRequest.getParameter("state");
if (StringUtils.isEmpty(code) || StringUtils.isEmpty(state)) {
throw new UsernameNotFoundException("CustomUsernamePasswordAuthenticationFilter获取用户认证信息失败");
}
/**
* 使用用户输入的用户名和密码信息创建一个未认证的用户认证Token
*/
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(code, state);
// 设置身份认证的详情信息
this.setDetails(httpServletRequest, authRequest);
// 通过AuthenticationManager调用相应的AuthenticationProvider进行用户认证
return this.getAuthenticationManager().authenticate(authRequest);
}
/**
* 设置身份认证的详情信息
*/
private void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
}

View File

@ -0,0 +1,94 @@
package io.qyi.e5.controller.auth2;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import io.qyi.e5.bean.result.Result;
import io.qyi.e5.bean.result.ResultEnum;
import io.qyi.e5.github.entity.Github;
import io.qyi.e5.github.entity.UserInfo;
import io.qyi.e5.github.mapper.GithubMapper;
import io.qyi.e5.service.github.GithubService;
import io.qyi.e5.user.mapper.UserMapper;
import io.qyi.e5.util.EncryptUtil;
import io.qyi.e5.util.ResultUtil;
import io.qyi.e5.util.redis.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-19 00:23
**/
@RequestMapping("/auth2")
@RestController
public class Auth {
@Autowired
RedisUtil redisUtil;
@Autowired
GithubService githubService;
@Autowired
UserMapper userMapper;
@Autowired
GithubMapper githubMapper;
@Value("${redis.auth2.github}")
String states;
@Value("${github.client_id}")
String client_id;
@RequestMapping("/getGithubUrl")
public void getGithubUrl(HttpServletResponse response) {
String state = EncryptUtil.getInstance().SHA1Hex(UUID.randomUUID().toString());
redisUtil.set(states + state, true, 600);
response.setStatus(302);
response.setHeader("Location", "https://github.com/login/oauth/authorize?client_id=" + client_id + "&redirect_uri=https://e5.qyi.io/auth2/receive&state=" + state);
}
/* @RequestMapping("/receive")
public Result Receive(String code, String state, HttpServletResponse response) throws Exception {
System.out.println(code);
System.out.println(state);
if (!redisUtil.hasKey(states + state)) {
return ResultUtil.error(ResultEnum.STATE_HAS_EXPIRED);
}
redisUtil.del(states + state);
String accessToken = githubService.getAccessToken(code);
if (accessToken != null) {
UserInfo userInfo = githubService.getUserInfo(accessToken);
if (userInfo != null) {
QueryWrapper<Github> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("github_id", userInfo.getGithub_id());
Github github = githubMapper.selectOne(queryWrapper);
// 未注册就进行注册
if (github == null) {
github = new Github();
github.setAccessToken(accessToken)
.setAvatarUrl(userInfo.getAvatar_url())
.setGithubId(userInfo.getGithub_id())
.setName(userInfo.getName())
.setLogin(userInfo.getLogin());
githubMapper.insert(github);
} else {
// 已注册就进行更新 AccessToken
github.setAccessToken(accessToken);
githubMapper.update(github, queryWrapper);
}
return ResultUtil.success();
}
}
return ResultUtil.error(ResultEnum.INVALID_EMAIL);
}*/
}

View File

@ -0,0 +1,53 @@
package io.qyi.e5.controller.quartz;
import io.qyi.e5.bean.AppQuartz;
import io.qyi.e5.service.quartz.JobUtil;
import io.qyi.e5.service.quartz.MyQuartzJobService;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 14:59
**/
@Controller
@RequestMapping("/quartz")
public class QuartzController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${qz_cron}")
private String qz_cron;
@Autowired
private JobUtil jobUtil;
@GetMapping("/add")
public void add() throws Exception {
logger.info("添加定时任务");
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("aaa", "test");
JobKey jobKey = new JobKey("crom任务", "我的cron任务组名1");
TriggerKey triggerKey1 = new TriggerKey("我的cron触发器名1", "我的cron触发器组名1");
AppQuartz appQuartz = new AppQuartz();
appQuartz.setJobGroup("t1");
appQuartz.setJobName("t1");
appQuartz.setQuartzId(1);
appQuartz.setCronExpression(qz_cron);
appQuartz.setStartTime("2020-03-03 16:03:11");
jobUtil.addJob(appQuartz,MyQuartzJobService.class);
// quartzManager.addJob(jobKey,triggerKey1, MyQuartzJobService.class, "0/20 * * * * ?", jobDataMap);
}
}

View File

@ -0,0 +1,60 @@
package io.qyi.e5.controller.web;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken;
import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.service.IOutlookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-27 16:03
**/
@Controller
public class WebController {
@Autowired
IOutlookService outlookService;
@RequestMapping("/")
public void index(HttpServletResponse httpServletResponse) {
httpServletResponse.setStatus(302);
httpServletResponse.setHeader("Location", "/user/home");
}
@RequestMapping("/user/login")
public String login(Model model) {
model.addAttribute("welcome", "hello fishpro");
return "user/login";
}
@RequestMapping("/user/home")
public String home(Model model) {
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
int github_id = authentication.getGithub_id();
QueryWrapper<Outlook> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("github_id", github_id);
Outlook one = outlookService.getOne(queryWrapper);
if (one != null) {
model.addAttribute("client_id", one.getClientId());
model.addAttribute("client_secret", one.getClientSecret());
} else {
model.addAttribute("client_id", "");
model.addAttribute("client_secret", "");
}
model.addAttribute("welcome", "hello fishpro");
return "user/home";
}
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.github.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@RestController
@RequestMapping("/github/github")
public class GithubController {
}

View File

@ -0,0 +1,56 @@
package io.qyi.e5.github.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Github implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 用户id
*/
private Integer userId;
private String accessToken;
/**
* 登录名
*/
private String login;
/**
* github的用户名
*/
private String name;
/**
* 头像url
*/
private String avatarUrl;
/**
* id
*/
private Integer githubId;
}

View File

@ -0,0 +1,19 @@
package io.qyi.e5.github.entity;
import lombok.Data;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-24 15:20
**/
@Data
public class UserInfo {
String login;
String name;
int github_id;
String node_id;
String avatar_url;
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.github.mapper;
import io.qyi.e5.github.entity.Github;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface GithubMapper extends BaseMapper<Github> {
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.github.service;
import io.qyi.e5.github.entity.Github;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface IGithubService extends IService<Github> {
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.github.service.impl;
import io.qyi.e5.github.entity.Github;
import io.qyi.e5.github.mapper.GithubMapper;
import io.qyi.e5.github.service.IGithubService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Service
public class GithubServiceImpl extends ServiceImpl<GithubMapper, Github> implements IGithubService {
}

View File

@ -0,0 +1,95 @@
package io.qyi.e5.outlook.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken;
import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.mapper.OutlookMapper;
import io.qyi.e5.outlook.service.IOutlookService;
import io.qyi.e5.util.EncryptUtil;
import io.qyi.e5.util.redis.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-24 16:02
**/
@Controller
@RequestMapping("/outlook/auth2")
public class AuthController {
@Autowired
RedisUtil redisUtil;
@Autowired
OutlookMapper outlookMapper;
@Autowired
IOutlookService outlookService;
@Value("${redis.auth2.outlook}")
String states;
@Value("${outlook.authorize.url}")
String authorizeUrl;
@RequestMapping("/receive")
public String Receive(Model model, String code, String state, String session_state, HttpServletResponse response) throws Exception {
model.addAttribute("result", false);
if (!redisUtil.hasKey(states + state)) {
model.addAttribute("msg", "state已过期重新点击授权!");
return "/user/authorization_outlook";
}
// 这里不应该查询在进行授权时因该把基础数据丢到redis
QueryWrapper<Outlook> outlookQueryWrapper = new QueryWrapper<>();
outlookQueryWrapper.eq("github_id", redisUtil.get(states + state));
Outlook outlook = outlookMapper.selectOne(outlookQueryWrapper);
// 删除redis中的此键
redisUtil.del(states + state);
if (outlook == null) {
model.addAttribute("msg", "没有查询到此用户,请检查是否在系统中注册!");
return "/user/authorization_outlook";
}
System.out.println(outlook);
boolean authorization_code = outlookService.getTokenAndSave(code, outlook.getClientId(), outlook.getClientSecret(), "https://e5.qyi.io/outlook/auth2/receive"
, "authorization_code");
if (authorization_code) {
model.addAttribute("result", true);
} else {
model.addAttribute("msg", "未知错误,请联系管理员~");
}
return "/user/authorization_outlook";
}
@ResponseBody
@RequestMapping("/getAuthorizeUrl")
public void getAuthorizeUrl(HttpServletResponse response) {
// 查询此用户的github_id与
QueryWrapper<Outlook> outlookQueryWrapper = new QueryWrapper<>();
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
outlookQueryWrapper.eq("github_id", authentication.getGithub_id());
Outlook outlook = outlookMapper.selectOne(outlookQueryWrapper);
if (outlook != null) {
// 生成随机uuid标识用户
String state = EncryptUtil.getInstance().SHA1Hex(UUID.randomUUID().toString());
redisUtil.set(states + state, outlook.getGithubId(), 600);
System.out.println(outlook);
String url = String.format(authorizeUrl, outlook.getClientId(), "https://e5.qyi.io/outlook/auth2/receive", state);
System.out.println(url);
response.setStatus(302);
response.setHeader("Location", url);
}
}
}

View File

@ -0,0 +1,37 @@
package io.qyi.e5.outlook.controller;
import io.qyi.e5.bean.result.Result;
import io.qyi.e5.bean.result.ResultEnum;
import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken;
import io.qyi.e5.outlook.service.IOutlookService;
import io.qyi.e5.util.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 前端控制器
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@RestController
@RequestMapping("/outlook/outlook")
public class OutlookController {
@Autowired
IOutlookService outlookService;
@PostMapping("/save")
public Result save(@RequestParam String client_id, @RequestParam String client_secret) {
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
if (outlookService.save(client_id, client_secret,authentication.getGithub_id())) {
return ResultUtil.success();
}
return ResultUtil.error(ResultEnum.UNKNOWN_ERROR);
}
}

View File

@ -0,0 +1,47 @@
package io.qyi.e5.outlook.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Outlook implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 用户id
*/
private Integer githubId;
private String idToken;
private String clientId;
private String clientSecret;
/**
* 刷新令牌
*/
private String refreshToken;
private String accessToken;
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.outlook.mapper;
import io.qyi.e5.outlook.entity.Outlook;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface OutlookMapper extends BaseMapper<Outlook> {
}

View File

@ -0,0 +1,26 @@
package io.qyi.e5.outlook.service;
import io.qyi.e5.outlook.entity.Outlook;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface IOutlookService extends IService<Outlook> {
boolean getTokenAndSave(String code,String client_id,String client_secret,String redirect_uri,String grant_type) throws Exception;
boolean save(String client_id,String client_secret,int github_id);
boolean getMailList(Outlook outlook);
List<Outlook> findAll();
}

View File

@ -0,0 +1,195 @@
package io.qyi.e5.outlook.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.qyi.e5.github.entity.Github;
import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.mapper.OutlookMapper;
import io.qyi.e5.outlook.service.IOutlookService;
import io.qyi.e5.outlook_log.service.IOutlookLogService;
import io.qyi.e5.util.netRequest.OkHttpClientUtil;
import io.qyi.e5.util.netRequest.OkHttpRequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 服务实现类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Service
public class OutlookServiceImpl extends ServiceImpl<OutlookMapper, Outlook> implements IOutlookService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
IOutlookLogService outlookLogService;
// 2020-03-2 10:38 这里需要进行查询判断数据库是否有内容再进行插入
@Override
public boolean getTokenAndSave(String code, String client_id, String client_secret, String redirect_uri, String grant_type) throws Exception {
Map<String, Object> head = new HashMap<>();
head.put("Content-Type", "application/x-www-form-urlencoded");
Map<String, Object> par = new HashMap<>();
par.put("client_id", client_id);
par.put("client_secret", client_secret);
par.put("code", code);
par.put("redirect_uri", redirect_uri);
par.put("grant_type", grant_type);
String s = OkHttpClientUtil.doPost("https://login.microsoftonline.com/common/oauth2/v2.0/token", head, par);
JSONObject jsonObject = JSON.parseObject(s);
logger.info("请求access_token返回数据" + s);
if (jsonObject.get("error") != null) {
logger.error("错授权误!");
return false;
} else {
int expires_in = jsonObject.getIntValue("expires_in");
String access_token = jsonObject.getString("access_token");
String refresh_token = jsonObject.getString("refresh_token");
String id_token = jsonObject.getString("id_token");
Outlook outlook = new Outlook();
outlook.setAccessToken(access_token)
.setRefreshToken(refresh_token)
.setIdToken(id_token);
UpdateWrapper<Outlook> outlookUpdateWrapper = new UpdateWrapper<>();
outlookUpdateWrapper.eq("client_id", client_id);
baseMapper.update(outlook, outlookUpdateWrapper);
return true;
}
}
@Override
public boolean save(String client_id, String client_secret, int github_id) {
if (github_id == 0) {
return false;
}
QueryWrapper<Outlook> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("github_id", github_id)
.or().eq("client_id",client_id);
Outlook outlook1 = baseMapper.selectOne(queryWrapper);
// 有数据
if (outlook1 != null) {
outlook1.setClientId(client_id)
.setClientSecret(client_secret);
int i = baseMapper.update(outlook1, queryWrapper);
if (i == 1) {
return true;
}
} else {
Outlook outlook = new Outlook();
outlook.setClientId(client_id)
.setClientSecret(client_secret)
.setGithubId(github_id);
int i = baseMapper.insert(outlook);
if (i == 1) {
return true;
}
}
return false;
}
@Override
public List<Outlook> findAll() {
return baseMapper.selectList(null);
}
@Override
public boolean getMailList(Outlook outlook) {
try {
String s = MailList(outlook.getAccessToken());
JSONObject json = JSON.parseObject(s);
// 报错
if (json.containsKey("error")) {
String code = json.getJSONObject("error").getString("code");
String message = json.getJSONObject("error").getString("message");
if (!("Access token has expired.".equals(message) || "Access token validation failure.".equals(message))) {
outlookLogService.addLog(outlook.getGithubId(), "无法刷新令牌!code:3", "0", json.getJSONObject("error").getString("message"));
return false;
}
logger.info("令牌过期!");
String token = refresh_token(outlook);
if (token == null) {
return false;
}
s = MailList(token);
json = JSON.parseObject(s);
if (json.containsKey("error")) {
outlookLogService.addLog(outlook.getGithubId(), "无法刷新令牌!code:2", "0", json.getJSONObject("error").getString("message"));
return false;
}
}
outlookLogService.addLog(outlook.getGithubId(), "ok", "1", "");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public String MailList(String access_token) throws Exception {
Map<String, Object> head = new HashMap<>();
head.put("Content-Type", "application/json");
head.put("Authorization", access_token);
String s = OkHttpRequestUtils.doGet("https://graph.microsoft.com/v1.0/me/messages?$select=sender,subject", head, null);
logger.info("请求邮件列表返回数据:" + s);
return s;
}
// 刷新令牌同时更新数据库中的令牌
public String refresh_token(Outlook outlook) {
Map<String, Object> head = new HashMap<>();
head.put("Content-Type", "application/x-www-form-urlencoded");
Map<String, Object> par = new HashMap<>();
par.put("client_id", outlook.getClientId());
par.put("scope", "openid offline_access Mail.Read");
par.put("client_secret", outlook.getClientSecret());
par.put("grant_type", "refresh_token");
par.put("refresh_token", outlook.getRefreshToken());
String s = null;
try {
s = OkHttpClientUtil.doPost("https://login.microsoftonline.com/common/oauth2/v2.0/token", head, par);
logger.info("请求刷新列表返回数据:" + s);
JSONObject jsonObject = JSON.parseObject(s);
if (!jsonObject.containsKey("access_token")) {
logger.info("返回的access_token字段不存在");
outlookLogService.addLog(outlook.getGithubId(), "无法刷新令牌! 需要重新授权!", "0", s);
// 字段不存在
return null;
}
outlook.setRefreshToken(jsonObject.getString("refresh_token"));
outlook.setAccessToken(jsonObject.getString("access_token"));
outlook.setIdToken(jsonObject.getString("id_token"));
QueryWrapper<Outlook> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("client_id", outlook.getClientId());
if (baseMapper.update(outlook, queryWrapper) != 1) {
logger.info("返更新行数不为1");
outlookLogService.addLog(outlook.getGithubId(), "更新数据库时发现有重复的key", "0", "");
return null;
}
return outlook.getAccessToken();
// 更新数据库
} catch (Exception e) {
e.printStackTrace();
outlookLogService.addLog(outlook.getGithubId(), e.getMessage(), "0", e.getMessage());
return null;
}
}
}

View File

@ -0,0 +1,85 @@
package io.qyi.e5.outlook_log.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.qyi.e5.config.security.UsernamePasswordAuthenticationToken;
import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.service.IOutlookService;
import io.qyi.e5.outlook_log.entity.OutlookLog;
import io.qyi.e5.outlook_log.mapper.OutlookLogMapper;
import io.qyi.e5.outlook_log.service.IOutlookLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @author 落叶
* @since 2020-03-03
*/
@Controller
@RequestMapping("/outlookLog")
public class OutlookLogController {
// @Autowired
// private OutlookLogMapper outlookLogMapper;
@Autowired
private IOutlookLogService outlookLogService;
@Autowired
IOutlookService outlookService;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Value("${page.size}")
private int pageSize;
@GetMapping("/findLog")
public String findLog(Model model){
UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
int github_id = authentication.getGithub_id();
/*QueryWrapper<OutlookLog> wrapper = new QueryWrapper();
wrapper.eq("github_id", github_id);
Page<OutlookLog> page = new Page<>(8,pageSize);
IPage<Map<String, Object>> mapIPage = outlookLogMapper.selectMapsPage(page, wrapper);
System.out.println("总页数"+mapIPage.getPages());
System.out.println("总记录数"+mapIPage.getTotal());
List<Map<String, Object>> records = mapIPage.getRecords();
records.forEach(System.out::println);*/
QueryWrapper<OutlookLog> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("github_id", github_id);
List<OutlookLog> list = outlookLogService.list(queryWrapper);
model.addAttribute("list_log", list);
return "/outlookLog/findLog";
}
@GetMapping("/exec111111")
public void s(){
List<Outlook> list = outlookService.findAll();
logger.info(String.valueOf(list.size()));
for (Outlook outlook :list) {
logger.info(outlook.toString());
outlookService.getMailList(outlook);
}
}
}

View File

@ -0,0 +1,54 @@
package io.qyi.e5.outlook_log.entity;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 落叶
* @since 2020-03-03
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class OutlookLog implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* github_id
*/
private Integer githubId;
/**
* 调用时间
*/
private String callTime;
/**
* 调用结果
*/
private String result;
/**
* 如果有错误原因则记录
*/
private String msg;
/**
* 原始错误消息
*/
private String originalMsg;
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.outlook_log.mapper;
import io.qyi.e5.outlook_log.entity.OutlookLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author 落叶
* @since 2020-03-03
*/
public interface OutlookLogMapper extends BaseMapper<OutlookLog> {
}

View File

@ -0,0 +1,17 @@
package io.qyi.e5.outlook_log.service;
import io.qyi.e5.outlook_log.entity.OutlookLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author 落叶
* @since 2020-03-03
*/
public interface IOutlookLogService extends IService<OutlookLog> {
void addLog(int githubId, String msg,String result,String original_msg);
}

View File

@ -0,0 +1,30 @@
package io.qyi.e5.outlook_log.service.impl;
import io.qyi.e5.outlook_log.entity.OutlookLog;
import io.qyi.e5.outlook_log.mapper.OutlookLogMapper;
import io.qyi.e5.outlook_log.service.IOutlookLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author 落叶
* @since 2020-03-03
*/
@Service
public class OutlookLogServiceImpl extends ServiceImpl<OutlookLogMapper, OutlookLog> implements IOutlookLogService {
@Override
public void addLog(int githubId, String msg, String result,String original_msg) {
OutlookLog outlookLog = new OutlookLog();
outlookLog.setGithubId(githubId)
.setResult(result.equals("1") ? "1" : "0")
.setCallTime(String.valueOf(System.currentTimeMillis() / 1000))
.setMsg(msg)
.setOriginalMsg(original_msg);
baseMapper.insert(outlookLog);
}
}

View File

@ -0,0 +1,18 @@
package io.qyi.e5.service.github;
import io.qyi.e5.github.entity.UserInfo;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-20 00:47
**/
public interface GithubService {
String getAccessToken(String code);
String getUserEmail(String access_token) throws Exception;
UserInfo getUserInfo(String access_token);
}

View File

@ -0,0 +1,90 @@
package io.qyi.e5.service.github.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.qyi.e5.github.entity.UserInfo;
import io.qyi.e5.service.github.GithubService;
import io.qyi.e5.util.StringUtil;
import io.qyi.e5.util.netRequest.OkHttpRequestUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-20 00:56
**/
@Service("GithubService")
public class GithubServiceImpl implements GithubService {
@Value("${github.client_id}")
private String client_id;
@Value("${github.client_secret}")
private String client_secret;
@Override
public String getAccessToken(String code) {
Map<String, Object> par = new HashMap<>();
par.put("client_id", client_id);
par.put("client_secret", client_secret);
par.put("code", code);
Map<String, Object> head = new HashMap<>();
head.put("Content-Type", "application/x-www-form-urlencoded");
String s = null;
try {
s = OkHttpRequestUtils.doPost("https://github.com/login/oauth/access_token", head, par);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(s);
Map<String, String> map = StringUtil.ParsingUrl(s);
return map.get("access_token");
}
@Override
public String getUserEmail(String access_token) throws Exception {
Map<String, Object> head = new HashMap<>();
head.put("Authorization", "token " + access_token);
head.put("Content-Type", "application/vnd.github.machine-man-preview+json");
String s = OkHttpRequestUtils.doGet("https://api.github.com/user/emails", head, null);
System.out.println(s);
JSONArray jsonArray = JSON.parseArray(s);
if (!jsonArray.isEmpty()) {
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
// 电子邮件是主要的并且已通过验证
if (jsonObject.getBoolean("primary") && jsonObject.getBoolean("verified")) {
return jsonObject.getString("email");
}
}
}
return null;
}
@Override
public UserInfo getUserInfo(String access_token) {
Map<String, Object> head = new HashMap<>();
head.put("Authorization", "token " + access_token);
head.put("Content-Type", "application/vnd.github.machine-man-preview+json");
try {
String s = OkHttpRequestUtils.doGet("https://api.github.com/user", head, null);
JSONObject jsonObject = JSON.parseObject(s);
UserInfo userInfo = new UserInfo();
if (!jsonObject.isEmpty()) {
userInfo.setLogin(jsonObject.getString("login"));
userInfo.setName(jsonObject.getString("name"));
userInfo.setAvatar_url(jsonObject.getString("avatar_url"));
userInfo.setGithub_id(jsonObject.getIntValue("id"));
userInfo.setNode_id(jsonObject.getString("node_id"));
}
return userInfo;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,152 @@
package io.qyi.e5.service.quartz;
import io.qyi.e5.bean.AppQuartz;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 16:18
**/
@Service
public class JobUtil {
@Autowired
private Scheduler scheduler;
/**
* 新建一个任务
*/
public String addJob(AppQuartz appQuartz, Class aClass) throws Exception {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Date date = df.parse(appQuartz.getStartTime());
if (!CronExpression.isValidExpression(appQuartz.getCronExpression())) {
return "Illegal cron expression"; //表达式格式不正确
}
// JobDetail jobDetail = null;
//构建job信息
/*if("JobOne".equals(appQuartz.getJobGroup())) {
jobDetail = JobBuilder.newJob(JobOne.class).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
}
if("JobTwo".equals(appQuartz.getJobGroup())) {
jobDetail = JobBuilder.newJob(JobTwo.class).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
}*/
JobDetail jobDetail = JobBuilder.newJob(aClass).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
//表达式调度构建器(即任务执行的时间,不立即执行)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(appQuartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).startNow()
.withSchedule(scheduleBuilder).build();
//传递参数
if (appQuartz.getInvokeParam() != null && !"".equals(appQuartz.getInvokeParam())) {
trigger.getJobDataMap().put("invokeParam", appQuartz.getInvokeParam());
}
scheduler.scheduleJob(jobDetail, trigger);
// pauseJob(appQuartz.getJobName(),appQuartz.getJobGroup());
return "success";
}
/**
* 获取Job状态
*
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public String getJobState(String jobName, String jobGroup) throws SchedulerException {
TriggerKey triggerKey = new TriggerKey(jobName, jobGroup);
return scheduler.getTriggerState(triggerKey).name();
}
//暂停所有任务
public void pauseAllJob() throws SchedulerException {
scheduler.pauseAll();
}
//暂停任务
public String pauseJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return "fail";
} else {
scheduler.pauseJob(jobKey);
return "success";
}
}
//恢复所有任务
public void resumeAllJob() throws SchedulerException {
scheduler.resumeAll();
}
// 恢复某个任务
public String resumeJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return "fail";
} else {
scheduler.resumeJob(jobKey);
return "success";
}
}
//删除某个任务
public String deleteJob(AppQuartz appQuartz) throws SchedulerException {
JobKey jobKey = new JobKey(appQuartz.getJobName(), appQuartz.getJobGroup());
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return "jobDetail is null";
} else if (!scheduler.checkExists(jobKey)) {
return "jobKey is not exists";
} else {
scheduler.deleteJob(jobKey);
return "success";
}
}
//修改任务
public String modifyJob(AppQuartz appQuartz) throws SchedulerException {
if (!CronExpression.isValidExpression(appQuartz.getCronExpression())) {
return "Illegal cron expression";
}
TriggerKey triggerKey = TriggerKey.triggerKey(appQuartz.getJobName(), appQuartz.getJobGroup());
JobKey jobKey = new JobKey(appQuartz.getJobName(), appQuartz.getJobGroup());
if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//表达式调度构建器,不立即执行
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(appQuartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//修改参数
if (!trigger.getJobDataMap().get("invokeParam").equals(appQuartz.getInvokeParam())) {
trigger.getJobDataMap().put("invokeParam", appQuartz.getInvokeParam());
}
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
return "success";
} else {
return "job or trigger not exists";
}
}
}

View File

@ -0,0 +1,38 @@
package io.qyi.e5.service.quartz;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.qyi.e5.outlook.entity.Outlook;
import io.qyi.e5.outlook.service.IOutlookService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 14:37
**/
public class MyQuartzJobService implements Job {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
IOutlookService outlookService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.info("定时任务被调用~");
// QueryWrapper<Outlook> queryWrapper = new QueryWrapper<>();
List<Outlook> list = outlookService.findAll();
logger.info(String.valueOf(list.size()));
for (Outlook outlook :list) {
logger.info(outlook.toString());
outlookService.getMailList(outlook);
}
}
}

View File

@ -0,0 +1,39 @@
package io.qyi.e5.service.security;
import io.qyi.e5.user.mapper.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-02-26 21:38
**/
@Component
public class SecurityUserService implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String encode = bCryptPasswordEncoder.encode("123");
String encodePasswd = encode;
logger.info("登录用户名: {} , 密码:{}",s,encodePasswd);
UserDetails userDetails = new User(s, encode, AuthorityUtils.createAuthorityList("admin"));
return userDetails;
}
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.user.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@RestController
@RequestMapping("/user/permission")
public class PermissionController {
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.user.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@RestController
@RequestMapping("/user/role")
public class RoleController {
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.user.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@RestController
@RequestMapping("/user/user")
public class UserController {
}

View File

@ -0,0 +1,34 @@
package io.qyi.e5.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Permission implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 所拥有的权限
*/
private String permission;
}

View File

@ -0,0 +1,39 @@
package io.qyi.e5.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class Role implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 角色名称
*/
private String rolename;
/**
* 权限id
*/
private String permission;
}

View File

@ -0,0 +1,51 @@
package io.qyi.e5.user.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
private String name;
/**
* 密码使用sha512
*/
private String passwd;
/**
* 角色id
*/
private String role;
/**
* 邮箱
*/
private String email;
/**
* 账户状态,1启用 0禁用
*/
private String status;
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.user.mapper;
import io.qyi.e5.user.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface PermissionMapper extends BaseMapper<Permission> {
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.user.mapper;
import io.qyi.e5.user.entity.Role;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface RoleMapper extends BaseMapper<Role> {
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.user.mapper;
import io.qyi.e5.user.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface UserMapper extends BaseMapper<User> {
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.user.service;
import io.qyi.e5.user.entity.Permission;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface IPermissionService extends IService<Permission> {
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.user.service;
import io.qyi.e5.user.entity.Role;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface IRoleService extends IService<Role> {
}

View File

@ -0,0 +1,16 @@
package io.qyi.e5.user.service;
import io.qyi.e5.user.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
public interface IUserService extends IService<User> {
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.user.service.impl;
import io.qyi.e5.user.entity.Permission;
import io.qyi.e5.user.mapper.PermissionMapper;
import io.qyi.e5.user.service.IPermissionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.user.service.impl;
import io.qyi.e5.user.entity.Role;
import io.qyi.e5.user.mapper.RoleMapper;
import io.qyi.e5.user.service.IRoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements IRoleService {
}

View File

@ -0,0 +1,20 @@
package io.qyi.e5.user.service.impl;
import io.qyi.e5.user.entity.User;
import io.qyi.e5.user.mapper.UserMapper;
import io.qyi.e5.user.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author 落叶
* @since 2020-02-24
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

View File

@ -0,0 +1,339 @@
package io.qyi.e5.util;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
public class EncryptUtil {
public static final String MD5 = "MD5";
public static final String SHA1 = "SHA1";
public static final String HmacMD5 = "HmacMD5";
public static final String HmacSHA1 = "HmacSHA1";
public static final String DES = "DES";
public static final String AES = "AES";
/**
* 编码格式默认使用uft-8
*/
public String charset = "utf-8";
/**
* DES
*/
public int keysizeDES = 0;
/**
* AES
*/
public int keysizeAES = 128;
public static EncryptUtil me;
private EncryptUtil() {
//单例
}
//双重锁
public static EncryptUtil getInstance() {
if (me == null) {
synchronized (EncryptUtil.class) {
if (me == null) {
me = new EncryptUtil();
}
}
}
return me;
}
/**
* 使用MessageDigest进行单向加密无密码
*
* @param res 被加密的文本
* @param algorithm 加密算法名称
* @return
*/
private String messageDigest(String res, String algorithm) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
return base64(md.digest(resBytes));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 使用MessageDigest进行单向加密无密码
*
* @param res 被加密的文本
* @param algorithm 加密算法名称
* @return
*/
private String messageDigestHex(String res, String algorithm) {
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
return NumConvertUtil.bytesToHexString(md.digest(resBytes));
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 使用KeyGenerator进行单向/双向加密可设密码
*
* @param res 被加密的原文
* @param algorithm 加密使用的算法名称
* @param key 加密使用的秘钥
* @return
*/
private String keyGeneratorMac(String res, String algorithm, String key) {
try {
SecretKey sk = null;
if (key == null) {
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
sk = kg.generateKey();
} else {
byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
sk = new SecretKeySpec(keyBytes, algorithm);
}
Mac mac = Mac.getInstance(algorithm);
mac.init(sk);
byte[] result = mac.doFinal(res.getBytes());
return base64(result);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 使用KeyGenerator双向加密DES/AES注意这里转化为字符串的时候是将2进制转为16进制格式的字符串不是直接转因为会出错
*
* @param res 加密的原文
* @param algorithm 加密使用的算法名称
* @param key 加密的秘钥
* @param keysize
* @param isEncode
* @return
*/
private String keyGeneratorES(String res, String algorithm, String key, int keysize, boolean isEncode) {
try {
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
if (keysize == 0) {
byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
kg.init(new SecureRandom(keyBytes));
} else if (key == null) {
kg.init(keysize);
} else {
byte[] keyBytes = charset == null ? key.getBytes() : key.getBytes(charset);
kg.init(keysize, new SecureRandom(keyBytes));
}
SecretKey sk = kg.generateKey();
SecretKeySpec sks = new SecretKeySpec(sk.getEncoded(), algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
if (isEncode) {
cipher.init(Cipher.ENCRYPT_MODE, sks);
byte[] resBytes = charset == null ? res.getBytes() : res.getBytes(charset);
return parseByte2HexStr(cipher.doFinal(resBytes));
} else {
cipher.init(Cipher.DECRYPT_MODE, sks);
return new String(cipher.doFinal(parseHexStr2Byte(res)));
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private String base64(byte[] res) {
return Base64.encode(res);
}
/**
* 将二进制转换成16进制
*/
public static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*/
public static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
/**
* md5加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @return
*/
public String MD5(String res) {
return messageDigest(res, MD5);
}
/**
* md5加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @param key 秘钥
* @return
*/
public String MD5(String res, String key) {
return keyGeneratorMac(res, HmacMD5, key);
}
/**
* 使用SHA1加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @return
*/
public String SHA1(String res) {
return messageDigest(res, SHA1);
}
public String SHA1Hex(String res) {
return messageDigestHex(res, SHA1);
}
/**
* 使用SHA1加密算法进行加密不可逆
*
* @param res 需要加密的原文
* @param key 秘钥
* @return
*/
public String SHA1(String res, String key) {
return keyGeneratorMac(res, HmacSHA1, key);
}
/**
* 使用DES加密算法进行加密可逆
*
* @param res 需要加密的原文
* @param key 秘钥
* @return
*/
public String DESencode(String res, String key) {
return keyGeneratorES(res, DES, key, keysizeDES, true);
}
/**
* 对使用DES加密算法的密文进行解密可逆
*
* @param res 需要解密的密文
* @param key 秘钥
* @return
*/
public String DESdecode(String res, String key) {
return keyGeneratorES(res, DES, key, keysizeDES, false);
}
/**
* 使用AES加密算法经行加密可逆
*
* @param res 需要加密的密文
* @param key 秘钥
* @return
*/
public String AESencode(String res, String key) {
return keyGeneratorES(res, AES, key, keysizeAES, true);
}
/**
* 对使用AES加密算法的密文进行解密
*
* @param res 需要解密的密文
* @param key 秘钥
* @return
*/
public String AESdecode(String res, String key) {
return keyGeneratorES(res, AES, key, keysizeAES, false);
}
/**
* 使用异或进行加密
*
* @param res 需要加密的密文
* @param key 秘钥
* @return
*/
public String XORencode(String res, String key) {
byte[] bs = res.getBytes();
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) ((bs[i]) ^ key.hashCode());
}
return parseByte2HexStr(bs);
}
/**
* 使用异或进行解密
*
* @param res 需要解密的密文
* @param key 秘钥
* @return
*/
public String XORdecode(String res, String key) {
byte[] bs = parseHexStr2Byte(res);
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) ((bs[i]) ^ key.hashCode());
}
return new String(bs);
}
/**
* 直接使用异或第一调用加密第二次调用解密
*
* @param res 密文
* @param key 秘钥
* @return
*/
public int XOR(int res, String key) {
return res ^ key.hashCode();
}
/**
* 使用Base64进行加密
*
* @param res 密文
* @return
*/
public String Base64Encode(String res) {
return Base64.encode(res.getBytes());
}
/**
* 使用Base64进行解密
*
* @param res
* @return
*/
public String Base64Decode(String res) {
return new String(Base64.decode(res));
}
}

View File

@ -0,0 +1,185 @@
package io.qyi.e5.util;
import java.text.DecimalFormat;
/**
* 数据类型转换工具类
* @author cyf
*
*/
public class NumConvertUtil{
/**
* bytes 转16进制字符串
* @param bArray
* @return
*/
public static final String bytesToHexString(byte[] bArray) {
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString(0xFF & bArray[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
/**
* 16进制字符串转bytes
* @param hex
* @return
*/
public static byte[] hexStringToByte(String hex) {
int len = 0;
int num=0;
//判断字符串的长度是否是两位
if(hex.length()>=2){
//判断字符喜欢是否是偶数
len=(hex.length() / 2);
num = (hex.length() % 2);
if (num == 1) {
hex = "0" + hex;
len=len+1;
}
}else{
hex = "0" + hex;
len=1;
}
byte[] result = new byte[len];
char[] achar = hex.toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
}
return result;
}
private static int toByte(char c) {
if (c >= 'a')
return (c - 'a' + 10) & 0x0f;
if (c >= 'A')
return (c - 'A' + 10) & 0x0f;
return (c - '0') & 0x0f;
}
/**
* 16进制字符串转十进制int
* @param HexString
* @return
*/
public static int HexStringToInt(String HexString) {
int inJTFingerLockAddress = Integer.valueOf(HexString, 16);
return inJTFingerLockAddress;
}
/**
* 十进制int转16进制字符串
* @param HexString
* @return
*/
public static String IntToHexString(int num) {
String hexString = Integer.toHexString(num);
return hexString;
}
/**
* 16进制String转BCD
* @param asc
* @return
*/
public static byte[] strToBcd(String asc) {
int len = asc.length();
int mod = len % 2;
if (mod != 0) {
asc = "0" + asc;
len = asc.length();
}
byte abt[] = new byte[len];
if (len >= 2) {
len = len / 2;
}
byte bbt[] = new byte[len];
abt = asc.getBytes();
int j, k;
for (int p = 0; p < asc.length()/2; p++) {
if ( (abt[2 * p] >= '0') && (abt[2 * p] <= '9')) {
j = abt[2 * p] - '0';
} else if ( (abt[2 * p] >= 'a') && (abt[2 * p] <= 'z')) {
j = abt[2 * p] - 'a' + 0x0a;
} else {
j = abt[2 * p] - 'A' + 0x0a;
}
if ( (abt[2 * p + 1] >= '0') && (abt[2 * p + 1] <= '9')) {
k = abt[2 * p + 1] - '0';
} else if ( (abt[2 * p + 1] >= 'a') && (abt[2 * p + 1] <= 'z')) {
k = abt[2 * p + 1] - 'a' + 0x0a;
}else {
k = abt[2 * p + 1] - 'A' + 0x0a;
}
int a = (j << 4) + k;
byte b = (byte) a;
bbt[p] = b;
}
return bbt;
}
/**
* String 类型数字转化为Double 保留置顶小数位(用于显示金额等)
* @param money
* @param type 保留小数点位数 #.00保留两位 #.0保留一位 #保留整数
* @return
*/
public static String strToDouble(String money,String type){
String toDouble= new DecimalFormat(type).format(Double.parseDouble(money));
return toDouble;
}
}

View File

@ -0,0 +1,49 @@
package io.qyi.e5.util;
import io.qyi.e5.bean.result.Result;
import io.qyi.e5.bean.result.ResultEnum;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-05 21:05
**/
public class ResultUtil extends Throwable {
public static Result success(Object object) {
Result result = new Result();
result.setCode(0);
result.setMsg("ok");
result.setData(object);
return result;
}
public static Result success() {
return success(null);
}
public static Result error(Integer code, String msg) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
public static Result success(ResultEnum resultEnum, Object object) {
Result result = new Result();
result.setCode(resultEnum.getCode());
result.setMsg(resultEnum.getMsg());
result.setData(object);
return result;
}
public static Result error(ResultEnum msg) {
Result result = new Result();
result.setCode(msg.getCode());
result.setMsg(msg.getMsg());
return result;
}
}

View File

@ -0,0 +1,48 @@
package io.qyi.e5.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @program: lotter2
* @description:
* @author: 落叶随风
* @create: 2019-10-09 01:26
**/
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(this.applicationContext == null) {
this.applicationContext = applicationContext;
}
System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringUtil.applicationContext+"========");
System.out.println("---------------------------------------------------------------------");
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
}

View File

@ -0,0 +1,27 @@
package io.qyi.e5.util;
import java.util.HashMap;
import java.util.Map;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-20 23:59
**/
public class StringUtil {
public static Map<String, String> ParsingUrl(String url){
String[] split = url.split("&");
Map<String, String> map = new HashMap<>();
for (int i = 0; i < split.length; i++) {
String[] split1 = split[i].split("=");
if (split1.length > 1) {
System.out.println(split1[0] + " --- " + split1[1]);
map.put(split1[0], split1[1]);
} else {
map.put(split1[0], "");
}
}
return map;
}
}

View File

@ -0,0 +1,260 @@
package io.qyi.e5.util;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Random;
/**
* @author yellowcong
* 创建日期:2018/02/06
* 验证码信息
*/
public class VerifyCode {
//宽度
private static final int CAPTCHA_WIDTH = 100;
//高度
private static final int CAPTCHA_HEIGHT = 35;
//数字的长度
private static final int NUMBER_CNT = 6;
//图片类型
private static final String IMAGE_TYPE = "JPEG";
private Random r = new Random();
// 字体
// private String[] fontNames = { "宋体", "华文楷体", "黑体", "华文新魏", "华文隶书", "微软雅黑", "楷体_GB2312" };
private String[] fontNames = {"宋体", "黑体", "微软雅黑"};
// 可选字符
private String codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
// 背景色,白色
private Color bgColor = new Color(255, 255, 255);
// 验证码上的文本
private String text;
private static VerifyCode utils = null;
/**
* 实例化对象
*
* @return
*/
public static VerifyCode getInstance() {
if (utils == null) {
synchronized (VerifyCode.class) {
if (utils == null) {
utils = new VerifyCode();
}
}
}
return utils;
}
/**
* 创建验证码
*
* @param path 路径地址
* @return
* @throws Exception
*/
public String getCode(String path) throws Exception {
BufferedImage bi = utils.getImage();
output(bi, new FileOutputStream(path));
return this.text;
}
/**
* 创建日期:2018年2月6日<br/>
* 创建时间:下午7:22:36<br/>
* 创建用户:yellowcong<br/>
* 机能概要:生成图片对象并返回
*
* @return
* @throws Exception
*/
public CaptchaCode getCode() throws Exception {
BufferedImage img = utils.getImage();
//返回验证码对象
CaptchaCode code = new CaptchaCode();
code.setText(this.text);
code.setData(this.copyImage2Byte(img));
return code;
}
/**
* 创建日期:2018年2月6日<br/>
* 创建时间:下午7:17:28<br/>
* 创建用户:yellowcong<br/>
* 机能概要:将图片转化为 二进制数据
*
* @param img
* @return
* @throws Exception
*/
public byte[] copyImage2Byte(BufferedImage img) throws Exception {
//字节码输出流
ByteArrayOutputStream bout = new ByteArrayOutputStream();
//写数据到输出流中
ImageIO.write(img, IMAGE_TYPE, bout);
//返回数据
return bout.toByteArray();
}
/**
* 创建日期:2018年2月6日<br/>
* 创建时间:下午7:20:50<br/>
* 创建用户:yellowcong<br/>
* 机能概要:将二进制数据转化为文件
*
* @param data
* @param file
* @throws Exception
*/
public boolean copyByte2File(byte[] data, String file) throws Exception {
ByteArrayInputStream in = new ByteArrayInputStream(data);
FileOutputStream out = new FileOutputStream(file);
try {
byte[] buff = new byte[1024];
int len = 0;
while ((len = in.read(buff)) > -1) {
out.write(buff, 0, len);
}
out.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
out.close();
in.close();
}
}
/**
* 创建日期:2018年2月6日<br/>
* 创建时间:下午7:03:57<br/>
* 创建用户:yellowcong<br/>
* 机能概要:生成随机的颜色
*
* @return
*/
private Color randomColor() {
int red = r.nextInt(150);
int green = r.nextInt(150);
int blue = r.nextInt(150);
return new Color(red, green, blue);
}
/**
* 创建日期:2018年2月6日<br/>
* 创建时间:下午7:03:20<br/>
* 创建用户:yellowcong<br/>
* 机能概要:生成随机的字体
*
* @return
*/
private Font randomFont() {
int index = r.nextInt(fontNames.length);
String fontName = fontNames[index];// 生成随机的字体名称
int style = r.nextInt(4);// 生成随机的样式, 0(无样式), 1(粗体), 2(斜体), 3(粗体+斜体)
int size = r.nextInt(5) + 24; // 生成随机字号, 24 ~ 28
return new Font(fontName, style, size);
}
// 画干扰线
private void drawLine(BufferedImage image) {
int num = 9;// 一共画9条
Graphics2D g2 = (Graphics2D) image.getGraphics();
for (int i = 0; i < num; i++) {// 生成两个点的坐标即4个值
int x1 = r.nextInt(CAPTCHA_WIDTH);
int y1 = r.nextInt(CAPTCHA_HEIGHT);
int x2 = r.nextInt(CAPTCHA_WIDTH);
int y2 = r.nextInt(CAPTCHA_HEIGHT);
g2.setStroke(new BasicStroke(1.5F));
g2.setColor(randomColor()); // 随机生成干扰线颜色
g2.drawLine(x1, y1, x2, y2);// 画线
}
}
// 随机生成一个字符
private char randomChar() {
int index = r.nextInt(codes.length());
return codes.charAt(index);
}
// 创建BufferedImage
private BufferedImage createImage() {
BufferedImage image = new BufferedImage(CAPTCHA_WIDTH, CAPTCHA_HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = (Graphics2D) image.getGraphics();
g2.setColor(this.bgColor);
g2.fillRect(0, 0, CAPTCHA_WIDTH, CAPTCHA_HEIGHT);
return image;
}
// 调用这个方法得到验证码
public BufferedImage getImage() {
BufferedImage image = createImage();// 创建图片缓冲区
Graphics2D g2 = (Graphics2D) image.getGraphics();// 得到绘制环境
StringBuilder sb = new StringBuilder();// 用来装载生成的验证码文本
// 向图片中画4个字符
for (int i = 0; i < NUMBER_CNT; i++) {// 循环四次每次生成一个字符
String s = randomChar() + "";// 随机生成一个字母
sb.append(s); // 把字母添加到sb中
float x = i * 1.0F * CAPTCHA_WIDTH / NUMBER_CNT; // 设置当前字符的x轴坐标
g2.setFont(randomFont()); // 设置随机字体
g2.setColor(randomColor()); // 设置随机颜色
g2.drawString(s, x, CAPTCHA_HEIGHT - 5); // 画图
}
this.text = sb.toString(); // 把生成的字符串赋给了this.text
drawLine(image); // 添加干扰线
return image;
}
/**
* 创建日期:2018年2月6日<br/>
* 创建时间:下午7:09:49<br/>
* 创建用户:yellowcong<br/>
* 机能概要:
*
* @return 返回验证码图片上的文本
*/
public String getText() {
return text;
}
// 保存图片到指定的输出流
public static void output(BufferedImage image, OutputStream out) throws IOException {
ImageIO.write(image, IMAGE_TYPE, out);
}
//图片验证码对象
static class CaptchaCode {
//验证码文字信息
private String text;
//验证码二进制数据
private byte[] data;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
}
}

View File

@ -0,0 +1,130 @@
package io.qyi.e5.util.netRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class OkHttpClientUtil {
private static int connTimeOut = 5;
private static int readTimeOut = 20;
private static int writeTimeOut = 10;
public static OkHttpClient client = null;
static {
client = new OkHttpClient.Builder()
.connectTimeout(5L, TimeUnit.SECONDS)
.readTimeout(20L, TimeUnit.SECONDS)
.writeTimeout(10L, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
}
public static String doGet(String host, String path, Map<String, String> headers, Map<String, String> querys) throws Exception {
StringBuffer url = new StringBuffer(host + (path == null ? "" : path));
if (querys != null) {
url.append("?");
Iterator iterator = querys.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> e = (Map.Entry) iterator.next();
url.append((String) e.getKey()).append("=").append((String) e.getValue() + "&");
}
url = new StringBuffer(url.substring(0, url.length() - 1));
}
Request.Builder requestBuilder = new Request.Builder();
if (headers != null && headers.size() > 0) {
Iterator iterator = headers.keySet().iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
requestBuilder.addHeader(key, (String) headers.get(key));
}
}
Request request = (requestBuilder).url(url.toString()).build();
Response response = client.newCall(request).execute();
String responseStr = response.body() == null ? "" : response.body().string();
return responseStr;
}
public static String doPost(String url, Map<String, Object> headers, Map<String, Object> querys) throws Exception {
FormBody.Builder formbody = new FormBody.Builder();
if (null != querys) {
Iterator iterator = querys.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> elem = (Map.Entry) iterator.next();
formbody.add((String) elem.getKey(), (String) elem.getValue());
}
}
RequestBody body = formbody.build();
Request.Builder requestBuilder = (new Request.Builder()).url(url);
if (headers != null && headers.size() > 0) {
Iterator iteratorHeader = headers.keySet().iterator();
while (iteratorHeader.hasNext()) {
String key = (String) iteratorHeader.next();
requestBuilder.addHeader(key, (String) headers.get(key));
}
}
Request requet = requestBuilder.post(body).build();
Response response = client.newCall(requet).execute();
String responseStr = response.body() == null ? "" : response.body().string();
return responseStr;
}
public static String doPost(String url, Map<String, String> headers, String sendMessage) throws Exception {
RequestBody body = FormBody.create(MediaType.parse("application/json"), sendMessage);
;
Request.Builder requestBuilder = (new Request.Builder()).url(url);
if (headers != null && headers.size() > 0) {
Iterator iteratorHeader = headers.keySet().iterator();
while (iteratorHeader.hasNext()) {
String key = (String) iteratorHeader.next();
requestBuilder.addHeader(key, (String) headers.get(key));
}
}
Request requet = requestBuilder.post(body).build();
Response response = client.newCall(requet).execute();
String responseStr = response.body() == null ? "" : response.body().string();
return responseStr;
}
public static String doPut(String host, String path, Map<String, String> headers, Map<String, String> querys) throws Exception {
FormBody.Builder builder = new FormBody.Builder();
Iterator iterator = querys.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> elem = (Map.Entry) iterator.next();
builder.add((String) elem.getKey(), (String) elem.getValue());
}
RequestBody body = builder.build();
Request.Builder requestBuilder = (new Request.Builder()).url(host + path);
if (headers != null && headers.size() > 0) {
Iterator iteratorHeader = headers.keySet().iterator();
while (iteratorHeader.hasNext()) {
String key = (String) iteratorHeader.next();
requestBuilder.addHeader(key, (String) headers.get(key));
}
}
Request requet = requestBuilder.put(body).build();
Response response = client.newCall(requet).execute();
String responseStr = response.body() == null ? "" : response.body().string();
return responseStr;
}
}

View File

@ -0,0 +1,322 @@
package io.qyi.e5.util.netRequest;
import com.google.common.collect.Maps;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
/**
* 封装请求
*
* @author weiximei
*/
public class OkHttpRequestUtils {
/**
* 定义请求客户端
*/
private static OkHttpClient client = new OkHttpClient();
/**
* get 请求
*
* @param url 请求URL
* @return
* @throws Exception
*/
public static String doGet(String url) throws Exception {
return doGet(url, Maps.newHashMap());
}
/**
* get 请求
*
* @param url 请求URL
* @param query 携带参数参数
* @return
* @throws Exception
*/
public static String doGet(String url, Map<String, Object> query) throws Exception {
return doGet(url, Maps.newHashMap(), query);
}
/**
* get 请求
*
* @param url url
* @param header 请求头参数
* @param query 参数
* @return
*/
public static String doGet(String url, Map<String, Object> header, Map<String, Object> query) throws Exception {
// 创建一个请求 Builder
Request.Builder builder = new Request.Builder();
// 创建一个 request
Request request = builder.url(url).build();
// 创建一个 HttpUrl.Builder
HttpUrl.Builder urlBuilder = request.url().newBuilder();
// 创建一个 Headers.Builder
Headers.Builder headerBuilder = request.headers().newBuilder();
// 装载请求头参数
if (header != null) {
Iterator<Map.Entry<String, Object>> headerIterator = header.entrySet().iterator();
headerIterator.forEachRemaining(e -> {
headerBuilder.add(e.getKey(), (String) e.getValue());
});
}
if (query != null) {
// 装载请求的参数
Iterator<Map.Entry<String, Object>> queryIterator = query.entrySet().iterator();
queryIterator.forEachRemaining(e -> urlBuilder.addQueryParameter(e.getKey(), (String) e.getValue()));
}
// 设置自定义的 builder
// 因为 get 请求的参数是在 URL 后面追加 http://xxxx:8080/user?name=xxxx?sex=1
builder.url(urlBuilder.build()).headers(headerBuilder.build());
try (Response execute = client.newCall(builder.build()).execute()) {
return execute.body().string();
}
}
/**
* post 请求 请求参数 并且 携带文件上传
*
* @param url
* @param header
* @param parameter
* @param file 文件
* @param fileFormName 远程接口接收 file 的参数
* @return
* @throws Exception
*/
public static String doPost(String url, Map<String, Object> header, Map<String, Object> parameter, File file, String fileFormName) throws Exception {
// 创建一个请求 Builder
Request.Builder builder = new Request.Builder();
// 创建一个 request
Request request = builder.url(url).build();
// 创建一个 Headers.Builder
Headers.Builder headerBuilder = request.headers().newBuilder();
// 装载请求头参数
Iterator<Map.Entry<String, Object>> headerIterator = header.entrySet().iterator();
headerIterator.forEachRemaining(e -> headerBuilder.add(e.getKey(), (String) e.getValue()));
// 或者 FormBody.create 方式只适用于接口只接收文件流的情况
// RequestBody requestBody = FormBody.create(MediaType.parse("application/octet-stream"), file);
MultipartBody.Builder requestBuilder = new MultipartBody.Builder();
// 状态请求参数
Iterator<Map.Entry<String, Object>> queryIterator = parameter.entrySet().iterator();
queryIterator.forEachRemaining(e -> requestBuilder.addFormDataPart(e.getKey(), (String) e.getValue()));
if (null != file) {
// application/octet-stream
requestBuilder.addFormDataPart(StringUtils.isNotBlank(fileFormName) ? fileFormName : "file", file.getName(), RequestBody.create(MediaType.parse("application/octet-stream"), file));
}
// 设置自定义的 builder
builder.headers(headerBuilder.build()).post(requestBuilder.build());
// 然后再 build 一下
try (Response execute = client.newCall(builder.build()).execute()) {
return execute.body().string();
}
}
/**
* post 请求 请求参数
*
* @param url
* @param header
* @param parameter
* @return
* @throws Exception
*/
public static String doPostFrom(String url, Map<String, Object> header, Map<String, Object> parameter) throws Exception {
// 创建一个请求 Builder
Request.Builder builder = new Request.Builder();
// 创建一个 request
Request request = builder.url(url).build();
// 创建一个 Headers.Builder
Headers.Builder headerBuilder = request.headers().newBuilder();
// 装载请求头参数
Iterator<Map.Entry<String, Object>> headerIterator = header.entrySet().iterator();
headerIterator.forEachRemaining(e -> headerBuilder.add(e.getKey(), (String) e.getValue()));
// 或者 FormBody.create 方式只适用于接口只接收文件流的情况
// RequestBody requestBody = FormBody.create(MediaType.parse("application/octet-stream"), file);
FormBody.Builder FormBody = new FormBody.Builder();
// 状态请求参数
Iterator<Map.Entry<String, Object>> queryIterator = parameter.entrySet().iterator();
queryIterator.forEachRemaining(e -> FormBody.add(e.getKey(), (String) e.getValue()));
// 设置自定义的 builder
builder.headers(headerBuilder.build()).post(FormBody.build());
// 然后再 build 一下
try (Response execute = client.newCall(builder.build()).execute()) {
return execute.body().string();
}
}
/**
* post 请求 请求参数 并且 携带文件上传二进制流
*
* @param url
* @param header
* @param parameter
* @param fileName 文件名
* @param fileByte 文件的二进制流
* @param fileFormName 远程接口接收 file 的参数
* @return
* @throws Exception
*/
public static String doPost(String url, Map<String, Object> header, Map<String, Object> parameter, String fileName, byte[] fileByte, String fileFormName) throws Exception {
// 创建一个请求 Builder
Request.Builder builder = new Request.Builder();
// 创建一个 request
Request request = builder.url(url).build();
// 创建一个 Headers.Builder
Headers.Builder headerBuilder = request.headers().newBuilder();
// 装载请求头参数
Iterator<Map.Entry<String, Object>> headerIterator = header.entrySet().iterator();
headerIterator.forEachRemaining(e -> {
headerBuilder.add(e.getKey(), (String) e.getValue());
});
MultipartBody.Builder requestBuilder = new MultipartBody.Builder();
// 状态请求参数
Iterator<Map.Entry<String, Object>> queryIterator = parameter.entrySet().iterator();
queryIterator.forEachRemaining(e -> {
requestBuilder.addFormDataPart(e.getKey(), (String) e.getValue());
});
if (fileByte.length > 0) {
// application/octet-stream
requestBuilder.addFormDataPart(StringUtils.isNotBlank(fileFormName) ? fileFormName : "file", fileName, RequestBody.create(MediaType.parse("application/octet-stream"), fileByte));
}
// 设置自定义的 builder
builder.headers(headerBuilder.build()).post(requestBuilder.build());
try (Response execute = client.newCall(builder.build()).execute()) {
return execute.body().string();
}
}
/**
* post 请求 携带文件上传
*
* @param url
* @param file
* @return
* @throws Exception
*/
public static String doPost(String url, File file, String fileFormName) throws Exception {
return doPost(url, Maps.newHashMap(), Maps.newHashMap(), file, fileFormName);
}
/**
* post 请求
*
* @param url
* @param header 请求头
* @param parameter 参数
* @return
* @throws Exception
*/
public static String doPost(String url, Map<String, Object> header, Map<String, Object> parameter) throws Exception {
return doPostFrom(url, header, parameter);
}
/**
* post 请求
*
* @param url
* @param parameter 参数
* @return
* @throws Exception
*/
public static String doPost(String url, Map<String, Object> parameter) throws Exception {
return doPost(url, Maps.newHashMap(), parameter, null, null);
}
/**
* JSON数据格式请求
*
* @param url
* @param header
* @param json
* @return
*/
private static String json(String url, Map<String, Object> header, String json) throws IOException {
// 创建一个请求 Builder
Request.Builder builder = new Request.Builder();
// 创建一个 request
Request request = builder.url(url).build();
// 创建一个 Headers.Builder
Headers.Builder headerBuilder = request.headers().newBuilder();
// 装载请求头参数
Iterator<Map.Entry<String, Object>> headerIterator = header.entrySet().iterator();
headerIterator.forEachRemaining(e -> {
headerBuilder.add(e.getKey(), (String) e.getValue());
});
// application/octet-stream
RequestBody requestBody = FormBody.create(MediaType.parse("application/json"), json);
// 设置自定义的 builder
builder.headers(headerBuilder.build()).post(requestBody);
try (Response execute = client.newCall(builder.build()).execute()) {
return execute.body().string();
}
}
/**
* post请求 参数JSON格式
*
* @param url
* @param header 请求头
* @param json JSON数据
* @return
* @throws IOException
*/
public static String doPost(String url, Map<String, Object> header, String json) throws IOException {
return json(url, header, json);
}
/**
* post请求 参数JSON格式
*
* @param url
* @param json JSON数据
* @return
* @throws IOException
*/
public static String doPost(String url, String json) throws IOException {
return json(url, Maps.newHashMap(), json);
}
}

View File

@ -0,0 +1,592 @@
package io.qyi.e5.util.redis;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @program: msgpush
* @description:
* @author: 落叶随风
* @create: 2020-02-04 00:31
**/
@Component
public class RedisUtil {
@Resource
private RedisTemplate<String, Object> redisTemplate;
public Set<String> keys(String keys) {
try {
return redisTemplate.keys(keys);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 指定缓存失效时间
*
* @param key
* @param time 时间()
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 不能为null
* @return 时间() 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
/**
* 普通缓存获取
*
* @param key
* @return
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key
* @param value
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key
* @param value
* @param time 时间() time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
*
* @param key
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
/**
* HashGet
*
* @param key 不能为null
* @param item 不能为null
* @return
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key
* @param map 对应多个键值
* @param time 时间()
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* @param item
* @param value
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key
* @param item
* @param value
* @param time 时间() 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 不能为null
* @param item 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 不能为null
* @param item 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key
* @param item
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
*
* @param key
* @param item
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
/**
* 根据key获取Set中的所有值
*
* @param key
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key
* @param value
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key
* @param values 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key
* @param time 时间()
* @param values 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
*
* @param key
* @param values 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key
* @param start 开始
* @param end 结束 0 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key
* @param index 索引 index>=0时 0 表头1 第二个元素依次类推index<0时-1表尾-2倒数第二个元素依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @param time 时间()
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
*
* @param key
* @param value
* @param time 时间()
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key
* @param index 索引
* @param value
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
*
* @param key
* @param count 移除多少个
* @param value
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* @title lRemove
* @description
* @author 落叶随风
* @param: key
* @param: count
* @param: value
* @updateTime 2020/2/4 14:59
* @return: long
* @throws
*/
public boolean lTrim(String key, long start, long end) {
try {
redisTemplate.opsForList().trim(key,start,end);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--设置log4j2的自身log级别为warn-->
<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--Configuration后面的status这个用于设置log4j2自身内部的信息输出可以不设置
当设置成trace时会看到log4j2内部各种详细输出-->
<!--monitorIntervalLog4j能够自动检测修改配置 文件和重新配置本身,设置间隔秒数-->
<configuration status="DEBUG" monitorInterval="5">
<Properties>
<!-- 日志模板 -->
<Property name="log_pattern" value="[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
<!-- 存储日志文件路径 -->
<Property name="file_path" value="logs/log"/>
<!-- 日志文件的最大容量,超过该值就进行备份 -->
<Property name="file_max_size" value="30MB"/>
<!-- 备份的文件夹名称 -->
<Property name="backup_folder" value="$${date:yyyy-MM}"/>
<!-- 备份文件的后缀 -->
<Property name="backup_file_suffix" value="-%d{yyyy-MM-dd}-%i.log"/>
</Properties>
<!--定义appender-->
<appenders>
<!--控制台的输出配置-->
<console name="Console" target="SYSTEM_OUT">
<!--输出日志的格式-->
<PatternLayout pattern="${log_pattern}"/>
</console>
<!-- 所有级别的日志会存入该文件当append属性设置为false时每次启动程序会自动清空 -->
<File name="AllLog" fileName="${file_path}/all_log.log" append="false">
<!-- <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/> -->
<PatternLayout pattern="${log_pattern}"/>
</File>
<!--
该RollingFile存储INFO级别的日志
默认存储到 fileName 文件中
超过SizeBasedTriggeringPolicy的设定值则存储到 filePattern 文件中
-->
<RollingFile name="RollingFileInfo" fileName="${file_path}/info.log"
filePattern="${file_path}/${backup_folder}/info${backup_file_suffix}">
<Filters>
<!--控制台只输出level及以上级别的信息onMatch其他的直接拒绝onMismatch-->
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<!-- 写入日志文件的模板 -->
<PatternLayout pattern="${log_pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="${file_max_size}"/>
</Policies>
<!-- DefaultRolloverStrategy属性如不设置则默认为最多同一文件夹下7个文件超过该数量会滚动删除前面的记录 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
<RollingFile name="RollingFileWarn" fileName="${file_path}/warn.log"
filePattern="${file_path}/${backup_folder}/warn${backup_file_suffix}">
<Filters>
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
<ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
</Filters>
<PatternLayout pattern="${log_pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="${file_max_size}"/>
</Policies>
</RollingFile>
<RollingFile name="RollingFileError" fileName="${file_path}/error.log"
filePattern="${file_path}/${backup_folder}/error${backup_file_suffix}">
<ThresholdFilter level="ERROR"/>
<PatternLayout pattern="${log_pattern}"/>
<Policies>
<TimeBasedTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="${file_max_size}"/>
</Policies>
</RollingFile>
</appenders>
<!-- 只有定义了logger并使用appender-refappender才会生效 -->
<loggers>
<!--过滤掉spring和hibernate的一些无用的debug信息-->
<logger name="org.springframework" level="INFO"/>
<logger name="org.mybatis" level="INFO">
<!-- 添加如下设置,控制台会再打印一次 -->
<AppenderRef ref="Console"/>
</logger>
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFileInfo"/>
<appender-ref ref="RollingFileWarn"/>
<appender-ref ref="RollingFileError"/>
<appender-ref ref="AllLog"/>
</root>
</loggers>
</configuration>

View File

@ -0,0 +1,5 @@
<?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="io.qyi.e5.github.mapper.GithubMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?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="io.qyi.e5.outlook.mapper.OutlookMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?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="io.qyi.e5.outlook_log.mapper.OutlookLogMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?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="io.qyi.e5.user.mapper.PermissionMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?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="io.qyi.e5.user.mapper.RoleMapper">
</mapper>

View File

@ -0,0 +1,5 @@
<?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="io.qyi.e5.user.mapper.UserMapper">
</mapper>

View File

@ -0,0 +1,21 @@
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.tablePrefix = QRTZ_
#org.quartz.scheduler.instanceName = MyScheduler
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#org.quartz.jobStore.dataSource = mysqlDatabase
#
#org.quartz.dataSource.mysqlDatabase.driver = com.mysql.jdbc.Driver
#org.quartz.dataSource.mysqlDatabase.URL = jdbc:mysql://localhost:3306/e5?characterEncoding=utf-8
#org.quartz.dataSource.mysqlDatabase.user = root
#org.quartz.dataSource.mysqlDatabase.password = 123456
#org.quartz.dataSource.mysqlDatabase.maxConnections = 10
#
#
#Ï̳߳ØÅäÖÃ
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#
##³Ö¾Ã»¯ÅäÖÃ
#org.quartz.jobStore.misfireThreshold = 50000

View File

@ -0,0 +1,835 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>404</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
background: #f2f2f2;
}
canvas {
display:block;
margin: 50px auto 200px;
margin-left: 300px;
border: 1px solid #333;
box-shadow: 0 0 16px 2px rgba(0,0,0,0.8);
}
p, a {
font-family: Helvetica, Arial, sans-serif;
font-size: 20px;
color: #777;
display: block;
width: 400px;
margin: 0 auto;
text-align: center;
text-decoration:none;
}
.info {
margin:50px auto;
text-align: justify;
font-size: 20px;
color: #999;
}
a {
color:#3377ee;
}
#info{
position: absolute;
z-index: 55;
width: 400px;
right: 100px;
top: 200px;
}
/* TENTH BUTTON */
#tenth>button{
letter-spacing:0;
}
#tenth span{
letter-spacing:0;
display:inline-block;
position:relative;
width:8px;
transition:all .5s ease-in-out;
}
#tenth span:nth-of-type(4){
width:5px;
}
#tenth span:nth-of-type(6){
width:1px;
}
#tenth span:nth-of-type(8){
width:4px;
}
#tenth:hover span:nth-of-type(1){
animation:h .5s;
}
#tenth:hover span:nth-of-type(2){
animation:o .5s;
}
#tenth:hover span:nth-of-type(3){
animation:v .5s;
}
#tenth:hover span:nth-of-type(4){
animation:e .5s;
}
#tenth:hover span:nth-of-type(5){
animation:r .5s;
}
#tenth:hover span:nth-of-type(7){
animation:t .5s;
}
#tenth:hover span:nth-of-type(8){
animation:e .5s;
}
#tenth:hover span:nth-of-type(9){
animation:n .5s;
}
@keyframes h{
0%{transform:translate(0, 0);}
50%{transform:translate(50px, 5px);}
75%{transform:translate(5px, 5px);}
80%{transform:translate(0, 0);}
100%{transform:translate(0, 0);}
}
@keyframes o{
0%{transform:translate(0, 0);}
25%{transform:translate(-4px, 0);}
50%{transform:translate(3px, 4px);}
80%{transform:translate(0, 0);}
100%{transform:translate(0, 0);}
}
@keyframes v{
0%{transform:translate(0, 0);}
20%{transform:rotate(360deg);}
50%{transform:scale(2);}
80%{transform:translate(0, 0);}
100%{transform:translate(0, 0);}
}
@keyframes e{
0%{transform:translate(0, 0);}
20%{transform:translate(-10px, -2px);}
80%{transform:translate(0, 0);}
100%{transform:translate(0, 0);}
}
@keyframes r{
0%{transform:translate(0, 0);}
20%{transform:translate(0, 10px);}
80%{transform:translate(0, 32px);}
100%{transform:translate(0, 0);}
}
@keyframes t{
0%{transform:translate(0, 0);}
20%{transform:translate(0, -10px);}
40%{transform:translate(0, 0);}
60%{transform:translate(0, -10px);}
80%{transform:translate(0, 0);}
100%{transform:translate(0, 0);}
}
@keyframes n{
0%{transform:translate(0, 0);}
50%{transform:skewY(50deg);}
80%{transform:translate(0, 0);}
100%{transform:translate(0, 0);}
}
button{
position: absolute;
right: 400px;
top: 500px;
z-index: 99;
width:180px;
height:60px;
background:transparent;
color:black;
font-weight:700;
letter-spacing:1px;
border:none;
font-size:18px;
outline:none;
cursor: pointer;
} </style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="info">
<p style="color: #333333;font-size: 100px;font-weight: 700;margin-bottom: 50px;">404</p>
<p>没找到页面,倒有个小游戏可以先玩一哈。</p>
<p class="info">使用左键、右键和上箭头键移动。</p>
</div>
<div id="tenth" class="buttonBox">
<button>
<a href="/user/home">
<span></span>
<span> </span>
<span></span>
<span> </span>
<span></span>
<span> </span>
<span></span>
</a>
</button>
</div>
<script>
/* Customisable map data */
var map = {
tile_size: 16,
/*
Key vairables:
id [required] - an integer that corresponds with a tile in the data array.
colour [required] - any javascript compatible colour variable.
solid [optional] - whether the tile is solid or not, defaults to false.
bounce [optional] - how much velocity is preserved upon hitting the tile, 0.5 is half.
jump [optional] - whether the player can jump while over the tile, defaults to false.
friction [optional] - friction of the tile, must have X and Y values (e.g {x:0.5, y:0.5}).
gravity [optional] - gravity of the tile, must have X and Y values (e.g {x:0.5, y:0.5}).
fore [optional] - whether the tile is drawn in front of the player, defaults to false.
script [optional] - refers to a script in the scripts section, executed if it is touched.
*/
keys: [
{id: 0, colour: '#333', solid: 0},
{id: 1, colour: '#888', solid: 0},
{id: 2,colour: '#555',solid: 1,bounce: 0.35},
{id: 3,colour: 'rgba(121, 220, 242, 0.4)',friction: {x: 0.9,y: 0.9},gravity: {x: 0,y: 0.1},jump: 1,fore: 1},
{id: 4,colour: '#777',jump: 1},
{id: 5,colour: '#E373FA',solid: 1,bounce: 1.1},
{id: 6,colour: '#666',solid: 1,bounce: 0},
{id: 7,colour: '#73C6FA',solid: 0,script: 'change_colour'},
{id: 8,colour: '#FADF73',solid: 0,script: 'next_level'},
{id: 9,colour: '#C93232',solid: 0,script: 'death'},
{id: 10,colour: '#555',solid: 1},
{id: 11,colour: '#0FF',solid: 0,script: 'unlock'}
],
/* An array representing the map tiles. Each number corresponds to a key */
data: [
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 6, 6, 6, 6, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 1, 1, 1, 2, 2, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 4, 2, 2, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2, 2, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 1, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2],
[2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2],
[2, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2],
[2, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 8, 1, 1, 1, 2],
[2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2],
[2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 9, 9, 9, 2, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 11, 2, 2, 2, 2, 4, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 2, 1, 1, 1, 1, 1, 1, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2],
[2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 2, 5, 5, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2],
[2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
],
/* Default gravity of the map */
gravity: {
x: 0,
y: 0.3
},
/* Velocity limits */
vel_limit: {
x: 2,
y: 16
},
/* Movement speed when the key is pressed */
movement_speed: {
jump: 6,
left: 0.3,
right: 0.3
},
/* The coordinates at which the player spawns and the colour of the player */
player: {
x: 2,
y: 2,
colour: '#FF9900'
},
/* scripts refered to by the "script" variable in the tile keys */
scripts: {
/* you can just use "this" instead of your engine variable ("game"), but Codepen doesn't like it */
change_colour: 'game.player.colour = "#"+(Math.random()*0xFFFFFF<<0).toString(16);',
/* you could load a new map variable here */
next_level: 'alert("过关啦!");game.load_map(map);',
death: 'alert("再来一次?");game.load_map(map);',
unlock: 'game.current_map.keys[10].solid = 0;game.current_map.keys[10].colour = "#888";'
}
};
/* Clarity engine */
var Clarity = function () {
this.alert_errors = false;
this.log_info = true;
this.tile_size = 16;
this.limit_viewport = false;
this.jump_switch = 0;
this.viewport = {
x: 200,
y: 200
};
this.camera = {
x: 0,
y: 0
};
this.key = {
left: false,
right: false,
up: false
};
this.player = {
loc: {
x: 0,
y: 0
},
vel: {
x: 0,
y: 0
},
can_jump: true
};
window.onkeydown = this.keydown.bind(this);
window.onkeyup = this.keyup.bind(this);
};
Clarity.prototype.error = function (message) {
if (this.alert_errors) alert(message);
if (this.log_info) console.log(message);
};
Clarity.prototype.log = function (message) {
if (this.log_info) console.log(message);
};
Clarity.prototype.set_viewport = function (x, y) {
this.viewport.x = x;
this.viewport.y = y;
};
Clarity.prototype.keydown = function (e) {
var _this = this;
switch (e.keyCode) {
case 37:
_this.key.left = true;
break;
case 38:
_this.key.up = true;
break;
case 39:
_this.key.right = true;
break;
}
};
Clarity.prototype.keyup = function (e) {
var _this = this;
switch (e.keyCode) {
case 37:
_this.key.left = false;
break;
case 38:
_this.key.up = false;
break;
case 39:
_this.key.right = false;
break;
}
};
Clarity.prototype.load_map = function (map) {
if (typeof map === 'undefined'
|| typeof map.data === 'undefined'
|| typeof map.keys === 'undefined') {
this.error('Error: Invalid map data!');
return false;
}
this.current_map = map;
this.current_map.background = map.background || '#333';
this.current_map.gravity = map.gravity || {x: 0, y: 0.3};
this.tile_size = map.tile_size || 16;
var _this = this;
this.current_map.width = 0;
this.current_map.height = 0;
map.keys.forEach(function (key) {
map.data.forEach(function (row, y) {
_this.current_map.height = Math.max(_this.current_map.height, y);
row.forEach(function (tile, x) {
_this.current_map.width = Math.max(_this.current_map.width, x);
if (tile == key.id)
_this.current_map.data[y][x] = key;
});
});
});
this.current_map.width_p = this.current_map.width * this.tile_size;
this.current_map.height_p = this.current_map.height * this.tile_size;
this.player.loc.x = map.player.x * this.tile_size || 0;
this.player.loc.y = map.player.y * this.tile_size || 0;
this.player.colour = map.player.colour || '#000';
this.key.left = false;
this.key.up = false;
this.key.right = false;
this.camera = {
x: 0,
y: 0
};
this.player.vel = {
x: 0,
y: 0
};
this.log('Successfully loaded map data.');
return true;
};
Clarity.prototype.get_tile = function (x, y) {
return (this.current_map.data[y] && this.current_map.data[y][x]) ? this.current_map.data[y][x] : 0;
};
Clarity.prototype.draw_tile = function (x, y, tile, context) {
if (!tile || !tile.colour) return;
context.fillStyle = tile.colour;
context.fillRect(
x,
y,
this.tile_size,
this.tile_size
);
};
Clarity.prototype.draw_map = function (context, fore) {
for (var y = 0; y < this.current_map.data.length; y++) {
for (var x = 0; x < this.current_map.data[y].length; x++) {
if ((!fore && !this.current_map.data[y][x].fore) || (fore && this.current_map.data[y][x].fore)) {
var t_x = (x * this.tile_size) - this.camera.x;
var t_y = (y * this.tile_size) - this.camera.y;
if(t_x < -this.tile_size
|| t_y < -this.tile_size
|| t_x > this.viewport.x
|| t_y > this.viewport.y) continue;
this.draw_tile(
t_x,
t_y,
this.current_map.data[y][x],
context
);
}
}
}
if (!fore) this.draw_map(context, true);
};
Clarity.prototype.move_player = function () {
var tX = this.player.loc.x + this.player.vel.x;
var tY = this.player.loc.y + this.player.vel.y;
var offset = Math.round((this.tile_size / 2) - 1);
var tile = this.get_tile(
Math.round(this.player.loc.x / this.tile_size),
Math.round(this.player.loc.y / this.tile_size)
);
if(tile.gravity) {
this.player.vel.x += tile.gravity.x;
this.player.vel.y += tile.gravity.y;
} else {
this.player.vel.x += this.current_map.gravity.x;
this.player.vel.y += this.current_map.gravity.y;
}
if (tile.friction) {
this.player.vel.x *= tile.friction.x;
this.player.vel.y *= tile.friction.y;
}
var t_y_up = Math.floor(tY / this.tile_size);
var t_y_down = Math.ceil(tY / this.tile_size);
var y_near1 = Math.round((this.player.loc.y - offset) / this.tile_size);
var y_near2 = Math.round((this.player.loc.y + offset) / this.tile_size);
var t_x_left = Math.floor(tX / this.tile_size);
var t_x_right = Math.ceil(tX / this.tile_size);
var x_near1 = Math.round((this.player.loc.x - offset) / this.tile_size);
var x_near2 = Math.round((this.player.loc.x + offset) / this.tile_size);
var top1 = this.get_tile(x_near1, t_y_up);
var top2 = this.get_tile(x_near2, t_y_up);
var bottom1 = this.get_tile(x_near1, t_y_down);
var bottom2 = this.get_tile(x_near2, t_y_down);
var left1 = this.get_tile(t_x_left, y_near1);
var left2 = this.get_tile(t_x_left, y_near2);
var right1 = this.get_tile(t_x_right, y_near1);
var right2 = this.get_tile(t_x_right, y_near2); if (tile.jump && this.jump_switch > 15) {
this.player.can_jump = true;
this.jump_switch = 0;
} else this.jump_switch++;
this.player.vel.x = Math.min(Math.max(this.player.vel.x, -this.current_map.vel_limit.x), this.current_map.vel_limit.x);
this.player.vel.y = Math.min(Math.max(this.player.vel.y, -this.current_map.vel_limit.y), this.current_map.vel_limit.y);
this.player.loc.x += this.player.vel.x;
this.player.loc.y += this.player.vel.y;
this.player.vel.x *= .9;
if (left1.solid || left2.solid || right1.solid || right2.solid) {
/* fix overlap */
while (this.get_tile(Math.floor(this.player.loc.x / this.tile_size), y_near1).solid
|| this.get_tile(Math.floor(this.player.loc.x / this.tile_size), y_near2).solid)
this.player.loc.x += 0.1;
while (this.get_tile(Math.ceil(this.player.loc.x / this.tile_size), y_near1).solid
|| this.get_tile(Math.ceil(this.player.loc.x / this.tile_size), y_near2).solid)
this.player.loc.x -= 0.1;
/* tile bounce */
var bounce = 0;
if (left1.solid && left1.bounce > bounce) bounce = left1.bounce;
if (left2.solid && left2.bounce > bounce) bounce = left2.bounce;
if (right1.solid && right1.bounce > bounce) bounce = right1.bounce;
if (right2.solid && right2.bounce > bounce) bounce = right2.bounce;
this.player.vel.x *= -bounce || 0;
}
if (top1.solid || top2.solid || bottom1.solid || bottom2.solid) {
/* fix overlap */
while (this.get_tile(x_near1, Math.floor(this.player.loc.y / this.tile_size)).solid
|| this.get_tile(x_near2, Math.floor(this.player.loc.y / this.tile_size)).solid)
this.player.loc.y += 0.1;
while (this.get_tile(x_near1, Math.ceil(this.player.loc.y / this.tile_size)).solid
|| this.get_tile(x_near2, Math.ceil(this.player.loc.y / this.tile_size)).solid)
this.player.loc.y -= 0.1;
/* tile bounce */
var bounce = 0;
if (top1.solid && top1.bounce > bounce) bounce = top1.bounce;
if (top2.solid && top2.bounce > bounce) bounce = top2.bounce;
if (bottom1.solid && bottom1.bounce > bounce) bounce = bottom1.bounce;
if (bottom2.solid && bottom2.bounce > bounce) bounce = bottom2.bounce;
this.player.vel.y *= -bounce || 0;
if ((bottom1.solid || bottom2.solid) && !tile.jump) {
this.player.on_floor = true;
this.player.can_jump = true;
}
}
// adjust camera
var c_x = Math.round(this.player.loc.x - this.viewport.x/2);
var c_y = Math.round(this.player.loc.y - this.viewport.y/2);
var x_dif = Math.abs(c_x - this.camera.x);
var y_dif = Math.abs(c_y - this.camera.y);
if(x_dif > 5) {
var mag = Math.round(Math.max(1, x_dif * 0.1));
if(c_x != this.camera.x) {
this.camera.x += c_x > this.camera.x ? mag : -mag;
if(this.limit_viewport) {
this.camera.x =
Math.min(
this.current_map.width_p - this.viewport.x + this.tile_size,
this.camera.x
);
this.camera.x =
Math.max(
0,
this.camera.x
);
}
}
}
if(y_dif > 5) {
var mag = Math.round(Math.max(1, y_dif * 0.1));
if(c_y != this.camera.y) {
this.camera.y += c_y > this.camera.y ? mag : -mag;
if(this.limit_viewport) {
this.camera.y =
Math.min(
this.current_map.height_p - this.viewport.y + this.tile_size,
this.camera.y
);
this.camera.y =
Math.max(
0,
this.camera.y
);
}
}
}
if(this.last_tile != tile.id && tile.script) {
eval(this.current_map.scripts[tile.script]);
}
this.last_tile = tile.id;
};
Clarity.prototype.update_player = function () {
if (this.key.left) {
if (this.player.vel.x > -this.current_map.vel_limit.x)
this.player.vel.x -= this.current_map.movement_speed.left;
}
if (this.key.up) {
if (this.player.can_jump && this.player.vel.y > -this.current_map.vel_limit.y) {
this.player.vel.y -= this.current_map.movement_speed.jump;
this.player.can_jump = false;
}
}
if (this.key.right) {
if (this.player.vel.x < this.current_map.vel_limit.x)
this.player.vel.x += this.current_map.movement_speed.left;
}
this.move_player();
};
Clarity.prototype.draw_player = function (context) {
context.fillStyle = this.player.colour;
context.beginPath();
context.arc(
this.player.loc.x + this.tile_size / 2 - this.camera.x,
this.player.loc.y + this.tile_size / 2 - this.camera.y,
this.tile_size / 2 - 1,
0,
Math.PI * 2
);
context.fill();
};
Clarity.prototype.update = function () {
this.update_player();
};
Clarity.prototype.draw = function (context) {
this.draw_map(context, false);
this.draw_player(context);
};
/* Setup of the engine */
window.requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, 1000 / 60);
};
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 600;
var game = new Clarity();
game.set_viewport(canvas.width, canvas.height);
game.load_map(map);
/* Limit the viewport to the confines of the map */
game.limit_viewport = true;
var Loop = function() {
ctx.fillStyle = '#333';
ctx.fillRect(0, 0, canvas.width, canvas.height);
game.update();
game.draw(ctx);
window.requestAnimFrame(Loop);
};
Loop();
</script>
</body>
</html>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>日志查询</title>
<body>
<table border="1" cellpadding="3" cellspacing="0">
<tr>
<th style="width: 15%">调用时间</th>
<th style="width: 5%">调用结果</th>
<th style="width: 15%">信息</th>
<th>原始信息</th>
</tr>
<#list list_log?sort_by('callTime')?reverse as log>
<#-- <span>${log},-->
<#-- ${log.result}</span></br>-->
<tr>
<#assign dlong = (log.callTime + '000')?number?number_to_datetime/>
<#-- <td>${num?log.callTime?number_to_datetime?string('yyyy-MM-dd')}</td>-->
<td >${dlong?string("yyyy-MM-dd HH:mm:ss")}</td>
<#if log.result == '1'>
<td >成功</td>
<#else >
<td style="background: red">失败</td>
</#if>
<td>${log.msg}</td>
<td>${log.originalMsg}</td>
</tr>
</#list>
</table>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>outlook授权结果</title>
</head>
<body>
<#if result>
<h3>授权成功!</h3>
<#else >
<h3>授权失败!</h3>
<h4>错误: ${msg}</h4>
</#if>
<a href="/user/home">返回用户中心</a>
</body>
</html>

View File

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Home</title>
<link rel="stylesheet" href="//cdnjs.loli.net/ajax/libs/mdui/0.4.3/css/mdui.min.css">
<script src="//cdnjs.loli.net/ajax/libs/mdui/0.4.3/js/mdui.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</head>
<body class="mdui-appbar-with-toolbar mdui-theme-primary-indigo mdui-theme-accent-blue mdui-loaded">
<header class="mdui-appbar mdui-appbar-fixed">
<div class="mdui-toolbar mdui-color-theme">
<span class="mdui-typo-title">Office E5 自动续订</span>
<div class="mdui-toolbar-spacer"></div>
</div>
</header>
<div class="mdui-card-media in floats">
使用说明
<ol>
<#--<li>输入 client_id 与 client_secret 保存</li>
<li>点击 “授权”,请用不使用的空账号登录授权</li>
<li>授权成功后就不用管了系统会自动调用你的out api</li>-->
<li>程序会读取授权的outlook账号邮箱邮件但不会保存任何信息仅仅是调用api。</li>
<li>请单独创建一个同域 E5 子账号,不要使用此账号进行发送、接收个人邮件,以免发生误会。</li>
</ol>
</div>
<#--数据输入-->
<div class="mdui-card-media in floats">
<div class="mdui-textfield">
<label class="mdui-textfield-label" style="font-weight: 500;">client_id</label>
<input id="client_id" class="mdui-textfield-input" type="text" value="${client_id!}"/>
</div>
<div class="mdui-textfield">
<label class="mdui-textfield-label" style="font-weight: 500;">client_secret</label>
<input id="client_secret" class="mdui-textfield-input" type="text" value="${client_secret!}"/>
</div>
<button id="authorization" class="mdui-btn mdui-color-theme-accent mdui-ripple">授权</button>
<button id="save" class="mdui-btn mdui-color-theme-accent mdui-ripple">保存</button>
</div>
<div class="mdui-divider"></div>
<#--日志表格-->
<div class="mdui-table-fluid table-container floats">
<p>日志会在每日0点清空。</p>
<button id="findLog" class="mdui-btn mdui-color-theme-accent mdui-ripple">查询日志</button>
</div>
</body>
<script src="//www.mdui.org/source/dist/js/mdui.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
//日志查询
$("#findLog").click(function () {
var url = "/outlookLog/findLog"
window.open(url,'_blank')
})
// 授权
$("#authorization").click(function () {
var url = "/outlook/auth2/getAuthorizeUrl"
window.location.href = url;
})
//保存
$("#save").click(function () {
var client_id = $("#client_id").val();
var client_secret = $("#client_secret").val();
if ((client_id || client_secret) == "") {
alert("client_id 或 client_secret 不能为空!")
return;
}
;
$.post("/outlook/outlook/save", {
client_id: client_id,
client_secret: client_secret
}, function (data, status) {
console.log(data);
if (status != "success") {
alert("未知错误,请联系管理员!")
return;
}
if (data.code == 0) {
alert("保存成功!");
} else {
alert("错误: + " + data.msg);
}
})
});
});
</script>
<style>
.table-container {
border-radius: 15px;
background-clip: padding-box;
margin: 1% 1%;
width: 25%;
padding: 35px 35px 15px 35px;
background: #fff;
border: 1px solid #eaeaea;
box-shadow: 0 0 25px #cac6c6;
}
.in {
border-radius: 15px;
background-clip: padding-box;
margin: 1% 1%;
width: 25%;
padding: 35px 35px 15px 35px;
background: #fff;
border: 1px solid #eaeaea;
box-shadow: 0 0 25px #cac6c6;
float: left;
}
.floats {
display: inline-block;
}
</style>
</html>

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body class="mdui-theme-primary-indigo mdui-theme-accent-light-blue">
<div class="mdui-card login-container">
<div style="margin: auto;">
<a href="/auth2/getGithubUrl" data-hotkey="g d" aria-label="Homepage"
data-ga-click="Header, go to dashboard, icon:logo">
<svg class="octicon octicon-mark-github v-align-middle" height="64" width="64" viewBox="0 0 16 16"
version="1.1" aria-hidden="true">
<path fill-rule="evenodd"
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path>
</svg>
</a>
</div>
</div>
</body>
<style>
.login-container {
border-radius: 15px;
background-clip: padding-box;
margin: 5% auto;
width: 5%;
padding: 35px 35px 15px 35px;
background: #fff;
border: 1px solid #eaeaea;
box-shadow: 0 0 25px #cac6c6;
}
</style>
</html>

View File

@ -0,0 +1,13 @@
package io.qyi.e5;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class E5ApplicationTests {
@Test
void contextLoads() {
}
}

View File

@ -0,0 +1,33 @@
package io.qyi.e5.test;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-03 09:39
**/
public class MailJobListener implements JobListener {
@Override
public String getName() {
return "listener of mail job";
}
@Override
public void jobToBeExecuted(JobExecutionContext context) {
System.out.println("取消执行:\t "+context.getJobDetail().getKey());
}
@Override
public void jobExecutionVetoed(JobExecutionContext context) {
System.out.println("准备执行:\t "+context.getJobDetail().getKey());
}
@Override
public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
System.out.println("执行结束:\t "+context.getJobDetail().getKey());
}
}

View File

@ -0,0 +1,25 @@
package io.qyi.e5.test;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.time.LocalTime;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-02 16:37
**/
public class RamJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("启动定时任务......每十秒执行一次,共执行三次");
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
System.out.println(LocalTime.now().toString());
System.out.println(jobDataMap.get("level") + "" + jobDataMap.get("job"));
}
}

View File

@ -0,0 +1,65 @@
package io.qyi.e5.test;
import org.junit.jupiter.api.Test;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.KeyMatcher;
/**
* @program: e5
* @description:
* @author: 落叶随风
* @create: 2020-03-02 16:37
**/
public class quartzDome01 {
@Test
public void d0() throws Exception {
try {
demo01();
} catch (SchedulerException e) {
System.err.println("发现任务已经在数据库存在了,直接从数据库里运行:"+ e.getMessage());
// TODO Auto-generated catch block
resumeJobFromDatabase();
}
}
private void resumeJobFromDatabase() throws Exception {
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
// 等待200秒让前面的任务都执行完了之后再关闭调度器
Thread.sleep(200000);
scheduler.shutdown(true);
}
public void demo01() throws SchedulerException {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
JobDetail jobDetail = JobBuilder.newJob(RamJob.class)
.withDescription("this is a job")
.withIdentity("job1", "group1")
.usingJobData("level", "")
.build();
JobDataMap jobDataMap = jobDetail.getJobDataMap();
jobDataMap.put("job","司机");
CronTrigger trigger = TriggerBuilder.newTrigger()
.startNow()
// .withDescription("this is a trigger1")
// .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
.withIdentity("mailjob1", "mailgroup") //定义任务名称和分组
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
//增加Job监听
MailJobListener mailJobListener = new MailJobListener();
KeyMatcher<JobKey> uKeyMatcher = KeyMatcher.keyEquals(jobDetail.getKey());
scheduler.getListenerManager().addJobListener(mailJobListener,uKeyMatcher);
//将触发器以及调度任务详情绑定到调度器上
scheduler.scheduleJob(jobDetail,trigger);
//启动调度器
scheduler.start();
}
}