commit 16cc30f513bb5e63c21bc59a5866dd9b08cbf10e Author: 小海 Date: Thu Nov 28 19:18:16 2019 +0800 从"Blog"仓库中分离出来 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4ca3a46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.idea/ +*.imi +target/ + +# 本地项目的私有文件 +back-end/blog-dev.sql +src/main/resources/application-prod.properties +src/main/resources/application-dev.properties diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 0000000..82e87fe --- /dev/null +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,114 @@ +/* +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. +*/ + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.Properties; + +public class MavenWrapperDownloader { + + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: : " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..01e6799 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..6b0f4f2 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..517beb5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 小海 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bce9a5c --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ + # 小海博客后端管理系统 + + + + ## 基于Springboot的后端博客管理系统 + + + + + ### 主要使用的技术 + +| 使用的技术 | 名称 | 版本 | +| :--------------: | :--------: | :-----------: | +| 后端框架 | Springoot | 2.1.3.RELEASE | +| orm | mybatis | 2.0.1 | +| 分页 | pageHelper | 1.2.12 | +| 权限管理 | shiro | 1.3.2 | +| 项目构建 | Maven | 3.6.1 | +| 运行环境 | Ubuntu | 16.04.6 LTS | +| 接口文档 | Swagger | 2.6.1 | +| 数据库连接池 | druid | 1.1.14 | +| 缓存(线上环境) | redis | 3.0.6 | +|数据库|mysql|5.7| + + ### 接口文档 + + 项目采用swagger2,接口文档自动生成,具体为 http://ip:端口/swagger-ui.html + + ### 📝TODO + + - [x] 密码重置 + - [x] 信息修改 + - [ ] 接入qq登录 + + ### 📌FIXME + + - [ ] `/write` 图片上传的跨域问题 diff --git a/blog.iml b/blog.iml new file mode 100644 index 0000000..7aecb0e --- /dev/null +++ b/blog.iml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/blog.sql b/blog.sql new file mode 100644 index 0000000..e07a364 --- /dev/null +++ b/blog.sql @@ -0,0 +1,92 @@ +CREATE DATABASE `blog`; + +USE blog; + +CREATE TABLE `article` +( + `a_id` bigint(20) primary key auto_increment, + `a_title` varchar(255) not null unique comment '文章标题', + `a_summary` varchar(255) not null comment '文章摘要', + `a_md_content` longtext not null comment '文章Markdown内容', + `a_tags_id` varchar(255) not null comment '标签id \',\'处于最尾端', + `a_category_id` bigint(20) not null comment '分类的id', + `a_url` tinytext default null comment '转载文章的原文链接', + `a_author_id` bigint(20) not null comment '作者id', + `a_is_open` boolean default true comment '文章是否可见', + `a_is_original` boolean default true comment '文章是否原创', + `next_a_id` bigint(20) default -1 comment '下篇文章id', + `pre_a_id` bigint(20) default -1 comment '前一篇文章的id', + `a_reading_number` int default 0 comment '文章阅读数', + `a_publish_date` datetime not null comment '文章发布时间', + `a_update_date` datetime default null comment '文章的更新时间' +) DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci,comment '文章表'; + +CREATE TABLE `tag` +( + `tag_id` bigint(20) primary key auto_increment, + `tag_name` varchar(255) unique not null, + `articles` tinytext default null comment 'tag对应的文章id' +) comment '标签表'; + +CREATE table `category` +( + `c_id` bigint(20) primary key auto_increment, + `c_name` varchar(255) unique not null, + `articles` varchar(255) comment '分类下的文章' +)comment '分类表'; + +CREATE TABLE `comment` +( + `co_id` bigint(20) primary key auto_increment, + `co_article_id` bigint(20) default -1 comment '文章id', + `is_comment` boolean default true comment '是否是评论', + `author_id` bigint(20) not null comment '留言者id', + `co_content` text not null comment '评论/留言内容', + `co_date` datetime not null comment '评论/留言的日期', + `co_pid` bigint not null default -1 comment '评论/留言的父id', + `co_response_id` tinytext +) DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci,comment '评论/留言表'; + +CREATE TABLE `links` +( + `site_id` bigint(20) primary key auto_increment, + `site_name` varchar(255) not null comment '友站名称', + `is_open` boolean default true comment '是否公开', + `site_url` varchar(255) not null comment '首页地址' +) comment '友站表'; + +CREATE TABLE `visitor` +( + `v_id` bigint(20) primary key auto_increment, + `v_date` datetime not null comment '访问时间', + `v_ip` varchar(255) not null comment '访客ip', + `v_user_agent` text comment '访客ua' +) comment '访客表'; + + + +CREATE TABLE IF NOT EXISTS `web_update` +( + `update_id` bigint(20) primary key auto_increment, + `update_info` varchar(255) not null comment '更新内容', + `update_time` datetime not null comment '更新时间' +) comment '更新内容表'; + +create table `user` +( + `u_id` int not null primary key auto_increment, + `u_email` varchar(50) not null, + `u_uid` varchar(40) default null comment '用户唯一标识码', + `u_pwd` varchar(40) not null comment '密码', + `email_status` boolean default false comment '邮箱验证状态', + `u_avatar` varchar(255) comment '用户头像', + `u_desc` tinytext comment '用户的描述', + `recently_landed_time` datetime comment '最近的登录时间', + `email_verify_id` varchar(40) comment '用于找回密码或验证邮箱的id', + `display_name` varchar(30) comment '展示的昵称', + `role` varchar(40) not null default 'user' comment '权限组', + unique key `uni_user_id` (`u_id`), + unique key `uni_user_uid` (`u_uid`), + unique key `uni_user_email` (`u_email`) +) comment '用户表'; + diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..65f10d2 --- /dev/null +++ b/mvnw @@ -0,0 +1,286 @@ +#!/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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 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)`" + # TODO classpath? +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 + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" + 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 command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + wget "$jarUrl" -O "$wrapperJarPath" + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + curl -o "$wrapperJarPath" "$jarUrl" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + 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 + +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 "$@" \ No newline at end of file diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..a5284c7 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,161 @@ +@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 Maven2 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 key stroke 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 my 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.4.2/maven-wrapper-0.4.2.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% ( + echo Found %WRAPPER_JAR% +) else ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" + echo Finished downloading %WRAPPER_JAR% +) +@REM End of extension + +%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..40e8772 --- /dev/null +++ b/pom.xml @@ -0,0 +1,162 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + cn.celess + blog + 0.0.1-SNAPSHOT + blog + personal blog system project for Spring Boot + + + 1.8 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + mysql + mysql-connector-java + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + + + com.alibaba + druid + 1.1.14 + + + + + org.projectlombok + lombok + 1.18.6 + + + + + + io.springfox + springfox-swagger2 + 2.6.1 + + + io.springfox + springfox-swagger-ui + 2.6.1 + + + + + com.youbenzi + MDTool + 1.2.3 + + + net.minidev + json-smart + 2.3 + compile + + + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + + + + + com.qiniu + qiniu-java-sdk + [7.2.0, 7.2.99] + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.0.1 + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + 1.2.12 + + + + + com.dyuproject.protostuff + protostuff-core + 1.0.8 + + + com.dyuproject.protostuff + protostuff-runtime + 1.0.8 + + + + + eu.bitwalker + UserAgentUtils + 1.20 + + + + junit + junit + 4.12 + + + + + io.jsonwebtoken + jjwt + 0.9.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/cn/celess/blog/BlogApplication.java b/src/main/java/cn/celess/blog/BlogApplication.java new file mode 100644 index 0000000..f65dc22 --- /dev/null +++ b/src/main/java/cn/celess/blog/BlogApplication.java @@ -0,0 +1,20 @@ +package cn.celess.blog; + +import org.mybatis.spring.annotation.MapperScan; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; + +@SpringBootApplication +@EnableAsync +@MapperScan("cn.celess.blog.mapper") +public class BlogApplication { + public static final Logger logger = LoggerFactory.getLogger(BlogApplication.class); + + public static void main(String[] args) { + SpringApplication.run(BlogApplication.class, args); + logger.info("启动完成!"); + } +} diff --git a/src/main/java/cn/celess/blog/configuration/CorsConfig.java b/src/main/java/cn/celess/blog/configuration/CorsConfig.java new file mode 100644 index 0000000..2638306 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/CorsConfig.java @@ -0,0 +1,38 @@ +package cn.celess.blog.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +/** + * @author : xiaohai + * @date : 2019/03/30 19:55 + * 跨域 + */ +@Configuration +public class CorsConfig { + @Bean + public CorsFilter corsFilter() { + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + CorsConfiguration config = new CorsConfiguration(); + config.addAllowedOrigin("http://celess.cn"); + config.addAllowedOrigin("http://www.celess.cn"); + config.addAllowedOrigin("https://celess.cn"); + config.addAllowedOrigin("https://www.celess.cn"); + // 本地调试时的跨域 + config.addAllowedOrigin("http://localhost:4200"); + config.addAllowedOrigin("http://127.0.0.1:4200"); + config.addAllowedHeader("*"); + config.addAllowedMethod("OPTIONS"); + config.addAllowedMethod("GET"); + config.addAllowedMethod("POST"); + config.addAllowedMethod("PUT"); + config.addAllowedMethod("DELETE"); + config.setAllowCredentials(true); + config.setMaxAge(10800L); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/java/cn/celess/blog/configuration/DruidConfig.java b/src/main/java/cn/celess/blog/configuration/DruidConfig.java new file mode 100644 index 0000000..8f92b61 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/DruidConfig.java @@ -0,0 +1,41 @@ +package cn.celess.blog.configuration; + +import com.alibaba.druid.pool.DruidDataSource; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author : xiaohai + * @date : 2019/03/28 14:26 + */ +@Configuration +public class DruidConfig { + @Value("${spring.datasource.url}") + private String dbUrl; + + @Value("${spring.datasource.username}") + private String username; + + @Value("${spring.datasource.password}") + private String password; + + @Value("${spring.datasource.driver-class-name}") + private String driverClassName; + + @Bean + public DruidDataSource druidDataSource() { + DruidDataSource dataSource = new DruidDataSource(); + dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); + // 数据库基本信息 + dataSource.setUrl(dbUrl); + dataSource.setUsername(username); + dataSource.setPassword(password); + + // 数据库连接池配置 + dataSource.setInitialSize(10); + dataSource.setMinIdle(10); + dataSource.setMaxActive(100); + return dataSource; + } +} diff --git a/src/main/java/cn/celess/blog/configuration/InterceptorConfig.java b/src/main/java/cn/celess/blog/configuration/InterceptorConfig.java new file mode 100644 index 0000000..1e22834 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/InterceptorConfig.java @@ -0,0 +1,41 @@ +package cn.celess.blog.configuration; + +import cn.celess.blog.configuration.filter.AuthenticationFilter; +import cn.celess.blog.configuration.filter.MultipleSubmitFilter; +import cn.celess.blog.configuration.filter.VisitorRecord; +import cn.celess.blog.configuration.listener.SessionListener; +import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @Author: 小海 + * @Date: 2019/10/18 14:19 + * @Description: + */ +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new MultipleSubmitFilter()).addPathPatterns("/*"); + registry.addInterceptor(authenticationFilter()).addPathPatterns("/**"); + + // visitor 输出信息杂乱 暂时放弃使用 +// registry.addInterceptor(new VisitorRecord()).addPathPatterns("/*"); + } + + @Bean + public AuthenticationFilter authenticationFilter() { + return new AuthenticationFilter(); + } + +// // session listener register bean +// @Bean +// public ServletListenerRegistrationBean servletListenerRegistrationBean() { +// ServletListenerRegistrationBean slrBean = new ServletListenerRegistrationBean(); +// slrBean.setListener(new SessionListener()); +// return slrBean; +// } +} diff --git a/src/main/java/cn/celess/blog/configuration/RedisConfig.java b/src/main/java/cn/celess/blog/configuration/RedisConfig.java new file mode 100644 index 0000000..c36798c --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/RedisConfig.java @@ -0,0 +1,72 @@ +package cn.celess.blog.configuration; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +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.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; + +import java.lang.reflect.Method; + + +/** + * @author : xiaohai + * @date : 2019/05/22 17:35 + */ +@Configuration +@EnableCaching +public class RedisConfig extends CachingConfigurerSupport { + + /** + * 缓存的命名前缀 + * + * @return KeyGenerator + */ + @Override + @Bean + public KeyGenerator keyGenerator() { + return new KeyGenerator() { + @Override + public Object generate(Object target, Method method, Object... params) { + StringBuilder sb = new StringBuilder(); + String name = target.getClass().getName(); + sb.append(name.substring(name.lastIndexOf(".") + 1)); + sb.append(":"); + sb.append(method.getName()); + for (Object obj : params) { + sb.append("-").append(obj.toString()); + } + return sb.toString(); + } + }; + } + + /** + * 配置redisTemplate + * + * @param redisConnectionFactory redisConnectionFactory + * @return redisTemplate + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + 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); + RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(redisConnectionFactory); + template.setKeySerializer(jackson2JsonRedisSerializer); + template.setValueSerializer(jackson2JsonRedisSerializer); + template.setHashKeySerializer(jackson2JsonRedisSerializer); + template.setHashValueSerializer(jackson2JsonRedisSerializer); + template.afterPropertiesSet(); + return template; + } +} \ No newline at end of file diff --git a/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java b/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java new file mode 100644 index 0000000..01bbdc0 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/SwaggerConfig.java @@ -0,0 +1,45 @@ +package cn.celess.blog.configuration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * @author : xiaohai + * @date : 2019/03/28 15:55 + */ +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + + @Value("${spring.profiles.active}") + private String environment; + + @Bean + public Docket createRestApi() { + return new Docket(DocumentationType.SWAGGER_2) + .enable("dev".equals(environment)) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage("cn.celess.blog")) + .paths(PathSelectors.any()) + .build(); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("小海博客的APi") + .description("小海博客的APi") + .contact("小海") + .version("1.0") + .build(); + } + +} \ No newline at end of file diff --git a/src/main/java/cn/celess/blog/configuration/filter/AuthenticationFilter.java b/src/main/java/cn/celess/blog/configuration/filter/AuthenticationFilter.java new file mode 100644 index 0000000..b80cf40 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/filter/AuthenticationFilter.java @@ -0,0 +1,83 @@ +package cn.celess.blog.configuration.filter; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.service.UserService; +import cn.celess.blog.util.JwtUtil; +import cn.celess.blog.util.RedisUtil; +import cn.celess.blog.util.ResponseUtil; +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @Author: 小海 + * @Date: 2019/11/16 11:21 + * @Description: 鉴权拦截器 + */ +public class AuthenticationFilter implements HandlerInterceptor { + @Autowired + JwtUtil jwtUtil; + @Autowired + RedisUtil redisUtil; + @Autowired + UserService userService; + + private static final Logger logger = LoggerFactory.getLogger(AuthenticationFilter.class); + + private static final String USER_PREFIX = "/user"; + private static final String ADMIN_PREFIX = "/admin"; + private static final String ROLE_ADMIN = "admin"; + private static final String ROLE_USER = "user"; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String path = request.getRequestURI(); + path = path.replaceAll("/+", "/"); + int indexOf = path.indexOf("/", 1); + String rootPath = indexOf == -1 ? path : path.substring(0, indexOf); + // 不需要鉴权的路径 + if (!USER_PREFIX.equals(rootPath.toLowerCase()) && !ADMIN_PREFIX.equals(rootPath.toLowerCase())) { + return true; + } + + String jwtStr = request.getHeader("Authorization"); + if (jwtStr == null || jwtStr.isEmpty()) { + return writeResponse(ResponseEnum.HAVE_NOT_LOG_IN, response, request); + } + if (jwtUtil.isTokenExpired(jwtStr)) { + return writeResponse(ResponseEnum.LOGIN_EXPIRED, response, request); + } + String email = jwtUtil.getUsernameFromToken(jwtStr); + if (!redisUtil.hasKey(email + "-login") || jwtUtil.isTokenExpired(jwtStr)) { + // 登陆过期 + return writeResponse(ResponseEnum.LOGIN_EXPIRED, response, request); + } + String role = userService.getUserRoleByEmail(email); + if (role.equals(ROLE_ADMIN)) { + // admin + return true; + } + if (role.equals(ROLE_USER) && !rootPath.equals(ADMIN_PREFIX)) { + // user not admin page + return true; + } + return writeResponse(ResponseEnum.PERMISSION_ERROR, response, request); + } + + private boolean writeResponse(ResponseEnum e, HttpServletResponse response, HttpServletRequest request) { + response.setHeader("Content-Type", "application/json;charset=UTF-8"); + try { + logger.info("鉴权失败,[code:{},msg:{},path:{}]", e.getCode(), e.getMsg(), request.getRequestURI() + "?" + request.getQueryString()); + response.getWriter().println(JSONObject.fromObject(ResponseUtil.response(e, null))); + } catch (IOException ex) { + ex.printStackTrace(); + } + return false; + } +} diff --git a/src/main/java/cn/celess/blog/configuration/filter/MultipleSubmitFilter.java b/src/main/java/cn/celess/blog/configuration/filter/MultipleSubmitFilter.java new file mode 100644 index 0000000..c0557cc --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/filter/MultipleSubmitFilter.java @@ -0,0 +1,44 @@ +package cn.celess.blog.configuration.filter; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Response; +import cn.celess.blog.util.RequestUtil; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +/** + * @Author: 小海 + * @Date: 2019/10/18 13:46 + * @Description: 多次请求拦截器 + */ +public class MultipleSubmitFilter implements HandlerInterceptor { + private static final int WAIT_TIME = 200;// 多次提交中间的间隔 + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + Long lastSubmitTime = (Long) request.getSession().getAttribute("lastSubmitTime"); + String completeUrl = (String) request.getSession().getAttribute("completeUrl&method"); + if (lastSubmitTime == null || completeUrl == null) { + return true; + } + if (System.currentTimeMillis() - lastSubmitTime < WAIT_TIME && RequestUtil.getCompleteUrlAndMethod(request).equals(completeUrl)) { + // 请求参数和路径均相同 且请求时间间隔小于 WAIT_TIME + response.setContentType("application/json"); + response.setCharacterEncoding("UTF-8"); + Response result = new Response(ResponseEnum.FAILURE.getCode(), "重复请求", null, System.currentTimeMillis()); + response.getWriter().println(result.toString()); + return false; + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + HttpSession session = request.getSession(); + session.setAttribute("lastSubmitTime", System.currentTimeMillis()); + session.setAttribute("completeUrl&method", RequestUtil.getCompleteUrlAndMethod(request)); + } +} diff --git a/src/main/java/cn/celess/blog/configuration/filter/VisitorRecord.java b/src/main/java/cn/celess/blog/configuration/filter/VisitorRecord.java new file mode 100644 index 0000000..0082cc8 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/filter/VisitorRecord.java @@ -0,0 +1,34 @@ +package cn.celess.blog.configuration.filter; + +import cn.celess.blog.util.RequestUtil; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.util.HashMap; + +/** + * @Author: 小海 + * @Date: 2019/10/18 15:38 + * @Description: 记录访问情况 + */ +@Configuration +public class VisitorRecord implements HandlerInterceptor { + + @SuppressWarnings("unchecked") + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + HttpSession session = request.getSession(); + HashMap visitDetail = (HashMap) session.getAttribute("visitDetail"); + // 获取访问次数 + Integer count = visitDetail.get(RequestUtil.getCompleteUrlAndMethod(request)); + // 自增 + count = count == null ? 1 : ++count; + // 更新 + visitDetail.put(RequestUtil.getCompleteUrlAndMethod(request), count); + session.setAttribute("ip",request.getRemoteAddr()); + return true; + } +} diff --git a/src/main/java/cn/celess/blog/configuration/listener/SessionListener.java b/src/main/java/cn/celess/blog/configuration/listener/SessionListener.java new file mode 100644 index 0000000..26b2bd3 --- /dev/null +++ b/src/main/java/cn/celess/blog/configuration/listener/SessionListener.java @@ -0,0 +1,50 @@ +package cn.celess.blog.configuration.listener; + +import cn.celess.blog.entity.User; +import cn.celess.blog.util.RedisUserUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; +import java.util.HashMap; + +/** + * @Author: 小海 + * @Date: 2019/10/18 15:33 + * @Description: 监听session的情况 + */ +@WebListener +public class SessionListener implements HttpSessionListener { + @Autowired + RedisUserUtil redisUserUtil; + @Autowired + HttpServletRequest request; + private static final Logger logger = LoggerFactory.getLogger(SessionListener.class); + + @Override + public void sessionCreated(HttpSessionEvent se) { + // TODO : can move 'visit' api to here + se.getSession().setAttribute("visitDetail", new HashMap()); + // se.getSession().setMaxInactiveInterval(10);// 10s for debug + logger.info("新增一个Session[{}]", se.getSession().getId()); + } + + @SuppressWarnings("unchecked") + @Override + public void sessionDestroyed(HttpSessionEvent se) { + HashMap visitDetail = (HashMap) se.getSession().getAttribute("visitDetail"); + StringBuilder sb = new StringBuilder(); + sb.append("ip => ").append(se.getSession().getAttribute("ip")); + User user = redisUserUtil.get(request); + sb.append("\t登录情况 => "); + sb.append(user == null ? "游客访问" : user.getEmail()); + visitDetail.forEach((s, integer) -> { + sb.append("\n").append("Method:[").append(s.split(":")[1]).append("]\tTimes:[").append(integer).append("]\tPath:[").append(s.split(":")[0]).append("]"); + }); + logger.info(sb.toString()); + } +} diff --git a/src/main/java/cn/celess/blog/controller/ArticleController.java b/src/main/java/cn/celess/blog/controller/ArticleController.java new file mode 100644 index 0000000..09f58ef --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/ArticleController.java @@ -0,0 +1,154 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.model.ArticleModel; +import cn.celess.blog.entity.request.ArticleReq; +import cn.celess.blog.service.ArticleService; +import cn.celess.blog.util.RedisUserUtil; +import cn.celess.blog.util.ResponseUtil; +import cn.celess.blog.util.SitemapGenerateUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author : xiaohai + * @date : 2019/03/28 15:18 + */ +@RestController +public class ArticleController { + @Autowired + ArticleService articleService; + @Autowired + SitemapGenerateUtil sitemapGenerateUtil; + @Autowired + RedisUserUtil redisUserUtil; + + /** + * 新建一篇文章 + * + * @param body 请求数据 + * @return Response + */ + @PostMapping("/admin/article/create") + public Response create(@RequestBody ArticleReq body) { + ArticleModel articleModel = articleService.create(body); + sitemapGenerateUtil.createSitemap(); + return ResponseUtil.success(articleModel); + } + + /** + * 通过文章id 删除一篇文章 + * + * @param articleId 文章id + * @return Response + */ + @DeleteMapping("/admin/article/del") + public Response delete(@RequestParam("articleID") long articleId) { + boolean delete = articleService.delete(articleId); + sitemapGenerateUtil.createSitemap(); + return ResponseUtil.success(delete); + } + + /** + * 更新文章 + * + * @param body 请求数据 + * @return Response + */ + @PutMapping("/admin/article/update") + public Response update(@RequestBody ArticleReq body) { + ArticleModel update = articleService.update(body); + sitemapGenerateUtil.createSitemap(); + return ResponseUtil.success(update); + } + + /** + * 通过id查找一篇文章 + * 公开 =>返回数据 + * 不公开 + * *** =>作者 返回数据 + * *** =>其他 抛出错误 + * + * @param articleId 文章id + * @param is4update 是否是更新 + * @return Response + */ + @GetMapping("/article/articleID/{articleID}") + public Response retrieveOneById(@PathVariable("articleID") long articleId, + @RequestParam(value = "update", defaultValue = "false") boolean is4update, + HttpServletRequest request) { + ArticleModel article = articleService.retrieveOneByID(articleId, is4update); + if (article.getOpen()) { + return ResponseUtil.success(article); + } else if (article.getAuthorId().equals(redisUserUtil.get(request).getId())) { + return ResponseUtil.success(article); + } + return ResponseUtil.response(ResponseEnum.PERMISSION_ERROR, null); + } + + /** + * 分页获取所有文章状态为开放的的文章 + * + * @param page 页码 + * @param count 单页数据量 + * @return Response + */ + @GetMapping("/articles") + public Response articles(@RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "count", defaultValue = "5") int count) { + return ResponseUtil.success(articleService.retrievePageForOpen(count, page)); + } + + /** + * 分页获取所有文章 + * + * @param page 页码 + * @param count 单页数据量 + * @return Response + */ + @GetMapping("/admin/articles") + public Response adminArticles(@RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "count", defaultValue = "10") int count) { + return ResponseUtil.success(articleService.adminArticles(count, page)); + } + + /** + * 通过分类获取文章(文章摘要) + * + * @param name 分类名 + * @param page 页码 + * @param count 单页数据量 + * @return Response + */ + @GetMapping("/articles/category/{name}") + public Response findByCategory(@PathVariable("name") String name, + @RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "count", defaultValue = "10") int count) { + return ResponseUtil.success(articleService.findByCategory(name, page, count)); + } + + /** + * 通过标签名获取文章(文章摘要) + * + * @param name 标签名 + * @param page 页码 + * @param count 单页数据量 + * @return Response + */ + @GetMapping("/articles/tag/{name}") + public Response findByTag(@PathVariable("name") String name, + @RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "count", defaultValue = "10") int count) { + return ResponseUtil.success(articleService.findByTag(name, page, count)); + } + + + @GetMapping("/createSitemap") + public Response createSitemap() { + sitemapGenerateUtil.createSitemap(); + return ResponseUtil.success(null); + } +} diff --git a/src/main/java/cn/celess/blog/controller/CategoryController.java b/src/main/java/cn/celess/blog/controller/CategoryController.java new file mode 100644 index 0000000..c9a7fab --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/CategoryController.java @@ -0,0 +1,63 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.entity.Response; +import cn.celess.blog.service.CategoryService; +import cn.celess.blog.util.ResponseUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author : xiaohai + * @date : 2019/03/30 20:36 + */ +@RestController +public class CategoryController { + + @Autowired + CategoryService categoryService; + + /** + * 新增一个分类 + * + * @param name 分类名 + * @return Response + */ + @PostMapping("/admin/category/create") + public Response addOne(@RequestParam("name") String name) { + return ResponseUtil.success(categoryService.create(name)); + } + + /** + * 删除一个分类 + * + * @param id 分类id + * @return Response + */ + @DeleteMapping("/admin/category/del") + public Response deleteOne(@RequestParam("id") long id) { + return ResponseUtil.success(categoryService.delete(id)); + } + + /** + * 更新一个分类 + * + * @param id 分类id + * @param name 更新后的名字 + * @return Response + */ + @PutMapping("/admin/category/update") + public Response updateOne(@RequestParam("id") Long id, + @RequestParam("name") String name) { + return ResponseUtil.success(categoryService.update(id, name)); + } + + /** + * 获取所有的分类 + * + * @return Response + */ + @GetMapping("/categories") + public Response getPage() { + return ResponseUtil.success(categoryService.retrievePage()); + } +} diff --git a/src/main/java/cn/celess/blog/controller/CommentController.java b/src/main/java/cn/celess/blog/controller/CommentController.java new file mode 100644 index 0000000..5db0bbd --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/CommentController.java @@ -0,0 +1,101 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.entity.Comment; +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.request.CommentReq; +import cn.celess.blog.service.CommentService; +import cn.celess.blog.util.ResponseUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + + +/** + * @author : xiaohai + * @date : 2019/03/30 20:37 + */ +@RestController +public class CommentController { + @Autowired + CommentService commentService; + + /** + * 新增一条评论数据 + * + * @param reqBody 请求数据 + * @return Response + */ + @PostMapping("/user/comment/create") + public Response addOne(@RequestBody CommentReq reqBody) { + return ResponseUtil.success(commentService.create(reqBody)); + } + + @DeleteMapping("/user/comment/del") + public Response delete(@RequestParam("id") long id) { + return ResponseUtil.success(commentService.delete(id)); + } + + @PutMapping("/user/comment/update") + public Response update(@RequestBody CommentReq reqBody) { + return ResponseUtil.success(commentService.update(reqBody)); + } + + /** + * 获取所有的一级评论 + * + * @param articleId 文章id + * @param count 单页数据量 + * @param page 页码 + * @return Response + */ + @GetMapping("/comments") + public Response commentsOfArticle(@RequestParam("articleId") long articleId, + @RequestParam(value = "count", required = false, defaultValue = "10") int count, + @RequestParam(value = "page", required = false, defaultValue = "1") int page) { + return ResponseUtil.success(commentService.retrievePageByArticle(articleId, -1, page, count)); + } + + /** + * 通过pid获取数据 + * + * @param pid + * @param count + * @param page + * @return + */ + @GetMapping("/comment/pid/{pid}") + public Response retrievePage(@PathVariable("pid") long pid, + @RequestParam(value = "count", required = false, defaultValue = "10") int count, + @RequestParam(value = "page", required = false, defaultValue = "1") int page) { + return ResponseUtil.success(commentService.retrievePageByPid(pid, page, count)); + } + + /** + * 获取所以的一级留言 + * + * @param count + * @param page + * @return + */ + @GetMapping("/leaveMsg") + public Response retrievePageOfLeaveMsg(@RequestParam(value = "count", required = false, defaultValue = "10") int count, + @RequestParam(value = "page", required = false, defaultValue = "1") int page) { + return ResponseUtil.success(commentService.retrievePageByTypeAndPid(false, -1, page, count)); + } + + @GetMapping("/admin/comment/type/{type}") + public Response retrievePageAdmin( + @PathVariable("type") int isComment, + @RequestParam(value = "count", required = false, defaultValue = "10") int count, + @RequestParam(value = "page", required = false, defaultValue = "1") int page) { + return ResponseUtil.success(commentService.retrievePageByType(1 == isComment, page, count)); + } + + @GetMapping("/user/comment/type/{type}") + public Response retrievePageByAuthor( + @PathVariable(value = "type") int isComment, + @RequestParam(value = "count", required = false, defaultValue = "10") int count, + @RequestParam(value = "page", required = false, defaultValue = "1") int page) { + return ResponseUtil.success(commentService.retrievePageByAuthor(1 == isComment, page, count)); + } + +} diff --git a/src/main/java/cn/celess/blog/controller/LinksController.java b/src/main/java/cn/celess/blog/controller/LinksController.java new file mode 100644 index 0000000..16c751f --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/LinksController.java @@ -0,0 +1,99 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.PartnerSite; +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.request.LinkReq; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.service.MailService; +import cn.celess.blog.service.PartnerSiteService; +import cn.celess.blog.util.RedisUtil; +import cn.celess.blog.util.RegexUtil; +import cn.celess.blog.util.ResponseUtil; +import cn.celess.blog.util.DateFormatUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author : xiaohai + * @date : 2019/05/12 13:26 + */ +@RestController +public class LinksController { + @Autowired + PartnerSiteService partnerSiteService; + @Autowired + MailService mailService; + @Autowired + RedisUtil redisUtil; + @Autowired + HttpServletRequest request; + + @PostMapping("/admin/links/create") + public Response create(@RequestBody LinkReq reqBody) { + return ResponseUtil.success(partnerSiteService.create(reqBody)); + } + + @DeleteMapping("/admin/links/del/{id}") + public Response del(@PathVariable("id") long id) { + return ResponseUtil.success(partnerSiteService.del(id)); + } + + @PutMapping("/admin/links/update") + public Response update(@RequestBody LinkReq reqBody) { + return ResponseUtil.success(partnerSiteService.update(reqBody)); + } + + @GetMapping("/links") + public Response allForOpen() { + List sites = new ArrayList<>(); + for (PartnerSite p : partnerSiteService.findAll()) { + if (p.getOpen()) { + //隐藏open字段 + p.setOpen(null); + sites.add(p); + } + } + return ResponseUtil.success(sites); + } + + @GetMapping("/admin/links") + public Response all(@RequestParam("page") int page, + @RequestParam("count") int count) { + return ResponseUtil.success(partnerSiteService.PartnerSitePages(page, count)); + } + + @PostMapping("/apply") + public Response apply(@RequestParam("name") String name, + @RequestParam("url") String url) { + // TODO :: 弃用发送邮件的方式。 + if (name == null || name.replaceAll(" ", "").isEmpty()) { + return ResponseUtil.response(ResponseEnum.PARAMETERS_ERROR, null); + } + if (!RegexUtil.urlMatch(url)) { + return ResponseUtil.response(ResponseEnum.PARAMETERS_URL_ERROR, null); + } + String applyTimeStr = redisUtil.get(request.getRemoteAddr() + "-Apply"); + int applyTime = 0; + if (applyTimeStr != null) { + applyTime = Integer.parseInt(applyTimeStr); + } + if (applyTime == 10) { + throw new MyException(ResponseEnum.FAILURE.getCode(), "申请次数已达10次,请2小时后重试"); + } + SimpleMailMessage message = new SimpleMailMessage(); + message.setSubject("友链申请:" + name); + message.setTo("a@celess.cn"); + message.setText("name:" + name + "\nurl:" + url + "\n" + DateFormatUtil.getNow()); + Boolean send = mailService.send(message); + redisUtil.setEx(request.getRemoteAddr() + "-Apply", applyTime + 1 + "", 2, TimeUnit.HOURS); + return send ? ResponseUtil.success("") : ResponseUtil.failure(""); + + } +} diff --git a/src/main/java/cn/celess/blog/controller/Other.java b/src/main/java/cn/celess/blog/controller/Other.java new file mode 100644 index 0000000..2db1c32 --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/Other.java @@ -0,0 +1,172 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.model.QiniuResponse; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.service.CountService; +import cn.celess.blog.service.QiniuService; +import cn.celess.blog.util.RedisUtil; +import cn.celess.blog.util.ResponseUtil; +import cn.celess.blog.util.VeriCodeUtil; +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * @author : xiaohai + * @date : 2019/04/02 22:03 + */ +@RestController +public class Other { + public static final Logger logger = LoggerFactory.getLogger(Object.class); + + @Autowired + CountService countService; + @Autowired + QiniuService qiniuService; + @Autowired + RedisUtil redisUtil; + @Autowired + HttpServletRequest request; + + + @GetMapping("/counts") + public Response allCount() { + Map countMap = new HashMap<>(); + countMap.put("articleCount", countService.getArticleCount()); + countMap.put("commentCount", countService.getCommentCount()); + countMap.put("leaveMsgCount", countService.getLeaveMessageCount()); + countMap.put("categoryCount", countService.getCategoriesCount()); + countMap.put("tagCount", countService.getTagsCount()); + countMap.put("visitorCount", countService.getVisitorCount()); + return ResponseUtil.success(countMap); + } + + + /** + * 获取header的全部参数 + * + * @param request HttpServletRequest + * @return Response + */ + @GetMapping("/headerInfo") + public Response headerInfo(HttpServletRequest request) { + Map map = new HashMap<>(); + Enumeration headerNames = request.getHeaderNames(); + String str = null; + while ((str = headerNames.nextElement()) != null) { + map.put(str, request.getHeader(str)); + } + map.put("sessionID", request.getSession().getId()); + map.put("request.getRemoteAddr()", request.getRemoteAddr()); + return ResponseUtil.success(map); + } + + /** + * 返回验证码 + * + * @param response HttpServletResponse + * @throws IOException IOException + */ + @GetMapping(value = "/imgCode", produces = MediaType.IMAGE_PNG_VALUE) + public void getImg(HttpServletResponse response) throws IOException { + Object[] obj = VeriCodeUtil.createImage(); + request.getSession().setAttribute("code", obj[0]); + //将图片输出给浏览器 + BufferedImage image = (BufferedImage) obj[1]; + response.setContentType("image/png"); + OutputStream os = response.getOutputStream(); + ImageIO.write(image, "png", os); + os.close(); + } + + /** + * 验证 验证码的正确性 + * + * @param code 传进来的验证码 + * @param request HttpServletRequest + * @return Session中写入验证状态 + */ + @PostMapping("/verCode") + public Response verCode(@RequestParam("code") String code, HttpServletRequest request) { + request.getSession().setAttribute("verImgCodeStatus", false); + String codeStr = (String) request.getSession().getAttribute("code"); + if (code == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + if (codeStr == null) { + throw new MyException(ResponseEnum.IMG_CODE_TIMEOUT); + } + code = code.toLowerCase(); + codeStr = codeStr.toLowerCase(); + if (code.equals(codeStr)) { + request.getSession().removeAttribute("code"); + request.getSession().setAttribute("verImgCodeStatus", true); + return ResponseUtil.success("验证成功"); + } else { + request.getSession().removeAttribute("code"); + return ResponseUtil.failure("验证失败,请重新获取验证码"); + } + } + + /** + * FIXME :: 单张图片多次上传的问题 + * editor.md图片上传的接口 + * FUCK !!! + * + * @param file 文件 + * @return + * @throws IOException + */ + @PostMapping("/imgUpload") + public void upload(HttpServletRequest request, HttpServletResponse response, @RequestParam("editormd-image-file") MultipartFile file) throws IOException { + JSONObject jsonObject = new JSONObject(); + String uploadTimesStr = redisUtil.get(request.getRemoteAddr() + "-ImgUploadTimes"); + int uploadTimes = 0; + if (uploadTimesStr != null) { + uploadTimes = Integer.parseInt(uploadTimesStr); + } + if (uploadTimes == 10) { + throw new MyException(ResponseEnum.FAILURE.getCode(), "上传次数已达10次,请2小时后在上传"); + } + request.setCharacterEncoding("utf-8"); + response.setContentType("text/html"); + if (file.isEmpty()) { + jsonObject.put("success", 0); + jsonObject.put("message", "上传失败,请选择文件"); + response.getWriter().println(jsonObject.toString()); + return; + } + String fileName = file.getOriginalFilename(); + String mime = fileName.substring(fileName.lastIndexOf(".")); + if (".png".equals(mime.toLowerCase()) || ".jpg".equals(mime.toLowerCase()) || + ".jpeg".equals(mime.toLowerCase()) || ".bmp".equals(mime.toLowerCase())) { + QiniuResponse qiniuResponse = qiniuService.uploadFile(file.getInputStream(), "img_" + System.currentTimeMillis() + mime); + jsonObject.put("success", 0); + jsonObject.put("message", "上传成功"); + jsonObject.put("url", "http://cdn.celess.cn/" + qiniuResponse.key); + response.getWriter().println(jsonObject.toString()); + redisUtil.setEx(request.getRemoteAddr() + "-ImgUploadTimes", uploadTimes + 1 + "", 2, TimeUnit.HOURS); + return; + } + jsonObject.put("success", 0); + jsonObject.put("message", "上传失败,请上传图片文件"); + response.getWriter().println(jsonObject.toString()); + } +} diff --git a/src/main/java/cn/celess/blog/controller/TagController.java b/src/main/java/cn/celess/blog/controller/TagController.java new file mode 100644 index 0000000..c942f60 --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/TagController.java @@ -0,0 +1,70 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.Tag; +import cn.celess.blog.service.TagService; +import cn.celess.blog.util.ResponseUtil; +import net.sf.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/30 20:36 + */ +@RestController +public class TagController { + @Autowired + TagService tagService; + + + @PostMapping("/admin/tag/create") + public Response addOne(@RequestParam("name") String name) { + return ResponseUtil.success(tagService.create(name)); + } + + @DeleteMapping("/admin/tag/del") + public Response delOne(@RequestParam("id") long id) { + return ResponseUtil.success(tagService.delete(id)); + } + + + @PutMapping("/admin/tag/update") + public Response updateOne(@RequestParam("id") Long id, @RequestParam("name") String name) { + return ResponseUtil.success(tagService.update(id, name)); + } + + @GetMapping("/tag/id/{id}") + public Response retrieveOneById(@PathVariable("id") long id) { + return ResponseUtil.success(tagService.retrieveOneById(id)); + } + + @GetMapping("/tag/name/{name}") + public Response retrieveOneByName(@PathVariable("name") String name) { + return ResponseUtil.success(tagService.retrieveOneByName(name)); + } + + @GetMapping("/tags") + public Response getPage(@RequestParam(required = false, defaultValue = "10", value = "count") int count, + @RequestParam(required = false, defaultValue = "1", value = "page") int page) { + return ResponseUtil.success(tagService.retrievePage(page, count)); + } + + @GetMapping("/tags/nac") + public Response getTagNameAndCount() { + List nameAndCount = new ArrayList<>(); + List all = tagService.findAll(); + for (Tag t : all) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("name", t.getName()); + String articles = t.getArticles(); + jsonObject.put("size", articles == null ? 0 : articles.split(",").length); + nameAndCount.add(jsonObject); + } + return ResponseUtil.success(nameAndCount); + } + +} diff --git a/src/main/java/cn/celess/blog/controller/UserController.java b/src/main/java/cn/celess/blog/controller/UserController.java new file mode 100644 index 0000000..5e4a7ca --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/UserController.java @@ -0,0 +1,122 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.request.LoginReq; +import cn.celess.blog.entity.request.UserReq; +import cn.celess.blog.service.UserService; +import cn.celess.blog.util.ResponseUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +/** + * @author : xiaohai + * @date : 2019/03/30 20:37 + */ +@RestController +public class UserController { + @Autowired + UserService userService; + + + @PostMapping("/login") + public Response login(@RequestBody LoginReq loginReq) { + return ResponseUtil.success(userService.login(loginReq)); + } + + @PostMapping("/registration") + public Response registration(@RequestParam("email") String email, + @RequestParam("password") String password) { + return ResponseUtil.success(userService.registration(email, password)); + } + + @GetMapping("/logout") + public Response logout() { + return ResponseUtil.success(userService.logout()); + } + + @PutMapping("/user/userInfo/update") + public Response updateInfo(String desc, String displayName) { + return ResponseUtil.success(userService.update(desc, displayName)); + } + + @GetMapping("/user/userInfo") + public Response getUserInfo() { + return ResponseUtil.success(userService.getUserInfoBySession()); + } + + /** + * 更新头像 + * + * @param file file + * @return + * @throws IOException + */ + @PostMapping("/user/imgUpload") + @ResponseBody + public Response upload(@RequestParam("file") MultipartFile file) throws IOException { + if (file.isEmpty()) { + return ResponseUtil.failure("上传失败,请选择文件"); + } + String fileName = file.getOriginalFilename(); + String mime = fileName.substring(fileName.lastIndexOf(".")); + if (".png".equals(mime.toLowerCase()) || ".jpg".equals(mime.toLowerCase()) || + ".jpeg".equals(mime.toLowerCase()) || ".bmp".equals(mime.toLowerCase())) { + return (Response) userService.updateUserAavatarImg(file.getInputStream(), mime); + } + return ResponseUtil.failure("请上传图片文件"); + } + + @PostMapping("/sendResetPwdEmail") + public Response sendResetPwdEmail(@RequestParam("email") String email) { + return ResponseUtil.success(userService.sendResetPwdEmail(email)); + } + + @PostMapping("/sendVerifyEmail") + public Response sendVerifyEmail(@RequestParam("email") String email) { + return ResponseUtil.success(userService.sendVerifyEmail(email)); + } + + + @PostMapping("/emailVerify") + public Response emailVerify(@RequestParam("verifyId") String verifyId, + @RequestParam("email") String mail) { + return ResponseUtil.success(userService.verifyEmail(verifyId, mail)); + } + + @PostMapping("/resetPwd") + public Response resetPwd(@RequestParam("verifyId") String verifyId, + @RequestParam("email") String email, + @RequestParam("pwd") String pwd) { + return ResponseUtil.success(userService.reSetPwd(verifyId, email, pwd)); + } + + @DeleteMapping("/admin/user/delete") + public Response multipleDelete(@RequestBody Integer[] ids) { + return ResponseUtil.success(userService.deleteUser(ids)); + } + + @DeleteMapping("/admin/user/delete/{id}") + public Response delete(@PathVariable("id") Integer id) { + return ResponseUtil.success(userService.deleteUser(new Integer[]{id})); + } + + @PutMapping("/admin/user") + public Response updateInfoByAdmin(@RequestBody UserReq user) { + return ResponseUtil.success(userService.adminUpdate(user)); + } + + @GetMapping("/admin/users") + public Response getAllUser(@RequestParam("page") int pageNum, @RequestParam("count") int count) { + return ResponseUtil.success(userService.getUserList(pageNum, count)); + } + + @GetMapping("/emailStatus/{email}") + public Response getEmailStatus(@PathVariable("email") String email) { + return ResponseUtil.success(userService.getStatusOfEmail(email)); + } + + +} diff --git a/src/main/java/cn/celess/blog/controller/VisitorController.java b/src/main/java/cn/celess/blog/controller/VisitorController.java new file mode 100644 index 0000000..741e8ef --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/VisitorController.java @@ -0,0 +1,60 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.entity.Response; +import cn.celess.blog.service.CountService; +import cn.celess.blog.service.VisitorService; +import cn.celess.blog.util.ResponseUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author : xiaohai + * @date : 2019/04/02 23:09 + */ +@RestController +public class VisitorController { + @Autowired + VisitorService visitorService; + @Autowired + CountService countService; + + @GetMapping("/visitor/count") + public Response getVisitorCount() { + return ResponseUtil.success(countService.getVisitorCount()); + } + + @GetMapping("/admin/visitor/page") + public Response page(@RequestParam(value = "count", required = false, defaultValue = "10") int count, + @RequestParam(value = "page", required = false, defaultValue = "1") int page, + @RequestParam(value = "showLocation", required = false, defaultValue = "false") boolean showLocation) { + return ResponseUtil.success(visitorService.visitorPage(page, count, showLocation)); + } + + @PostMapping("/visit") + public Response add(HttpServletRequest request) { + return ResponseUtil.success(visitorService.addVisitor(request)); + } + + @GetMapping("/dayVisitCount") + public Response dayVisitCount() { + return ResponseUtil.success(countService.getDayVisitCount()); + } + + @GetMapping("/ip/{ip}") + public Response ipLocation(@PathVariable("ip") String ip) { + return ResponseUtil.success(visitorService.location(ip)); + } + + /** + * 获取本地访问者的ip + * + * @param request + * @return + */ + @GetMapping("/ip") + public Response getIp(HttpServletRequest request) { + return ResponseUtil.success(request.getRemoteAddr()); + } +} diff --git a/src/main/java/cn/celess/blog/controller/WebUpdateInfoController.java b/src/main/java/cn/celess/blog/controller/WebUpdateInfoController.java new file mode 100644 index 0000000..a69f4b0 --- /dev/null +++ b/src/main/java/cn/celess/blog/controller/WebUpdateInfoController.java @@ -0,0 +1,48 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.entity.Response; +import cn.celess.blog.service.WebUpdateInfoService; +import cn.celess.blog.util.ResponseUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @author : xiaohai + * @date : 2019/05/12 13:09 + */ +@RestController +public class WebUpdateInfoController { + @Autowired + WebUpdateInfoService webUpdateInfoService; + + @PostMapping("/admin/webUpdate/create") + public Response create(@RequestParam("info") String info) { + return ResponseUtil.success(webUpdateInfoService.create(info)); + } + + @DeleteMapping("/admin/webUpdate/del/{id}") + public Response del(@PathVariable("id") long id) { + return ResponseUtil.success(webUpdateInfoService.del(id)); + } + + @PutMapping("/admin/webUpdate/update") + public Response update(@RequestParam("id") long id, @RequestParam("info") String info) { + return ResponseUtil.success(webUpdateInfoService.update(id, info)); + } + + @GetMapping("/webUpdate") + public Response findAll() { + return ResponseUtil.success(webUpdateInfoService.findAll()); + } + + @GetMapping("/webUpdate/pages") + public Response page(@RequestParam("page") int page, @RequestParam("count") int count) { + return ResponseUtil.success(webUpdateInfoService.pages(count, page)); + } + @GetMapping("/lastestUpdateTime") + public Response lastestUpdateTime() { + return ResponseUtil.success(webUpdateInfoService.getLastestUpdateTime()); + } + + +} diff --git a/src/main/java/cn/celess/blog/enmu/LevelEnum.java b/src/main/java/cn/celess/blog/enmu/LevelEnum.java new file mode 100644 index 0000000..feb9d2c --- /dev/null +++ b/src/main/java/cn/celess/blog/enmu/LevelEnum.java @@ -0,0 +1,27 @@ +package cn.celess.blog.enmu; + +import lombok.Getter; + +/** + * @Author: 小海 + * @Date: 2019/06/29 00:00 + * @Description: 文章数据模型转换的级别(响应参数的选择) + */ +@Getter +public enum LevelEnum { + //低级 + LOW(0), + //中级 + MIDDLE(1), + //另一个级别的转化 + BETWEEN_M_AND_H(2), + //高级 + HEIGHT(3); + + private int levelCode; + + LevelEnum(int levelCode) { + this.levelCode = levelCode; + } + +} diff --git a/src/main/java/cn/celess/blog/enmu/ResponseEnum.java b/src/main/java/cn/celess/blog/enmu/ResponseEnum.java new file mode 100644 index 0000000..0e16b0f --- /dev/null +++ b/src/main/java/cn/celess/blog/enmu/ResponseEnum.java @@ -0,0 +1,81 @@ +package cn.celess.blog.enmu; + +/** + * @author : xiaohai + * @date : 2019/03/28 15:37 + */ +public enum ResponseEnum { + // Response enum + + SUCCESS(0, "成功"), + FAILURE(-1, "失败"), + ERROR(-2, "错误"), + + //文章类 + ARTICLE_NOT_EXIST(201, "文章不存在"), + ARTICLE_HAS_EXIST(202, "文章已存在"), + ARTICLE_NOT_PUBLIC(203, "文章暂未公开"), + ARTICLE_NOT_BELONG_YOU(204, "无权限操作别人的文章"), + + //用户类 + HAVE_NOT_LOG_IN(301, "还未登录"), + PERMISSION_ERROR(302, "没有此权限"), + USER_NOT_EXIST(303, "用户不存在"), + USERNAME_HAS_EXIST(304, "用户名已存在"), + USERNAME_TOO_SHORT(305, "用户名太短"), + PASSWORD_TOO_SHORT_OR_LONG(306, "密码长度过长或者过短"), + LOGIN_FAILURE(310, "登录失败,用户名/密码不正确"), + USEREMAIL_NULL(331, "未设置邮箱"), + USEREMAIL_NOT_VERIFY(332, "邮箱未验证"), + LOGIN_LATER(350, "错误次数已达5次,请稍后再试"), + PWD_SAME(360, "新密码与原密码相同"), + LOGIN_EXPIRED(370, "登陆过期"), + + //标签 + TAG_NOT_EXIST(401, "标签不存在"), + TAG_HAS_EXIST(402, "标签已存在"), + + //分类 + CATEGORY_NOT_EXIST(501, "分类不存在"), + CATEGORY_HAS_EXIST(502, "分类已存在"), + + //评论/留言 + COMMENT_NOT_EXIST(601, "评论/留言不存在"), + COMMENT_HAS_EXIST(602, "评论/留言已存在,请不要重复提交"), + + //webUdpateInfo amd PartnerSite + DATA_NOT_EXIST(701, "数据不存在"), + DATA_HAS_EXIST(702, "数据已存在"), + + //其他 + + //提交更新之前,没有获取数据/, + DID_NOT_GET_THE_DATA(802, "非法访问"), + IMG_CODE_TIMEOUT(810, "验证码已失效"), + IMG_CODE_DIDNOTVERIFY(820, "请先验证验证码"), + VERIFY_ERROR(830, "验证失败"), + PARAMETERS_ERROR(850, "参数错误"), + PARAMETERS_URL_ERROR(851, "链接格式错误"), + PARAMETERS_EMAIL_ERROR(852, "邮箱格式错误"), + PARAMETERS_PHONE_ERROR(853, "手机格式错误"), + PARAMETERS_QQ_ERROR(854, "QQ格式错误"), + PARAMETERS_PWD_ERROR(855, "密码格式错误"), + VERIFY_OUT(840, "已经验证过了"); + + private int code; + private String msg; + + + ResponseEnum(int code, String msg) { + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} diff --git a/src/main/java/cn/celess/blog/entity/Article.java b/src/main/java/cn/celess/blog/entity/Article.java new file mode 100644 index 0000000..29b865c --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/Article.java @@ -0,0 +1,61 @@ +package cn.celess.blog.entity; + +import lombok.Data; + +import java.util.Date; + +/** + * @author : xiaohai + * @date : 2019/03/28 14:51 + */ +@Data +public class Article { + private Long id; + + /** + * 标题 + */ + private String title; + + /** + * 摘要 + */ + private String summary; + + /** + * Markdown正文 + */ + private String mdContent; + + /** + * 文章类型 true(1)为原创 false(0)为转载 + */ + private Boolean type; + + /** + * 若为转载 则为转载文章的url + */ + private String url = null; + + private Date publishDate; + + private Date updateDate = null; + + private Long categoryId; + + private String tagsId; + + private Long authorId; + + private Long preArticleId; + + private Long nextArticleId; + + private Long readingNumber; + + /** + * 文章的状态 true:公开 false:不公开 + */ + private Boolean open; + +} diff --git a/src/main/java/cn/celess/blog/entity/Category.java b/src/main/java/cn/celess/blog/entity/Category.java new file mode 100644 index 0000000..b72c9a0 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/Category.java @@ -0,0 +1,20 @@ +package cn.celess.blog.entity; + + +import lombok.Data; + + +/** + * @author : xiaohai + * @date : 2019/03/28 22:18 + */ +@Data +public class Category { + + private Long id; + + private String name; + + private String articles; + +} diff --git a/src/main/java/cn/celess/blog/entity/Comment.java b/src/main/java/cn/celess/blog/entity/Comment.java new file mode 100644 index 0000000..90b480f --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/Comment.java @@ -0,0 +1,40 @@ +package cn.celess.blog.entity; + +import lombok.Data; + +import java.util.Date; + +/** + * @author : xiaohai + * @date : 2019/03/29 16:47 + */ + +@Data +public class Comment { + + private Long id; + + /** + * 是评论还是留言 0:评论 其他(1):留言 + */ + private Boolean type; + + private Long authorID; + + private String content; + + private Long articleID; + + private Date date; + + /** + * 回应着ID 默认为顶级回复 + */ + private String responseId = ""; + + /** + * 评论的父ID + */ + private Long pid; + +} diff --git a/src/main/java/cn/celess/blog/entity/PartnerSite.java b/src/main/java/cn/celess/blog/entity/PartnerSite.java new file mode 100644 index 0000000..c1a1493 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/PartnerSite.java @@ -0,0 +1,30 @@ +package cn.celess.blog.entity; + +import lombok.Data; + +/** + * 友链 + * + * @author : xiaohai + * @date : 2019/05/12 11:33 + */ +@Data +public class PartnerSite { + + private Long id; + + private String name; + + private String url; + + private Boolean open; + + public PartnerSite() { + } + + public PartnerSite(String name, String url, Boolean open) { + this.name = name; + this.url = url; + this.open = open; + } +} diff --git a/src/main/java/cn/celess/blog/entity/Response.java b/src/main/java/cn/celess/blog/entity/Response.java new file mode 100644 index 0000000..f2fa23f --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/Response.java @@ -0,0 +1,34 @@ +package cn.celess.blog.entity; + +import lombok.Data; +import net.sf.json.JSONObject; + +import java.io.Serializable; + +/** + * @author : xiaohai + * @date : 2019/03/28 15:24 + */ +@Data +public class Response implements Serializable { + private int code; + private String msg; + private Object result; + private long date; + + public Response() { + } + + public Response(int code, String msg, Object result, long date) { + this.code = code; + this.msg = msg; + this.result = result; + this.date = date; + } + + @Override + public String toString() { + JSONObject jsonObject = JSONObject.fromObject(this); + return jsonObject.toString(); + } +} diff --git a/src/main/java/cn/celess/blog/entity/Tag.java b/src/main/java/cn/celess/blog/entity/Tag.java new file mode 100644 index 0000000..58526a4 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/Tag.java @@ -0,0 +1,16 @@ +package cn.celess.blog.entity; + +import lombok.Data; + +/** + * @author : xiaohai + * @date : 2019/03/28 22:19 + */ +@Data +public class Tag { + private Long id; + + private String name; + + private String articles; +} diff --git a/src/main/java/cn/celess/blog/entity/User.java b/src/main/java/cn/celess/blog/entity/User.java new file mode 100644 index 0000000..7a3d9dd --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/User.java @@ -0,0 +1,60 @@ +package cn.celess.blog.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Data; + +import java.util.Date; + +/** + * @author : xiaohai + * @date : 2019/03/28 14:52 + */ +@Data +public class User { + private Long id; + + /** + * 邮箱 + */ + private String email; + + /** + * 用户唯一标识码 + */ + @JsonIgnore + private String uid; + + /** + * 密码 + */ + @JsonIgnore + private String pwd; + + /** + * 昵称 + */ + private String displayName; + + private Boolean emailStatus = false; + + /** + * 头像地址 + */ + private String avatarImgUrl; + + private String desc; + + private Date recentlyLandedDate; + + /** + * 随机码 用户验证邮箱/找回密码 + * 暂时废弃这一字段 + */ + private String emailVerifyId; + + private String role = "user"; + + public User() { + } + +} diff --git a/src/main/java/cn/celess/blog/entity/Visitor.java b/src/main/java/cn/celess/blog/entity/Visitor.java new file mode 100644 index 0000000..2092745 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/Visitor.java @@ -0,0 +1,27 @@ +package cn.celess.blog.entity; + +import lombok.Data; + +import java.util.Date; + +/** + * @author : xiaohai + * @date : 2019/04/02 22:14 + */ +@Data +public class Visitor { + + private long id; + private String ip; + private Date date; + private String ua; + + public Visitor(String ip, Date date, String ua) { + this.ip = ip; + this.date = date; + this.ua = ua; + } + + public Visitor() { + } +} diff --git a/src/main/java/cn/celess/blog/entity/WebUpdate.java b/src/main/java/cn/celess/blog/entity/WebUpdate.java new file mode 100644 index 0000000..8cb3ee6 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/WebUpdate.java @@ -0,0 +1,27 @@ +package cn.celess.blog.entity; + +import lombok.Data; + +import java.util.Date; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:29 + */ +@Data +public class WebUpdate { + + private long id; + + private String updateInfo; + + private Date updateTime; + + public WebUpdate() { + } + + public WebUpdate(String updateInfo, Date updateTime) { + this.updateInfo = updateInfo; + this.updateTime = updateTime; + } +} diff --git a/src/main/java/cn/celess/blog/entity/model/ArticleModel.java b/src/main/java/cn/celess/blog/entity/model/ArticleModel.java new file mode 100644 index 0000000..22cd274 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/model/ArticleModel.java @@ -0,0 +1,96 @@ +package cn.celess.blog.entity.model; + +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; + +/** + * @author : xiaohai + * @date : 2019/04/23 12:02 + */ +@Getter +@Setter +public class ArticleModel { + private Long id; + + /** + * 标题 + */ + private String title; + + /** + * 摘要 + */ + private String summary; + + /** + * Markdown正文 + */ + private String mdContent; + + /** + * 文章类型 true(1)为原创 false(0)为转载 + */ + private Boolean original; + + /** + * 若为转载 则为转载文章的url + */ + private String url; + + /** + * 发布时间 + */ + private String publishDateFormat; + + /** + * 更新时间 + */ + private String updateDateFormat; + + /** + * 分类 + */ + private String category; + + /** + * 标签 + */ + private String[] tags; + + /** + * 作者 + */ + private Long authorId; + + /** + * 作者名字 + */ + private String authorName; + + /** + * 上一篇文章 + */ + private Long preArticleId; + + /** + * 下一篇文章 + */ + private Long nextArticleId; + + private String preArticleTitle; + + private String nextArticleTitle; + + /** + * 阅读数 + */ + private Long readingNumber; + + /** + * 文章的状态 true:公开 false:不公开 + */ + private Boolean open; + +} diff --git a/src/main/java/cn/celess/blog/entity/model/CommentModel.java b/src/main/java/cn/celess/blog/entity/model/CommentModel.java new file mode 100644 index 0000000..93201db --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/model/CommentModel.java @@ -0,0 +1,57 @@ +package cn.celess.blog.entity.model; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Date; + +/** + * @author : xiaohai + * @date : 2019/04/22 21:50 + */ +@Setter +@Getter +public class CommentModel { + private long id; + + /** + * 是评论还是留言 0:评论 其他(1):留言 + */ + private boolean isComment; + + private String authorName; + + private String authorAvatarImgUrl; + + /** + * 内容 + */ + private String content; + + /** + * 文章ID + */ + private long articleID; + + /** + * 文章标题 + */ + private String articleTitle; + + /** + * 发布日期 + */ + private String date; + + /** + * 回应着ID 默认为顶级回复 + */ + private String responseId = ""; + + /** + * 评论的父ID + */ + private long pid = -1; + + +} diff --git a/src/main/java/cn/celess/blog/entity/model/QiniuResponse.java b/src/main/java/cn/celess/blog/entity/model/QiniuResponse.java new file mode 100644 index 0000000..2048f14 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/model/QiniuResponse.java @@ -0,0 +1,13 @@ +package cn.celess.blog.entity.model; + + +/** + * @author : xiaohai + * @date : 2019/04/21 22:43 + */ +public class QiniuResponse { + public String key; + public String hash; + public String bucket; + public long fsize; +} diff --git a/src/main/java/cn/celess/blog/entity/model/UserModel.java b/src/main/java/cn/celess/blog/entity/model/UserModel.java new file mode 100644 index 0000000..4e240e6 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/model/UserModel.java @@ -0,0 +1,40 @@ +package cn.celess.blog.entity.model; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author : xiaohai + * @date : 2019/04/22 23:13 + */ +@Getter +@Setter +public class UserModel { + + private Long id; + + /** + * 邮箱 + */ + private String email; + + /** + * 昵称 + */ + private String displayName; + + private Boolean emailStatus = false; + + /** + * 头像地址 + */ + private String avatarImgUrl; + + private String desc; + + private String recentlyLandedDate; + + private String role = "user"; + + private String token; +} diff --git a/src/main/java/cn/celess/blog/entity/model/VisitorModel.java b/src/main/java/cn/celess/blog/entity/model/VisitorModel.java new file mode 100644 index 0000000..6afd55c --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/model/VisitorModel.java @@ -0,0 +1,24 @@ +package cn.celess.blog.entity.model; + +import lombok.Data; + +/** + * @author : xiaohai + * @date : 2019/05/05 16:05 + */ +@Data +public class VisitorModel { + private long id; + + private String ip; + + private String date; + + private String browserName; + + private String browserVersion; + + private String OSName; + + private String location; +} diff --git a/src/main/java/cn/celess/blog/entity/model/WebUpdateModel.java b/src/main/java/cn/celess/blog/entity/model/WebUpdateModel.java new file mode 100644 index 0000000..0aecf09 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/model/WebUpdateModel.java @@ -0,0 +1,24 @@ +package cn.celess.blog.entity.model; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:32 + */ +@Data +@NoArgsConstructor +public class WebUpdateModel { + private long id; + + private String info; + + private String time; + + public WebUpdateModel(long id, String info, String time) { + this.id = id; + this.info = info; + this.time = time; + } +} diff --git a/src/main/java/cn/celess/blog/entity/request/ArticleReq.java b/src/main/java/cn/celess/blog/entity/request/ArticleReq.java new file mode 100644 index 0000000..ae30c2c --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/request/ArticleReq.java @@ -0,0 +1,19 @@ +package cn.celess.blog.entity.request; + +import lombok.Data; + +/** + * @author : xiaohai + * @date : 2019/06/01 22:46 + */ +@Data +public class ArticleReq { + private Long id; + private String title; + private String mdContent; + private String tags; + private Boolean type; + private String url; + private String category; + private Boolean open = true; +} diff --git a/src/main/java/cn/celess/blog/entity/request/CommentReq.java b/src/main/java/cn/celess/blog/entity/request/CommentReq.java new file mode 100644 index 0000000..a310c30 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/request/CommentReq.java @@ -0,0 +1,17 @@ +package cn.celess.blog.entity.request; + +import lombok.Data; + +/** + * @author : xiaohai + * @date : 2019/06/02 10:35 + */ +@Data +public class CommentReq { + private Long id; + private Boolean comment; + private String content; + private Long pid; + private Long articleID; + private String responseId; +} diff --git a/src/main/java/cn/celess/blog/entity/request/LinkReq.java b/src/main/java/cn/celess/blog/entity/request/LinkReq.java new file mode 100644 index 0000000..137673e --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/request/LinkReq.java @@ -0,0 +1,15 @@ +package cn.celess.blog.entity.request; + +import lombok.Data; + +/** + * @author : xiaohai + * @date : 2019/06/02 11:40 + */ +@Data +public class LinkReq { + private long id; + private String name; + private String url; + private boolean open; +} diff --git a/src/main/java/cn/celess/blog/entity/request/LoginReq.java b/src/main/java/cn/celess/blog/entity/request/LoginReq.java new file mode 100644 index 0000000..d0f8813 --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/request/LoginReq.java @@ -0,0 +1,19 @@ +package cn.celess.blog.entity.request; + +import lombok.Data; + +/** + * @author : xiaohai + * @date : 2019/06/01 22:47 + */ +@Data +public class LoginReq { + private String email; + private String password; + /** + * isRememberMe默认为false + */ + private Boolean isRememberMe = false; + +} + diff --git a/src/main/java/cn/celess/blog/entity/request/UserReq.java b/src/main/java/cn/celess/blog/entity/request/UserReq.java new file mode 100644 index 0000000..5bbad0b --- /dev/null +++ b/src/main/java/cn/celess/blog/entity/request/UserReq.java @@ -0,0 +1,26 @@ +package cn.celess.blog.entity.request; + +import lombok.Data; + +/** + * @Author: 小海 + * @Date: 2019/09/06 13:33 + * @Description: + */ +@Data +public class UserReq { + private Long id; + + private String email; + + private String pwd; + + private String displayName; + + private Boolean emailStatus; + + private String desc; + + private String role; + +} diff --git a/src/main/java/cn/celess/blog/exception/ExceptionHandle.java b/src/main/java/cn/celess/blog/exception/ExceptionHandle.java new file mode 100644 index 0000000..480a686 --- /dev/null +++ b/src/main/java/cn/celess/blog/exception/ExceptionHandle.java @@ -0,0 +1,95 @@ +package cn.celess.blog.exception; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Response; +import cn.celess.blog.service.MailService; +import cn.celess.blog.util.DateFormatUtil; +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.mail.SimpleMailMessage; +import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author : xiaohai + * @date : 2019/03/28 17:02 + */ + +@ControllerAdvice +public class ExceptionHandle { + @Autowired + MailService mailService; + @Autowired + HttpServletRequest request; + public static final Logger logger = LoggerFactory.getLogger(ExceptionHandle.class); + + @Value("${spring.profiles.active}") + private String activeModel; + + @ExceptionHandler(value = Exception.class) + @ResponseBody + public Response handle(Exception e) { + //自定义错误 + if (e instanceof MyException) { + logger.debug("返回了自定义的exception,[code={},msg={}]", ((MyException) e).getCode(), e.getMessage()); + return new Response(((MyException) e).getCode(), e.getMessage(), null, System.currentTimeMillis()); + } + //请求路径不支持该方法 + if (e instanceof HttpRequestMethodNotSupportedException) { + logger.debug("遇到请求路径与请求方法不匹配的请求,[msg={},path:{},method:{}]", e.getMessage(),request.getRequestURL(),request.getMethod()); + return new Response(ResponseEnum.ERROR.getCode(), e.getMessage(), null, System.currentTimeMillis()); + } + //数据输入类型不匹配 + if (e instanceof MethodArgumentTypeMismatchException) { + logger.debug("输入类型不匹配,[msg={}]", e.getMessage()); + return new Response(ResponseEnum.PARAMETERS_ERROR.getCode(), "数据输入有问题,请修改后再访问", null, System.currentTimeMillis()); + } + //数据验证失败 + if (e instanceof BindException) { + logger.debug("数据验证失败,[msg={}]", e.getMessage()); + return new Response(ResponseEnum.PARAMETERS_ERROR.getCode(), "数据输入有问题,请修改", null, System.currentTimeMillis()); + } + //数据输入不完整 + if (e instanceof MissingServletRequestParameterException) { + logger.debug("数据输入不完整,[msg={}]", e.getMessage()); + return new Response(ResponseEnum.PARAMETERS_ERROR.getCode(), "数据输入不完整,请检查", null, System.currentTimeMillis()); + } + + // 发送错误信息到邮箱 + if ("prod".equals(activeModel)) { + logger.debug("有一个未捕获的bug,已发送到邮箱"); + sendMessage(e); + } + e.printStackTrace(); + return new Response(ResponseEnum.ERROR.getCode(), "服务器出现错误,已记录", null, System.currentTimeMillis()); + } + + /** + * 发送错误信息 + * + * @param e 错误 + */ + private void sendMessage(Exception e) { + SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); + simpleMailMessage.setTo("a@celess.cn"); + simpleMailMessage.setSubject("服务器出现了错误"); + StringBuilder msg = new StringBuilder(); + msg.append("requirePath:\n").append(request.getRequestURL().toString()).append("?").append(request.getQueryString()).append("\n\n\n"); + msg.append("msg:\n").append(e.getMessage()).append("\n\n\n"); + msg.append("date:\n").append(DateFormatUtil.getNow()).append("\n\n\n"); + msg.append("from:\n").append(request.getHeader("User-Agent")).append("\n\n\n"); + msg.append("ip:\n").append(request.getRemoteAddr()).append("\n\n\n"); + simpleMailMessage.setText(msg.toString()); + mailService.AsyncSend(simpleMailMessage); + } + +} diff --git a/src/main/java/cn/celess/blog/exception/MyException.java b/src/main/java/cn/celess/blog/exception/MyException.java new file mode 100644 index 0000000..7c4d412 --- /dev/null +++ b/src/main/java/cn/celess/blog/exception/MyException.java @@ -0,0 +1,34 @@ +package cn.celess.blog.exception; + +import cn.celess.blog.enmu.ResponseEnum; + +/** + * @author : xiaohai + * @date : 2019/03/28 16:56 + */ +public class MyException extends RuntimeException { + private int code; + + public MyException(int code, String msg) { + super(msg); + this.code = code; + } + + public MyException(ResponseEnum e) { + super(e.getMsg()); + this.code = e.getCode(); + } + + public MyException(ResponseEnum e, String msg) { + super(msg + e.getMsg()); + this.code = e.getCode(); + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } +} diff --git a/src/main/java/cn/celess/blog/mapper/ArticleMapper.java b/src/main/java/cn/celess/blog/mapper/ArticleMapper.java new file mode 100644 index 0000000..aef3de4 --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/ArticleMapper.java @@ -0,0 +1,58 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.Article; +import org.apache.ibatis.annotations.*; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/06/27 20:43 + * @Description: + */ +@Mapper +@Repository +public interface ArticleMapper { + + int insert(Article a); + + int delete(long id); + + int update(Article a); + + int updateNextArticleId(long targetArticleID, long nextArticleID); + + int updatePreArticleId(long targetArticleID, long preArticleID); + + long getLastestArticleId(); + + Article getLastestArticle(); + + Article findArticleById(long id); + + boolean existsByTitle(String title); + + boolean existsById(long id); + + List
findAllByAuthorId(long authorID); + + List
findAllByOpen(boolean isOpen); + + String getTitleById(long id); + + List
findAllByCategoryId(long id); + + List
findAll(); + + Article getSimpleInfo(long id); + + List
getSimpleInfoByCategory(long categoryId); + + List
getSimpleInfoByTag(List idList); + + int setReadingNumber(long number, long id); + + long count(); + +} diff --git a/src/main/java/cn/celess/blog/mapper/CategoryMapper.java b/src/main/java/cn/celess/blog/mapper/CategoryMapper.java new file mode 100644 index 0000000..2c3f941 --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/CategoryMapper.java @@ -0,0 +1,42 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.Category; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/06/30 12:56 + * @Description: + */ +@Mapper +@Repository +public interface CategoryMapper { + int insert(Category c); + + int delete(long id); + + int update(Category c); + + boolean existsByName(String name); + + boolean existsById(long id); + + Category findCategoryByName(String name); + + Category findCategoryById(long id); + + List findAll(); + + List getAllName(); + + String getNameById(long id); + + Long getIDByName(String name); + + Category getLastestCategory(); + + long count(); +} diff --git a/src/main/java/cn/celess/blog/mapper/CommentMapper.java b/src/main/java/cn/celess/blog/mapper/CommentMapper.java new file mode 100644 index 0000000..4b0bd7f --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/CommentMapper.java @@ -0,0 +1,48 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.Comment; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/06/30 16:19 + * @Description: + */ +@Mapper +@Repository +public interface CommentMapper { + int insert(Comment c); + + int updateContent(String content, long id); + + int updateResponder(String responder, long id); + + int delete(long id); + + int deleteByArticleId(long articleId); + + boolean existsById(long id); + + Comment findCommentById(long id); + + Comment getLastestComment(); + + List findAllByAuthorIDAndType(long id, boolean isComment); + + List findAllByPId(long pid); + + List findAllByArticleID(long articleId); + + List findAllByArticleIDAndPId(long articleID, long pid); + + List findCommentsByTypeAndPId(boolean isComment, long pid); + + List findAllByPId(int pid); + + List findAllByType(boolean isComment); + + long countByType(boolean isComment); +} diff --git a/src/main/java/cn/celess/blog/mapper/PartnerMapper.java b/src/main/java/cn/celess/blog/mapper/PartnerMapper.java new file mode 100644 index 0000000..4785ee5 --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/PartnerMapper.java @@ -0,0 +1,40 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.PartnerSite; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/07/03 00:22 + * @Description: + */ +@Mapper +@Repository +public interface PartnerMapper { + int insert(PartnerSite site); + + int delete(long id); + + int update(PartnerSite site); + + boolean existsById(long id); + + boolean existsByName(String name); + + boolean existsByUrl(String url); + + PartnerSite findById(long id); + + PartnerSite findByName(String name); + + PartnerSite findByUrl(String url); + + PartnerSite getLastest(); + + List findAll(); + + +} diff --git a/src/main/java/cn/celess/blog/mapper/TagMapper.java b/src/main/java/cn/celess/blog/mapper/TagMapper.java new file mode 100644 index 0000000..4877747 --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/TagMapper.java @@ -0,0 +1,38 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.Tag; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/06/29 22:00 + * @Description: + */ +@Mapper +@Repository +public interface TagMapper { + int insert(Tag tag); + + int update(Tag tag); + + int delete(long id); + + Tag findTagById(long id); + + Tag findTagByName(String name); + + Boolean existsByName(String name); + + Long getIDByName(String name); + + String getNameById(long id); + + Tag getLastestTag(); + + List findAll(); + + long count(); +} diff --git a/src/main/java/cn/celess/blog/mapper/UserMapper.java b/src/main/java/cn/celess/blog/mapper/UserMapper.java new file mode 100644 index 0000000..6419da4 --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/UserMapper.java @@ -0,0 +1,58 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.User; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.Date; +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/07/03 00:23 + * @Description: + */ +@Mapper +@Repository +public interface UserMapper { + + int addUser(String email, String pwd); + + int updateInfo(String desc, String displayName, long id); + + int updateAvatarImgUrl(String avatarImgUrl, long id); + + int updateLoginTime(String email, Date date); + + int updateEmailStatus(String email, boolean status); + + int updatePwd(String email, String pwd); + + String getPwd(String email); + + boolean existsByEmail(String email); + + User findByEmail(String email); + + User findById(long id); + + String getAvatarImgUrlById(long id); + + String getEmail(long id); + + String getDisPlayName(long id); + + String getRoleByEmail(String email); + + String getRoleById(long id); + + long count(); + + int delete(long id); + + int setUserRole(Long uid, String role); + + List findAll(); + + int update(User user); +} diff --git a/src/main/java/cn/celess/blog/mapper/VisitorMapper.java b/src/main/java/cn/celess/blog/mapper/VisitorMapper.java new file mode 100644 index 0000000..ed84320 --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/VisitorMapper.java @@ -0,0 +1,24 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.Visitor; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/07/03 00:23 + * @Description: + */ +@Repository +@Mapper +public interface VisitorMapper { + int insert(Visitor visitor); + + int delete(long id); + + List findAll(); + + long count(); +} diff --git a/src/main/java/cn/celess/blog/mapper/WebUpdateInfoMapper.java b/src/main/java/cn/celess/blog/mapper/WebUpdateInfoMapper.java new file mode 100644 index 0000000..612fc9d --- /dev/null +++ b/src/main/java/cn/celess/blog/mapper/WebUpdateInfoMapper.java @@ -0,0 +1,31 @@ +package cn.celess.blog.mapper; + +import cn.celess.blog.entity.WebUpdate; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Repository; + +import java.util.Date; +import java.util.List; + +/** + * @Author: 小海 + * @Date: 2019/07/03 00:24 + * @Description: + */ +@Mapper +@Repository +public interface WebUpdateInfoMapper { + int insert(WebUpdate webUpdate); + + int delete(long id); + + int update(long id, String info); + + boolean existsById(long id); + + WebUpdate findById(long id); + + List findAll(); + + Date getLastestOne(); +} diff --git a/src/main/java/cn/celess/blog/service/ArticleService.java b/src/main/java/cn/celess/blog/service/ArticleService.java new file mode 100644 index 0000000..36f706e --- /dev/null +++ b/src/main/java/cn/celess/blog/service/ArticleService.java @@ -0,0 +1,85 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.model.ArticleModel; +import cn.celess.blog.entity.request.ArticleReq; +import com.github.pagehelper.PageInfo; +import org.springframework.stereotype.Service; + + +/** + * @author : xiaohai + * @date : 2019/03/28 15:20 + */ +@Service +public interface ArticleService { + /** + * 新增一篇文章 + * + * @param reqBody 请求文章的数据 + * @return 文章数据 + */ + ArticleModel create(ArticleReq reqBody); + + /** + * 删除一篇文章 + * + * @param articleID 文章id + * @return 删除状态 true:删除成功 false:失败 + */ + boolean delete(long articleID); + + /** + * 更新一篇文章 + * + * @param reqBody 请求数据 + * @return 文章数据 + */ + ArticleModel update(ArticleReq reqBody); + + /** + * 获取一篇文章的数据 + * + * @param articleID 文章id + * @param is4update 是否是因文章更新而请求数据 + * @return 文章数据 + */ + ArticleModel retrieveOneByID(long articleID, boolean is4update); + + /** + * 管理员 获取分页数据 + * + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo adminArticles(int count, int page); + + /** + * 获取文章状态为开放的文章 + * + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePageForOpen(int count, int page); + + /** + * 根据分类名获取文章数据 + * + * @param name 分类名 + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo findByCategory(String name, int page, int count); + + /** + * 根据标签名获取文章数据 + * + * @param name 标签名 + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo findByTag(String name, int page, int count); +} diff --git a/src/main/java/cn/celess/blog/service/CategoryService.java b/src/main/java/cn/celess/blog/service/CategoryService.java new file mode 100644 index 0000000..561b99f --- /dev/null +++ b/src/main/java/cn/celess/blog/service/CategoryService.java @@ -0,0 +1,54 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.Category; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/28 22:42 + */ +@Service +public interface CategoryService { + /** + * 增加一个分类 + * + * @param name 分类名 + * @return 所增加的分类数据 + */ + Category create(String name); + + /** + * 增加一个分类 + * + * @param category 分类对象 + * @return 所增加的分类数据 + */ + Category create(Category category); + + /** + * 通过id删除分类 + * + * @param id 分类id + * @return 删除状态 + */ + boolean delete(long id); + + /** + * 编辑分类的名字 + * + * @param id 分类id + * @param name 分类名字 + * @return 更新后的分类的数据 + */ + Category update(Long id, String name); + + /** + * 获取全部的分类数据 + * + * @return 全部的分类数据 + */ + List retrievePage(); + +} diff --git a/src/main/java/cn/celess/blog/service/CommentService.java b/src/main/java/cn/celess/blog/service/CommentService.java new file mode 100644 index 0000000..b52a514 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/CommentService.java @@ -0,0 +1,101 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.model.CommentModel; +import cn.celess.blog.entity.request.CommentReq; +import com.github.pagehelper.PageInfo; +import org.springframework.stereotype.Service; + +/** + * @author : xiaohai + * @date : 2019/03/29 16:58 + */ +@Service +public interface CommentService { + /** + * 新增数据 + * + * @param reqBody 请求数据体 + * @return 增加的comment数据 + */ + CommentModel create(CommentReq reqBody); + + /** + * 删除数据 + * + * @param id comment的id + * @return 删除状态 + */ + boolean delete(long id); + + /** + * 更新数据 + * + * @param reqBody comment请求体 + * @return 更新后的数据 + */ + CommentModel update(CommentReq reqBody); + + /** + * 分页获取数据 + * + * @param isComment true:评论 false:留言 + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePage(Boolean isComment, int page, int count); + + /** + * 通过pid获取数据 + * + * @param pid 父id + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePageByPid(long pid, int page, int count); + + + /** + * 根据评论者获取数据 + * + * @param isComment true:评论 false:留言 + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePageByAuthor(Boolean isComment, int page, int count); + + /** + * 根据文章获取数据 + * + * @param articleID 文章id + * @param pid 父id + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePageByArticle(long articleID, long pid, int page, int count); + + /** + * 根据数据的type和pid获取数据 + * + * @param isComment true:评论 false:留言 + * @param pid 父id + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePageByTypeAndPid(Boolean isComment, int pid, int page, int count); + + /** + * 根据type获取数据 + * + * @param isComment true:评论 false:留言 + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePageByType(Boolean isComment, int page, int count); + +} diff --git a/src/main/java/cn/celess/blog/service/CountService.java b/src/main/java/cn/celess/blog/service/CountService.java new file mode 100644 index 0000000..b553031 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/CountService.java @@ -0,0 +1,66 @@ +package cn.celess.blog.service; + +import org.springframework.stereotype.Service; + +/** + * @author : xiaohai + * @date : 2019/04/02 22:04 + */ +@Service +public interface CountService { + /** + * 获取评论的数据量 + * + * @return 评论的数据量 + */ + long getCommentCount(); + + /** + * 获取文章的篇数 + * + * @return 文章的篇数 + */ + long getArticleCount(); + + /** + * 获取分类数量 + * + * @return 分类数量 + */ + long getCategoriesCount(); + + /** + * 获取标签数量 + * + * @return 标签数量 + */ + long getTagsCount(); + + /** + * 获取留言数量 + * + * @return 留言数量 + */ + long getLeaveMessageCount(); + + /** + * 获取用户量 + * + * @return 用户量 + */ + long getUserCount(); + + /** + * 获取总访问量 + * + * @return 总访问量 + */ + long getVisitorCount(); + + /** + * 获取日访问量 + * + * @return 日访问量 + */ + long getDayVisitCount(); +} diff --git a/src/main/java/cn/celess/blog/service/MailService.java b/src/main/java/cn/celess/blog/service/MailService.java new file mode 100644 index 0000000..61d8e35 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/MailService.java @@ -0,0 +1,27 @@ +package cn.celess.blog.service; + +import org.springframework.mail.SimpleMailMessage; +import org.springframework.stereotype.Service; + +/** + * @author : xiaohai + * @date : 2019/04/22 14:25 + */ +@Service +public interface MailService { + /** + * 异步发生邮件 + * + * @param message SimpleMailMessage对象 + * @return // + */ + Boolean AsyncSend(SimpleMailMessage message); + + /** + * 同步发送邮件 + * + * @param message SimpleMailMessage对象 + * @return 发送状态 + */ + Boolean send(SimpleMailMessage message); +} diff --git a/src/main/java/cn/celess/blog/service/PartnerSiteService.java b/src/main/java/cn/celess/blog/service/PartnerSiteService.java new file mode 100644 index 0000000..6874604 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/PartnerSiteService.java @@ -0,0 +1,56 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.PartnerSite; +import cn.celess.blog.entity.request.LinkReq; +import com.github.pagehelper.PageInfo; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:42 + */ +@Service +public interface PartnerSiteService { + /** + * 新增数据 + * + * @param reqBody 数据请求体 + * @return 新增数据 + */ + PartnerSite create(LinkReq reqBody); + + /** + * 删除数据 + * + * @param id 数据id + * @return 删除状态 + */ + Boolean del(long id); + + /** + * 更新数据 + * + * @param reqBody 数据请求体 + * @return 更新后的数据 + */ + PartnerSite update(LinkReq reqBody); + + /** + * 分页获取数据 + * + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo PartnerSitePages(int page, int count); + + /** + * 获取全部数据 + * + * @return 全部友链数据 + */ + List findAll(); + +} diff --git a/src/main/java/cn/celess/blog/service/QiniuService.java b/src/main/java/cn/celess/blog/service/QiniuService.java new file mode 100644 index 0000000..32bdc2a --- /dev/null +++ b/src/main/java/cn/celess/blog/service/QiniuService.java @@ -0,0 +1,31 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.model.QiniuResponse; +import com.qiniu.storage.model.FileInfo; +import org.springframework.stereotype.Service; + +import java.io.InputStream; + +/** + * @author : xiaohai + * @date : 2019/04/25 18:15 + */ +@Service +public interface QiniuService { + /** + * 上传文件 + * + * @param is InputStream流 + * @param fileName 文件名 + * @return 响应数据 + */ + QiniuResponse uploadFile(InputStream is, String fileName); + + /** + * 获取文件列表 + * + * @return 文件列表 + */ + FileInfo[] getFileList(); + +} diff --git a/src/main/java/cn/celess/blog/service/TagService.java b/src/main/java/cn/celess/blog/service/TagService.java new file mode 100644 index 0000000..e9b3301 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/TagService.java @@ -0,0 +1,82 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.Tag; +import com.github.pagehelper.PageInfo; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/28 22:23 + */ +@Service +public interface TagService { + /** + * 新增数据 + * + * @param name 标签名 + * @return 新增后的数据 + */ + Tag create(String name); + + /** + * 新增数据 + * + * @param tag tag对象 + * @return 新增后的数据 + */ + + Tag create(Tag tag); + + /** + * 删除数据 + * + * @param tagId 标签id + * @return 删除状态 + */ + boolean delete(long tagId); + + /** + * 更新数据 + * + * @param id 标签id + * @param name 改名的name值 + * @return 更新后的数据 + */ + Tag update(Long id, String name); + + /** + * 查询单个标签信息 + * + * @param tagId id + * @return 标签的数据 + */ + Tag retrieveOneById(long tagId); + + /** + * 通过name查询标签的信息 + * + * @param name tag的名称 + * @return 标签数据 + */ + Tag retrieveOneByName(String name); + + + /** + * 分页获取标签数据 + * + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo retrievePage(int page, int count); + + /** + * 获取全部标签数据 + * + * @return 标签数据列表 + */ + List findAll(); + +} diff --git a/src/main/java/cn/celess/blog/service/UserService.java b/src/main/java/cn/celess/blog/service/UserService.java new file mode 100644 index 0000000..c584b20 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/UserService.java @@ -0,0 +1,177 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.User; +import cn.celess.blog.entity.model.UserModel; +import cn.celess.blog.entity.request.LoginReq; +import cn.celess.blog.entity.request.UserReq; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONObject; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.InputStream; +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/30 18:40 + */ +@Service +public interface UserService { + /** + * 注册 + * + * @param email 邮箱 + * @param password 密码 + * @return 注册状态 + */ + Boolean registration(String email, String password); + + /** + * 登录 + * + * @param loginReq 请求数据 + * @return 用户数据 + */ + UserModel login(LoginReq loginReq); + + /** + * 注销登录 + * + * @return ** + */ + Object logout(); + + /** + * 获取用户头像的链接 + * + * @param id 用户id + * @return 头像链接 + */ + String getAvatarImg(long id); + + /** + * 更新用户数据 + * + * @param desc 用户描述 + * @param displayName 显示昵称 + * @return 用户数据 + */ + UserModel update(String desc, String displayName); + + /** + * 更新头像 + * + * @param is 头像文件的输入流 + * @param mime 文件的mime + * @return 响应数据 + */ + Object updateUserAavatarImg(InputStream is, String mime); + + /** + * 获取session中存储的用户资料 + * + * @return 用户资料 + */ + UserModel getUserInfoBySession(); + + /** + * 获取用户的角色 + * + * @param email 用户的邮箱 + * @return role + */ + String getUserRoleByEmail(String email); + + /** + * 通过邮箱获取用户的信息 + * + * @param email 用户邮箱 + * @return 用户信息 + */ + User getUserInfoByEmail(String email); + + /** + * 获取邮箱是否注册过 + * + * @param email 用户邮箱 + * @return 注册状态 + */ + boolean isExistOfEmail(String email); + + /** + * 获取用户的name 优先返回displayName 否则返回email + * + * @param id 用户id + * @return name + */ + String getNameById(long id); + + /** + * 发送重置密码邮件 + * + * @param email 用户邮箱 + * @return 发送状态 + */ + Object sendResetPwdEmail(String email); + + /** + * 发送验证邮箱邮件 + * + * @param email 用户邮箱 + * @return 发送状态 + */ + Object sendVerifyEmail(String email); + + /** + * 验证邮箱 + * + * @param verifyId 验证码 + * @param email 邮箱 + * @return 验证状态 + */ + Object verifyEmail(String verifyId, String email); + + /** + * 重置密码 + * + * @param verifyId 验证码 + * @param email 邮箱 + * @param pwd 新密码 + * @return 修改状态 + */ + Object reSetPwd(String verifyId, String email, String pwd); + + /** + * 删除用户 + * + * @param id 用户id的数组 + * @return 对应id 的删除状态 + */ + Object deleteUser(Integer[] id); + + /** + * 获取用户列表 + * + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo getUserList(Integer page, Integer count); + + /** + * 更改用户信息 + * + * @param user 用户数据 + * @return 用户信息 + */ + UserModel adminUpdate(UserReq user); + + /** + * 获取电子邮件的存在状态 + * + * @param email email + * @return true:存在 false:不存在 + */ + boolean getStatusOfEmail(String email); +} diff --git a/src/main/java/cn/celess/blog/service/VisitorService.java b/src/main/java/cn/celess/blog/service/VisitorService.java new file mode 100644 index 0000000..8f6f595 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/VisitorService.java @@ -0,0 +1,40 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.model.VisitorModel; +import com.github.pagehelper.PageInfo; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author : xiaohai + * @date : 2019/04/02 23:03 + */ +@Service +public interface VisitorService { + /** + * 分页获取访客数据 + * + * @param count 单页数据量 + * @param page 数据页 + * @param showLocation 是否显示位置信息 开启改选项数据响应超慢 + * @return 分页数据 + */ + PageInfo visitorPage(int page, int count, boolean showLocation); + + /** + * 新增访客 + * + * @param request HttpServletRequest + * @return 返回状态 null: 访客信息已记录、爬虫 + */ + VisitorModel addVisitor(HttpServletRequest request); + + /** + * 获取位置信息 + * + * @param ip ip地址 + * @return 位置信息 + */ + String location(String ip); +} diff --git a/src/main/java/cn/celess/blog/service/WebUpdateInfoService.java b/src/main/java/cn/celess/blog/service/WebUpdateInfoService.java new file mode 100644 index 0000000..cb6f3aa --- /dev/null +++ b/src/main/java/cn/celess/blog/service/WebUpdateInfoService.java @@ -0,0 +1,62 @@ +package cn.celess.blog.service; + +import cn.celess.blog.entity.model.WebUpdateModel; +import com.github.pagehelper.PageInfo; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:42 + */ +@Service +public interface WebUpdateInfoService { + /** + * 新增记录 + * + * @param info 更新内容 + * @return 创建状态 + */ + WebUpdateModel create(String info); + + /** + * 删除数据 + * + * @param id 数据id + * @return 删除状态 + */ + Boolean del(long id); + + /** + * 更新数据 + * + * @param id 数据id + * @param info 新内容 + * @return 数据 + */ + WebUpdateModel update(long id, String info); + + /** + * 分页获取更新记录 + * + * @param count 单页数据量 + * @param page 数据页 + * @return 分页数据 + */ + PageInfo pages(int count, int page); + + /** + * 获取全部的更新记录 + * + * @return 更新记录 + */ + List findAll(); + + /** + * 获取最后更新时间 + * + * @return + */ + String getLastestUpdateTime(); +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/ArticleServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/ArticleServiceImpl.java new file mode 100644 index 0000000..5c81ee0 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/ArticleServiceImpl.java @@ -0,0 +1,544 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.LevelEnum; +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.*; +import cn.celess.blog.entity.model.ArticleModel; +import cn.celess.blog.entity.request.ArticleReq; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.ArticleMapper; +import cn.celess.blog.mapper.CategoryMapper; +import cn.celess.blog.mapper.CommentMapper; +import cn.celess.blog.mapper.TagMapper; +import cn.celess.blog.service.ArticleService; +import cn.celess.blog.service.UserService; +import cn.celess.blog.util.DateFormatUtil; +import cn.celess.blog.util.RedisUserUtil; +import cn.celess.blog.util.RegexUtil; +import cn.celess.blog.util.StringFromHtmlUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.youbenzi.mdtool.tool.MDTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + + +/** + * @author : xiaohai + * @date : 2019/03/28 15:21 + */ +@Service +public class ArticleServiceImpl implements ArticleService { + public static final Logger logger = LoggerFactory.getLogger(ArticleServiceImpl.class); + + @Autowired + ArticleMapper articleMapper; + + @Autowired + TagMapper tagMapper; + @Autowired + CategoryMapper categoryMapper; + @Autowired + CommentMapper commentMapper; + @Autowired + UserService userService; + @Autowired + HttpServletRequest request; + @Autowired + RedisUserUtil redisUserUtil; + + @Override + @Transactional(rollbackFor = Exception.class) + public ArticleModel create(ArticleReq reqBody) { + if (reqBody == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //数据判断 + if (reqBody.getTitle() == null || reqBody.getTitle().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } else if (reqBody.getMdContent() == null || reqBody.getMdContent().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //转载 判断链接 + if (!reqBody.getType()) { + if (reqBody.getUrl() == null || reqBody.getUrl().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } else if (!RegexUtil.urlMatch(reqBody.getUrl())) { + throw new MyException(ResponseEnum.PARAMETERS_URL_ERROR); + } + } + if (reqBody.getCategory() == null || reqBody.getCategory().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + if (reqBody.getTags() == null || reqBody.getTags().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + + + //写入数据库的数据 + Article article = new Article(); + article.setTitle(reqBody.getTitle()); + article.setOpen(reqBody.getOpen()); + article.setMdContent(reqBody.getMdContent()); + article.setUrl(reqBody.getUrl()); + article.setType(reqBody.getType()); + + article.setAuthorId(redisUserUtil.get(request).getId()); + article.setPublishDate(new Date()); + + //防止出现 “null,xxx”这种情况 + article.setTagsId(""); + + + //是否需要更新上一篇文章 + boolean isUpdatePreArticle = true; + + Article preArticle = null; + + + if (articleMapper.count() == 0) { + isUpdatePreArticle = false; + + + } else { + //获取最新的一条数据 + preArticle = articleMapper.getLastestArticle(); + } + + if (isUpdatePreArticle) { + logger.info("上一篇文章的id为:" + preArticle.getId()); + //设置上一篇文章的id + article.setPreArticleId(preArticle.getId()); + } + + //markdown->html->summary + String str = StringFromHtmlUtil.getString(MDTool.markdown2Html(article.getMdContent())); + //获取摘要 摘要长度为255个字符 + String summary = str.length() > 240 ? str.substring(0, 240) + "......" : str; + + //去除转换后存在的空格 + String tagStr = reqBody.getTags().replaceAll(" ", ""); + article.setSummary(summary); + + if (articleMapper.existsByTitle(article.getTitle())) { + throw new MyException(ResponseEnum.ARTICLE_HAS_EXIST); + } + + + //将分类写入数据库 + Category category1 = categoryMapper.findCategoryByName(reqBody.getCategory()); + if (category1 == null) { + category1 = new Category(); + category1.setArticles(""); + category1.setName(reqBody.getCategory()); + categoryMapper.insert(category1); + } + + article.setCategoryId(category1.getId()); + + //文章存数据库 + articleMapper.insert(article); + //获取新增的文章 + + if (isUpdatePreArticle) { + //更新上一篇文章的“下一篇文章ID” + articleMapper.updateNextArticleId(preArticle.getId(), article.getId()); + } + + //无效 + // articleMapper.updatePreArticleId(article.getId(), preArticle == null ? -1 : preArticle.getId()); + article.setPreArticleId(preArticle == null ? -1 : preArticle.getId()); + + category1.setArticles(category1.getArticles() + article.getId() + ","); + categoryMapper.update(category1); + + + //将标签写入数据库 + for (String t : tagStr.split(",")) { + if (t.replaceAll(" ", "").length() == 0) { + //单个标签只含空格 + continue; + } + Tag tag = tagMapper.findTagByName(t); + if (tag == null) { + tag = new Tag(); + tag.setName(t); + tag.setArticles(""); + tagMapper.insert(tag); + } + tag.setArticles(tag.getArticles() + article.getId() + ","); + article.setTagsId(article.getTagsId() + tag.getId() + ","); + tagMapper.update(tag); + } + articleMapper.update(article); + return fullTransform(articleMapper.getLastestArticle()); + } + + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean delete(long articleID) { + + Article articleForDel = articleMapper.findArticleById(articleID); + + if (articleForDel == null) { + throw new MyException(ResponseEnum.ARTICLE_NOT_EXIST);//文章不存在 + } + + Article preArticle = articleMapper.findArticleById(articleForDel.getPreArticleId()); + Article nextArticle = articleMapper.findArticleById(articleForDel.getNextArticleId()); + + //对访问情况进行判断 非博主/非自己文章 拒绝访问 + User user = redisUserUtil.get(request); + if (!user.getRole().contains("admin") && !articleForDel.getAuthorId().equals(user.getId())) { + throw new MyException(ResponseEnum.PERMISSION_ERROR); + } + + //删除的文章处于中间位置 + if (nextArticle != null && preArticle != null) { + + //修改上一篇文章的“下一篇文章”y + articleMapper.updateNextArticleId(articleForDel.getPreArticleId(), articleForDel.getNextArticleId()); + + //修改下一篇文章的 “上一篇文章” + articleMapper.updatePreArticleId(articleForDel.getNextArticleId(), articleForDel.getPreArticleId()); + } + if (preArticle == null && nextArticle != null) { + //删除的是第一篇文章 + articleMapper.updatePreArticleId(nextArticle.getId(), -1); + } + if (nextArticle == null && preArticle != null) { + //删除的是最后一篇文章 + articleMapper.updateNextArticleId(preArticle.getId(), -1); + } + // delete count 为删除的数据数量 + int deleteCount = commentMapper.deleteByArticleId(articleID); + + //删除标签中的文章id + String tag = articleForDel.getTagsId(); + if (tag.length() > 0) { + String[] tags = tag.split(","); + for (String t : tags) { + if (t != null) { + //查询标签 + Tag tag1 = tagMapper.findTagById(Long.parseLong(t)); + //去除标签中的articleId中的待删除的文章id + String s = tag1.getArticles().replaceAll(articleForDel.getId() + ",", ""); + tag1.setArticles(s); + tagMapper.update(tag1); + } + } + } + + + //删除分类中的文章id + //获取文章的分类 + long categoryId = articleForDel.getCategoryId(); + Category category = categoryMapper.findCategoryById(categoryId); + //删除文章id + category.setArticles(category.getArticles().replaceAll(articleForDel.getId() + ",", "")); + //更新 + categoryMapper.update(category); + + //删除指定文章 + articleMapper.delete(articleID); + return true; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public ArticleModel update(ArticleReq reqBody) { + if (reqBody == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //数据判断 + if (reqBody.getTitle() == null || reqBody.getTitle().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } else if (reqBody.getMdContent() == null || reqBody.getMdContent().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //转载 判断链接 + if (!reqBody.getType()) { + if (reqBody.getUrl() == null || reqBody.getUrl().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } else if (!RegexUtil.urlMatch(reqBody.getUrl())) { + throw new MyException(ResponseEnum.PARAMETERS_URL_ERROR); + } + } + if (reqBody.getCategory() == null || reqBody.getCategory().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } +// 暂时不更新tags +// if (reqBody.getTags() == null || reqBody.getTags().replaceAll(" ", "").isEmpty()) { +// throw new MyException(ResponseEnum.PARAMETERS_ERROR); +// } + + //写入数据库的数据 + Article article = new Article(); + if (reqBody.getId() == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR.getCode(), "id不能为空"); + } + article.setId(reqBody.getId()); + article.setTitle(reqBody.getTitle()); + article.setOpen(reqBody.getOpen()); + article.setMdContent(reqBody.getMdContent()); + article.setUrl(reqBody.getUrl()); + article.setType(reqBody.getType()); + + + Article oldArticle = articleMapper.findArticleById(reqBody.getId()); + + Category category = categoryMapper.findCategoryById(oldArticle.getCategoryId()); + if (!(category.getName()).equals(reqBody.getCategory())) { + //修改更新之前数据 的分类 + category.setArticles(category.getArticles().replace(reqBody.getId() + ",", "")); + //更新 + categoryMapper.update(category); + + //更新 更新之后的分类 + Category category1 = categoryMapper.findCategoryByName(reqBody.getCategory()); + if (category1 == null) { + category1 = new Category(); + category1.setName(reqBody.getCategory()); + category1.setArticles(reqBody.getId() + ","); + categoryMapper.insert(category1); + } + article.setCategoryId(category1.getId()); + } else { + article.setCategoryId(oldArticle.getCategoryId()); + } + + +// String[] newTags = reqBody.getTags().replaceAll(" ", "").split(","); + +// //防止出现 ‘null2’这种情况 +// article.setTagsId(""); +// for (String t : newTags) { +// Tag tag = tagMapper.findTagByName(t); +// if (tag == null) { +// tag = new Tag(); +// tag.setName(t); +// tag.setArticles(oldArticle.getId() + ","); +// tag = tagMapper.save(tag); +// article.setTagsId(article.getTagsId() + tag.getId() + ","); +// continue; +// } +// article.setTagsId(article.getTagsId() + tag.getId() + ","); +// } + + // TODO:::: tag的更新 + article.setTagsId(oldArticle.getTagsId()); + + + article.setUpdateDate(new Date()); + // TODO::::换用beansUtil + // 设置不定参数 + article.setReadingNumber(oldArticle.getReadingNumber()); + article.setPublishDate(oldArticle.getPublishDate()); + article.setAuthorId(redisUserUtil.get(request).getId()); + article.setPreArticleId(oldArticle.getPreArticleId()); + article.setNextArticleId(oldArticle.getNextArticleId()); + String str = StringFromHtmlUtil.getString(MDTool.markdown2Html(article.getMdContent())); + article.setSummary(str.length() > 240 ? str.substring(0, 240) + "......" : str); + articleMapper.update(article); + //更新完成移除 + request.getSession().removeAttribute("article4update"); + return fullTransform(article); + } + + @Override + public ArticleModel retrieveOneByID(long articleID, boolean is4update) { + Article article = articleMapper.findArticleById(articleID); + if (article == null) { + throw new MyException(ResponseEnum.ARTICLE_NOT_EXIST); + } + if (!article.getOpen()) { + User user = redisUserUtil.getWithOutExc(request); + if (user == null || "user".equals(user.getRole())) { + throw new MyException(ResponseEnum.ARTICLE_NOT_PUBLIC); + } + } + article.setReadingNumber(article.getReadingNumber() + 1); + if (is4update) { + //因更新而获取文章 不需要增加阅读量 + request.getSession().setAttribute("article4update", article); + return fullTransform(article); + } + articleMapper.setReadingNumber(article.getReadingNumber() + 1, articleID); + return fullTransform(article); + } + + /** + * @param count 数目 + * @param page 页面 默认减1 + * @return + */ + @Override + public PageInfo adminArticles(int count, int page) { + PageHelper.startPage(page, count); + List
articleList = articleMapper.findAll(); + PageInfo pageInfo = new PageInfo(articleList); + pageInfo.setList(list2list(articleList, LevelEnum.BETWEEN_M_AND_H)); + return pageInfo; + } + + @Override + public PageInfo retrievePageForOpen(int count, int page) { + PageHelper.startPage(page, count); + List
articleList = articleMapper.findAllByOpen(true); + PageInfo pageInfo = new PageInfo(articleList); + pageInfo.setList(list2list(articleList, LevelEnum.MIDDLE)); + return pageInfo; + } + + @Override + public PageInfo findByCategory(String name, int page, int count) { + Long idByName = categoryMapper.getIDByName(name); + if (idByName == null) { + throw new MyException(ResponseEnum.CATEGORY_NOT_EXIST); + } + PageHelper.startPage(page, count); + PageInfo pageInfo = new PageInfo(articleMapper.getSimpleInfoByCategory(idByName)); + return pageInfo; + } + + @Override + public PageInfo findByTag(String name, int page, int count) { + Tag tag = tagMapper.findTagByName(name); + if (tag == null) { + throw new MyException(ResponseEnum.TAG_NOT_EXIST); + } + PageHelper.startPage(page, count); + String[] split = tag.getArticles().split(","); + List list = Arrays.asList(split); + List
articleList = articleMapper.getSimpleInfoByTag(list); + PageInfo pageInfo = new PageInfo(articleList); + return pageInfo; + } + + /** + * page转换 + * + * @param articleList 数据源 + * @param level 转换级别 + * @return list + */ + private List list2list(List
articleList, LevelEnum level) { + List content = new ArrayList<>(); + for (Article a : articleList) { + ArticleModel model; + switch (level.getLevelCode()) { + case 0: + model = simpleTransform(a); + break; + case 1: + model = suitableTransform(a); + break; + case 2: + model = suitableTransformForAdmin(a); + break; + case 3: + default: + model = fullTransform(a); + } + content.add(model); + } + return content; + } + + /** + * 简单的模型转换 + * [id,title,summary] + * + * @param a 源数据 + * @return 模型 + */ + private ArticleModel simpleTransform(Article a) { + ArticleModel model = new ArticleModel(); + model.setId(a.getId()); + model.setTitle(a.getTitle()); + model.setSummary(a.getSummary()); + + return model; + } + + /** + * 中等转换 + * [id,title,summary] + * + + * [original,tags,category] + * + * @param a + * @return + */ + private ArticleModel suitableTransform(Article a) { + ArticleModel model = simpleTransform(a); + model.setAuthorName(userService.getNameById(a.getAuthorId())); + model.setPublishDateFormat(DateFormatUtil.get(a.getPublishDate())); + model.setOriginal(a.getType()); + model.setCategory(categoryMapper.getNameById(a.getCategoryId())); + String[] split = a.getTagsId().split(","); + String[] tags = new String[split.length]; + for (int i = 0; i < split.length; i++) { + if (split[i] == null || "".equals(split[i])) { + continue; + } + tags[i] = tagMapper.getNameById(Long.parseLong(split[i])); + } + model.setTags(tags); + return model; + } + + /** + * 中等转换 for admin页面 + * [id,title] + * + + * [original,UpdateDate,open,readingNumber] + * + * @param a + * @return + */ + private ArticleModel suitableTransformForAdmin(Article a) { + ArticleModel model = simpleTransform(a); + model.setPublishDateFormat(DateFormatUtil.get(a.getPublishDate())); + model.setUpdateDateFormat(DateFormatUtil.get(a.getUpdateDate())); + model.setReadingNumber(a.getReadingNumber()); + model.setOpen(a.getOpen()); + model.setOriginal(a.getType()); + model.setSummary(null); + return model; + } + + /** + * 全转换 + * [id,title,summary,original,tags,category] + * + + * [UpdateDate,MdContent,NextArticleId,NextArticleTitle,preArticleId,preArticleTitle,open,url,readingNumber] + * + * @param a + * @return + */ + private ArticleModel fullTransform(Article a) { + ArticleModel model = suitableTransform(a); + model.setUpdateDateFormat(DateFormatUtil.get(a.getUpdateDate())); + model.setMdContent(a.getMdContent()); + model.setNextArticleId(a.getNextArticleId()); + model.setNextArticleTitle(a.getNextArticleId() == -1 ? "无" : articleMapper.getTitleById(a.getNextArticleId())); + model.setPreArticleId(a.getPreArticleId()); + model.setPreArticleTitle(a.getPreArticleId() == -1 ? "无" : articleMapper.getTitleById(a.getPreArticleId())); + model.setOpen(a.getOpen()); + model.setUrl(a.getUrl()); + model.setReadingNumber(a.getReadingNumber()); + return model; + } + +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/CategoryServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/CategoryServiceImpl.java new file mode 100644 index 0000000..3c319b5 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/CategoryServiceImpl.java @@ -0,0 +1,91 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Article; +import cn.celess.blog.entity.Category; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.ArticleMapper; +import cn.celess.blog.mapper.CategoryMapper; +import cn.celess.blog.service.CategoryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/28 22:43 + */ +@Service +public class CategoryServiceImpl implements CategoryService { + @Autowired + CategoryMapper categoryMapper; + @Autowired + HttpServletRequest request; + @Autowired + ArticleMapper articleMapper; + + @Override + public Category create(String name) { + if (categoryMapper.existsByName(name)) { + throw new MyException(ResponseEnum.CATEGORY_HAS_EXIST); + } + Category category = new Category(); + category.setName(name); + category.setArticles(""); + categoryMapper.insert(category); + return category; + } + + @Override + public Category create(Category category) { + if (category == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + categoryMapper.insert(category); + return category; + } + + @Override + public boolean delete(long id) { + Category category = categoryMapper.findCategoryById(id); + + if (category == null) { + throw new MyException(ResponseEnum.CATEGORY_NOT_EXIST); + } + String[] articleArray = category.getArticles().split(","); + for (int i = 0; i < articleArray.length; i++) { + if (articleArray[i] == null || "".equals(articleArray[i])) { + continue; + } + long articleId = Long.parseLong(articleArray[i]); + Article article = articleMapper.findArticleById(articleId); + if (article == null) { + continue; + } + article.setCategoryId(-1L); + //一个 文章只对应一个分类,分类不存在则文章默认不可见 + article.setOpen(false); + articleMapper.update(article); + } + return categoryMapper.delete(id) == 1; + } + + + @Override + public Category update(Long id, String name) { + if (id == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR.getCode(), "id不可为空"); + } + Category category = categoryMapper.findCategoryById(id); + category.setName(name); + categoryMapper.update(category); + return category; + } + + @Override + public List retrievePage() { + return categoryMapper.findAll(); + } +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/CommentServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/CommentServiceImpl.java new file mode 100644 index 0000000..0c54937 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/CommentServiceImpl.java @@ -0,0 +1,192 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Comment; +import cn.celess.blog.entity.model.CommentModel; +import cn.celess.blog.entity.request.CommentReq; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.ArticleMapper; +import cn.celess.blog.mapper.CommentMapper; +import cn.celess.blog.service.CommentService; +import cn.celess.blog.service.UserService; +import cn.celess.blog.util.DateFormatUtil; +import cn.celess.blog.util.RedisUserUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/29 17:05 + */ +@Service +public class CommentServiceImpl implements CommentService { + @Autowired + CommentMapper commentMapper; + @Autowired + UserService userService; + @Autowired + ArticleMapper articleMapper; + @Autowired + HttpServletRequest request; + @Autowired + RedisUserUtil redisUserUtil; + + @Override + public CommentModel create(CommentReq reqBody) { + + if (reqBody == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + long authorID = redisUserUtil.get(request).getId(); + Comment pComment = null; + if (reqBody.getPid() != null && reqBody.getPid() != -1) { + pComment = commentMapper.findCommentById(reqBody.getPid()); + } + if (reqBody.getPid() == null) { + reqBody.setPid(-1L); + } + //不是一级评论 + if (reqBody.getPid() != -1 && pComment == null) { + //父评论不存在 + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + Comment comment = new Comment(); + comment.setAuthorID(authorID); + comment.setType(reqBody.getComment()); + if (reqBody.getComment()) { + //若为评论 + if (reqBody.getArticleID() <= 0) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + comment.setArticleID(reqBody.getArticleID()); + } else { + comment.setArticleID(-1L); + } + comment.setContent(reqBody.getContent()); + comment.setPid(reqBody.getPid()); + comment.setDate(new Date()); + comment.setResponseId(""); + commentMapper.insert(comment); + if (reqBody.getPid() != -1) { + commentMapper.updateResponder(pComment.getResponseId() + comment.getId() + ",", reqBody.getPid()); + } + return trans(comment); + } + + @Override + public boolean delete(long id) { + boolean b = commentMapper.existsById(id); + if (!b) { + throw new MyException(ResponseEnum.COMMENT_NOT_EXIST); + } + commentMapper.delete(id); + return true; + } + + @Override + public CommentModel update(CommentReq reqBody) { + if (reqBody.getId() == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR.getCode(), "id不可为空"); + } + Comment comment = commentMapper.findCommentById(reqBody.getId()); + if (!comment.getContent().equals(reqBody.getContent())) { + commentMapper.updateContent(reqBody.getContent(), reqBody.getId()); + comment.setContent(reqBody.getContent()); + } + if (!comment.getResponseId().equals(reqBody.getResponseId())) { + commentMapper.updateResponder(reqBody.getResponseId(), reqBody.getId()); + comment.setResponseId(reqBody.getResponseId()); + } + return trans(comment); + } + + + @Override + public PageInfo retrievePage(Boolean isComment, int page, int count) { + PageHelper.startPage(page, count); + List commentList = commentMapper.findAllByType(isComment); + PageInfo pageInfo = new PageInfo(commentList); + pageInfo.setList(list2List(commentList)); + return pageInfo; + } + + @Override + public PageInfo retrievePageByPid(long pid, int page, int count) { + PageHelper.startPage(page, count); + List commentList = commentMapper.findAllByPId(pid); + PageInfo pageInfo = new PageInfo(commentList); + pageInfo.setList(list2List(commentList)); + return pageInfo; + } + + @Override + public PageInfo retrievePageByArticle(long articleID, long pid, int page, int count) { + PageHelper.startPage(page, count); + List commentList = commentMapper.findAllByArticleIDAndPId(articleID, pid); + PageInfo pageInfo = new PageInfo(commentList); + pageInfo.setList(list2List(commentList)); + return pageInfo; + } + + @Override + public PageInfo retrievePageByTypeAndPid(Boolean isComment, int pid, int page, int count) { + PageHelper.startPage(page, count); + List commentList = commentMapper.findCommentsByTypeAndPId(isComment, pid); + PageInfo pageInfo = new PageInfo(commentList); + pageInfo.setList(list2List(commentList)); + return pageInfo; + } + + @Override + public PageInfo retrievePageByAuthor(Boolean isComment, int page, int count) { + PageHelper.startPage(page, count); + List commentList = commentMapper.findAllByAuthorIDAndType(redisUserUtil.get(request).getId(), isComment); + PageInfo pageInfo = new PageInfo(commentList); + pageInfo.setList(list2List(commentList)); + return pageInfo; + } + + + @Override + public PageInfo retrievePageByType(Boolean isComment, int page, int count) { + PageHelper.startPage(page, count); + List commentList = commentMapper.findAllByType(isComment); + PageInfo pageInfo = new PageInfo(commentList); + pageInfo.setList(list2List(commentList)); + return pageInfo; + } + + private List list2List(List commentList) { + List content = new ArrayList<>(); + for (Comment c : commentList) { + content.add(trans(c)); + } + return content; + } + + private CommentModel trans(Comment comment) { + CommentModel commentModel = new CommentModel(); + commentModel.setId(comment.getId()); + commentModel.setComment(comment.getType()); + commentModel.setContent(comment.getContent()); + commentModel.setArticleID(comment.getArticleID()); + commentModel.setDate(DateFormatUtil.get(comment.getDate())); + commentModel.setResponseId(comment.getResponseId()); + commentModel.setPid(comment.getPid()); + commentModel.setAuthorName(userService.getNameById(comment.getAuthorID())); + commentModel.setAuthorAvatarImgUrl("http://cdn.celess.cn/" + userService.getAvatarImg(comment.getAuthorID())); + + if (comment.getType() && commentModel.getArticleID() > 0) { + commentModel.setArticleTitle(articleMapper.getTitleById(comment.getArticleID())); + } + return commentModel; + } + +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/CountServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/CountServiceImpl.java new file mode 100644 index 0000000..3165768 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/CountServiceImpl.java @@ -0,0 +1,73 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.mapper.*; +import cn.celess.blog.service.CountService; +import cn.celess.blog.util.RedisUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @author : xiaohai + * @date : 2019/04/02 22:06 + */ +@Service +public class CountServiceImpl implements CountService { + @Autowired + ArticleMapper articleMapper; + @Autowired + TagMapper tagMapper; + @Autowired + CommentMapper commentMapper; + @Autowired + CategoryMapper categoryMapper; + @Autowired + UserMapper userMapper; + @Autowired + VisitorMapper visitorMapper; + @Autowired + RedisUtil redisUtil; + + @Override + public long getCommentCount() { + return commentMapper.countByType(true); + } + + @Override + public long getArticleCount() { + return articleMapper.count(); + } + + @Override + public long getCategoriesCount() { + return categoryMapper.count(); + } + + @Override + public long getTagsCount() { + return tagMapper.count(); + } + + @Override + public long getLeaveMessageCount() { + return commentMapper.countByType(false); + } + + @Override + public long getUserCount() { + return userMapper.count(); + } + + @Override + public long getVisitorCount() { + return visitorMapper.count(); + } + + @Override + public long getDayVisitCount() { + String dayVisitCount = redisUtil.get("dayVisitCount"); + if (dayVisitCount == null) { + return 1; + } + return Integer.parseInt(dayVisitCount); + } +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/MailServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/MailServiceImpl.java new file mode 100644 index 0000000..eeab067 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/MailServiceImpl.java @@ -0,0 +1,41 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.service.MailService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.io.UnsupportedEncodingException; + +/** + * @author : xiaohai + * @date : 2019/04/22 14:26 + */ +@Service +public class MailServiceImpl implements MailService { + public static final String FROM = ""; + @Autowired + JavaMailSender javaMailSender; + + @Override + @Async + public Boolean AsyncSend(SimpleMailMessage message) { + this.send(message); + return true; + } + + @Override + public Boolean send(SimpleMailMessage message) { + String nick = null; + try { + nick = javax.mail.internet.MimeUtility.encodeText("小海博客"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + message.setFrom(nick + FROM); + javaMailSender.send(message); + return true; + } +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java new file mode 100644 index 0000000..af47434 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/PartnerSiteServiceImpl.java @@ -0,0 +1,104 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.PartnerSite; +import cn.celess.blog.entity.request.LinkReq; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.PartnerMapper; +import cn.celess.blog.service.PartnerSiteService; +import cn.celess.blog.util.RegexUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:43 + */ +@Service +public class PartnerSiteServiceImpl implements PartnerSiteService { + @Autowired + PartnerMapper partnerMapper; + + @Override + public PartnerSite create(LinkReq reqBody) { + if (reqBody == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //判空 + if (reqBody.getName() == null || reqBody.getUrl() == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //判空 + if (reqBody.getName().replaceAll(" ", "").isEmpty() || reqBody.getUrl().replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + //是否存在 同名 + if (partnerMapper.existsByName(reqBody.getName())) { + throw new MyException(ResponseEnum.DATA_HAS_EXIST); + } + //url是否合法 + if (!RegexUtil.urlMatch(reqBody.getUrl())) { + throw new MyException(ResponseEnum.PARAMETERS_URL_ERROR); + } + PartnerSite partnerSite = new PartnerSite(); + reqBody.setId(0); + if (!reqBody.getUrl().contains("http://") && !reqBody.getUrl().contains("https://")) { + reqBody.setUrl("http://" + reqBody.getUrl()); + } + BeanUtils.copyProperties(reqBody, partnerSite); + partnerMapper.insert(partnerSite); + return partnerSite; + } + + @Override + public Boolean del(long id) { + //判断数据是否存在 + if (!partnerMapper.existsById(id)) { + throw new MyException(ResponseEnum.DATA_NOT_EXIST); + } + return partnerMapper.delete(id) == 1; + } + + @Override + public PartnerSite update(LinkReq reqBody) { + PartnerSite partnerSite = partnerMapper.findById(reqBody.getId()); + if (partnerSite == null) { + throw new MyException(ResponseEnum.DATA_NOT_EXIST); + } + if (partnerMapper.existsByName(reqBody.getName()) && !reqBody.getName().equals(partnerSite.getName())) { + throw new MyException(ResponseEnum.DATA_HAS_EXIST); + } + if (!RegexUtil.urlMatch(reqBody.getUrl())) { + throw new MyException(ResponseEnum.PARAMETERS_URL_ERROR); + } + if (!reqBody.getUrl().contains("http://") && !reqBody.getUrl().contains("https://")) { + reqBody.setUrl("http://" + reqBody.getUrl()); + } + partnerSite.setName(reqBody.getName()); + partnerSite.setUrl(reqBody.getUrl()); + partnerSite.setOpen(reqBody.isOpen()); + partnerMapper.update(partnerSite); + return partnerSite; + } + + @Override + public PageInfo PartnerSitePages(int page, int count) { + PageHelper.startPage(page, count); + List sitePage = partnerMapper.findAll(); + PageInfo pageInfo = new PageInfo(sitePage); + return pageInfo; + } + + @Override + public List findAll() { + List all = partnerMapper.findAll(); + return all; + } + + +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/QiniuServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/QiniuServiceImpl.java new file mode 100644 index 0000000..503aa86 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/QiniuServiceImpl.java @@ -0,0 +1,90 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.entity.model.QiniuResponse; +import cn.celess.blog.service.QiniuService; +import com.qiniu.common.QiniuException; +import com.qiniu.common.Zone; +import com.qiniu.http.Response; +import com.qiniu.storage.BucketManager; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.UploadManager; +import com.qiniu.storage.model.FileInfo; +import com.qiniu.util.Auth; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Service; + +import java.io.InputStream; + +/** + * @author : xiaohai + * @date : 2019/04/25 18:15 + */ +@Service +public class QiniuServiceImpl implements QiniuService { + private Configuration cfg = new Configuration(Zone.zone2()); + private UploadManager uploadManager; + private BucketManager bucketManager; + private Auth auth; + + private static String bucket; + + + { + /* ***** 必填 ****** + * 七牛的配置 * + * ***** 必填 ****** + */ + // accessKeyString,secretKeyString,bucketString:请替换为自己的值 + String accessKey = "accessKeyString"; + String secretKey = "secretKeyString"; + bucket = "bucketString"; + + auth = Auth.create(accessKey, secretKey); + uploadManager = new UploadManager(cfg); + bucketManager = new BucketManager(auth, cfg); + } + + @Override + public QiniuResponse uploadFile(InputStream is, String fileName) { + //文件存在则删除文件 + if (continueFile(fileName)) { + try { + System.out.println(bucketManager.delete(bucket, fileName).toString()); + } catch (QiniuException e) { + e.printStackTrace(); + } + } + //上传 + try { + Response response = uploadManager.put(is, fileName, auth.uploadToken(bucket), null, null); + return response.jsonToObject(QiniuResponse.class); + } catch (QiniuException e) { + Response r = e.response; + System.err.println(r.toString()); + return null; + } + } + + @Override + public FileInfo[] getFileList() { + BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(bucket, "", 1000, ""); + FileInfo[] items = null; + while (fileListIterator.hasNext()) { + //处理获取的file list结果 + items = fileListIterator.next(); + } + return items; + } + + private boolean continueFile(String key) { + FileInfo[] allFile = getFileList(); + for (FileInfo fileInfo : allFile) { + if (key.equals(fileInfo.key)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/TagServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/TagServiceImpl.java new file mode 100644 index 0000000..098c7ca --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/TagServiceImpl.java @@ -0,0 +1,120 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Article; +import cn.celess.blog.entity.Tag; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.ArticleMapper; +import cn.celess.blog.mapper.TagMapper; +import cn.celess.blog.service.TagService; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/03/28 22:29 + */ +@Service +public class TagServiceImpl implements TagService { + @Autowired + TagMapper tagMapper; + @Autowired + HttpServletRequest request; + @Autowired + ArticleMapper articleMapper; + + @Override + public Tag create(String name) { + boolean b = tagMapper.existsByName(name); + if (b) { + throw new MyException(ResponseEnum.TAG_HAS_EXIST); + } + Tag tag = new Tag(); + tag.setName(name); + tagMapper.insert(tag); + return tag; + } + + @Override + public Tag create(Tag tag) { + if (tag == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + tagMapper.insert(tag); + return tag; + } + + @Override + public boolean delete(long tagId) { + Tag tag = tagMapper.findTagById(tagId); + if (tag == null) { + throw new MyException(ResponseEnum.TAG_NOT_EXIST); + } + if (tag.getArticles()==null){ + return tagMapper.delete(tagId) == 1; + } + String[] articleArray = tag.getArticles().split(","); + for (int i = 0; i < articleArray.length; i++) { + if (articleArray[i] == null || "".equals(articleArray)) { + continue; + } + long articleID = Long.parseLong(articleArray[i]); + Article article = articleMapper.findArticleById(articleID); + if (article == null) { + continue; + } + article.setTagsId(article.getTagsId().replace(tagId + ",", "")); + articleMapper.update(article); + } + return tagMapper.delete(tagId) == 1; + } + + + @Override + public Tag update(Long id,String name) { + if (id == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR.getCode(), "缺少ID"); + } + Tag tagFromDB = tagMapper.findTagById(id); + tagFromDB.setName(name); + + tagMapper.update(tagFromDB); + return tagFromDB; + + } + + @Override + public Tag retrieveOneById(long tagId) { + Tag tag = tagMapper.findTagById(tagId); + if (tag == null) { + throw new MyException(ResponseEnum.TAG_NOT_EXIST); + } + return tag; + } + + @Override + public Tag retrieveOneByName(String name) { + Tag tag = tagMapper.findTagByName(name); + if (tag == null) { + throw new MyException(ResponseEnum.TAG_NOT_EXIST); + } + return tag; + } + + @Override + public PageInfo retrievePage(int page, int count) { + PageHelper.startPage(page, count); + PageInfo pageInfo = new PageInfo(tagMapper.findAll()); + return pageInfo; + } + + @Override + public List findAll() { + return tagMapper.findAll(); + } +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/UserServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/UserServiceImpl.java new file mode 100644 index 0000000..07eb7b6 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/UserServiceImpl.java @@ -0,0 +1,449 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.User; +import cn.celess.blog.entity.model.QiniuResponse; +import cn.celess.blog.entity.model.UserModel; +import cn.celess.blog.entity.request.LoginReq; +import cn.celess.blog.entity.request.UserReq; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.UserMapper; +import cn.celess.blog.service.MailService; +import cn.celess.blog.service.QiniuService; +import cn.celess.blog.service.UserService; +import cn.celess.blog.util.*; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.beans.Transient; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * @author : xiaohai + * @date : 2019/03/30 18:41 + */ +@Service +public class UserServiceImpl implements UserService { + private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); + + @Autowired + UserMapper userMapper; + @Autowired + HttpServletRequest request; + @Autowired + MailService mailService; + @Autowired + QiniuService qiniuService; + @Autowired + RedisUtil redisUtil; + @Autowired + JwtUtil jwtUtil; + @Autowired + RedisUserUtil redisUserUtil; + + @Override + @Transient + public Boolean registration(String email, String password) { + if (password.length() < 6 || password.length() > 16) { + throw new MyException(ResponseEnum.PASSWORD_TOO_SHORT_OR_LONG); + } + if (!RegexUtil.emailMatch(email)) { + throw new MyException(ResponseEnum.PARAMETERS_EMAIL_ERROR); + } + if (!RegexUtil.pwdMatch(password)) { + throw new MyException(ResponseEnum.PARAMETERS_PWD_ERROR); + } + //验证码验证状态 + Boolean verifyStatus = (Boolean) request.getSession().getAttribute("verImgCodeStatus"); + if (verifyStatus == null || !verifyStatus) { + throw new MyException(ResponseEnum.IMG_CODE_DIDNOTVERIFY); + } + if (userMapper.existsByEmail(email)) { + throw new MyException(ResponseEnum.USERNAME_HAS_EXIST); + } + boolean b = userMapper.addUser(email, MD5Util.getMD5(password)) == 1; + if (b) { + String verifyId = UUID.randomUUID().toString().replaceAll("-", ""); + redisUtil.setEx(email + "-verify", verifyId, 2, TimeUnit.DAYS); + SimpleMailMessage mailMessage = new SimpleMailMessage(); + mailMessage.setTo(email); + mailMessage.setSubject("邮箱验证"); + mailMessage.setText("欢迎注册小海博客,点击下面链接进行邮箱验证:\n https://www.celess.cn/emailVerify?email=" + email + "&verifyId=" + + verifyId + "\n该链接两日内有效,若失效了,请登录后台进行重新激活。"); + mailService.send(mailMessage); + } + return b; + } + + @Override + public UserModel login(LoginReq loginReq) { + if (loginReq == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + if (!RegexUtil.emailMatch(loginReq.getEmail())) { + throw new MyException(ResponseEnum.PARAMETERS_EMAIL_ERROR); + } + if (!RegexUtil.pwdMatch(loginReq.getPassword())) { + throw new MyException(ResponseEnum.PARAMETERS_PWD_ERROR); + } + //获取redis缓存中登录失败次数 + String s = redisUtil.get(loginReq.getEmail() + "-passwordWrongTime"); + if (s != null) { + if (Integer.parseInt(s) == 5) { + throw new MyException(ResponseEnum.LOGIN_LATER, loginReq.getEmail()); + } + } + User user = null; + user = userMapper.findByEmail(loginReq.getEmail()); + String token = null; + // 密码比对 + if (user == null) { + // 用户不存在 + throw new MyException(ResponseEnum.USER_NOT_EXIST); + } + if (user.getPwd().equals(MD5Util.getMD5(loginReq.getPassword()))) { + logger.info("====> {} 进行权限认证 状态:登录成功 <====", loginReq.getEmail()); + userMapper.updateLoginTime(loginReq.getEmail(), new Date()); + redisUtil.delete(loginReq.getEmail() + "-passwordWrongTime"); + // redis 标记 + redisUtil.setEx(loginReq.getEmail() + "-login", JSONObject.fromObject(user).toString(), + (loginReq.getIsRememberMe() ? JwtUtil.EXPIRATION_LONG_TIME : JwtUtil.EXPIRATION_SHORT_TIME), TimeUnit.MILLISECONDS); + token = jwtUtil.generateToken(user, loginReq.getIsRememberMe()); + } else { + logger.info("====> {} 进行权限认证 状态:登录失败 <====", loginReq.getEmail()); + request.getSession().removeAttribute("code"); + //登录失败 + //设置登录失败的缓存 + if (s == null) { + redisUtil.setEx(loginReq.getEmail() + "-passwordWrongTime", "1", 2, TimeUnit.HOURS); + s = "0"; + } + int count = Integer.parseInt(s); + //登录次数++ + count++; + //更新登录失败的次数 + redisUtil.setEx(loginReq.getEmail() + "-passwordWrongTime", count + "", 2, TimeUnit.HOURS); + throw new MyException(ResponseEnum.LOGIN_FAILURE); + } + UserModel trans = trans(user); + trans.setToken(token); + return trans; + + } + + @Override + public Object logout() { + String token = request.getHeader("Authorization"); + if (token == null || token.isEmpty()) { + return "注销登录成功"; + } + String email = jwtUtil.getUsernameFromToken(token); + if (redisUtil.hasKey(email + "-login")) { + redisUtil.delete(email + "-login"); + } + return "注销登录成功"; + } + + @Override + public UserModel update(String desc, String displayName) { + User user = redisUserUtil.get(request); + user.setDesc(desc); + user.setDisplayName(displayName); + + userMapper.updateInfo(desc, displayName, user.getId()); + redisUserUtil.set(user); + return trans(user); + } + + @Override + public String getUserRoleByEmail(String email) { + String role = userMapper.getRoleByEmail(email); + if (role == null) { + throw new MyException(ResponseEnum.USER_NOT_EXIST); + } + return role; + } + + @Override + public User getUserInfoByEmail(String email) { + User user = userMapper.findByEmail(email); + if (user == null) { + throw new MyException(ResponseEnum.USER_NOT_EXIST); + } + return user; + } + + @Override + public String getAvatarImg(long id) { + return userMapper.getAvatarImgUrlById(id); + } + + @Override + public Object updateUserAavatarImg(InputStream is, String mime) { + User user = redisUserUtil.get(request); + QiniuResponse upload = qiniuService.uploadFile(is, user.getEmail() + "_" + user.getId() + mime.toLowerCase()); + user.setAvatarImgUrl(upload.key); + userMapper.updateAvatarImgUrl(upload.key, user.getId()); + redisUserUtil.set(user); + return ResponseUtil.success(user.getAvatarImgUrl()); + } + + @Override + public UserModel getUserInfoBySession() { + User user = redisUserUtil.get(request); + return trans(user); + } + + @Override + public boolean isExistOfEmail(String email) { + return userMapper.existsByEmail(email); + } + + @Override + public String getNameById(long id) { + String name = userMapper.getDisPlayName(id); + if (name == null) { + name = userMapper.getEmail(id); + if (name == null) { + throw new MyException(ResponseEnum.USER_NOT_EXIST); + } + } + return name; + } + + /** + * 找回密码 + */ + @Override + public Object sendResetPwdEmail(String email) { + if (!RegexUtil.emailMatch(email)) { + throw new MyException(ResponseEnum.PARAMETERS_EMAIL_ERROR); + } + + User user = userMapper.findByEmail(email); + if (user == null) { + return "发送成功!"; + } + + if (!user.getEmailStatus()) { + throw new MyException(ResponseEnum.USEREMAIL_NOT_VERIFY); + } + + String verifyId = UUID.randomUUID().toString().replaceAll("-", ""); + + redisUtil.setEx(user.getEmail() + "-resetPwd", verifyId, 2, TimeUnit.DAYS); + + SimpleMailMessage mailMessage = new SimpleMailMessage(); + mailMessage.setTo(email); + mailMessage.setSubject("密码重置"); + mailMessage.setText("点击下面链接进行重置密码:\n https://www.celess.cn/resetPwd?email=" + email + "&verifyId=" + verifyId); + + mailService.send(mailMessage); + return "发送成功!"; + } + + //TODO + @Override + public Object sendVerifyEmail(String email) { + if (!RegexUtil.emailMatch(email)) { + throw new MyException(ResponseEnum.PARAMETERS_EMAIL_ERROR); + } + + User user = userMapper.findByEmail(email); + if (user == null) { + return "发送成功!"; + } + + if (user.getEmailStatus()) { + return "已经验证过了!"; + } + + String verifyId = UUID.randomUUID().toString().replaceAll("-", ""); + + redisUtil.setEx(user.getEmail() + "-verify", verifyId, 2, TimeUnit.DAYS); + + SimpleMailMessage mailMessage = new SimpleMailMessage(); + mailMessage.setTo(email); + mailMessage.setSubject("邮箱验证"); + mailMessage.setText("点击下面链接进行邮箱验证:\n https://www.celess.cn/emailVerify?email=" + email + "&verifyId=" + verifyId); + mailService.send(mailMessage); + return "发送成功!"; + } + + @Override + public Object verifyEmail(String verifyId, String email) { + User user = userMapper.findByEmail(email); + if (user == null) { + throw new MyException(ResponseEnum.FAILURE); + } + if (user.getEmailStatus()) { + throw new MyException(ResponseEnum.FAILURE.getCode(), "邮箱已验证过了"); + } + String verifyIdFromCache = redisUtil.get(user.getEmail() + "-verify"); + if (verifyIdFromCache == null) { + throw new MyException(ResponseEnum.FAILURE.getCode(), "验证链接无效"); + } + if (verifyIdFromCache.equals(verifyId)) { + userMapper.updateEmailStatus(email, true); + redisUtil.delete(user.getEmail() + "-verify"); + user.setEmailStatus(true); + redisUserUtil.set(user); + return "验证成功"; + } else { + throw new MyException(ResponseEnum.FAILURE); + } + } + + @Override + public Object reSetPwd(String verifyId, String email, String pwd) { + User user = userMapper.findByEmail(email); + if (user == null) { + throw new MyException(ResponseEnum.USER_NOT_EXIST); + } + if (!RegexUtil.pwdMatch(pwd)) { + throw new MyException(ResponseEnum.PARAMETERS_PWD_ERROR); + } + if (!user.getEmailStatus()) { + throw new MyException(ResponseEnum.USEREMAIL_NOT_VERIFY); + } + String resetPwdIdFromCache = redisUtil.get(user.getEmail() + "-resetPwd"); + if (resetPwdIdFromCache == null) { + throw new MyException(ResponseEnum.FAILURE.getCode(), "请先获取重置密码的邮件"); + } + if (resetPwdIdFromCache.equals(verifyId)) { + if (MD5Util.getMD5(pwd).equals(user.getPwd())) { + throw new MyException(ResponseEnum.PWD_SAME); + } + userMapper.updatePwd(email, MD5Util.getMD5(pwd)); + redisUtil.delete(user.getEmail() + "-resetPwd"); + return "验证成功"; + } else { + throw new MyException(ResponseEnum.FAILURE.getCode(), "标识码不一致"); + } + } + + @Override + public Object deleteUser(Integer[] id) { + JSONArray status = new JSONArray(); + if (id == null || id.length == 0) { + return null; + } + for (Integer integer : id) { + String role = userMapper.getRoleById(integer); + int deleteResult = 0; + JSONObject deleteStatus = new JSONObject(); + deleteStatus.put("id", integer); + // 管理员账户不可删 + if ("admin".equals(role)) { + deleteStatus.put("msg", "用户为管理员,不可删除"); + deleteStatus.put("status", false); + status.add(deleteStatus); + logger.info("删除用户id为{}的用户,删除状态{}, 原因:用户为管理员,不可删除", integer, false); + continue; + } + // 非管理员账户 + deleteResult = userMapper.delete(integer); + deleteStatus.put("status", deleteResult == 1); + logger.info("删除用户id为{}的用户,删除状态{}", integer, deleteResult == 1); + if (deleteResult == 0) { + deleteStatus.put("msg", "用户不存在"); + } + status.add(deleteStatus); + } + return status; + } + + @Override + public PageInfo getUserList(Integer page, Integer count) { + PageHelper.startPage(page, count); + List all = userMapper.findAll(); + PageInfo pageInfo = PageInfo.of(all); + List modelList = new ArrayList<>(); + all.forEach(user -> modelList.add(trans(user))); + pageInfo.setList(modelList); + return pageInfo; + } + + @Override + public UserModel adminUpdate(UserReq userReq) { + if (userReq == null || userReq.getId() == null) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + User user = userMapper.findById(userReq.getId()); + // 设置数据 + if (userReq.getDesc() != null) { + user.setDesc(userReq.getDesc()); + } + if (userReq.getDisplayName() != null) { + user.setDisplayName(userReq.getDisplayName()); + } + if (userReq.getEmailStatus() != null) { + user.setEmailStatus(userReq.getEmailStatus()); + } + if (userReq.getPwd() != null) { + if (userReq.getPwd().length() < 6 || userReq.getPwd().length() > 16) { + throw new MyException(ResponseEnum.PASSWORD_TOO_SHORT_OR_LONG); + } + if (!RegexUtil.pwdMatch(userReq.getPwd())) { + throw new MyException(ResponseEnum.PARAMETERS_PWD_ERROR); + } + user.setPwd(MD5Util.getMD5(userReq.getPwd())); + } + if (userReq.getRole() != null) { + // TODO:用enum存放角色分类 + if ("user".equals(userReq.getRole()) || "admin".equals(userReq.getRole())) { + user.setRole(userReq.getRole()); + } else { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + } + if (userReq.getEmail() != null) { + if (!RegexUtil.emailMatch(userReq.getEmail())) { + throw new MyException(ResponseEnum.PARAMETERS_EMAIL_ERROR); + } + // TODO :: 邮件提醒 + user.setEmail(userReq.getEmail()); + } + // 数据写入 + int updateResult = userMapper.update(user); + if (updateResult == 0) { + throw new MyException(ResponseEnum.FAILURE); + } + if (redisUserUtil.get(request).getId().equals(userReq.getId())) { + redisUserUtil.set(user); + } + logger.info("修改了用户 [id={}] 的用户的资料", userReq.getId()); + return trans(user); + } + + @Override + public boolean getStatusOfEmail(String email) { + return userMapper.existsByEmail(email); + } + + private UserModel trans(User u) { + UserModel user = new UserModel(); + user.setId(u.getId()); + user.setAvatarImgUrl(u.getAvatarImgUrl() == null ? null : "http://cdn.celess.cn/" + u.getAvatarImgUrl()); + user.setEmail(u.getEmail()); + user.setDesc(u.getDesc()); + user.setDisplayName(u.getDisplayName() == null ? u.getEmail() : u.getDisplayName()); + user.setEmailStatus(u.getEmailStatus()); + user.setRecentlyLandedDate(DateFormatUtil.get(u.getRecentlyLandedDate())); + user.setRole(u.getRole()); + return user; + } +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/VisitorServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/VisitorServiceImpl.java new file mode 100644 index 0000000..d1d7fc3 --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/VisitorServiceImpl.java @@ -0,0 +1,210 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Visitor; +import cn.celess.blog.entity.model.VisitorModel; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.VisitorMapper; +import cn.celess.blog.service.VisitorService; +import cn.celess.blog.util.DateFormatUtil; +import cn.celess.blog.util.RedisUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import eu.bitwalker.useragentutils.Browser; +import eu.bitwalker.useragentutils.OperatingSystem; +import eu.bitwalker.useragentutils.UserAgent; +import eu.bitwalker.useragentutils.Version; +import org.apache.commons.lang.time.DateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.json.JsonParserFactory; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.*; +import java.util.concurrent.TimeUnit; + +/** + * @author : xiaohai + * @date : 2019/04/02 23:04 + */ +@Service +public class VisitorServiceImpl implements VisitorService { + @Autowired + VisitorMapper visitorMapper; + @Autowired + RedisUtil redisUtil; + + @Override + public String location(String ip) { + return getLocation(ip); + } + + @Override + public PageInfo visitorPage(int page, int count, boolean showLocation) { + PageHelper.startPage(page, count); + List visitorList = visitorMapper.findAll(); + PageInfo pageInfo = new PageInfo(visitorList); + pageInfo.setList(list2List(visitorList, showLocation)); + return pageInfo; + } + + @Override + public VisitorModel addVisitor(HttpServletRequest request) { + //新session + if (!request.getSession().isNew()) { + return null; + } + if (isSpiderBot(request.getHeader("User-Agent"))) { + return null; + } + Visitor visitor = new Visitor(); + visitor.setIp(request.getRemoteAddr()); + visitor.setDate(new Date()); + visitor.setUa(request.getHeader("User-Agent")); + //记录当日的访问 + String dayVisitCount = redisUtil.get("dayVisitCount"); + long secondsLeftToday = 86400 - DateUtils.getFragmentInSeconds(Calendar.getInstance(), Calendar.DATE); + Date date = new Date(Calendar.YEAR); + if (dayVisitCount == null) { + redisUtil.setEx("dayVisitCount", "1", secondsLeftToday, TimeUnit.SECONDS); + } else { + int count = Integer.parseInt(dayVisitCount) + 1; + redisUtil.setEx("dayVisitCount", count + "", secondsLeftToday, TimeUnit.SECONDS); + } + if (visitorMapper.insert(visitor) == 0) { + throw new MyException(ResponseEnum.FAILURE); + } + return trans(visitor); + } + + + /** + * 数据修改 + * + * @return + */ + private List list2List(List visitorList, boolean showLocation) { + List visitorModelList = new ArrayList<>(); + for (Visitor v : visitorList) { + VisitorModel trans = trans(v); + if (showLocation) { + trans.setLocation(getLocation(v.getIp())); + } + visitorModelList.add(trans); + } + return visitorModelList; + } + + /*** + * 转化为model + * + * @param v + * @return + */ + private VisitorModel trans(Visitor v) { + UserAgent userAgent = UserAgent.parseUserAgentString(v.getUa()); + VisitorModel visitor = new VisitorModel(); + visitor.setId(v.getId()); + visitor.setDate(DateFormatUtil.get(v.getDate())); + visitor.setIp(v.getIp()); + Browser browser = userAgent.getBrowser(); + visitor.setBrowserName(browser == null ? "" : browser.getName()); + OperatingSystem operatingSystem = userAgent.getOperatingSystem(); + visitor.setOSName(operatingSystem == null ? "" : operatingSystem.getName()); + Version browserVersion = userAgent.getBrowserVersion(); + visitor.setBrowserVersion(browserVersion == null ? "" : browserVersion.getVersion()); + return visitor; + } + + /** + * 根据ua判断是不是爬虫 + * + * @param ua ua + * @return true:爬虫 false :不是爬虫 + */ + private boolean isSpiderBot(String ua) { + if (ua == null) { + return false; + } + //服务器端的缓存抓取 + if (ua.contains("https://github.com/prerender/prerender")) { + return true; + } + //搜索引擎得爬虫ua一般有链接 + if (ua.contains("http://")) { + return true; + } + //防止没有匹配到http + return ua.toLowerCase().contains("spider"); + } + + /** + * 获取ip的地址 + * + * @param ip + * @return + */ + private String getLocation(String ip) { + StringBuilder result = new StringBuilder(); + URL url; + HttpURLConnection conn = null; + InputStream inputStream = null; + InputStreamReader inputStreamReader = null; + BufferedReader bufferedReader = null; + try { + url = new URL("http://ip.taobao.com/service/getIpInfo.php?ip=" + ip); + conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(3000); + conn.setDoInput(true); + conn.setRequestMethod("GET"); + inputStream = conn.getInputStream(); + inputStreamReader = new InputStreamReader(inputStream); + bufferedReader = new BufferedReader(inputStreamReader); + String tmp; + while ((tmp = bufferedReader.readLine()) != null) { + result.append(tmp); + } + } catch (Exception e) { + // ignore + } finally { + try { + if (conn != null) { + conn.disconnect(); + } + if (inputStream != null) { + inputStream.close(); + } + if (inputStreamReader != null) { + inputStreamReader.close(); + } + if (bufferedReader != null) { + bufferedReader.close(); + } + } catch (Exception e) { + // ignore + } + } + StringBuilder sb = new StringBuilder(); + if ("".equals(result.toString())) { + throw new MyException(ResponseEnum.FAILURE); + } + Map stringObjectMap = JsonParserFactory.getJsonParser().parseMap(result.toString()); + if ((Integer) stringObjectMap.get("code") == 0) { + LinkedHashMap data = (LinkedHashMap) stringObjectMap.get("data"); + sb.append(data.get("country")) + .append("-") + .append(data.get("region")) + .append("-") + .append(data.get("city")); + } + return sb.toString(); + + } + + +} diff --git a/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java b/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java new file mode 100644 index 0000000..1a70f8a --- /dev/null +++ b/src/main/java/cn/celess/blog/service/serviceimpl/WebUpdateInfoServiceImpl.java @@ -0,0 +1,99 @@ +package cn.celess.blog.service.serviceimpl; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.WebUpdate; +import cn.celess.blog.entity.model.WebUpdateModel; +import cn.celess.blog.exception.MyException; +import cn.celess.blog.mapper.WebUpdateInfoMapper; +import cn.celess.blog.service.WebUpdateInfoService; +import cn.celess.blog.util.DateFormatUtil; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:43 + */ +@Service +public class WebUpdateInfoServiceImpl implements WebUpdateInfoService { + @Autowired + WebUpdateInfoMapper webUpdateInfoMapper; + + + @Override + public WebUpdateModel create(String info) { + if (info == null || info.replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + WebUpdate webUpdate = new WebUpdate(info, new Date()); + if (webUpdateInfoMapper.insert(webUpdate) == 0) { + throw new MyException(ResponseEnum.FAILURE); + } + return trans(webUpdate); + } + + @Override + public Boolean del(long id) { + if (!webUpdateInfoMapper.existsById(id)) { + throw new MyException(ResponseEnum.DATA_NOT_EXIST); + } + return webUpdateInfoMapper.delete(id) == 1; + } + + @Override + public WebUpdateModel update(long id, String info) { + WebUpdate webUpdate = webUpdateInfoMapper.findById(id); + if (webUpdate == null) { + throw new MyException(ResponseEnum.DATA_NOT_EXIST); + } + if (info == null || info.replaceAll(" ", "").isEmpty()) { + throw new MyException(ResponseEnum.PARAMETERS_ERROR); + } + webUpdate.setUpdateInfo(info); + webUpdateInfoMapper.update(id, info); + return trans(webUpdate); + } + + @Override + public PageInfo pages(int count, int page) { + PageHelper.startPage(page, count); + List updateList = webUpdateInfoMapper.findAll(); + PageInfo pageInfo = new PageInfo(updateList); + pageInfo.setList(list2List(updateList)); + return pageInfo; + } + + @Override + public List findAll() { + List all = webUpdateInfoMapper.findAll(); + List webUpdateModels = new ArrayList<>(); + for (WebUpdate w : all) { + webUpdateModels.add(trans(w)); + } + return webUpdateModels; + } + + @Override + public String getLastestUpdateTime() { + return DateFormatUtil.get(webUpdateInfoMapper.getLastestOne()); + } + + private List list2List(List webUpdates) { + List webUpdateModels = new ArrayList<>(); + for (WebUpdate w : webUpdates) { + webUpdateModels.add(trans(w)); + } + return webUpdateModels; + } + + private WebUpdateModel trans(WebUpdate webUpdate) { + return new WebUpdateModel(webUpdate.getId(), webUpdate.getUpdateInfo(), DateFormatUtil.get(webUpdate.getUpdateTime())); + } + +} diff --git a/src/main/java/cn/celess/blog/util/DateFormatUtil.java b/src/main/java/cn/celess/blog/util/DateFormatUtil.java new file mode 100644 index 0000000..9ca8279 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/DateFormatUtil.java @@ -0,0 +1,42 @@ +package cn.celess.blog.util; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.GregorianCalendar; + +/** + * @author : xiaohai + * @date : 2019/03/28 17:22 + */ +public class DateFormatUtil { + public static String get(Date date) { + if (date == null) { + return null; + } + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return sdf.format(date); + } + + public static String getForXmlDate(Date date) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ"); + GregorianCalendar gc = new GregorianCalendar(); + String dateString = sdf.format(date); + try { + gc.setTime(sdf.parse(dateString)); + XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc); + return date2.toString(); + } catch (DatatypeConfigurationException | ParseException e) { + e.printStackTrace(); + return null; + } + } + + + public static String getNow() { + return get(new Date()); + } +} diff --git a/src/main/java/cn/celess/blog/util/JwtUtil.java b/src/main/java/cn/celess/blog/util/JwtUtil.java new file mode 100644 index 0000000..eb4af71 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/JwtUtil.java @@ -0,0 +1,93 @@ +package cn.celess.blog.util; + +import cn.celess.blog.entity.User; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * @Author: 小海 + * @Date: 2019/11/16 11:26 + * @Description: JWT工具类 + */ +@Component +public class JwtUtil { + private static final String CLAIM_KEY_USERNAME = "sub"; + + /** + * 5天(毫秒) + */ + public static final long EXPIRATION_LONG_TIME = 432000000; + + /** + * 两小时(毫秒) + */ + public static final long EXPIRATION_SHORT_TIME = 7200000; + /** + * JWT 秘钥需自行设置不可泄露 + */ + private static final String SECRET = "xxx"; + + + public String generateToken(User user, boolean isRemember) { + Map claims = new HashMap<>(16); + claims.put(CLAIM_KEY_USERNAME, user.getEmail()); + + return Jwts.builder() + .setClaims(claims) + .setExpiration(new Date(Instant.now().toEpochMilli() + (isRemember ? EXPIRATION_LONG_TIME : EXPIRATION_SHORT_TIME))) + .signWith(SignatureAlgorithm.HS512, SECRET) + .compact(); + } + + public Boolean validateToken(String token, User user) { + String username = getUsernameFromToken(token); + + return (username.equals(user.getEmail()) && !isTokenExpired(token)); + } + + /** + * 获取token是否过期 + */ + public Boolean isTokenExpired(String token) { + try { + Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } catch (ExpiredJwtException e) { + return true; + } + } + + /** + * 根据token获取username + */ + public String getUsernameFromToken(String token) { + return getClaimsFromToken(token).getSubject(); + } + + /** + * 获取token的过期时间 + */ + public Date getExpirationDateFromToken(String token) { + return getClaimsFromToken(token).getExpiration(); + } + + /** + * 解析JWT + */ + private Claims getClaimsFromToken(String token) { + Claims claims = Jwts.parser() + .setSigningKey(SECRET) + .parseClaimsJws(token) + .getBody(); + return claims; + } + +} diff --git a/src/main/java/cn/celess/blog/util/MD5Util.java b/src/main/java/cn/celess/blog/util/MD5Util.java new file mode 100644 index 0000000..2d7f82a --- /dev/null +++ b/src/main/java/cn/celess/blog/util/MD5Util.java @@ -0,0 +1,14 @@ +package cn.celess.blog.util; + +import org.springframework.util.DigestUtils; + +/** + * @author : xiaohai + * @date : 2019/03/30 18:56 + */ +public class MD5Util { + public static String getMD5(String str) { + String md5 = DigestUtils.md5DigestAsHex(str.getBytes()); + return md5; + } +} diff --git a/src/main/java/cn/celess/blog/util/ProtoStuffSerializerUtil.java b/src/main/java/cn/celess/blog/util/ProtoStuffSerializerUtil.java new file mode 100644 index 0000000..ec3d805 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/ProtoStuffSerializerUtil.java @@ -0,0 +1,126 @@ +package cn.celess.blog.util; + + +import com.dyuproject.protostuff.LinkedBuffer; +import com.dyuproject.protostuff.ProtostuffIOUtil; +import com.dyuproject.protostuff.Schema; +import com.dyuproject.protostuff.runtime.RuntimeSchema; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +/** + * ProtoStuffSerializerUtil + * + * @author Sirius + * @date 2019-1-8 + */ +public class ProtoStuffSerializerUtil { + /** + * 序列化对象 + * + * @param obj + * @return + */ + public static byte[] serialize(T obj) { + if (obj == null) { + throw new RuntimeException("序列化对象(" + obj + ")!"); + } + @SuppressWarnings("unchecked") + Schema schema = (Schema) RuntimeSchema.getSchema(obj.getClass()); + LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024); + byte[] protostuff = null; + try { + protostuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer); + } catch (Exception e) { + throw new RuntimeException("序列化(" + obj.getClass() + ")对象(" + obj + ")发生异常!", e); + } finally { + buffer.clear(); + } + return protostuff; + } + + /** + * 反序列化对象 + * + * @param paramArrayOfByte + * @param targetClass + * @return + */ + public static T deserialize(byte[] paramArrayOfByte, Class targetClass) { + if (paramArrayOfByte == null || paramArrayOfByte.length == 0) { + throw new RuntimeException("反序列化对象发生异常,byte序列为空!"); + } + T instance = null; + try { + instance = targetClass.newInstance(); + } catch (InstantiationException e1) { + throw new RuntimeException("反序列化过程中依据类型创建对象失败!", e1); + } catch (IllegalAccessException e2) { + throw new RuntimeException("反序列化过程中依据类型创建对象失败!", e2); + } + Schema schema = RuntimeSchema.getSchema(targetClass); + ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema); + return instance; + } + + /** + * 序列化列表 + * + * @param objList + * @return + */ + public static byte[] serializeList(List objList) { + if (objList == null || objList.isEmpty()) { + throw new RuntimeException("序列化对象列表(" + objList + ")参数异常!"); + } + @SuppressWarnings("unchecked") + Schema schema = (Schema) RuntimeSchema.getSchema(objList.get(0).getClass()); + LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024); + byte[] protostuff = null; + ByteArrayOutputStream bos = null; + try { + bos = new ByteArrayOutputStream(); + ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer); + protostuff = bos.toByteArray(); + } catch (Exception e) { + throw new RuntimeException("序列化对象列表(" + objList + ")发生异常!", e); + } finally { + buffer.clear(); + try { + if (bos != null) { + bos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + return protostuff; + } + + /** + * 反序列化列表 + * + * @param paramArrayOfByte + * @param targetClass + * @return + */ + public static List deserializeList(byte[] paramArrayOfByte, Class targetClass) { + if (paramArrayOfByte == null || paramArrayOfByte.length == 0) { + throw new RuntimeException("反序列化对象发生异常,byte序列为空!"); + } + + Schema schema = RuntimeSchema.getSchema(targetClass); + List result = null; + try { + result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema); + } catch (IOException e) { + throw new RuntimeException("反序列化对象列表发生异常!", e); + } + return result; + } + +} diff --git a/src/main/java/cn/celess/blog/util/RedisUserUtil.java b/src/main/java/cn/celess/blog/util/RedisUserUtil.java new file mode 100644 index 0000000..935c725 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/RedisUserUtil.java @@ -0,0 +1,46 @@ +package cn.celess.blog.util; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.User; +import cn.celess.blog.exception.MyException; +import net.sf.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.util.concurrent.TimeUnit; + +/** + * @author : xiaohai + * @date : 2019/03/08 15:06 + */ +@Component +public class RedisUserUtil { + @Autowired + RedisUtil redisUtil; + @Autowired + JwtUtil jwtUtil; + + public User get(HttpServletRequest request) { + User user = getWithOutExc(request); + if (user == null) { + throw new MyException(ResponseEnum.HAVE_NOT_LOG_IN); + } + return user; + } + + public User getWithOutExc(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + if (token == null || token.isEmpty()) { + return null; + } + String email = jwtUtil.getUsernameFromToken(token); + return (User) JSONObject.toBean(JSONObject.fromObject(redisUtil.get(email + "-login")), User.class); + } + + public User set(User user) { + redisUtil.setEx(user.getEmail() + "-login", JSONObject.fromObject(user).toString(), + redisUtil.getExpire(user.getEmail() + "-login"), TimeUnit.MILLISECONDS); + return user; + } +} diff --git a/src/main/java/cn/celess/blog/util/RedisUtil.java b/src/main/java/cn/celess/blog/util/RedisUtil.java new file mode 100644 index 0000000..7bf60a3 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/RedisUtil.java @@ -0,0 +1,1411 @@ +package cn.celess.blog.util; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.data.redis.connection.DataType; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.ScanOptions; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ZSetOperations.TypedTuple; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +/** + * Redis工具类 + * + * @author WangFan + * @date 2018-02-24 下午03:09:50 + * @version 1.1 (GitHub文档: https://github.com/whvcse/RedisUtil ) + */ + +@Component +public class RedisUtil { + @Autowired + private StringRedisTemplate redisTemplate; + + public void setRedisTemplate(StringRedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + public StringRedisTemplate getRedisTemplate() { + return this.redisTemplate; + } + + /** -------------------key相关操作--------------------- */ + + /** + * 删除key + * + * @param key + */ + public void delete(String key) { + redisTemplate.delete(key); + } + + /** + * 批量删除key + * + * @param keys + */ + public void delete(Collection keys) { + redisTemplate.delete(keys); + } + + /** + * 序列化key + * + * @param key + * @return + */ + public byte[] dump(String key) { + return redisTemplate.dump(key); + } + + /** + * 是否存在key + * + * @param key + * @return + */ + public Boolean hasKey(String key) { + return redisTemplate.hasKey(key); + } + + /** + * 设置过期时间 + * + * @param key + * @param timeout + * @param unit + * @return + */ + public Boolean expire(String key, long timeout, TimeUnit unit) { + return redisTemplate.expire(key, timeout, unit); + } + + /** + * 设置过期时间 + * + * @param key + * @param date + * @return + */ + public Boolean expireAt(String key, Date date) { + return redisTemplate.expireAt(key, date); + } + + /** + * 查找匹配的key + * + * @param pattern + * @return + */ + public Set keys(String pattern) { + return redisTemplate.keys(pattern); + } + + /** + * 将当前数据库的 key 移动到给定的数据库 db 当中 + * + * @param key + * @param dbIndex + * @return + */ + public Boolean move(String key, int dbIndex) { + return redisTemplate.move(key, dbIndex); + } + + /** + * 移除 key 的过期时间,key 将持久保持 + * + * @param key + * @return + */ + public Boolean persist(String key) { + return redisTemplate.persist(key); + } + + /** + * 返回 key 的剩余的过期时间 + * + * @param key + * @param unit + * @return + */ + public Long getExpire(String key, TimeUnit unit) { + return redisTemplate.getExpire(key, unit); + } + + /** + * 返回 key 的剩余的过期时间 + * + * @param key + * @return + */ + public Long getExpire(String key) { + return redisTemplate.getExpire(key); + } + + /** + * 从当前数据库中随机返回一个 key + * + * @return + */ + public String randomKey() { + return redisTemplate.randomKey(); + } + + /** + * 修改 key 的名称 + * + * @param oldKey + * @param newKey + */ + public void rename(String oldKey, String newKey) { + redisTemplate.rename(oldKey, newKey); + } + + /** + * 仅当 newkey 不存在时,将 oldKey 改名为 newkey + * + * @param oldKey + * @param newKey + * @return + */ + public Boolean renameIfAbsent(String oldKey, String newKey) { + return redisTemplate.renameIfAbsent(oldKey, newKey); + } + + /** + * 返回 key 所储存的值的类型 + * + * @param key + * @return + */ + public DataType type(String key) { + return redisTemplate.type(key); + } + + /** -------------------string相关操作--------------------- */ + + /** + * 设置指定 key 的值 + * @param key + * @param value + */ + public void set(String key, String value) { + redisTemplate.opsForValue().set(key, value); + } + + /** + * 获取指定 key 的值 + * @param key + * @return + */ + public String get(String key) { + return redisTemplate.opsForValue().get(key); + } + + /** + * 返回 key 中字符串值的子字符 + * @param key + * @param start + * @param end + * @return + */ + public String getRange(String key, long start, long end) { + return redisTemplate.opsForValue().get(key, start, end); + } + + /** + * 将给定 key 的值设为 value ,并返回 key 的旧值(old value) + * + * @param key + * @param value + * @return + */ + public String getAndSet(String key, String value) { + return redisTemplate.opsForValue().getAndSet(key, value); + } + + /** + * 对 key 所储存的字符串值,获取指定偏移量上的位(bit) + * + * @param key + * @param offset + * @return + */ + public Boolean getBit(String key, long offset) { + return redisTemplate.opsForValue().getBit(key, offset); + } + + /** + * 批量获取 + * + * @param keys + * @return + */ + public List multiGet(Collection keys) { + return redisTemplate.opsForValue().multiGet(keys); + } + + /** + * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value + * + * @param key + * @param postion + * 位置 + * @param value + * 值,true为1, false为0 + * @return + */ + public boolean setBit(String key, long offset, boolean value) { + return redisTemplate.opsForValue().setBit(key, offset, value); + } + + /** + * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout + * + * @param key + * @param value + * @param timeout + * 过期时间 + * @param unit + * 时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES + * 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS + */ + public void setEx(String key, String value, long timeout, TimeUnit unit) { + redisTemplate.opsForValue().set(key, value, timeout, unit); + } + + /** + * 只有在 key 不存在时设置 key 的值 + * + * @param key + * @param value + * @return 之前已经存在返回false,不存在返回true + */ + public boolean setIfAbsent(String key, String value) { + return redisTemplate.opsForValue().setIfAbsent(key, value); + } + + /** + * 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始 + * + * @param key + * @param value + * @param offset + * 从指定位置开始覆写 + */ + public void setRange(String key, String value, long offset) { + redisTemplate.opsForValue().set(key, value, offset); + } + + /** + * 获取字符串的长度 + * + * @param key + * @return + */ + public Long size(String key) { + return redisTemplate.opsForValue().size(key); + } + + /** + * 批量添加 + * + * @param maps + */ + public void multiSet(Map maps) { + redisTemplate.opsForValue().multiSet(maps); + } + + /** + * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 + * + * @param maps + * @return 之前已经存在返回false,不存在返回true + */ + public boolean multiSetIfAbsent(Map maps) { + return redisTemplate.opsForValue().multiSetIfAbsent(maps); + } + + /** + * 增加(自增长), 负数则为自减 + * + * @param key + * @param value + * @return + */ + public Long incrBy(String key, long increment) { + return redisTemplate.opsForValue().increment(key, increment); + } + + /** + * + * @param key + * @param value + * @return + */ + public Double incrByFloat(String key, double increment) { + return redisTemplate.opsForValue().increment(key, increment); + } + + /** + * 追加到末尾 + * + * @param key + * @param value + * @return + */ + public Integer append(String key, String value) { + return redisTemplate.opsForValue().append(key, value); + } + + /** -------------------hash相关操作------------------------- */ + + /** + * 获取存储在哈希表中指定字段的值 + * + * @param key + * @param field + * @return + */ + public Object hGet(String key, String field) { + return redisTemplate.opsForHash().get(key, field); + } + + /** + * 获取所有给定字段的值 + * + * @param key + * @return + */ + public Map hGetAll(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * 获取所有给定字段的值 + * + * @param key + * @param fields + * @return + */ + public List hMultiGet(String key, Collection fields) { + return redisTemplate.opsForHash().multiGet(key, fields); + } + + public void hPut(String key, String hashKey, String value) { + redisTemplate.opsForHash().put(key, hashKey, value); + } + + public void hPutAll(String key, Map maps) { + redisTemplate.opsForHash().putAll(key, maps); + } + + /** + * 仅当hashKey不存在时才设置 + * + * @param key + * @param hashKey + * @param value + * @return + */ + public Boolean hPutIfAbsent(String key, String hashKey, String value) { + return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value); + } + + /** + * 删除一个或多个哈希表字段 + * + * @param key + * @param fields + * @return + */ + public Long hDelete(String key, Object... fields) { + return redisTemplate.opsForHash().delete(key, fields); + } + + /** + * 查看哈希表 key 中,指定的字段是否存在 + * + * @param key + * @param field + * @return + */ + public boolean hExists(String key, String field) { + return redisTemplate.opsForHash().hasKey(key, field); + } + + /** + * 为哈希表 key 中的指定字段的整数值加上增量 increment + * + * @param key + * @param field + * @param increment + * @return + */ + public Long hIncrBy(String key, Object field, long increment) { + return redisTemplate.opsForHash().increment(key, field, increment); + } + + /** + * 为哈希表 key 中的指定字段的整数值加上增量 increment + * + * @param key + * @param field + * @param delta + * @return + */ + public Double hIncrByFloat(String key, Object field, double delta) { + return redisTemplate.opsForHash().increment(key, field, delta); + } + + /** + * 获取所有哈希表中的字段 + * + * @param key + * @return + */ + public Set hKeys(String key) { + return redisTemplate.opsForHash().keys(key); + } + + /** + * 获取哈希表中字段的数量 + * + * @param key + * @return + */ + public Long hSize(String key) { + return redisTemplate.opsForHash().size(key); + } + + /** + * 获取哈希表中所有值 + * + * @param key + * @return + */ + public List hValues(String key) { + return redisTemplate.opsForHash().values(key); + } + + /** + * 迭代哈希表中的键值对 + * + * @param key + * @param options + * @return + */ + public Cursor> hScan(String key, ScanOptions options) { + return redisTemplate.opsForHash().scan(key, options); + } + + /** ------------------------list相关操作---------------------------- */ + + /** + * 通过索引获取列表中的元素 + * + * @param key + * @param index + * @return + */ + public String lIndex(String key, long index) { + return redisTemplate.opsForList().index(key, index); + } + + /** + * 获取列表指定范围内的元素 + * + * @param key + * @param start + * 开始位置, 0是开始位置 + * @param end + * 结束位置, -1返回所有 + * @return + */ + public List lRange(String key, long start, long end) { + return redisTemplate.opsForList().range(key, start, end); + } + + /** + * 存储在list头部 + * + * @param key + * @param value + * @return + */ + public Long lLeftPush(String key, String value) { + return redisTemplate.opsForList().leftPush(key, value); + } + + /** + * + * @param key + * @param value + * @return + */ + public Long lLeftPushAll(String key, String... value) { + return redisTemplate.opsForList().leftPushAll(key, value); + } + + /** + * + * @param key + * @param value + * @return + */ + public Long lLeftPushAll(String key, Collection value) { + return redisTemplate.opsForList().leftPushAll(key, value); + } + + /** + * 当list存在的时候才加入 + * + * @param key + * @param value + * @return + */ + public Long lLeftPushIfPresent(String key, String value) { + return redisTemplate.opsForList().leftPushIfPresent(key, value); + } + + /** + * 如果pivot存在,再pivot前面添加 + * + * @param key + * @param pivot + * @param value + * @return + */ + public Long lLeftPush(String key, String pivot, String value) { + return redisTemplate.opsForList().leftPush(key, pivot, value); + } + + /** + * + * @param key + * @param value + * @return + */ + public Long lRightPush(String key, String value) { + return redisTemplate.opsForList().rightPush(key, value); + } + + /** + * + * @param key + * @param value + * @return + */ + public Long lRightPushAll(String key, String... value) { + return redisTemplate.opsForList().rightPushAll(key, value); + } + + /** + * + * @param key + * @param value + * @return + */ + public Long lRightPushAll(String key, Collection value) { + return redisTemplate.opsForList().rightPushAll(key, value); + } + + /** + * 为已存在的列表添加值 + * + * @param key + * @param value + * @return + */ + public Long lRightPushIfPresent(String key, String value) { + return redisTemplate.opsForList().rightPushIfPresent(key, value); + } + + /** + * 在pivot元素的右边添加值 + * + * @param key + * @param pivot + * @param value + * @return + */ + public Long lRightPush(String key, String pivot, String value) { + return redisTemplate.opsForList().rightPush(key, pivot, value); + } + + /** + * 通过索引设置列表元素的值 + * + * @param key + * @param index + * 位置 + * @param value + */ + public void lSet(String key, long index, String value) { + redisTemplate.opsForList().set(key, index, value); + } + + /** + * 移出并获取列表的第一个元素 + * + * @param key + * @return 删除的元素 + */ + public String lLeftPop(String key) { + return redisTemplate.opsForList().leftPop(key); + } + + /** + * 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 + * + * @param key + * @param timeout + * 等待时间 + * @param unit + * 时间单位 + * @return + */ + public String lBLeftPop(String key, long timeout, TimeUnit unit) { + return redisTemplate.opsForList().leftPop(key, timeout, unit); + } + + /** + * 移除并获取列表最后一个元素 + * + * @param key + * @return 删除的元素 + */ + public String lRightPop(String key) { + return redisTemplate.opsForList().rightPop(key); + } + + /** + * 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 + * + * @param key + * @param timeout + * 等待时间 + * @param unit + * 时间单位 + * @return + */ + public String lBRightPop(String key, long timeout, TimeUnit unit) { + return redisTemplate.opsForList().rightPop(key, timeout, unit); + } + + /** + * 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 + * + * @param sourceKey + * @param destinationKey + * @return + */ + public String lRightPopAndLeftPush(String sourceKey, String destinationKey) { + return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, + destinationKey); + } + + /** + * 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 + * + * @param sourceKey + * @param destinationKey + * @param timeout + * @param unit + * @return + */ + public String lBRightPopAndLeftPush(String sourceKey, String destinationKey, + long timeout, TimeUnit unit) { + return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, + destinationKey, timeout, unit); + } + + /** + * 删除集合中值等于value得元素 + * + * @param key + * @param index + * index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素; + * index<0, 从尾部开始删除第一个值等于value的元素; + * @param value + * @return + */ + public Long lRemove(String key, long index, String value) { + return redisTemplate.opsForList().remove(key, index, value); + } + + /** + * 裁剪list + * + * @param key + * @param start + * @param end + */ + public void lTrim(String key, long start, long end) { + redisTemplate.opsForList().trim(key, start, end); + } + + /** + * 获取列表长度 + * + * @param key + * @return + */ + public Long lLen(String key) { + return redisTemplate.opsForList().size(key); + } + + /** --------------------set相关操作-------------------------- */ + + /** + * set添加元素 + * + * @param key + * @param values + * @return + */ + public Long sAdd(String key, String... values) { + return redisTemplate.opsForSet().add(key, values); + } + + /** + * set移除元素 + * + * @param key + * @param values + * @return + */ + public Long sRemove(String key, Object... values) { + return redisTemplate.opsForSet().remove(key, values); + } + + /** + * 移除并返回集合的一个随机元素 + * + * @param key + * @return + */ + public String sPop(String key) { + return redisTemplate.opsForSet().pop(key); + } + + /** + * 将元素value从一个集合移到另一个集合 + * + * @param key + * @param value + * @param destKey + * @return + */ + public Boolean sMove(String key, String value, String destKey) { + return redisTemplate.opsForSet().move(key, value, destKey); + } + + /** + * 获取集合的大小 + * + * @param key + * @return + */ + public Long sSize(String key) { + return redisTemplate.opsForSet().size(key); + } + + /** + * 判断集合是否包含value + * + * @param key + * @param value + * @return + */ + public Boolean sIsMember(String key, Object value) { + return redisTemplate.opsForSet().isMember(key, value); + } + + /** + * 获取两个集合的交集 + * + * @param key + * @param otherKey + * @return + */ + public Set sIntersect(String key, String otherKey) { + return redisTemplate.opsForSet().intersect(key, otherKey); + } + + /** + * 获取key集合与多个集合的交集 + * + * @param key + * @param otherKeys + * @return + */ + public Set sIntersect(String key, Collection otherKeys) { + return redisTemplate.opsForSet().intersect(key, otherKeys); + } + + /** + * key集合与otherKey集合的交集存储到destKey集合中 + * + * @param key + * @param otherKey + * @param destKey + * @return + */ + public Long sIntersectAndStore(String key, String otherKey, String destKey) { + return redisTemplate.opsForSet().intersectAndStore(key, otherKey, + destKey); + } + + /** + * key集合与多个集合的交集存储到destKey集合中 + * + * @param key + * @param otherKeys + * @param destKey + * @return + */ + public Long sIntersectAndStore(String key, Collection otherKeys, + String destKey) { + return redisTemplate.opsForSet().intersectAndStore(key, otherKeys, + destKey); + } + + /** + * 获取两个集合的并集 + * + * @param key + * @param otherKeys + * @return + */ + public Set sUnion(String key, String otherKeys) { + return redisTemplate.opsForSet().union(key, otherKeys); + } + + /** + * 获取key集合与多个集合的并集 + * + * @param key + * @param otherKeys + * @return + */ + public Set sUnion(String key, Collection otherKeys) { + return redisTemplate.opsForSet().union(key, otherKeys); + } + + /** + * key集合与otherKey集合的并集存储到destKey中 + * + * @param key + * @param otherKey + * @param destKey + * @return + */ + public Long sUnionAndStore(String key, String otherKey, String destKey) { + return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey); + } + + /** + * key集合与多个集合的并集存储到destKey中 + * + * @param key + * @param otherKeys + * @param destKey + * @return + */ + public Long sUnionAndStore(String key, Collection otherKeys, + String destKey) { + return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey); + } + + /** + * 获取两个集合的差集 + * + * @param key + * @param otherKey + * @return + */ + public Set sDifference(String key, String otherKey) { + return redisTemplate.opsForSet().difference(key, otherKey); + } + + /** + * 获取key集合与多个集合的差集 + * + * @param key + * @param otherKeys + * @return + */ + public Set sDifference(String key, Collection otherKeys) { + return redisTemplate.opsForSet().difference(key, otherKeys); + } + + /** + * key集合与otherKey集合的差集存储到destKey中 + * + * @param key + * @param otherKey + * @param destKey + * @return + */ + public Long sDifference(String key, String otherKey, String destKey) { + return redisTemplate.opsForSet().differenceAndStore(key, otherKey, + destKey); + } + + /** + * key集合与多个集合的差集存储到destKey中 + * + * @param key + * @param otherKeys + * @param destKey + * @return + */ + public Long sDifference(String key, Collection otherKeys, + String destKey) { + return redisTemplate.opsForSet().differenceAndStore(key, otherKeys, + destKey); + } + + /** + * 获取集合所有元素 + * + * @param key + * @param otherKeys + * @param destKey + * @return + */ + public Set setMembers(String key) { + return redisTemplate.opsForSet().members(key); + } + + /** + * 随机获取集合中的一个元素 + * + * @param key + * @return + */ + public String sRandomMember(String key) { + return redisTemplate.opsForSet().randomMember(key); + } + + /** + * 随机获取集合中count个元素 + * + * @param key + * @param count + * @return + */ + public List sRandomMembers(String key, long count) { + return redisTemplate.opsForSet().randomMembers(key, count); + } + + /** + * 随机获取集合中count个元素并且去除重复的 + * + * @param key + * @param count + * @return + */ + public Set sDistinctRandomMembers(String key, long count) { + return redisTemplate.opsForSet().distinctRandomMembers(key, count); + } + + /** + * + * @param key + * @param options + * @return + */ + public Cursor sScan(String key, ScanOptions options) { + return redisTemplate.opsForSet().scan(key, options); + } + + /**------------------zSet相关操作--------------------------------*/ + + /** + * 添加元素,有序集合是按照元素的score值由小到大排列 + * + * @param key + * @param value + * @param score + * @return + */ + public Boolean zAdd(String key, String value, double score) { + return redisTemplate.opsForZSet().add(key, value, score); + } + + /** + * + * @param key + * @param values + * @return + */ + public Long zAdd(String key, Set> values) { + return redisTemplate.opsForZSet().add(key, values); + } + + /** + * + * @param key + * @param values + * @return + */ + public Long zRemove(String key, Object... values) { + return redisTemplate.opsForZSet().remove(key, values); + } + + /** + * 增加元素的score值,并返回增加后的值 + * + * @param key + * @param value + * @param delta + * @return + */ + public Double zIncrementScore(String key, String value, double delta) { + return redisTemplate.opsForZSet().incrementScore(key, value, delta); + } + + /** + * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列 + * + * @param key + * @param value + * @return 0表示第一位 + */ + public Long zRank(String key, Object value) { + return redisTemplate.opsForZSet().rank(key, value); + } + + /** + * 返回元素在集合的排名,按元素的score值由大到小排列 + * + * @param key + * @param value + * @return + */ + public Long zReverseRank(String key, Object value) { + return redisTemplate.opsForZSet().reverseRank(key, value); + } + + /** + * 获取集合的元素, 从小到大排序 + * + * @param key + * @param start + * 开始位置 + * @param end + * 结束位置, -1查询所有 + * @return + */ + public Set zRange(String key, long start, long end) { + return redisTemplate.opsForZSet().range(key, start, end); + } + + /** + * 获取集合元素, 并且把score值也获取 + * + * @param key + * @param start + * @param end + * @return + */ + public Set> zRangeWithScores(String key, long start, + long end) { + return redisTemplate.opsForZSet().rangeWithScores(key, start, end); + } + + /** + * 根据Score值查询集合元素 + * + * @param key + * @param min + * 最小值 + * @param max + * 最大值 + * @return + */ + public Set zRangeByScore(String key, double min, double max) { + return redisTemplate.opsForZSet().rangeByScore(key, min, max); + } + + /** + * 根据Score值查询集合元素, 从小到大排序 + * + * @param key + * @param min + * 最小值 + * @param max + * 最大值 + * @return + */ + public Set> zRangeByScoreWithScores(String key, + double min, double max) { + return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max); + } + + /** + * + * @param key + * @param min + * @param max + * @param start + * @param end + * @return + */ + public Set> zRangeByScoreWithScores(String key, + double min, double max, long start, long end) { + return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, + start, end); + } + + /** + * 获取集合的元素, 从大到小排序 + * + * @param key + * @param start + * @param end + * @return + */ + public Set zReverseRange(String key, long start, long end) { + return redisTemplate.opsForZSet().reverseRange(key, start, end); + } + + /** + * 获取集合的元素, 从大到小排序, 并返回score值 + * + * @param key + * @param start + * @param end + * @return + */ + public Set> zReverseRangeWithScores(String key, + long start, long end) { + return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, + end); + } + + /** + * 根据Score值查询集合元素, 从大到小排序 + * + * @param key + * @param min + * @param max + * @return + */ + public Set zReverseRangeByScore(String key, double min, + double max) { + return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max); + } + + /** + * 根据Score值查询集合元素, 从大到小排序 + * + * @param key + * @param min + * @param max + * @return + */ + public Set> zReverseRangeByScoreWithScores( + String key, double min, double max) { + return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, + min, max); + } + + /** + * + * @param key + * @param min + * @param max + * @param start + * @param end + * @return + */ + public Set zReverseRangeByScore(String key, double min, + double max, long start, long end) { + return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, + start, end); + } + + /** + * 根据score值获取集合元素数量 + * + * @param key + * @param min + * @param max + * @return + */ + public Long zCount(String key, double min, double max) { + return redisTemplate.opsForZSet().count(key, min, max); + } + + /** + * 获取集合大小 + * + * @param key + * @return + */ + public Long zSize(String key) { + return redisTemplate.opsForZSet().size(key); + } + + /** + * 获取集合大小 + * + * @param key + * @return + */ + public Long zZCard(String key) { + return redisTemplate.opsForZSet().zCard(key); + } + + /** + * 获取集合中value元素的score值 + * + * @param key + * @param value + * @return + */ + public Double zScore(String key, Object value) { + return redisTemplate.opsForZSet().score(key, value); + } + + /** + * 移除指定索引位置的成员 + * + * @param key + * @param start + * @param end + * @return + */ + public Long zRemoveRange(String key, long start, long end) { + return redisTemplate.opsForZSet().removeRange(key, start, end); + } + + /** + * 根据指定的score值的范围来移除成员 + * + * @param key + * @param min + * @param max + * @return + */ + public Long zRemoveRangeByScore(String key, double min, double max) { + return redisTemplate.opsForZSet().removeRangeByScore(key, min, max); + } + + /** + * 获取key和otherKey的并集并存储在destKey中 + * + * @param key + * @param otherKey + * @param destKey + * @return + */ + public Long zUnionAndStore(String key, String otherKey, String destKey) { + return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey); + } + + /** + * + * @param key + * @param otherKeys + * @param destKey + * @return + */ + public Long zUnionAndStore(String key, Collection otherKeys, + String destKey) { + return redisTemplate.opsForZSet() + .unionAndStore(key, otherKeys, destKey); + } + + /** + * 交集 + * + * @param key + * @param otherKey + * @param destKey + * @return + */ + public Long zIntersectAndStore(String key, String otherKey, + String destKey) { + return redisTemplate.opsForZSet().intersectAndStore(key, otherKey, + destKey); + } + + /** + * 交集 + * + * @param key + * @param otherKeys + * @param destKey + * @return + */ + public Long zIntersectAndStore(String key, Collection otherKeys, + String destKey) { + return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys, + destKey); + } + + /** + * + * @param key + * @param options + * @return + */ + public Cursor> zScan(String key, ScanOptions options) { + return redisTemplate.opsForZSet().scan(key, options); + } + + /** + * 获取Redis List 序列化 + * @param key + * @param targetClass + * @param + * @return + */ + public List getListCache(final String key, Class targetClass) { + byte[] result = redisTemplate.execute(new RedisCallback() { + @Override + public byte[] doInRedis(RedisConnection connection) throws DataAccessException { + return connection.get(key.getBytes()); + } + }); + if (result == null) { + return null; + } + return ProtoStuffSerializerUtil.deserializeList(result, targetClass); + } + + /*** + * 将List 放进缓存里面 + * @param key + * @param objList + * @param expireTime + * @param + * @return + */ + public boolean putListCacheWithExpireTime(String key, List objList, final long expireTime) { + final byte[] bkey = key.getBytes(); + final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList); + boolean result = redisTemplate.execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws DataAccessException { + connection.setEx(bkey, expireTime, bvalue); + return true; + } + }); + return result; + } +} \ No newline at end of file diff --git a/src/main/java/cn/celess/blog/util/RegexUtil.java b/src/main/java/cn/celess/blog/util/RegexUtil.java new file mode 100644 index 0000000..6926229 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/RegexUtil.java @@ -0,0 +1,80 @@ +package cn.celess.blog.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author : xiaohai + * @date : 2019/05/12 11:04 + */ +public class RegexUtil { + /** + * 网址匹配 + * + * @param url + * @return + */ + public static boolean urlMatch(String url) { + if (url == null || url.replaceAll(" ", "").isEmpty()) { + return false; + } + //正则 (http(s)://www.celess/xxxx,www.celess.cn/xxx) + String pattern = "^(http://|https://|)([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?$"; + return match(url, pattern); + } + + /** + * 邮箱验证 + * + * @param email + * @return + */ + public static boolean emailMatch(String email) { + if (email == null || email.replaceAll(" ", "").isEmpty()) { + return false; + } + //正则 + String pattern = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$"; + return match(email, pattern); + } + + /** + * 手机号匹配 + * + * @param phone + * @return + */ + public static boolean phoneMatch(String phone) { + if (phone == null || phone.replaceAll(" ", "").isEmpty()) { + return false; + } + //正则 + String pattern = "^([1][3,4,5,6,7,8,9])\\d{9}$"; + return match(phone, pattern); + } + + /** + * 密码正则 + * 最短6位,最长16位 {6,16} + * 可以包含小写大母 [a-z] 和大写字母 [A-Z] + * 可以包含数字 [0-9] + * 可以包含下划线 [ _ ] 和减号 [ - ] + * + * @param pwd + * @return + */ + public static boolean pwdMatch(String pwd) { + if (pwd == null || pwd.replaceAll(" ", "").isEmpty()) { + return false; + } + //正则 + String pattern = "^[\\w_-]{6,16}$"; + return match(pwd, pattern); + } + + private static boolean match(String str, String pattern) { + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(str); + return m.matches(); + } +} diff --git a/src/main/java/cn/celess/blog/util/RequestUtil.java b/src/main/java/cn/celess/blog/util/RequestUtil.java new file mode 100644 index 0000000..1a5336e --- /dev/null +++ b/src/main/java/cn/celess/blog/util/RequestUtil.java @@ -0,0 +1,17 @@ +package cn.celess.blog.util; + +import javax.servlet.http.HttpServletRequest; + +/** + * @Author: 小海 + * @Date: 2019/10/18 15:44 + * @Description: + */ +public class RequestUtil { + public static String getCompleteUrlAndMethod(HttpServletRequest request) { + // like this : /articles?page=1&count=5:GET + return request.getRequestURI() + + (request.getQueryString() == null ? "" : "?" + request.getQueryString()) + + ":" + request.getMethod(); + } +} diff --git a/src/main/java/cn/celess/blog/util/ResponseUtil.java b/src/main/java/cn/celess/blog/util/ResponseUtil.java new file mode 100644 index 0000000..0cf49e5 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/ResponseUtil.java @@ -0,0 +1,59 @@ +package cn.celess.blog.util; + +import cn.celess.blog.enmu.ResponseEnum; +import cn.celess.blog.entity.Response; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author : xiaohai + * @date : 2019/03/28 15:32 + */ +@ResponseBody +public class ResponseUtil { + + /** + * 成功相应 + * + * @param result 结果 + * @return + */ + public static Response success(Object result) { + Response response = new Response(); + response.setCode(ResponseEnum.SUCCESS.getCode()); + response.setMsg(ResponseEnum.SUCCESS.getMsg()); + response.setDate(System.currentTimeMillis()); + response.setResult(result); + return response; + } + + /** + * 失败的响应 + * + * @param result 结果 + * @return + */ + public static Response failure(String result) { + Response response = new Response(); + response.setCode(ResponseEnum.FAILURE.getCode()); + response.setMsg(ResponseEnum.FAILURE.getMsg()); + response.setDate(System.currentTimeMillis()); + response.setResult(result); + return response; + } + + /** + * 其他的响应 + * + * @param r 枚举常量 + * @param result 结果 + * @return + */ + public static Response response(ResponseEnum r, String result) { + Response response = new Response(); + response.setCode(r.getCode()); + response.setMsg(r.getMsg()); + response.setDate(System.currentTimeMillis()); + response.setResult(result); + return response; + } +} diff --git a/src/main/java/cn/celess/blog/util/SitemapGenerateUtil.java b/src/main/java/cn/celess/blog/util/SitemapGenerateUtil.java new file mode 100644 index 0000000..ebcc737 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/SitemapGenerateUtil.java @@ -0,0 +1,109 @@ +package cn.celess.blog.util; + +import cn.celess.blog.entity.Article; +import cn.celess.blog.mapper.ArticleMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import java.io.File; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Author: 小海 + * @Date: 2019/07/30 17:29 + * @Description: + */ +@Component +public class SitemapGenerateUtil { + + @Value("${sitemap.path}") + private String path; + private Map urlList; + + @Autowired + ArticleMapper articleMapper; + + @Async + public void createSitemap() { + initList(); + File file = new File(path); + try { + if (file.exists()) { + file.delete(); + } else { + file.createNewFile(); + } + } catch (IOException e) { + e.printStackTrace(); + } + DocumentBuilder db = getDocumentBuilder(); + Document document = db.newDocument(); + document.setXmlVersion("1.0"); + document.setXmlStandalone(true); + Element urlset = document.createElement("urlset"); + urlset.setAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9"); + // 创建url 结点 + urlList.forEach((s, s2) -> { + Element url = document.createElement("url"); + Element loc = document.createElement("loc"); + Element lastmod = document.createElement("lastmod"); + loc.setTextContent(s); + lastmod.setTextContent(s2); + url.appendChild(loc); + url.appendChild(lastmod); + urlset.appendChild(url); + }); + document.appendChild(urlset); + try { + TransformerFactory tff = TransformerFactory.newInstance(); + Transformer tf = tff.newTransformer(); + tf.setOutputProperty(OutputKeys.INDENT, "yes"); + tf.transform(new DOMSource(document), new StreamResult(file)); + } catch (TransformerException e) { + e.printStackTrace(); + } + } + + private void initList() { + urlList = new HashMap<>(); + urlList.put("https://www.celess.cn", DateFormatUtil.getForXmlDate(new Date())); + urlList.put("https://www.celess.cn/links", DateFormatUtil.getForXmlDate(new Date())); + urlList.put("https://www.celess.cn/leaveMsg", DateFormatUtil.getForXmlDate(new Date())); + List
articles = articleMapper.findAll(); + articles.forEach(article -> { + urlList.put("https://www.celess.cn/article/" + article.getId(), DateFormatUtil.getForXmlDate( + article.getUpdateDate() == null ? article.getPublishDate() : article.getUpdateDate())); + }); + } + + + private static DocumentBuilder getDocumentBuilder() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = null; + try { + db = dbf.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } + return db; + } + +} + diff --git a/src/main/java/cn/celess/blog/util/StringFromHtmlUtil.java b/src/main/java/cn/celess/blog/util/StringFromHtmlUtil.java new file mode 100644 index 0000000..afd1502 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/StringFromHtmlUtil.java @@ -0,0 +1,17 @@ +package cn.celess.blog.util; + +/** + * @author : xiaohai + * @date : 2019/03/28 17:21 + */ +public class StringFromHtmlUtil { + public static String getString(String html) { + //从html中提取纯文本 + //剔出的标签 + String txtcontent = html.replaceAll("]+>", ""); + //去除字符串中的空格,回车,换行符,制表符 + txtcontent = txtcontent.replaceAll("\\s*|\t|\r|\n", ""); + return txtcontent; + } +} + diff --git a/src/main/java/cn/celess/blog/util/VeriCodeUtil.java b/src/main/java/cn/celess/blog/util/VeriCodeUtil.java new file mode 100644 index 0000000..e3cb153 --- /dev/null +++ b/src/main/java/cn/celess/blog/util/VeriCodeUtil.java @@ -0,0 +1,90 @@ +package cn.celess.blog.util; + + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Random; + +/** + * @author : xiaohai + * @date : 2019/04/11 15:42 + */ + +public class VeriCodeUtil { + // 验证码字符集 + private static final char[] chars = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + + // 字符数量 + private static final int SIZE = 4; + // 干扰线数量 + private static final int LINES = 5; + // 宽度 + private static final int WIDTH = 80; + // 高度 + private static final int HEIGHT = 40; + // 字体大小 + private static final int FONT_SIZE = 30; + + /** + * 生成随机验证码及图片 + * Object[0]:验证码字符串; + * Object[1]:验证码图片。 + */ + public static Object[] createImage() { + StringBuffer sb = new StringBuffer(); + // 1.创建空白图片 + BufferedImage image = new BufferedImage( + WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); + // 2.获取图片画笔 + Graphics graphic = image.getGraphics(); + // 3.设置画笔颜色 + graphic.setColor(Color.LIGHT_GRAY); + // 4.绘制矩形背景 + graphic.fillRect(0, 0, WIDTH, HEIGHT); + // 5.画随机字符 + Random ran = new Random(); + for (int i = 0; i < SIZE; i++) { + // 取随机字符索引 + int n = ran.nextInt(chars.length); + // 设置随机颜色 + graphic.setColor(getRandomColor()); + // 设置字体大小 + graphic.setFont(new Font( + null, Font.BOLD + Font.ITALIC, FONT_SIZE)); + // 画字符 + graphic.drawString( + chars[n] + "", i * WIDTH / SIZE, HEIGHT * 2 / 3); + // 记录字符 + sb.append(chars[n]); + } + // 6.画干扰线 + for (int i = 0; i < LINES; i++) { + // 设置随机颜色 + graphic.setColor(getRandomColor()); + // 随机画线 + graphic.drawLine(ran.nextInt(WIDTH), ran.nextInt(HEIGHT), + ran.nextInt(WIDTH), ran.nextInt(HEIGHT)); + } + // 7.返回验证码和图片 + return new Object[]{sb.toString(), image}; + } + + /** + * 随机取色 + */ + public static Color getRandomColor() { + Random ran = new Random(); + Color color = new Color(ran.nextInt(256), + ran.nextInt(256), ran.nextInt(256)); + return color; + } + + +} + + diff --git a/src/main/resources/application-openSource.properties b/src/main/resources/application-openSource.properties new file mode 100644 index 0000000..ad00d95 --- /dev/null +++ b/src/main/resources/application-openSource.properties @@ -0,0 +1,75 @@ +server.port=8081 + +spring.jpa.show-sql=false +spring.jpa.hibernate.ddl-auto=update +# 上传单个文件的大小 +spring.servlet.multipart.max-file-size=10MB +# 上传文件的总大小 +spring.servlet.multipart.max-request-size=10MB +##null字段不显示 +spring.jackson.default-property-inclusion=non_null + + +################# 数据库 ################## +#请先填写下面的配置 +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +spring.datasource.url= +spring.datasource.username= +spring.datasource.password= +spring.datasource.driver-class-name=com.mysql.jdbc.Driver + + +################## mybatis ################## +mybatis.mapper-locations=classpath:mapper/*.xml +mybatis.type-aliases-package=cn.celess.blog.entity + + +pagehelper.helper-dialect=mysql +pagehelper.reasonable=true +pagehelper.support-methods-arguments=true +pagehelper.params=count=countSql + + + + +################ email ############## +#请先填写下面的配置,不然可能运行不起来 +spring.mail.host= +spring.mail.username= +spring.mail.password= +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true +spring.mail.properties.mail.smtp.starttls.required=true +spring.mail.default-encoding=UTF-8 +spring.mail.port=465 +spring.mail.properties.mail.smtp.socketFactory.port=465 +spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory +spring.mail.properties.mail.smtp.socketFactory.fallback=false + + +#### 用于nginx的代理 获取真实ip +server.use-forward-headers = true +server.tomcat.remote-ip-header = X-Real-IP +server.tomcat.protocol-header = X-Forwarded-Proto + + +############### redis ############## +# REDIS (RedisProperties) +# Redis数据库索引(默认为0) +spring.redis.database=0 +# Redis服务器地址 +spring.redis.host= +# Redis服务器连接端口 +spring.redis.port=6379 +# Redis服务器连接密码(默认为空) +spring.redis.password= +# 连接池最大连接数(使用负值表示没有限制) +spring.redis.jedis.pool.max-active=-1 +# 连接池最大阻塞等待时间(使用负值表示没有限制) +spring.redis.jedis.pool.max-wait=-1 +# 连接池中的最大空闲连接 +spring.redis.jedis.pool.max-idle=8 +# 连接池中的最小空闲连接 +spring.redis.jedis.pool.min-idle=0 +# 连接超时时间(毫秒) +spring.redis.timeout=5000 \ No newline at end of file diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties new file mode 100644 index 0000000..6fa9d06 --- /dev/null +++ b/src/main/resources/application-test.properties @@ -0,0 +1,80 @@ +server.port=8081 + +sitemap.path=C:\\Users\\zh564\\Desktop\\sitemap.xml + +##spring.jpa.show-sql=false +##spring.jpa.hibernate.ddl-auto=update + +mybatis.type-handlers-package=cn.celess.blog.mapper.typehandler + +# 上传单个文件的大小 +spring.servlet.multipart.max-file-size=10MB +# 上传文件的总大小 +spring.servlet.multipart.max-request-size=10MB + +spring.jackson.default-property-inclusion=non_null + + +################# 数据库 ################## +spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +spring.datasource.url=jdbc:mysql://localhost:3306/test_blog?serverTimezone=UCT&allowPublicKeyRetrieval=true&useSSL=false +spring.datasource.username=root +spring.datasource.password=zhenghai +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + + +################## mybatis ################## +mybatis.mapper-locations=classpath:mapper/*.xml +mybatis.type-aliases-package=cn.celess.blog.entity + + +pagehelper.helper-dialect=mysql +pagehelper.reasonable=true +pagehelper.support-methods-arguments=true +pagehelper.params=count=countSql + + + +#### 用于nginx的代理 获取真实ip +server.use-forward-headers = true +server.tomcat.remote-ip-header = X-Real-IP +server.tomcat.protocol-header = X-Forwarded-Proto + + +############### email ############## +spring.mail.host=smtp.163.com +spring.mail.username= +spring.mail.password= +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true +spring.mail.properties.mail.smtp.starttls.required=true +spring.mail.default-encoding=UTF-8 +spring.mail.port=465 +spring.mail.properties.mail.smtp.socketFactory.port=465 +spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory +spring.mail.properties.mail.smtp.socketFactory.fallback=false + + + +############### redis ############## + +# REDIS (RedisProperties) +# Redis数据库索引(默认为0) +spring.redis.database=1 +# Redis服务器地址 +spring.redis.host=127.0.0.1 +# Redis服务器连接端口 +spring.redis.port=6379 +# Redis服务器连接密码(默认为空) +spring.redis.password= +# 连接池最大连接数(使用负值表示没有限制) +spring.redis.jedis.pool.max-active=-1 +# 连接池最大阻塞等待时间(使用负值表示没有限制) +spring.redis.jedis.pool.max-wait=-1 +# 连接池中的最大空闲连接 +spring.redis.jedis.pool.max-idle=8 +# 连接池中的最小空闲连接 +spring.redis.jedis.pool.min-idle=0 +# 连接超时时间(毫秒) +spring.redis.timeout=5000 + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..37a7772 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,5 @@ +spring.profiles.active=prod +####七牛的配置 +####cn.celess.blog.service.serviceimpl.QiniuServiceImpl +logging.level.cn.celess.blog=debug +logging.level.cn.celess.blog.mapper=info \ No newline at end of file diff --git a/src/main/resources/mapper/CategoryMapper.xml b/src/main/resources/mapper/CategoryMapper.xml new file mode 100644 index 0000000..0a0c444 --- /dev/null +++ b/src/main/resources/mapper/CategoryMapper.xml @@ -0,0 +1,84 @@ + + + + + + + + + + insert into category (c_name, articles) + values (#{name}, #{articles}); + + SELECT LAST_INSERT_ID() AS id + + + + + update category + set c_name=#{name}, + articles=#{articles} + where c_id = #{id} + + + + delete + from category + where c_id = #{id} + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/CommentMapper.xml b/src/main/resources/mapper/CommentMapper.xml new file mode 100644 index 0000000..94c9973 --- /dev/null +++ b/src/main/resources/mapper/CommentMapper.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + insert into comment (co_article_id, is_comment, author_id, co_content, co_date, co_pid) + VALUES (#{articleID}, #{type}, #{authorID}, #{content}, #{date}, #{pid}) + + SELECT LAST_INSERT_ID() AS id + + + + + update comment + set co_content=#{content} + where co_id = #{id} + + + + update comment + set co_response_id =#{responder} + where co_id = #{id} + + + delete + from comment + where co_id = #{id} + + + delete + from comment + where co_article_id = #{articleId} + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/PartnerSiteMapper.xml b/src/main/resources/mapper/PartnerSiteMapper.xml new file mode 100644 index 0000000..563521d --- /dev/null +++ b/src/main/resources/mapper/PartnerSiteMapper.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + insert into links (site_name, is_open, site_url) + values (#{name}, #{open}, #{url}) + + SELECT LAST_INSERT_ID() AS id + + + + + update links set + site_name=#{name}, + site_url=#{url}, + is_open=#{open} + where site_id=#{id} + + + + delete + from links + where site_id = #{id} + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..b9888b8 --- /dev/null +++ b/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + insert into user(u_email, u_pwd) + values (#{email}, #{pwd}) + + + + update user set + `u_desc`=#{desc}, + `display_name`=#{displayName} + where u_id=#{id} + + + update user + set `recently_landed_time`=#{date} + where `u_email` = #{email} + + + update user + set `u_avatar`=#{avatarImgUrl} + where `u_id` = #{id} + + + update user + set `email_status`=#{status} + where `u_email` = #{email} + + + update user + set `u_pwd`=#{pwd} + where `u_email` = #{email} + + + update user + set role=#{role} + where u_id = #{uid} + + + update user + set `u_email` = #{email}, + `u_pwd` = #{pwd}, + `email_status` = #{emailStatus}, + `u_desc` = #{desc}, + `display_name` = #{displayName}, + `role` = #{role} + where `u_id` = #{id} + + + delete + from user + where u_id = #{id} + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/VisitorMapper.xml b/src/main/resources/mapper/VisitorMapper.xml new file mode 100644 index 0000000..d1899ce --- /dev/null +++ b/src/main/resources/mapper/VisitorMapper.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + insert into visitor (v_date, v_ip, v_user_agent) + values (#{date}, #{ip}, #{ua}) + + SELECT LAST_INSERT_ID() AS id + + + + delete + from visitor + where v_id = #{id} + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/WebUpdateInfoMapper.xml b/src/main/resources/mapper/WebUpdateInfoMapper.xml new file mode 100644 index 0000000..db9f799 --- /dev/null +++ b/src/main/resources/mapper/WebUpdateInfoMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + + + insert into web_update(update_info, update_time) + values (#{updateInfo}, #{updateTime}) + + SELECT LAST_INSERT_ID() AS id + + + + + update web_update + set update_info=#{info} + where update_id = #{id}; + + + + + delete + from web_update + where update_id = #{id} + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/articleMapper.xml b/src/main/resources/mapper/articleMapper.xml new file mode 100644 index 0000000..e994535 --- /dev/null +++ b/src/main/resources/mapper/articleMapper.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + insert into article (a_author_id, a_category_id, a_tags_id, a_md_content, a_publish_date, + a_summary, a_title, a_url) + values (#{authorId}, #{categoryId}, #{tagsId}, #{mdContent}, #{publishDate}, + #{summary}, #{title}, #{url}) + + SELECT LAST_INSERT_ID() AS id + + + + delete + from article + where a_id = #{id} + + + + update article + set + a_title=#{title}, + a_md_content=#{mdContent}, + a_summary=#{summary}, + a_is_original=#{type}, + a_url=#{url}, + a_update_date=#{updateDate}, + a_category_id=#{categoryId}, + a_tags_id=#{tagsId}, + next_a_id=#{nextArticleId}, + pre_a_id=#{preArticleId}, + a_is_open=#{open} + where a_id = #{id} + + + + update article + set next_a_id=#{nextArticleID} + where a_id = #{targetArticleID} + + + + update article + set pre_a_id=#{preArticleID} + where a_id = #{targetArticleID} + + + update article + set a_reading_number=#{number} + where a_id = #{id} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/tagMapper.xml b/src/main/resources/mapper/tagMapper.xml new file mode 100644 index 0000000..7c976e9 --- /dev/null +++ b/src/main/resources/mapper/tagMapper.xml @@ -0,0 +1,75 @@ + + + + + + + + + + insert into tag (tag_name, articles) + VALUES (#{name}, #{articles}); + + SELECT LAST_INSERT_ID() AS id + + + + + update tag + set tag_name=#{name}, + articles=#{articles} + where tag_id = #{id} + + + + delete + from tag + where tag_id = #{id} + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/BaseTest.java b/src/test/java/cn/celess/blog/BaseTest.java new file mode 100644 index 0000000..d29e89e --- /dev/null +++ b/src/test/java/cn/celess/blog/BaseTest.java @@ -0,0 +1,97 @@ +package cn.celess.blog; + +import cn.celess.blog.entity.request.LoginReq; +import net.sf.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultHandler; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import javax.servlet.http.Cookie; + +import static org.junit.Assert.*; + +/** + * @Author: 小海 + * @Date: 2019/08/22 12:46 + * @Description: 测试基类 + */ +@SpringBootTest +@RunWith(SpringRunner.class) +@WebAppConfiguration +@ActiveProfiles("test") +public class BaseTest { + + protected MockMvc mockMvc; + protected final static String Code = "code"; + protected final static String Result = "result"; + + @Autowired + private WebApplicationContext wac; + + @Before + public void before() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + System.out.println("==========> 开始测试 <========="); + } + + @After + public void after() { + System.out.println("==========> 测试结束 <========="); + } + + + protected String adminLogin() { + try { + LoginReq req = new LoginReq(); + req.setEmail("a@celess.cn"); + req.setPassword("123456789"); + req.setIsRememberMe(false); + JSONObject loginReq = JSONObject.fromObject(req); + String str = mockMvc.perform(MockMvcRequestBuilders.post("/login").content(loginReq.toString()).contentType("application/json")) +// .andDo(MockMvcResultHandlers.print()) + .andReturn().getResponse().getContentAsString(); + String token = JSONObject.fromObject(str).getJSONObject(Result).getString("token"); + assertNotNull(token); + return token; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + protected String userLogin() { + try { + LoginReq req = new LoginReq(); + req.setEmail("zh56462271@qq.com"); + req.setPassword("123456789"); + req.setIsRememberMe(false); + JSONObject loginReq = JSONObject.fromObject(req); + String str = mockMvc.perform(MockMvcRequestBuilders.post("/login").content(loginReq.toString()).contentType("application/json")) +// .andDo(MockMvcResultHandlers.print()) + .andReturn().getResponse().getContentAsString(); + String token = JSONObject.fromObject(str).getJSONObject(Result).getString("token"); + assertNotNull(token); + return token; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Test + public void test() { + + } +} diff --git a/src/test/java/cn/celess/blog/controller/ArticleControllerTest.java b/src/test/java/cn/celess/blog/controller/ArticleControllerTest.java new file mode 100644 index 0000000..de811ce --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/ArticleControllerTest.java @@ -0,0 +1,407 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.Article; +import cn.celess.blog.entity.Response; +import cn.celess.blog.entity.model.ArticleModel; +import cn.celess.blog.entity.request.ArticleReq; +import cn.celess.blog.mapper.ArticleMapper; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + + +import java.util.Arrays; +import java.util.UUID; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static cn.celess.blog.enmu.ResponseEnum.*; + +public class ArticleControllerTest extends BaseTest { + @Autowired + ArticleMapper articleMapper; + + @Test + public void create() { + ArticleReq articleReq = new ArticleReq(); + // 应该正常通过 + articleReq.setTitle("test-" + UUID.randomUUID().toString()); + articleReq.setMdContent("# test title"); + articleReq.setCategory("随笔"); + articleReq.setTags("test,SpringMvc"); + articleReq.setOpen(true); + articleReq.setType(true); + articleReq.setUrl("http://xxxx.com"); + JSONObject jsonObject = JSONObject.fromObject(articleReq); + + try { + // 未登录 + mockMvc.perform(post("/admin/article/create") + .content(jsonObject.toString()) + .contentType("application/json")) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), + JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code) + ); + }); + // User权限 + String token = userLogin(); + mockMvc.perform(post("/admin/article/create") + .content(jsonObject.toString()) + .contentType("application/json") + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(PERMISSION_ERROR.getCode(), + JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code) + ); + }); + + // Admin权限 + token = adminLogin(); + mockMvc.perform(post("/admin/article/create") + .content(jsonObject.toString()) + .contentType("application/json") + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + ArticleModel articleModel = (ArticleModel) JSONObject.toBean(object.getJSONObject(Result), ArticleModel.class); + assertNotNull(articleModel.getId()); + assertNotNull(articleModel.getTitle()); + assertNotNull(articleModel.getSummary()); + assertNotNull(articleModel.getOriginal()); + assertNotNull(articleModel.getTags()); + assertNotNull(articleModel.getCategory()); + assertNotNull(articleModel.getPublishDateFormat()); + assertNotNull(articleModel.getMdContent()); + assertNotNull(articleModel.getNextArticleId()); + assertNotNull(articleModel.getNextArticleTitle()); + assertNotNull(articleModel.getPreArticleId()); + assertNotNull(articleModel.getPreArticleTitle()); + assertNotNull(articleModel.getOpen()); + assertNotNull(articleModel.getReadingNumber()); + assertNotNull(articleModel.getAuthorName()); + assertNotNull(articleModel.getUrl()); + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void delete() { + long articleId = articleMapper.getLastestArticleId(); + + try { + // 未登录删除文章 + mockMvc.perform(MockMvcRequestBuilders.delete("/admin/article/del?articleID=" + articleId) + ).andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), + JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code) + ); + }); + // user 权限删除文章 + String token = userLogin(); + mockMvc.perform(MockMvcRequestBuilders.delete("/admin/article/del?articleID=" + articleId) + .header("Authorization", token)) + .andDo(result -> assertEquals(PERMISSION_ERROR.getCode(), + JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)) + ); + // admin 权限删除文章 + token = adminLogin(); + mockMvc.perform(MockMvcRequestBuilders.delete("/admin/article/del?articleID=" + articleId) + .header("Authorization", token)) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + // 断言删除成功 + assertTrue(object.getBoolean(Result)); + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void update() { + Article article = articleMapper.getLastestArticle(); + ArticleReq articleReq = new ArticleReq(); + articleReq.setId(article.getId()); + articleReq.setUrl("http://www.test.test"); + articleReq.setType(!article.getType()); + articleReq.setCategory("test"); + articleReq.setMdContent("test-" + article.getMdContent()); + articleReq.setOpen(!article.getOpen()); + articleReq.setTags("tag"); + articleReq.setTitle("test-" + article.getTitle()); + try { + mockMvc.perform(put("/admin/article/update") + .content(JSONObject.fromObject(articleReq).toString()) + .contentType("application/json")) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // User 权限 + String token = userLogin(); + mockMvc.perform(put("/admin/article/update") + .content(JSONObject.fromObject(articleReq).toString()) + .contentType("application/json") + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // Admin 权限 + token = adminLogin(); + mockMvc.perform(put("/admin/article/update") + .content(JSONObject.fromObject(articleReq).toString()) + .contentType("application/json") + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject jsonObject = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), jsonObject.getInt(Code)); + ArticleModel a = (ArticleModel) JSONObject.toBean(jsonObject.getJSONObject(Result), ArticleModel.class); + assertEquals(articleReq.getCategory(), a.getCategory()); + assertEquals(articleReq.getUrl(), a.getUrl()); + assertEquals(articleReq.getMdContent(), a.getMdContent()); + assertEquals(articleReq.getTitle(), a.getTitle()); + assertEquals(articleReq.getType(), a.getOriginal()); + // Tag 暂时不支持更新 +// assertEquals(articleReq.getTags(), Arrays.toString(a.getTags()).replaceAll(" ", "".replace("[", "".replace("]", "")))); + assertEquals(articleReq.getOpen(), a.getOpen()); + assertEquals(articleReq.getId(), a.getId()); + }); + + + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void retrieveOneById() { + try { + long articleID = 3; + mockMvc.perform(MockMvcRequestBuilders.get("/article/articleID/" + articleID)) + .andExpect(status().is(200)); + mockMvc.perform(MockMvcRequestBuilders.get("/article/articleID/" + articleID + "?update=true")) + .andExpect(status().is(200)); + + // 文章不存在 + mockMvc.perform(MockMvcRequestBuilders.get("/article/articleID/-1")) + .andExpect(status().is(200)) + .andDo(result -> { + JSONObject jsonObject = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(ARTICLE_NOT_EXIST.getCode(), jsonObject.getInt(Code)); + }); + + // 正常情况 + mockMvc.perform(MockMvcRequestBuilders.get("/article/articleID/" + articleID + "?update=false")) + .andExpect(status().is(200)) + .andDo(result -> { + JSONObject articleJson = JSONObject.fromObject(result.getResponse().getContentAsString()); + // 断言获取数据成功 + assertEquals(SUCCESS.getCode(), articleJson.getInt(Code)); + assertNotNull(articleJson.getJSONObject(Result)); + + ArticleModel a = (ArticleModel) JSONObject.toBean(articleJson.getJSONObject(Result), ArticleModel.class); + assertNotNull(a.getTitle()); + assertNotNull(a.getId()); + assertNotNull(a.getSummary()); + assertNotNull(a.getMdContent()); + assertNotNull(a.getUrl()); + assertNotNull(a.getUpdateDateFormat()); + assertNotNull(a.getPreArticleId()); + assertNotNull(a.getPreArticleId()); + assertNotNull(a.getNextArticleId()); + assertNotNull(a.getNextArticleTitle()); + assertNotNull(a.getReadingNumber()); + // assertNotNull(a.getOpen()); + assertNotNull(a.getOriginal()); + assertNotNull(a.getPublishDateFormat()); + assertNotNull(a.getCategory()); + assertNotNull(a.getTags()); + assertNotNull(a.getAuthorName()); + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void articles() { + try { + // 测试不带参数访问 + mockMvc.perform(MockMvcRequestBuilders.get("/articles")) + .andExpect(status().is(200)); + + mockMvc.perform(MockMvcRequestBuilders.get("/articles?page=1&count=5")) + .andExpect(status().is(200)) + .andDo(result -> { + JSONObject articlesJSON = JSONObject.fromObject(result.getResponse().getContentAsString()); + Response response = (Response) JSONObject.toBean(articlesJSON, Response.class); + // 断言获取数据成功 + assertEquals(SUCCESS.getCode(), response.getCode()); + // 结果集非空 + assertNotNull(response.getResult()); + // 判断pageInfo是否包装完全 + JSONObject resultJson = JSONObject.fromObject(response.getResult()); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(resultJson, PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(5, pageInfo.getPageSize()); + // 内容完整 + for (Object arc : pageInfo.getList()) { + ArticleModel a = (ArticleModel) JSONObject.toBean(JSONObject.fromObject(arc), ArticleModel.class); + assertNotNull(a.getTitle()); + assertNotNull(a.getId()); + assertNotNull(a.getSummary()); + assertNotNull(a.getOriginal()); + assertNotNull(a.getPublishDateFormat()); + assertNotNull(a.getCategory()); + assertNotNull(a.getTags()); + assertNotNull(a.getAuthorName()); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void adminArticles() { + String token; + try { + // 未登录 + mockMvc.perform(get("/admin/articles?page=1&count=10")) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), + JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code) + ); + }); + + // User权限登陆 + token = userLogin(); + mockMvc.perform(get("/admin/articles?page=1&count=10") + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(PERMISSION_ERROR.getCode(), object.getInt(Code)); + }); + + token = adminLogin(); + // admin权限登陆 + mockMvc.perform(get("/admin/articles?page=1&count=10") + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject adminLogin = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), adminLogin.getInt(Code)); + assertNotNull(adminLogin.getString(Result)); + // 判断pageInfo是否包装完全 + PageInfo pageInfo = (PageInfo) JSONObject.toBean(adminLogin.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + // 内容完整 + for (Object arc : pageInfo.getList()) { + ArticleModel a = (ArticleModel) JSONObject.toBean(JSONObject.fromObject(arc), ArticleModel.class); + assertNotNull(a.getTitle()); + assertNotNull(a.getId()); + assertNotNull(a.getOriginal()); + assertNotNull(a.getPublishDateFormat()); + assertNotNull(a.getOpen()); + assertNotNull(a.getReadingNumber()); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void findByCategory() { + try { + // 分类不存在 + String categoryName = "NoSuchCategory"; + mockMvc.perform(MockMvcRequestBuilders.get("/articles/category/" + categoryName + "?page=1&count=10")) + .andExpect(status().is(200)) + .andDo(result -> { + assertEquals(CATEGORY_NOT_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // 正常查询 + categoryName = "linux"; + mockMvc.perform(MockMvcRequestBuilders.get("/articles/category/" + categoryName + "?page=1&count=10")) + .andExpect(status().is(200)) + .andDo(result -> { + JSONObject jsonObject = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), jsonObject.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(jsonObject.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + for (Object arc : pageInfo.getList()) { + JSONObject jsonObject1 = JSONObject.fromObject(arc); + assertNotEquals(0, jsonObject1.getInt("id")); + assertNotNull(jsonObject1.getString("title")); + assertNotNull(jsonObject1.getString("summary")); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void findByTag() { + try { + // 分类不存在 + String tagName = "NoSuchTag"; + mockMvc.perform(MockMvcRequestBuilders.get("/articles/tag/" + tagName + "?page=1&count=10")) + .andExpect(status().is(200)) + .andDo(result -> { + assertEquals(TAG_NOT_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // 正常查询 + tagName = "linux"; + mockMvc.perform(MockMvcRequestBuilders.get("/articles/tag/" + tagName + "?page=1&count=10")) + .andExpect(status().is(200)) + .andDo(result -> { + JSONObject jsonObject = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), jsonObject.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(jsonObject.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + + for (Object arc : pageInfo.getList()) { + JSONObject jsonObject1 = JSONObject.fromObject(arc); + assertNotEquals(0, jsonObject1.getInt("id")); + assertNotNull(jsonObject1.getString("title")); + assertNotNull(jsonObject1.getString("summary")); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/CategoryControllerTest.java b/src/test/java/cn/celess/blog/controller/CategoryControllerTest.java new file mode 100644 index 0000000..258778f --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/CategoryControllerTest.java @@ -0,0 +1,132 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.Category; +import cn.celess.blog.mapper.CategoryMapper; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.UUID; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static cn.celess.blog.enmu.ResponseEnum.*; + +public class CategoryControllerTest extends BaseTest { + + @Autowired + CategoryMapper categoryMapper; + + @Test + public void addOne() throws Exception { + String categoryName = UUID.randomUUID().toString().substring(0, 4); + System.out.println("categoryName: ==> " + categoryName); + // 未登录 + mockMvc.perform(post("/admin/category/create?name=" + categoryName)).andExpect(status().isOk()) + .andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // User权限 + String token = userLogin(); + mockMvc.perform(post("/admin/category/create?name=" + categoryName) + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // Admin权限 + token = adminLogin(); + mockMvc.perform(post("/admin/category/create?name=" + categoryName) + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + Category category = (Category) JSONObject.toBean(object.getJSONObject(Result), Category.class); + assertEquals(categoryName, category.getName()); + assertNotNull(category.getId()); + assertNotNull(category.getArticles()); + }); + } + + @Test + public void deleteOne() throws Exception { + Category category = categoryMapper.getLastestCategory(); + // 未登录 + mockMvc.perform(delete("/admin/category/del?id=" + category.getId())).andExpect(status().isOk()) + .andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // User权限 + String token = userLogin(); + mockMvc.perform(delete("/admin/category/del?id=" + category.getId()) + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // Admin权限 + token = adminLogin(); + mockMvc.perform(delete("/admin/category/del?id=" + category.getId()) + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertTrue(object.getBoolean(Result)); + }); + } + + @Test + public void updateOne() throws Exception { + Category category = categoryMapper.getLastestCategory(); + String name = UUID.randomUUID().toString().substring(0, 4); + // 未登录 + mockMvc.perform(put("/admin/category/update?id=" + category.getId() + "&name=" + name)).andExpect(status().isOk()) + .andDo(result -> { + assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // User权限 + String token = userLogin(); + mockMvc.perform(put("/admin/category/update?id=" + category.getId() + "&name=" + name) + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + // Admin权限 + token = adminLogin(); + mockMvc.perform(put("/admin/category/update?id=" + category.getId() + "&name=" + name) + .header("Authorization", token)) + .andExpect(status().isOk()) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + Category c = (Category) JSONObject.toBean(object.getJSONObject(Result), Category.class); + assertEquals(name, c.getName()); + assertNotNull(c.getArticles()); + assertNotNull(c.getId()); + }); + } + + @Test + public void getPage() throws Exception { + mockMvc.perform(get("/categories")).andExpect(status().isOk()) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + JSONArray jsonArray = object.getJSONArray(Result); + assertNotNull(jsonArray); + jsonArray.forEach(o -> { + Category c = (Category) JSONObject.toBean(JSONObject.fromObject(o), Category.class); + assertNotNull(c.getName()); + assertNotNull(c.getId()); + assertNotNull(c.getArticles()); + }); + }); + + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/CommentControllerTest.java b/src/test/java/cn/celess/blog/controller/CommentControllerTest.java new file mode 100644 index 0000000..7a1dd87 --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/CommentControllerTest.java @@ -0,0 +1,329 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.Article; +import cn.celess.blog.entity.Comment; +import cn.celess.blog.entity.model.CommentModel; +import cn.celess.blog.entity.request.CommentReq; +import cn.celess.blog.mapper.ArticleMapper; +import cn.celess.blog.mapper.CommentMapper; +import cn.celess.blog.mapper.UserMapper; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.Assert.*; +import static cn.celess.blog.enmu.ResponseEnum.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; + +public class CommentControllerTest extends BaseTest { + @Autowired + ArticleMapper articleMapper; + @Autowired + CommentMapper commentMapper; + + @Test + public void addOne() throws Exception { + CommentReq commentReq = new CommentReq(); + // 测试留言 + commentReq.setArticleID(null); + commentReq.setComment(false); + commentReq.setContent(UUID.randomUUID().toString()); + commentReq.setPid(-1L); + commentReq.setResponseId(null); + String token = userLogin(); + CommentModel PC = null; + mockMvc.perform(post("/user/comment/create") + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(JSONObject.fromObject(commentReq).toString()) + .header("Authorization", token) + ).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + CommentModel model = (CommentModel) JSONObject.toBean(object.getJSONObject(Result), CommentModel.class); + assertNotEquals(0, model.getId()); + assertEquals(commentReq.getPid().longValue(), model.getPid()); + assertEquals(-1, model.getPid()); + assertEquals(commentReq.getComment(), model.isComment()); + assertEquals(commentReq.getContent(), model.getContent()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + }); + + Article article = articleMapper.getLastestArticle(); + // 测试评论 + commentReq.setArticleID(article.getId()); + commentReq.setComment(true); + commentReq.setContent(UUID.randomUUID().toString()); + commentReq.setPid(-1L); + commentReq.setResponseId(null); + mockMvc.perform(post("/user/comment/create") + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(JSONObject.fromObject(commentReq).toString()) + .header("Authorization", token) + ).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + CommentModel model = (CommentModel) JSONObject.toBean(object.getJSONObject(Result), CommentModel.class); + // 响应数据的完整性 + assertNotEquals(0, model.getId()); + assertEquals(commentReq.getPid().longValue(), model.getPid()); + assertEquals(-1, model.getPid()); + assertEquals(commentReq.getComment(), model.isComment()); + assertEquals(commentReq.getContent(), model.getContent()); + assertEquals(commentReq.getArticleID().longValue(), model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + }); + + // 测试二级回复 + Comment lastestComment = commentMapper.getLastestComment(); + commentReq.setArticleID(lastestComment.getArticleID()); + commentReq.setComment(lastestComment.getType()); + commentReq.setContent(UUID.randomUUID().toString()); + commentReq.setPid(lastestComment.getId()); + commentReq.setResponseId(null); + mockMvc.perform(post("/user/comment/create") + .contentType(MediaType.APPLICATION_JSON_UTF8) + .content(JSONObject.fromObject(commentReq).toString()) + .header("Authorization", token) + ).andDo(MockMvcResultHandlers.print()).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + CommentModel model = (CommentModel) JSONObject.toBean(object.getJSONObject(Result), CommentModel.class); + // 重新获取父评论信息 + Comment pCommon = commentMapper.findCommentById(lastestComment.getId()); + assertEquals(pCommon.getId().longValue(), model.getPid()); + // 判断父评论中是否有写入当前新增的评论的id + String[] ids = pCommon.getResponseId().split(","); + boolean contain = false; + for (String id : ids) { + if (!id.isEmpty() && Long.parseLong(id) == model.getId()) { + contain = true; + break; + } + } + assertTrue(contain); + }); + } + + @Test + public void deleteTest() throws Exception { + // 准备数据 + Comment c = new Comment(); + c.setArticleID(-1L); + c.setType(true); + c.setAuthorID(2L); + c.setDate(new Date()); + c.setPid(-1L); + commentMapper.insert(c); + Comment comment = commentMapper.getLastestComment(); + // 接口测试 + long id = comment.getId(); + assertNotEquals(0, id); + String token = userLogin(); + mockMvc.perform(delete("/user/comment/del?id=" + id).header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertTrue(object.getBoolean(Result)); + }); + mockMvc.perform(delete("/user/comment/del?id=" + id).header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(COMMENT_NOT_EXIST.getCode(), object.getInt(Code)); + }); + } + + @Test + public void update() throws Exception { + Comment comment = commentMapper.getLastestComment(); + CommentReq commentReq = new CommentReq(); + commentReq.setId(comment.getId()); + commentReq.setPid(comment.getPid()); + commentReq.setContent(UUID.randomUUID().toString()); + commentReq.setArticleID(comment.getArticleID()); + // 不合法数据 setResponseId + commentReq.setResponseId("xxxx"); + commentReq.setComment(comment.getType()); + mockMvc.perform(put("/user/comment/update") + .content(JSONObject.fromObject(commentReq).toString()) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .header("Authorization", userLogin()) + ).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + CommentModel c = (CommentModel) JSONObject.toBean(object.getJSONObject(Result), CommentModel.class); + assertEquals(commentReq.getContent(), c.getContent()); + assertEquals(commentReq.getResponseId(), c.getResponseId()); + assertNotNull(c.getAuthorAvatarImgUrl()); + assertNotNull(c.getAuthorName()); + assertNotNull(c.getDate()); + assertNotEquals(0, c.getPid()); + assertNotEquals(0, c.getArticleID()); + }); + } + + @Test + public void commentsOfArticle() throws Exception { + mockMvc.perform(get("/comments?articleId=3&page=1&count=10")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertEquals(3, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getArticleTitle()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + }); + }); + } + + @Test + public void retrievePage() throws Exception { + long pid = 17; + mockMvc.perform(get("/comment/pid/" + pid + "?articleId=3&page=1&count=10")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertEquals(3, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getArticleTitle()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + }); + }); + } + + @Test + public void retrievePageOfLeaveMsg() throws Exception { + mockMvc.perform(get("/leaveMsg?page=1&count=10")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertEquals(-1, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + assertFalse(model.isComment()); + }); + }); + } + + @Test + public void retrievePageAdmin() throws Exception { + mockMvc.perform(get("/admin/comment/type/1?page=1&count=10").header("Authorization", adminLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertNotEquals(-1, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + assertTrue(model.isComment()); + }); + }); + mockMvc.perform(get("/admin/comment/type/0?page=1&count=10").header("Authorization", adminLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertEquals(-1, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + assertFalse(model.isComment()); + }); + }); + } + + @Test + public void retrievePageByAuthor() throws Exception { + mockMvc.perform(get("/user/comment/type/1?page=1&count=10").header("Authorization", userLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertNotEquals(-1, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + assertTrue(model.isComment()); + }); + }); + mockMvc.perform(get("/user/comment/type/0?page=1&count=10").header("Authorization", userLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + CommentModel model = (CommentModel) JSONObject.toBean(JSONObject.fromObject(o), CommentModel.class); + assertEquals(-1, model.getArticleID()); + assertNotNull(model.getDate()); + assertNotNull(model.getAuthorName()); + assertNotNull(model.getAuthorAvatarImgUrl()); + assertNotNull(model.getContent()); + assertNotNull(model.getResponseId()); + assertFalse(model.isComment()); + }); + }); + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/LinksControllerTest.java b/src/test/java/cn/celess/blog/controller/LinksControllerTest.java new file mode 100644 index 0000000..7c78ac1 --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/LinksControllerTest.java @@ -0,0 +1,178 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.PartnerSite; +import cn.celess.blog.entity.request.LinkReq; +import cn.celess.blog.mapper.PartnerMapper; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; + +import java.util.UUID; + +import static cn.celess.blog.enmu.ResponseEnum.*; +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; + +public class LinksControllerTest extends BaseTest { + + @Autowired + PartnerMapper mapper; + + @Test + public void create() throws Exception { + LinkReq linkReq = new LinkReq(); + linkReq.setName(UUID.randomUUID().toString().substring(0, 4)); + linkReq.setOpen(false); + linkReq.setUrl("https://example.com"); + String token = adminLogin(); + mockMvc.perform( + post("/admin/links/create") + .content(JSONObject.fromObject(linkReq).toString()) + .header("Authorization", token) + .contentType(MediaType.APPLICATION_JSON) + ).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PartnerSite site = (PartnerSite) JSONObject.toBean(object.getJSONObject(Result), PartnerSite.class); + assertNotNull(site.getId()); + assertEquals(linkReq.getName(), site.getName()); + assertEquals(linkReq.getUrl(), site.getUrl()); + assertEquals(linkReq.isOpen(), site.getOpen()); + }); + + // https/http + linkReq.setName(UUID.randomUUID().toString().substring(0, 4)); + linkReq.setOpen(false); + linkReq.setUrl("example.com"); + mockMvc.perform( + post("/admin/links/create") + .content(JSONObject.fromObject(linkReq).toString()) + .header("Authorization", token) + .contentType("application/json") + ).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PartnerSite site = (PartnerSite) JSONObject.toBean(object.getJSONObject(Result), PartnerSite.class); + assertEquals("http://example.com", site.getUrl()); + }); + + // 测试已存在的数据 + mockMvc.perform( + post("/admin/links/create") + .content(JSONObject.fromObject(linkReq).toString()) + .header("Authorization", token) + .contentType("application/json") + ).andDo(result -> assertEquals(DATA_HAS_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + } + + @Test + public void del() throws Exception { + PartnerSite partnerSite = new PartnerSite(); + partnerSite.setName(UUID.randomUUID().toString().substring(0, 4)); + partnerSite.setOpen(true); + partnerSite.setUrl("https://www.celess.cn"); + mapper.insert(partnerSite); + PartnerSite lastest = mapper.getLastest(); + assertNotNull(lastest.getId()); + String token = adminLogin(); + mockMvc.perform(delete("/admin/links/del/" + lastest.getId()).header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertTrue(object.getBoolean(Result)); + }); + long id = lastest.getId(); + do { + id += 1; + } while (mapper.existsById(id)); + System.out.println("删除ID=" + id + "的数据"); + mockMvc.perform(delete("/admin/links/del/" + id).header("Authorization", token)).andDo(result -> + assertEquals(DATA_NOT_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)) + ); + } + + @Test + public void update() throws Exception { + // 增数据 + PartnerSite partnerSite = new PartnerSite(); + partnerSite.setName(UUID.randomUUID().toString().substring(0, 4)); + partnerSite.setOpen(true); + partnerSite.setUrl("https://www.celess.cn"); + mapper.insert(partnerSite); + // 查数据 + PartnerSite lastest = mapper.getLastest(); + assertNotNull(lastest.getId()); + String token = adminLogin(); + // 构建请求 + LinkReq linkReq = new LinkReq(); + linkReq.setUrl(lastest.getUrl()); + linkReq.setOpen(!lastest.getOpen()); + linkReq.setName(UUID.randomUUID().toString().substring(0, 4)); + linkReq.setId(lastest.getId()); + mockMvc.perform( + put("/admin/links/update") + .content(JSONObject.fromObject(linkReq).toString()) + .contentType(MediaType.APPLICATION_JSON) + .header("Authorization", token) + ).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PartnerSite site = (PartnerSite) JSONObject.toBean(object.getJSONObject(Result), PartnerSite.class); + assertNotNull(site.getId()); + assertEquals(linkReq.getId(), site.getId().longValue()); + assertEquals(linkReq.getUrl(), site.getUrl()); + assertEquals(linkReq.getName(), site.getName()); + assertEquals(linkReq.isOpen(), site.getOpen()); + }); + } + + @Test + public void allForOpen() throws Exception { + mockMvc.perform(get("/links")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + object.getJSONArray(Result).forEach(o -> { + PartnerSite site = (PartnerSite) JSONObject.toBean(JSONObject.fromObject(o), PartnerSite.class); + assertNotNull(site.getUrl()); + assertNull(site.getOpen()); + assertNotNull(site.getName()); + }); + }); + } + + @Test + public void all() throws Exception { + mockMvc.perform(get("/admin/links?page=1&count=10").header("Authorization", adminLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + PartnerSite site = (PartnerSite) JSONObject.toBean(JSONObject.fromObject(o), PartnerSite.class); + assertNotNull(site.getUrl()); + assertNotNull(site.getName()); + assertNotNull(site.getOpen()); + }); + }); + } + + @Test + public void apply() throws Exception { + long l = System.currentTimeMillis(); + String url = "https://www.example.com"; + mockMvc.perform(post("/apply?name=小海博客Api测试,请忽略&url=" + url)).andDo(result -> { + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + System.out.println("耗时:" + (System.currentTimeMillis() - l) / 1000 + "s"); + url = "xxxxxxxxxm"; + mockMvc.perform(post("/apply?name=小海博客Api测试,请忽略&url=" + url)).andDo(result -> { + assertEquals(PARAMETERS_URL_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + }); + + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/TagControllerTest.java b/src/test/java/cn/celess/blog/controller/TagControllerTest.java new file mode 100644 index 0000000..f742c55 --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/TagControllerTest.java @@ -0,0 +1,143 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.Tag; +import cn.celess.blog.mapper.TagMapper; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.UUID; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static cn.celess.blog.enmu.ResponseEnum.*; + +public class TagControllerTest extends BaseTest { + @Autowired + TagMapper tagMapper; + + @Test + public void addOne() throws Exception { + String name = UUID.randomUUID().toString().substring(0, 4); + mockMvc.perform(post("/admin/tag/create?name=" + name)).andDo(result -> assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(post("/admin/tag/create?name=" + name).header("authorization", userLogin())).andDo(result -> assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(post("/admin/tag/create?name=" + name).header("authorization", adminLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + JSONObject resJson = object.getJSONObject(Result); + Tag tag = (Tag) JSONObject.toBean(resJson, Tag.class); + assertNotNull(tag.getId()); + assertEquals(name, tag.getName()); + }); + + + } + + @Test + public void delOne() throws Exception { + Tag lastestTag = tagMapper.getLastestTag(); + assertNotNull(lastestTag.getId()); + String token = adminLogin(); + mockMvc.perform(delete("/admin/tag/del?id=" + lastestTag.getId()).header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertTrue(object.getBoolean(Result)); + }); + long id = lastestTag.getId() * 2; + mockMvc.perform(delete("/admin/tag/del?id=" + id).header("Authorization", token)).andDo(result -> + assertEquals(TAG_NOT_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)) + ); + + } + + @Test + public void updateOne() throws Exception { + Tag tag = tagMapper.getLastestTag(); + assertNotNull(tag.getId()); + String name = UUID.randomUUID().toString().substring(0, 4); + mockMvc.perform(put("/admin/tag/update?id=" + tag.getId() + "&name=" + name).header("Authorization", adminLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertNotNull(object.getJSONObject(Result)); + Tag t = (Tag) JSONObject.toBean(object.getJSONObject(Result), Tag.class); + assertEquals(name, t.getName()); + assertEquals(tag.getArticles(), t.getArticles()); + assertEquals(tag.getId(), t.getId()); + }); + + } + + @Test + public void retrieveOneById() throws Exception { + Tag tag = tagMapper.getLastestTag(); + assertNotNull(tag.getId()); + mockMvc.perform(get("/tag/id/" + tag.getId())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertNotNull(object.getJSONObject(Result)); + Tag t = (Tag) JSONObject.toBean(object.getJSONObject(Result), Tag.class); + assertEquals(tag.getId(), t.getId()); + assertNotNull(t.getName()); + }); + } + + @Test + public void retrieveOneByName() throws Exception { + Tag tag = tagMapper.getLastestTag(); + assertNotNull(tag.getName()); + mockMvc.perform(get("/tag/name/" + tag.getName())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertNotNull(object.getJSONObject(Result)); + Tag t = (Tag) JSONObject.toBean(object.getJSONObject(Result), Tag.class); + assertEquals(tag.getName(), t.getName()); + assertNotNull(t.getId()); + }); + } + + @Test + public void getPage() throws Exception { + mockMvc.perform(get("/tags?page=1&count=5")) + .andExpect(status().is(200)) + .andDo(result -> { + JSONObject articlesJSON = JSONObject.fromObject(result.getResponse().getContentAsString()); + // 断言获取数据成功 + assertEquals(SUCCESS.getCode(), articlesJSON.getInt(Code)); + // 结果集非空 + assertNotNull(articlesJSON.getJSONObject(Result)); + // 判断pageInfo是否包装完全 + JSONObject resultJson = JSONObject.fromObject(articlesJSON.getJSONObject(Result)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(resultJson, PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(5, pageInfo.getPageSize()); + // 内容完整 + for (Object tag : pageInfo.getList()) { + Tag t = (Tag) JSONObject.toBean(JSONObject.fromObject(tag), Tag.class); + assertNotNull(t.getId()); + assertNotNull(t.getName()); + } + }); + } + + @Test + public void getTagNameAndCount() throws Exception { + mockMvc.perform(get("/tags/nac")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + JSONArray jsonArray = object.getJSONArray(Result); + assertNotNull(jsonArray); + jsonArray.forEach(o -> { + JSONObject json = JSONObject.fromObject(o); + assertTrue(json.containsKey("size")); + assertTrue(json.containsKey("name")); + }); + }); + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/UserControllerTest.java b/src/test/java/cn/celess/blog/controller/UserControllerTest.java new file mode 100644 index 0000000..d404191 --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/UserControllerTest.java @@ -0,0 +1,247 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.User; +import cn.celess.blog.entity.model.UserModel; +import cn.celess.blog.entity.request.LoginReq; +import cn.celess.blog.entity.request.UserReq; +import cn.celess.blog.mapper.UserMapper; +import cn.celess.blog.util.MD5Util; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import java.io.File; +import java.io.FileInputStream; +import java.util.*; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static cn.celess.blog.enmu.ResponseEnum.*; + +public class UserControllerTest extends BaseTest { + + @Autowired + UserMapper userMapper; + + @Test + public void login() throws Exception { + assertNotNull(userLogin()); + assertNotNull(adminLogin()); + // 用户不存在 + LoginReq req = new LoginReq(); + req.setEmail("zh@celess.cn"); + req.setPassword("123456789"); + req.setIsRememberMe(false); + JSONObject loginReq = JSONObject.fromObject(req); + mockMvc.perform(post("/login").content(loginReq.toString()).contentType("application/json")) + .andDo(result -> + assertEquals(USER_NOT_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)) + ); + } + + @Test + public void registration() { + // 自行手动测试! + // TODO : + } + + @Test + public void logout() throws Exception { + mockMvc.perform(get("/logout")).andDo(result -> assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(get("/logout").header("Authorization", userLogin())).andDo(result -> assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + } + + @Test + public void updateInfo() throws Exception { + String desc = UUID.randomUUID().toString().substring(0, 4); + String disPlayName = UUID.randomUUID().toString().substring(0, 4); + mockMvc.perform(put("/user/userInfo/update?desc=" + desc + "&displayName=" + disPlayName).header("Authorization", userLogin())) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + UserModel u = (UserModel) JSONObject.toBean(object.getJSONObject(Result), UserModel.class); + assertEquals(desc, u.getDesc()); + assertEquals(disPlayName, u.getDisplayName()); + assertNotNull(u.getId()); + }); + } + + @Test + public void getUserInfo() throws Exception { + mockMvc.perform(get("/user/userInfo").header("Authorization", userLogin())) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + UserModel u = (UserModel) JSONObject.toBean(object.getJSONObject(Result), UserModel.class); + assertNotNull(u.getId()); + assertNotNull(u.getEmail()); + assertNotNull(u.getDisplayName()); + assertNotNull(u.getEmailStatus()); + assertNotNull(u.getAvatarImgUrl()); + assertNotNull(u.getDesc()); + assertNotNull(u.getRecentlyLandedDate()); + assertNotNull(u.getRole()); + }); + } + + @Test + public void upload() throws Exception { + File logoFile = new File("C:\\Users\\zh564\\Pictures\\logo.png"); + MockMultipartFile file = new MockMultipartFile("file", "logo.png", MediaType.IMAGE_PNG_VALUE, new FileInputStream(logoFile)); + mockMvc.perform(multipart("/user/imgUpload").file(file)).andDo(result -> assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(multipart("/user/imgUpload").file(file).header("Authorization", userLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertNotNull(object.getString(Result)); + }); + } + + @Test + public void sendResetPwdEmail() { + // ignore + } + + @Test + public void sendVerifyEmail() { + // ignore + } + + @Test + public void emailVerify() { + // ignore + } + + @Test + public void resetPwd() { + // ignore + } + + @Test + public void multipleDelete() throws Exception { + List userList = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + String s = UUID.randomUUID().toString(); + String email = s.substring(s.length() - 4) + "@celess.cn"; + String pwd = MD5Util.getMD5("123456789"); + int i1 = userMapper.addUser(email, pwd); + if (i1 == 0) { + continue; + } + userList.add(userMapper.findByEmail(email)); + if (i == 9) { + //设置一个管理员 + userMapper.setUserRole(userMapper.findByEmail(email).getId(), "admin"); + } + } + List idList = new ArrayList<>(); + userList.forEach(user -> idList.add(user.getId())); + System.out.println("id :: == > " + idList.toString()); + mockMvc.perform(delete("/admin/user/delete").content(idList.toString()).contentType("application/json")) + .andDo(result -> assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(delete("/admin/user/delete").content(idList.toString()).contentType("application/json").header("Authorization", userLogin())) + .andDo(result -> assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(delete("/admin/user/delete").content(idList.toString()).contentType("application/json").header("Authorization", adminLogin())) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + JSONArray jsonArray = object.getJSONArray(Result); + jsonArray.forEach(o -> { + JSONObject json = JSONObject.fromObject(o); + // 判断响应数据中是否包含输入的id + assertTrue(idList.contains((long) json.getInt("id"))); + // 判断处理状态 + boolean status = json.getBoolean("status"); + if (json.containsKey("msg")) + assertFalse(status); + else + assertTrue(status); + }); + }); + + } + + @Test + public void updateInfoByAdmin() throws Exception { + UserReq userReq = new UserReq(); + String email = UUID.randomUUID().toString().substring(0, 4) + "@celess.cn"; + userMapper.addUser(email, MD5Util.getMD5("123456789")); + User userByDb = userMapper.findByEmail(email); + userReq.setId(userByDb.getId()); + userReq.setPwd(UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10)); + userReq.setDesc(UUID.randomUUID().toString()); + userReq.setEmailStatus(new Random().nextBoolean()); + userReq.setRole("admin"); + userReq.setDisplayName(UUID.randomUUID().toString().substring(0, 4)); + userReq.setEmail(UUID.randomUUID().toString().substring(0, 5) + "@celess.cn"); + mockMvc.perform(put("/admin/user").contentType("application/json").content(JSONObject.fromObject(userReq).toString())) + .andDo(result -> assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(put("/admin/user").contentType("application/json").header("Authorization", userLogin()).content(JSONObject.fromObject(userReq).toString())) + .andDo(result -> assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(put("/admin/user").contentType("application/json").header("Authorization", adminLogin()).content(JSONObject.fromObject(userReq).toString())) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + UserModel user = (UserModel) JSONObject.toBean(object.getJSONObject(Result), UserModel.class); + assertEquals(userReq.getId(), user.getId()); + assertEquals(userReq.getRole(), user.getRole()); + assertEquals(userReq.getEmail(), user.getEmail()); + assertEquals(userReq.getDesc(), user.getDesc()); + assertEquals(userReq.getDisplayName(), user.getDisplayName()); + }); + } + + @Test + public void getAllUser() throws Exception { + mockMvc.perform(get("/admin/users?page=1&count=10")) + .andDo(result -> assertEquals(HAVE_NOT_LOG_IN.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(get("/admin/users?page=1&count=10").header("authorization", userLogin())) + .andDo(result -> assertEquals(PERMISSION_ERROR.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + mockMvc.perform(get("/admin/users?page=1&count=10").header("Authorization", adminLogin())) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + // 结果集非空 + assertNotNull(object.getJSONObject(Result)); + // 判断pageInfo是否包装完全 + JSONObject resultJson = JSONObject.fromObject(object.getJSONObject(Result)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(resultJson, PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + // 内容完整 + for (Object user : pageInfo.getList()) { + UserModel u = (UserModel) JSONObject.toBean(JSONObject.fromObject(user), UserModel.class); + assertNotNull(u.getId()); + assertNotNull(u.getEmail()); + assertNotNull(u.getRole()); + assertNotNull(u.getEmailStatus()); + assertNotNull(u.getDisplayName()); + } + }); + } + + @Test + public void getEmailStatus() throws Exception { + String email = UUID.randomUUID().toString().substring(0, 4) + "@celess.cn"; + mockMvc.perform(get("/emailStatus/" + email)).andDo(result -> { + String content = result.getResponse().getContentAsString(); + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(content).getInt(Code)); + assertFalse(JSONObject.fromObject(content).getBoolean(Result)); + }); + email = "a@celess.cn"; + mockMvc.perform(get("/emailStatus/" + email)).andDo(result -> { + String content = result.getResponse().getContentAsString(); + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(content).getInt(Code)); + assertTrue(JSONObject.fromObject(content).getBoolean(Result)); + }); + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/VisitorControllerTest.java b/src/test/java/cn/celess/blog/controller/VisitorControllerTest.java new file mode 100644 index 0000000..457613d --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/VisitorControllerTest.java @@ -0,0 +1,82 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.model.VisitorModel; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static cn.celess.blog.enmu.ResponseEnum.*; + +public class VisitorControllerTest extends BaseTest { + + @Test + public void getVisitorCount() throws Exception { + mockMvc.perform(get("/visitor/count")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertTrue(object.containsKey(Result)); + }); + } + + @Test + public void page() throws Exception { + int count = 10; + int page = 1; + mockMvc.perform(get("/admin/visitor/page?count=" + count + "&page=" + page).header("Authorization", adminLogin())) + .andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + JSONObject resultJson = JSONObject.fromObject(object.getJSONObject(Result)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(resultJson, PageInfo.class); + assertNotEquals(0, pageInfo.getTotal()); + assertNotEquals(0, pageInfo.getStartRow()); + assertNotEquals(0, pageInfo.getEndRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + for (Object ver : pageInfo.getList()) { + VisitorModel v = (VisitorModel) JSONObject.toBean(JSONObject.fromObject(ver), VisitorModel.class); + assertNotEquals(0, v.getId()); + assertNotNull(v.getDate()); + } + }); + } + + @Test + public void add() throws Exception { + mockMvc.perform(post("/visit")).andDo(MockMvcResultHandlers.print()).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + VisitorModel visitorModel = (VisitorModel) JSONObject.toBean(object.getJSONObject(Result), VisitorModel.class); + assertNotEquals(0, visitorModel.getId()); + assertNotNull(visitorModel.getIp()); + }); + } + + @Test + public void dayVisitCount() throws Exception { + mockMvc.perform(get("/dayVisitCount")).andDo(MockMvcResultHandlers.print()).andDo(result -> + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)) + ); + } + + @Test + public void ipLocation() throws Exception { + String ip = "127.0.0.1"; + mockMvc.perform(get("/ip/" + ip)).andDo(MockMvcResultHandlers.print()).andDo(result -> { + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + assertTrue(JSONObject.fromObject(result.getResponse().getContentAsString()).containsKey(Result)); + }); + } + + @Test + public void getIp() throws Exception { + mockMvc.perform(get("/ip")).andDo(MockMvcResultHandlers.print()).andDo(result -> { + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + assertEquals("127.0.0.1", JSONObject.fromObject(result.getResponse().getContentAsString()).getString(Result)); + }); + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/controller/WebUpdateInfoControllerTest.java b/src/test/java/cn/celess/blog/controller/WebUpdateInfoControllerTest.java new file mode 100644 index 0000000..ca42063 --- /dev/null +++ b/src/test/java/cn/celess/blog/controller/WebUpdateInfoControllerTest.java @@ -0,0 +1,125 @@ +package cn.celess.blog.controller; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.WebUpdate; +import cn.celess.blog.entity.model.WebUpdateModel; +import cn.celess.blog.mapper.WebUpdateInfoMapper; +import com.github.pagehelper.PageInfo; +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static cn.celess.blog.enmu.ResponseEnum.*; +import static org.junit.Assert.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; + +public class WebUpdateInfoControllerTest extends BaseTest { + @Autowired + WebUpdateInfoMapper mapper; + + @Test + public void create() throws Exception { + String info = UUID.randomUUID().toString(); + mockMvc.perform(post("/admin/webUpdate/create?info=" + info).header("Authorization", adminLogin())).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertTrue(object.containsKey(Result)); + WebUpdateModel webUpdateModel = (WebUpdateModel) JSONObject.toBean(object.getJSONObject(Result), WebUpdateModel.class); + assertEquals(info, webUpdateModel.getInfo()); + assertNotNull(webUpdateModel.getTime()); + assertNotEquals(0, webUpdateModel.getId()); + }); + } + + @Test + public void del() throws Exception { + // 新增数据 + WebUpdate webUpdate = new WebUpdate(); + webUpdate.setUpdateInfo(UUID.randomUUID().toString()); + webUpdate.setUpdateTime(new Date()); + mapper.insert(webUpdate); + // 接口测试 + List updateList = mapper.findAll(); + WebUpdate update = updateList.get(updateList.size() - 1); + assertNotEquals(0, update.getId()); + + long id = update.getId(); + mockMvc.perform(delete("/admin/webUpdate/del/" + id).header("Authorization", adminLogin())).andDo(result -> { + assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)); + assertTrue(JSONObject.fromObject(result.getResponse().getContentAsString()).getBoolean(Result)); + }); + do { + id += 2; + } while (mapper.existsById(id)); + System.out.println("准备删除ID=" + id + "的不存在记录"); + mockMvc.perform(delete("/admin/webUpdate/del/" + id).header("Authorization", adminLogin())).andDo(result -> + assertEquals(DATA_NOT_EXIST.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code)) + ); + } + + @Test + public void update() throws Exception { + // 新增数据 + WebUpdate webUpdate = new WebUpdate(); + webUpdate.setUpdateInfo(UUID.randomUUID().toString()); + webUpdate.setUpdateTime(new Date()); + mapper.insert(webUpdate); + List all = mapper.findAll(); + WebUpdate update = all.get(all.size() - 1); + assertNotEquals(0, update.getId()); + assertNotNull(update.getUpdateInfo()); + String info = UUID.randomUUID().toString(); + mockMvc.perform(put("/admin/webUpdate/update?id=" + update.getId() + "&info=" + info).header("Authorization", adminLogin())).andDo(result -> { + List list = mapper.findAll(); + WebUpdate up = list.get(list.size() - 1); + assertEquals(update.getId(), up.getId()); + assertEquals(update.getUpdateTime(), up.getUpdateTime()); + assertEquals(info, up.getUpdateInfo()); + }); + } + + @Test + public void findAll() throws Exception { + mockMvc.perform(get("/webUpdate")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + JSONArray jsonArray = object.getJSONArray(Result); + jsonArray.forEach(o -> { + WebUpdateModel webUpdate = (WebUpdateModel) JSONObject.toBean(JSONObject.fromObject(o), WebUpdateModel.class); + assertNotEquals(0, webUpdate.getId()); + assertNotNull(webUpdate.getTime()); + assertNotNull(webUpdate.getInfo()); + }); + }); + } + + @Test + public void page() throws Exception { + mockMvc.perform(get("/webUpdate/pages?page=1&count=10")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + assertNotNull(object.getJSONObject(Result)); + PageInfo pageInfo = (PageInfo) JSONObject.toBean(object.getJSONObject(Result), PageInfo.class); + assertNotEquals(0, pageInfo.getEndRow()); + assertNotEquals(0, pageInfo.getStartRow()); + assertEquals(1, pageInfo.getPageNum()); + assertEquals(10, pageInfo.getPageSize()); + pageInfo.getList().forEach(o -> { + WebUpdateModel model = (WebUpdateModel) JSONObject.toBean(JSONObject.fromObject(o), WebUpdateModel.class); + assertNotEquals(0, model.getId()); + assertNotNull(model.getTime()); + assertNotNull(model.getInfo()); + }); + }); + } + + @Test + public void lastestUpdateTime() throws Exception { + mockMvc.perform(get("/lastestUpdateTime")).andDo(result -> assertEquals(SUCCESS.getCode(), JSONObject.fromObject(result.getResponse().getContentAsString()).getInt(Code))); + } +} \ No newline at end of file diff --git a/src/test/java/cn/celess/blog/filter/AuthorizationFilter.java b/src/test/java/cn/celess/blog/filter/AuthorizationFilter.java new file mode 100644 index 0000000..0ff4b3a --- /dev/null +++ b/src/test/java/cn/celess/blog/filter/AuthorizationFilter.java @@ -0,0 +1,64 @@ +package cn.celess.blog.filter; + +import cn.celess.blog.BaseTest; +import net.sf.json.JSONObject; +import org.junit.Test; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.junit.Assert.*; +import static cn.celess.blog.enmu.ResponseEnum.*; + +/** + * @Author: 小海 + * @Date: 2019/11/28 16:05 + * @Description: 授权拦截器的测试类 + */ +public class AuthorizationFilter extends BaseTest { + + @Test + public void UserAccess() throws Exception { + String token = ""; + // 未登录 + mockMvc.perform(get("/user/userInfo").header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(HAVE_NOT_LOG_IN.getCode(), object.getInt(Code)); + }); + token = userLogin(); + mockMvc.perform(get("/user/userInfo").header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + }); + } + + @Test + public void AdminAccess() throws Exception { + String token = ""; + // 未登录 + mockMvc.perform(get("/admin/articles?page=1&count=1").header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(HAVE_NOT_LOG_IN.getCode(), object.getInt(Code)); + }); + token = userLogin(); + mockMvc.perform(get("/admin/articles?page=1&count=1").header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(PERMISSION_ERROR.getCode(), object.getInt(Code)); + }); + token = adminLogin(); + mockMvc.perform(get("/admin/articles?page=1&count=1").header("Authorization", token)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(SUCCESS.getCode(), object.getInt(Code)); + }); + } + + @Test + public void VisitorAccess() throws Exception { + mockMvc.perform(get("/user/userInfo")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(HAVE_NOT_LOG_IN.getCode(), object.getInt(Code)); + }); + mockMvc.perform(get("/admin/articles?page=1&count=1")).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + assertEquals(HAVE_NOT_LOG_IN.getCode(), object.getInt(Code)); + }); + } +} diff --git a/src/test/java/cn/celess/blog/filter/MultipleSubmitFilter.java b/src/test/java/cn/celess/blog/filter/MultipleSubmitFilter.java new file mode 100644 index 0000000..5eca79b --- /dev/null +++ b/src/test/java/cn/celess/blog/filter/MultipleSubmitFilter.java @@ -0,0 +1,42 @@ +package cn.celess.blog.filter; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.enmu.ResponseEnum; +import net.sf.json.JSONObject; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultHandlers; + +import javax.servlet.http.Cookie; + +/** + * @Author: 小海 + * @Date: 2019/11/28 16:17 + * @Description: 测试重复请求 + */ +public class MultipleSubmitFilter extends BaseTest { + + private MockHttpSession session = null; + + @Test + public void submitTest() throws Exception { + session = new MockHttpSession(); + sendRequest(ResponseEnum.SUCCESS); + sendRequest(ResponseEnum.FAILURE, "重复请求"); + } + + + private void sendRequest(ResponseEnum expectResponse, String... msg) throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/counts").session(session)).andDo(result -> { + JSONObject object = JSONObject.fromObject(result.getResponse().getContentAsString()); + Assert.assertEquals(expectResponse.getCode(), object.getInt(Code)); + if (msg.length != 0) { + Assert.assertEquals(msg[0], object.getString("msg")); + } + }); + } +} diff --git a/src/test/java/cn/celess/blog/util/JwtUtilTest.java b/src/test/java/cn/celess/blog/util/JwtUtilTest.java new file mode 100644 index 0000000..2a41ec4 --- /dev/null +++ b/src/test/java/cn/celess/blog/util/JwtUtilTest.java @@ -0,0 +1,52 @@ +package cn.celess.blog.util; + +import cn.celess.blog.BaseTest; +import cn.celess.blog.entity.User; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.junit.Assert.*; + +public class JwtUtilTest extends BaseTest { + + @Autowired + JwtUtil jwtUtil; + + + @Test + public void generateToken() { + User user = new User(); + user.setEmail("a@celess.cn"); + String s = jwtUtil.generateToken(user, true); + System.out.println(s); + assertNotNull(s); + } + + @Test + public void validateToken() { + User user = new User(); + user.setEmail("a@celess.cn"); + assertTrue(jwtUtil.validateToken(createToken(), user)); + } + + @Test + public void isTokenExpired() { + assertFalse(jwtUtil.isTokenExpired(createToken())); + } + + @Test + public void getUsernameFromToken() { + assertEquals("a@celess.cn", jwtUtil.getUsernameFromToken(createToken())); + } + + @Test + public void getExpirationDateFromToken() { + assertNotNull(jwtUtil.getExpirationDateFromToken(createToken())); + } + + private String createToken() { + User user = new User(); + user.setEmail("a@celess.cn"); + return jwtUtil.generateToken(user, true); + } +} \ No newline at end of file