commit 34ddc4d65693e865c63affebf0c84b831f68a885 Author: APLS Date: Thu Mar 5 11:42:05 2020 +0800 修复保存client_id时除了判断github_id存在,还需要判断client_id diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..a16b543 --- /dev/null +++ b/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..c8d4337 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..43c73a8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,174 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + io.qyi + e5 + 1.0.0 + e5 + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + org.springframework.boot + spring-boot-starter-security + + + + + junit + junit + + + + + + org.projectlombok + lombok + 1.16.22 + + + + commons-lang + commons-lang + 2.6 + + + com.alibaba + fastjson + 1.2.62 + + + mysql + mysql-connector-java + 5.1.21 + + + com.baomidou + mybatis-plus-boot-starter + 3.2.0 + + + + com.baomidou + mybatis-plus-generator + 3.2.0 + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + org.apache.commons + commons-pool2 + + + + + com.squareup.okhttp3 + okhttp + 3.10.0 + + + com.google.guava + guava + 28.1-jre + + + org.apache.commons + commons-lang3 + 3.9 + + + + org.aspectj + aspectjrt + + + + + org.aspectj + aspectjweaver + + + + org.jetbrains + annotations + RELEASE + compile + + + + + org.quartz-scheduler + quartz + 2.2.1 + + + org.quartz-scheduler + quartz-jobs + 2.2.1 + + + + org.springframework.boot + spring-boot-starter-mail + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/io/qyi/e5/AutoGenerator_.java b/src/main/java/io/qyi/e5/AutoGenerator_.java new file mode 100644 index 0000000..0f82e18 --- /dev/null +++ b/src/main/java/io/qyi/e5/AutoGenerator_.java @@ -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_ { + /** + *

+ * 读取控制台内容 + *

+ */ + 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 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(); + } +} diff --git a/src/main/java/io/qyi/e5/E5Application.java b/src/main/java/io/qyi/e5/E5Application.java new file mode 100644 index 0000000..aa8fc9f --- /dev/null +++ b/src/main/java/io/qyi/e5/E5Application.java @@ -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); + } + +} diff --git a/src/main/java/io/qyi/e5/bean/AppQuartz.java b/src/main/java/io/qyi/e5/bean/AppQuartz.java new file mode 100644 index 0000000..5c4c5c1 --- /dev/null +++ b/src/main/java/io/qyi/e5/bean/AppQuartz.java @@ -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;//需要传递的参数 + +} diff --git a/src/main/java/io/qyi/e5/bean/core/WebExceptionAspect.java b/src/main/java/io/qyi/e5/bean/core/WebExceptionAspect.java new file mode 100644 index 0000000..fe32a1f --- /dev/null +++ b/src/main/java/io/qyi/e5/bean/core/WebExceptionAspect.java @@ -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(); + } + } + +} diff --git a/src/main/java/io/qyi/e5/bean/result/Result.java b/src/main/java/io/qyi/e5/bean/result/Result.java new file mode 100644 index 0000000..7801731 --- /dev/null +++ b/src/main/java/io/qyi/e5/bean/result/Result.java @@ -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 { + /** 错误码. */ + private Integer code; + + /** 提示信息. */ + private String msg; + + /** 具体的内容. */ + private T data; +} diff --git a/src/main/java/io/qyi/e5/bean/result/ResultEnum.java b/src/main/java/io/qyi/e5/bean/result/ResultEnum.java new file mode 100644 index 0000000..85b53c8 --- /dev/null +++ b/src/main/java/io/qyi/e5/bean/result/ResultEnum.java @@ -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; + } +} diff --git a/src/main/java/io/qyi/e5/config/MybatisPlusConfig.java b/src/main/java/io/qyi/e5/config/MybatisPlusConfig.java new file mode 100644 index 0000000..d6cb422 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/MybatisPlusConfig.java @@ -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(); + } +} diff --git a/src/main/java/io/qyi/e5/config/quartz/JobFactory.java b/src/main/java/io/qyi/e5/config/quartz/JobFactory.java new file mode 100644 index 0000000..41bcf61 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/quartz/JobFactory.java @@ -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; + } +} diff --git a/src/main/java/io/qyi/e5/config/quartz/SchedulerConfig.java b/src/main/java/io/qyi/e5/config/quartz/SchedulerConfig.java new file mode 100644 index 0000000..d460952 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/quartz/SchedulerConfig.java @@ -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 { + + @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(); + } +} diff --git a/src/main/java/io/qyi/e5/config/redis/RedisConfig.java b/src/main/java/io/qyi/e5/config/redis/RedisConfig.java new file mode 100644 index 0000000..08cdeeb --- /dev/null +++ b/src/main/java/io/qyi/e5/config/redis/RedisConfig.java @@ -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 redisTemplate(RedisConnectionFactory redisConnectionFactory) { + + RedisTemplate 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 redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate(); + 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; + } + + +} diff --git a/src/main/java/io/qyi/e5/config/security/SecurityAuthenticationHandler.java b/src/main/java/io/qyi/e5/config/security/SecurityAuthenticationHandler.java new file mode 100644 index 0000000..2008022 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/SecurityAuthenticationHandler.java @@ -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(); + } +} diff --git a/src/main/java/io/qyi/e5/config/security/SecurityConfig.java b/src/main/java/io/qyi/e5/config/security/SecurityConfig.java new file mode 100644 index 0000000..b77c719 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/SecurityConfig.java @@ -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(",")); + }*/ +} diff --git a/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationConfig.java b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationConfig.java new file mode 100644 index 0000000..7d03b8c --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationConfig.java @@ -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 { + 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); + + + + } +} diff --git a/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationProvider.java b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationProvider.java new file mode 100644 index 0000000..8061475 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationProvider.java @@ -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 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); + } +} diff --git a/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java new file mode 100644 index 0000000..d9ac5d3 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/UsernamePasswordAuthenticationToken.java @@ -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 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; + } +} diff --git a/src/main/java/io/qyi/e5/config/security/filter/LoginAuthenticationFilter.java b/src/main/java/io/qyi/e5/config/security/filter/LoginAuthenticationFilter.java new file mode 100644 index 0000000..2fb64d3 --- /dev/null +++ b/src/main/java/io/qyi/e5/config/security/filter/LoginAuthenticationFilter.java @@ -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)); + } +} diff --git a/src/main/java/io/qyi/e5/controller/auth2/Auth.java b/src/main/java/io/qyi/e5/controller/auth2/Auth.java new file mode 100644 index 0000000..8f97615 --- /dev/null +++ b/src/main/java/io/qyi/e5/controller/auth2/Auth.java @@ -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 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); + }*/ + +} diff --git a/src/main/java/io/qyi/e5/controller/quartz/QuartzController.java b/src/main/java/io/qyi/e5/controller/quartz/QuartzController.java new file mode 100644 index 0000000..0850ab8 --- /dev/null +++ b/src/main/java/io/qyi/e5/controller/quartz/QuartzController.java @@ -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); + + } +} diff --git a/src/main/java/io/qyi/e5/controller/web/WebController.java b/src/main/java/io/qyi/e5/controller/web/WebController.java new file mode 100644 index 0000000..7bf5ced --- /dev/null +++ b/src/main/java/io/qyi/e5/controller/web/WebController.java @@ -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 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"; + } + +} diff --git a/src/main/java/io/qyi/e5/github/controller/GithubController.java b/src/main/java/io/qyi/e5/github/controller/GithubController.java new file mode 100644 index 0000000..ee28144 --- /dev/null +++ b/src/main/java/io/qyi/e5/github/controller/GithubController.java @@ -0,0 +1,20 @@ +package io.qyi.e5.github.controller; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@RestController +@RequestMapping("/github/github") +public class GithubController { + +} diff --git a/src/main/java/io/qyi/e5/github/entity/Github.java b/src/main/java/io/qyi/e5/github/entity/Github.java new file mode 100644 index 0000000..206d5c1 --- /dev/null +++ b/src/main/java/io/qyi/e5/github/entity/Github.java @@ -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; + +/** + *

+ * + *

+ * + * @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; + + +} diff --git a/src/main/java/io/qyi/e5/github/entity/UserInfo.java b/src/main/java/io/qyi/e5/github/entity/UserInfo.java new file mode 100644 index 0000000..6ce7688 --- /dev/null +++ b/src/main/java/io/qyi/e5/github/entity/UserInfo.java @@ -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; + +} diff --git a/src/main/java/io/qyi/e5/github/mapper/GithubMapper.java b/src/main/java/io/qyi/e5/github/mapper/GithubMapper.java new file mode 100644 index 0000000..e2a834a --- /dev/null +++ b/src/main/java/io/qyi/e5/github/mapper/GithubMapper.java @@ -0,0 +1,16 @@ +package io.qyi.e5.github.mapper; + +import io.qyi.e5.github.entity.Github; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface GithubMapper extends BaseMapper { + +} diff --git a/src/main/java/io/qyi/e5/github/service/IGithubService.java b/src/main/java/io/qyi/e5/github/service/IGithubService.java new file mode 100644 index 0000000..5717501 --- /dev/null +++ b/src/main/java/io/qyi/e5/github/service/IGithubService.java @@ -0,0 +1,16 @@ +package io.qyi.e5.github.service; + +import io.qyi.e5.github.entity.Github; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface IGithubService extends IService { + +} diff --git a/src/main/java/io/qyi/e5/github/service/impl/GithubServiceImpl.java b/src/main/java/io/qyi/e5/github/service/impl/GithubServiceImpl.java new file mode 100644 index 0000000..0712128 --- /dev/null +++ b/src/main/java/io/qyi/e5/github/service/impl/GithubServiceImpl.java @@ -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; + +/** + *

+ * 服务实现类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@Service +public class GithubServiceImpl extends ServiceImpl implements IGithubService { + +} diff --git a/src/main/java/io/qyi/e5/outlook/controller/AuthController.java b/src/main/java/io/qyi/e5/outlook/controller/AuthController.java new file mode 100644 index 0000000..cf11dd9 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook/controller/AuthController.java @@ -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 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 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); + } + + } +} diff --git a/src/main/java/io/qyi/e5/outlook/controller/OutlookController.java b/src/main/java/io/qyi/e5/outlook/controller/OutlookController.java new file mode 100644 index 0000000..b7c420c --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook/controller/OutlookController.java @@ -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.*; + +/** + *

+ * 前端控制器 + *

+ * + * @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); + } +} diff --git a/src/main/java/io/qyi/e5/outlook/entity/Outlook.java b/src/main/java/io/qyi/e5/outlook/entity/Outlook.java new file mode 100644 index 0000000..792bf40 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook/entity/Outlook.java @@ -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; + +/** + *

+ * + *

+ * + * @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; + + +} diff --git a/src/main/java/io/qyi/e5/outlook/mapper/OutlookMapper.java b/src/main/java/io/qyi/e5/outlook/mapper/OutlookMapper.java new file mode 100644 index 0000000..dce1ca9 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook/mapper/OutlookMapper.java @@ -0,0 +1,16 @@ +package io.qyi.e5.outlook.mapper; + +import io.qyi.e5.outlook.entity.Outlook; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface OutlookMapper extends BaseMapper { + +} diff --git a/src/main/java/io/qyi/e5/outlook/service/IOutlookService.java b/src/main/java/io/qyi/e5/outlook/service/IOutlookService.java new file mode 100644 index 0000000..a52f2f0 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook/service/IOutlookService.java @@ -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; + +/** + *

+ * 服务类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface IOutlookService extends IService { + + 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 findAll(); + +} diff --git a/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java b/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java new file mode 100644 index 0000000..52202e5 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook/service/impl/OutlookServiceImpl.java @@ -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; + +/** + *

+ * 服务实现类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@Service +public class OutlookServiceImpl extends ServiceImpl 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 head = new HashMap<>(); + head.put("Content-Type", "application/x-www-form-urlencoded"); + Map 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 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 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 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 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 head = new HashMap<>(); + head.put("Content-Type", "application/x-www-form-urlencoded"); + Map 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 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; + } + } +} diff --git a/src/main/java/io/qyi/e5/outlook_log/controller/OutlookLogController.java b/src/main/java/io/qyi/e5/outlook_log/controller/OutlookLogController.java new file mode 100644 index 0000000..9467d21 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook_log/controller/OutlookLogController.java @@ -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; + +/** + *

+ * 前端控制器 + *

+ * + * @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 wrapper = new QueryWrapper(); + wrapper.eq("github_id", github_id); + Page page = new Page<>(8,pageSize); + + IPage> mapIPage = outlookLogMapper.selectMapsPage(page, wrapper); + System.out.println("总页数"+mapIPage.getPages()); + System.out.println("总记录数"+mapIPage.getTotal()); + List> records = mapIPage.getRecords(); + records.forEach(System.out::println);*/ + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("github_id", github_id); + List list = outlookLogService.list(queryWrapper); + model.addAttribute("list_log", list); + return "/outlookLog/findLog"; + } + + @GetMapping("/exec111111") + public void s(){ + List list = outlookService.findAll(); + logger.info(String.valueOf(list.size())); + for (Outlook outlook :list) { + logger.info(outlook.toString()); + outlookService.getMailList(outlook); + } + + } + +} diff --git a/src/main/java/io/qyi/e5/outlook_log/entity/OutlookLog.java b/src/main/java/io/qyi/e5/outlook_log/entity/OutlookLog.java new file mode 100644 index 0000000..c07f856 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook_log/entity/OutlookLog.java @@ -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; + +/** + *

+ * + *

+ * + * @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; + + +} diff --git a/src/main/java/io/qyi/e5/outlook_log/mapper/OutlookLogMapper.java b/src/main/java/io/qyi/e5/outlook_log/mapper/OutlookLogMapper.java new file mode 100644 index 0000000..0f64ab0 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook_log/mapper/OutlookLogMapper.java @@ -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; + +/** + *

+ * Mapper 接口 + *

+ * + * @author 落叶 + * @since 2020-03-03 + */ +public interface OutlookLogMapper extends BaseMapper { + +} diff --git a/src/main/java/io/qyi/e5/outlook_log/service/IOutlookLogService.java b/src/main/java/io/qyi/e5/outlook_log/service/IOutlookLogService.java new file mode 100644 index 0000000..8fc026b --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook_log/service/IOutlookLogService.java @@ -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; + +/** + *

+ * 服务类 + *

+ * + * @author 落叶 + * @since 2020-03-03 + */ +public interface IOutlookLogService extends IService { + void addLog(int githubId, String msg,String result,String original_msg); + +} diff --git a/src/main/java/io/qyi/e5/outlook_log/service/impl/OutlookLogServiceImpl.java b/src/main/java/io/qyi/e5/outlook_log/service/impl/OutlookLogServiceImpl.java new file mode 100644 index 0000000..8c62ba4 --- /dev/null +++ b/src/main/java/io/qyi/e5/outlook_log/service/impl/OutlookLogServiceImpl.java @@ -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; + +/** + *

+ * 服务实现类 + *

+ * + * @author 落叶 + * @since 2020-03-03 + */ +@Service +public class OutlookLogServiceImpl extends ServiceImpl 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); + } +} diff --git a/src/main/java/io/qyi/e5/service/github/GithubService.java b/src/main/java/io/qyi/e5/service/github/GithubService.java new file mode 100644 index 0000000..205e63b --- /dev/null +++ b/src/main/java/io/qyi/e5/service/github/GithubService.java @@ -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); + +} diff --git a/src/main/java/io/qyi/e5/service/github/impl/GithubServiceImpl.java b/src/main/java/io/qyi/e5/service/github/impl/GithubServiceImpl.java new file mode 100644 index 0000000..38a6db1 --- /dev/null +++ b/src/main/java/io/qyi/e5/service/github/impl/GithubServiceImpl.java @@ -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 par = new HashMap<>(); + par.put("client_id", client_id); + par.put("client_secret", client_secret); + par.put("code", code); + Map 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 map = StringUtil.ParsingUrl(s); + return map.get("access_token"); + } + + @Override + public String getUserEmail(String access_token) throws Exception { + Map 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 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; + } +} diff --git a/src/main/java/io/qyi/e5/service/quartz/JobUtil.java b/src/main/java/io/qyi/e5/service/quartz/JobUtil.java new file mode 100644 index 0000000..7e5d8be --- /dev/null +++ b/src/main/java/io/qyi/e5/service/quartz/JobUtil.java @@ -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"; + } + + } + +} diff --git a/src/main/java/io/qyi/e5/service/quartz/MyQuartzJobService.java b/src/main/java/io/qyi/e5/service/quartz/MyQuartzJobService.java new file mode 100644 index 0000000..b5159c8 --- /dev/null +++ b/src/main/java/io/qyi/e5/service/quartz/MyQuartzJobService.java @@ -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 queryWrapper = new QueryWrapper<>(); + List list = outlookService.findAll(); + logger.info(String.valueOf(list.size())); + for (Outlook outlook :list) { + logger.info(outlook.toString()); + outlookService.getMailList(outlook); + } + } +} diff --git a/src/main/java/io/qyi/e5/service/security/SecurityUserService.java b/src/main/java/io/qyi/e5/service/security/SecurityUserService.java new file mode 100644 index 0000000..c0f8b29 --- /dev/null +++ b/src/main/java/io/qyi/e5/service/security/SecurityUserService.java @@ -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; + } +} diff --git a/src/main/java/io/qyi/e5/user/controller/PermissionController.java b/src/main/java/io/qyi/e5/user/controller/PermissionController.java new file mode 100644 index 0000000..b98b35e --- /dev/null +++ b/src/main/java/io/qyi/e5/user/controller/PermissionController.java @@ -0,0 +1,20 @@ +package io.qyi.e5.user.controller; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@RestController +@RequestMapping("/user/permission") +public class PermissionController { + +} diff --git a/src/main/java/io/qyi/e5/user/controller/RoleController.java b/src/main/java/io/qyi/e5/user/controller/RoleController.java new file mode 100644 index 0000000..b7371a3 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/controller/RoleController.java @@ -0,0 +1,20 @@ +package io.qyi.e5.user.controller; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@RestController +@RequestMapping("/user/role") +public class RoleController { + +} diff --git a/src/main/java/io/qyi/e5/user/controller/UserController.java b/src/main/java/io/qyi/e5/user/controller/UserController.java new file mode 100644 index 0000000..4a79d29 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/controller/UserController.java @@ -0,0 +1,20 @@ +package io.qyi.e5.user.controller; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@RestController +@RequestMapping("/user/user") +public class UserController { + +} diff --git a/src/main/java/io/qyi/e5/user/entity/Permission.java b/src/main/java/io/qyi/e5/user/entity/Permission.java new file mode 100644 index 0000000..8a1e4a3 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/entity/Permission.java @@ -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; + +/** + *

+ * + *

+ * + * @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; + + +} diff --git a/src/main/java/io/qyi/e5/user/entity/Role.java b/src/main/java/io/qyi/e5/user/entity/Role.java new file mode 100644 index 0000000..de64fd7 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/entity/Role.java @@ -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; + +/** + *

+ * + *

+ * + * @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; + + +} diff --git a/src/main/java/io/qyi/e5/user/entity/User.java b/src/main/java/io/qyi/e5/user/entity/User.java new file mode 100644 index 0000000..61e3888 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/entity/User.java @@ -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; + +/** + *

+ * + *

+ * + * @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; + + +} diff --git a/src/main/java/io/qyi/e5/user/mapper/PermissionMapper.java b/src/main/java/io/qyi/e5/user/mapper/PermissionMapper.java new file mode 100644 index 0000000..f36ff5f --- /dev/null +++ b/src/main/java/io/qyi/e5/user/mapper/PermissionMapper.java @@ -0,0 +1,16 @@ +package io.qyi.e5.user.mapper; + +import io.qyi.e5.user.entity.Permission; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface PermissionMapper extends BaseMapper { + +} diff --git a/src/main/java/io/qyi/e5/user/mapper/RoleMapper.java b/src/main/java/io/qyi/e5/user/mapper/RoleMapper.java new file mode 100644 index 0000000..7db2a9b --- /dev/null +++ b/src/main/java/io/qyi/e5/user/mapper/RoleMapper.java @@ -0,0 +1,16 @@ +package io.qyi.e5.user.mapper; + +import io.qyi.e5.user.entity.Role; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface RoleMapper extends BaseMapper { + +} diff --git a/src/main/java/io/qyi/e5/user/mapper/UserMapper.java b/src/main/java/io/qyi/e5/user/mapper/UserMapper.java new file mode 100644 index 0000000..3e43144 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/mapper/UserMapper.java @@ -0,0 +1,16 @@ +package io.qyi.e5.user.mapper; + +import io.qyi.e5.user.entity.User; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface UserMapper extends BaseMapper { + +} diff --git a/src/main/java/io/qyi/e5/user/service/IPermissionService.java b/src/main/java/io/qyi/e5/user/service/IPermissionService.java new file mode 100644 index 0000000..51f416a --- /dev/null +++ b/src/main/java/io/qyi/e5/user/service/IPermissionService.java @@ -0,0 +1,16 @@ +package io.qyi.e5.user.service; + +import io.qyi.e5.user.entity.Permission; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface IPermissionService extends IService { + +} diff --git a/src/main/java/io/qyi/e5/user/service/IRoleService.java b/src/main/java/io/qyi/e5/user/service/IRoleService.java new file mode 100644 index 0000000..39659f6 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/service/IRoleService.java @@ -0,0 +1,16 @@ +package io.qyi.e5.user.service; + +import io.qyi.e5.user.entity.Role; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface IRoleService extends IService { + +} diff --git a/src/main/java/io/qyi/e5/user/service/IUserService.java b/src/main/java/io/qyi/e5/user/service/IUserService.java new file mode 100644 index 0000000..dbf7621 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/service/IUserService.java @@ -0,0 +1,16 @@ +package io.qyi.e5.user.service; + +import io.qyi.e5.user.entity.User; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +public interface IUserService extends IService { + +} diff --git a/src/main/java/io/qyi/e5/user/service/impl/PermissionServiceImpl.java b/src/main/java/io/qyi/e5/user/service/impl/PermissionServiceImpl.java new file mode 100644 index 0000000..ed1227e --- /dev/null +++ b/src/main/java/io/qyi/e5/user/service/impl/PermissionServiceImpl.java @@ -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; + +/** + *

+ * 服务实现类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@Service +public class PermissionServiceImpl extends ServiceImpl implements IPermissionService { + +} diff --git a/src/main/java/io/qyi/e5/user/service/impl/RoleServiceImpl.java b/src/main/java/io/qyi/e5/user/service/impl/RoleServiceImpl.java new file mode 100644 index 0000000..6286b29 --- /dev/null +++ b/src/main/java/io/qyi/e5/user/service/impl/RoleServiceImpl.java @@ -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; + +/** + *

+ * 服务实现类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@Service +public class RoleServiceImpl extends ServiceImpl implements IRoleService { + +} diff --git a/src/main/java/io/qyi/e5/user/service/impl/UserServiceImpl.java b/src/main/java/io/qyi/e5/user/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..531b12b --- /dev/null +++ b/src/main/java/io/qyi/e5/user/service/impl/UserServiceImpl.java @@ -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; + +/** + *

+ * 服务实现类 + *

+ * + * @author 落叶 + * @since 2020-02-24 + */ +@Service +public class UserServiceImpl extends ServiceImpl implements IUserService { + +} diff --git a/src/main/java/io/qyi/e5/util/EncryptUtil.java b/src/main/java/io/qyi/e5/util/EncryptUtil.java new file mode 100644 index 0000000..95ea9ff --- /dev/null +++ b/src/main/java/io/qyi/e5/util/EncryptUtil.java @@ -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)); + } +} \ No newline at end of file diff --git a/src/main/java/io/qyi/e5/util/NumConvertUtil.java b/src/main/java/io/qyi/e5/util/NumConvertUtil.java new file mode 100644 index 0000000..848d3a2 --- /dev/null +++ b/src/main/java/io/qyi/e5/util/NumConvertUtil.java @@ -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; + + } + + + + + +} \ No newline at end of file diff --git a/src/main/java/io/qyi/e5/util/ResultUtil.java b/src/main/java/io/qyi/e5/util/ResultUtil.java new file mode 100644 index 0000000..4bde526 --- /dev/null +++ b/src/main/java/io/qyi/e5/util/ResultUtil.java @@ -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; + } +} diff --git a/src/main/java/io/qyi/e5/util/SpringUtil.java b/src/main/java/io/qyi/e5/util/SpringUtil.java new file mode 100644 index 0000000..d7bcd32 --- /dev/null +++ b/src/main/java/io/qyi/e5/util/SpringUtil.java @@ -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 getBean(Class clazz){ + return getApplicationContext().getBean(clazz); + } + + //通过name,以及Clazz返回指定的Bean + public static T getBean(String name,Class clazz){ + return getApplicationContext().getBean(name, clazz); + } + +} diff --git a/src/main/java/io/qyi/e5/util/StringUtil.java b/src/main/java/io/qyi/e5/util/StringUtil.java new file mode 100644 index 0000000..676657d --- /dev/null +++ b/src/main/java/io/qyi/e5/util/StringUtil.java @@ -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 ParsingUrl(String url){ + String[] split = url.split("&"); + Map 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; + } +} diff --git a/src/main/java/io/qyi/e5/util/VerifyCode.java b/src/main/java/io/qyi/e5/util/VerifyCode.java new file mode 100644 index 0000000..14afd8e --- /dev/null +++ b/src/main/java/io/qyi/e5/util/VerifyCode.java @@ -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日
+ * 创建时间:下午7:22:36
+ * 创建用户:yellowcong
+ * 机能概要:生成图片对象,并返回 + * + * @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日
+ * 创建时间:下午7:17:28
+ * 创建用户:yellowcong
+ * 机能概要:将图片转化为 二进制数据 + * + * @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日
+ * 创建时间:下午7:20:50
+ * 创建用户:yellowcong
+ * 机能概要:将二进制数据转化为文件 + * + * @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日
+ * 创建时间:下午7:03:57
+ * 创建用户:yellowcong
+ * 机能概要:生成随机的颜色 + * + * @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日
+ * 创建时间:下午7:03:20
+ * 创建用户:yellowcong
+ * 机能概要:生成随机的字体 + * + * @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日
+ * 创建时间:下午7:09:49
+ * 创建用户:yellowcong
+ * 机能概要: + * + * @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; + } + } +} \ No newline at end of file diff --git a/src/main/java/io/qyi/e5/util/netRequest/OkHttpClientUtil.java b/src/main/java/io/qyi/e5/util/netRequest/OkHttpClientUtil.java new file mode 100644 index 0000000..939c174 --- /dev/null +++ b/src/main/java/io/qyi/e5/util/netRequest/OkHttpClientUtil.java @@ -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 headers, Map 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 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 headers, Map querys) throws Exception { + FormBody.Builder formbody = new FormBody.Builder(); + if (null != querys) { + Iterator iterator = querys.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry 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 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 headers, Map querys) throws Exception { + FormBody.Builder builder = new FormBody.Builder(); + Iterator iterator = querys.entrySet().iterator(); + + while (iterator.hasNext()) { + Map.Entry 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; + } +} \ No newline at end of file diff --git a/src/main/java/io/qyi/e5/util/netRequest/OkHttpRequestUtils.java b/src/main/java/io/qyi/e5/util/netRequest/OkHttpRequestUtils.java new file mode 100644 index 0000000..1ff48b9 --- /dev/null +++ b/src/main/java/io/qyi/e5/util/netRequest/OkHttpRequestUtils.java @@ -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 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 header, Map 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> headerIterator = header.entrySet().iterator(); + headerIterator.forEachRemaining(e -> { + headerBuilder.add(e.getKey(), (String) e.getValue()); + }); + } + + if (query != null) { + // 装载请求的参数 + Iterator> 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 header, Map 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> 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> 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 header, Map 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> 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> 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 header, Map 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> headerIterator = header.entrySet().iterator(); + headerIterator.forEachRemaining(e -> { + headerBuilder.add(e.getKey(), (String) e.getValue()); + }); + + MultipartBody.Builder requestBuilder = new MultipartBody.Builder(); + + // 状态请求参数 + Iterator> 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 header, Map parameter) throws Exception { + return doPostFrom(url, header, parameter); + } + + /** + * post 请求 + * + * @param url + * @param parameter 参数 + * @return + * @throws Exception + */ + public static String doPost(String url, Map 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 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> 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 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); + } +} diff --git a/src/main/java/io/qyi/e5/util/redis/RedisUtil.java b/src/main/java/io/qyi/e5/util/redis/RedisUtil.java new file mode 100644 index 0000000..9a6bddb --- /dev/null +++ b/src/main/java/io/qyi/e5/util/redis/RedisUtil.java @@ -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 redisTemplate; + + public Set 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 hmget(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map 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 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 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 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 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 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; + } + } + +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..13784fc --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/github/GithubMapper.xml b/src/main/resources/mapper/github/GithubMapper.xml new file mode 100644 index 0000000..222ceea --- /dev/null +++ b/src/main/resources/mapper/github/GithubMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mapper/outlook/OutlookMapper.xml b/src/main/resources/mapper/outlook/OutlookMapper.xml new file mode 100644 index 0000000..d597ed9 --- /dev/null +++ b/src/main/resources/mapper/outlook/OutlookMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mapper/outlook_log/OutlookLogMapper.xml b/src/main/resources/mapper/outlook_log/OutlookLogMapper.xml new file mode 100644 index 0000000..521c776 --- /dev/null +++ b/src/main/resources/mapper/outlook_log/OutlookLogMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mapper/user/PermissionMapper.xml b/src/main/resources/mapper/user/PermissionMapper.xml new file mode 100644 index 0000000..56b9b2e --- /dev/null +++ b/src/main/resources/mapper/user/PermissionMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mapper/user/RoleMapper.xml b/src/main/resources/mapper/user/RoleMapper.xml new file mode 100644 index 0000000..11c9dd9 --- /dev/null +++ b/src/main/resources/mapper/user/RoleMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/mapper/user/UserMapper.xml b/src/main/resources/mapper/user/UserMapper.xml new file mode 100644 index 0000000..8b03387 --- /dev/null +++ b/src/main/resources/mapper/user/UserMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/main/resources/quartz.properties b/src/main/resources/quartz.properties new file mode 100644 index 0000000..c7c46db --- /dev/null +++ b/src/main/resources/quartz.properties @@ -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 \ No newline at end of file diff --git a/src/main/resources/static/error/4xx.html b/src/main/resources/static/error/4xx.html new file mode 100644 index 0000000..cfcb977 --- /dev/null +++ b/src/main/resources/static/error/4xx.html @@ -0,0 +1,835 @@ + + + + + 404 + + + + + + +
+

404

+

没找到页面,倒有个小游戏可以先玩一哈。

+

使用左键、右键和上箭头键移动。

+
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/outlookLog/findLog.ftl b/src/main/resources/templates/outlookLog/findLog.ftl new file mode 100644 index 0000000..6113826 --- /dev/null +++ b/src/main/resources/templates/outlookLog/findLog.ftl @@ -0,0 +1,32 @@ + + + + + 日志查询 + + + + + + + + + <#list list_log?sort_by('callTime')?reverse as log> + <#-- ${log},--> + <#-- ${log.result}
--> + + <#assign dlong = (log.callTime + '000')?number?number_to_datetime/> + <#-- --> + + <#if log.result == '1'> + + <#else > + + + + + + +
调用时间调用结果信息原始信息
${num?log.callTime?number_to_datetime?string('yyyy-MM-dd')}${dlong?string("yyyy-MM-dd HH:mm:ss")}成功失败${log.msg}${log.originalMsg}
+ + \ No newline at end of file diff --git a/src/main/resources/templates/user/authorization_outlook.ftl b/src/main/resources/templates/user/authorization_outlook.ftl new file mode 100644 index 0000000..6d02cb2 --- /dev/null +++ b/src/main/resources/templates/user/authorization_outlook.ftl @@ -0,0 +1,16 @@ + + + + + outlook授权结果 + + +<#if result> +

授权成功!

+<#else > +

授权失败!

+

错误: ${msg}

+ + 返回用户中心 + + \ No newline at end of file diff --git a/src/main/resources/templates/user/home.ftl b/src/main/resources/templates/user/home.ftl new file mode 100644 index 0000000..1064358 --- /dev/null +++ b/src/main/resources/templates/user/home.ftl @@ -0,0 +1,117 @@ + + + + + Home + + + + + +
+
+ Office E5 自动续订 +
+
+
+
+ 使用说明 +
    + <#--
  1. 输入 client_id 与 client_secret 保存
  2. +
  3. 点击 “授权”,请用不使用的空账号登录授权
  4. +
  5. 授权成功后就不用管了,系统会自动调用你的out api
  6. --> +
  7. 程序会读取授权的outlook账号邮箱邮件,但不会保存任何信息,仅仅是调用api。
  8. +
  9. 请单独创建一个同域 E5 子账号,不要使用此账号进行发送、接收个人邮件,以免发生误会。
  10. +
+
+<#--数据输入--> +
+
+ + +
+
+ + +
+ + +
+
+<#--日志表格--> +
+

日志会在每日0点清空。

+ +
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/user/login.ftl b/src/main/resources/templates/user/login.ftl new file mode 100644 index 0000000..7021a0a --- /dev/null +++ b/src/main/resources/templates/user/login.ftl @@ -0,0 +1,34 @@ + + + + + 登录 + + + + + + \ No newline at end of file diff --git a/src/test/java/io/qyi/e5/E5ApplicationTests.java b/src/test/java/io/qyi/e5/E5ApplicationTests.java new file mode 100644 index 0000000..009d058 --- /dev/null +++ b/src/test/java/io/qyi/e5/E5ApplicationTests.java @@ -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() { + } + +} diff --git a/src/test/java/io/qyi/e5/test/MailJobListener.java b/src/test/java/io/qyi/e5/test/MailJobListener.java new file mode 100644 index 0000000..83016ae --- /dev/null +++ b/src/test/java/io/qyi/e5/test/MailJobListener.java @@ -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()); + } +} diff --git a/src/test/java/io/qyi/e5/test/RamJob.java b/src/test/java/io/qyi/e5/test/RamJob.java new file mode 100644 index 0000000..4769e69 --- /dev/null +++ b/src/test/java/io/qyi/e5/test/RamJob.java @@ -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")); + } +} diff --git a/src/test/java/io/qyi/e5/test/quartzDome01.java b/src/test/java/io/qyi/e5/test/quartzDome01.java new file mode 100644 index 0000000..2d577c8 --- /dev/null +++ b/src/test/java/io/qyi/e5/test/quartzDome01.java @@ -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 uKeyMatcher = KeyMatcher.keyEquals(jobDetail.getKey()); + scheduler.getListenerManager().addJobListener(mailJobListener,uKeyMatcher); + + + //将触发器以及调度任务详情绑定到调度器上 + scheduler.scheduleJob(jobDetail,trigger); + //启动调度器 + scheduler.start(); + + } +}