从"Blog"仓库中分离出来

This commit is contained in:
小海
2019-11-28 19:18:16 +08:00
commit 16cc30f513
119 changed files with 11291 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@@ -0,0 +1,8 @@
.idea/
*.imi
target/
# 本地项目的私有文件
back-end/blog-dev.sql
src/main/resources/application-prod.properties
src/main/resources/application-dev.properties

114
.mvn/wrapper/MavenWrapperDownloader.java vendored Normal file
View File

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

BIN
.mvn/wrapper/maven-wrapper.jar vendored Normal file

Binary file not shown.

1
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

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

21
LICENSE Normal file
View File

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

37
README.md Normal file
View File

@@ -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` 图片上传的跨域问题

149
blog.iml Normal file
View File

@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.11.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.25" level="project" />
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.23" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.8" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.16" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.16" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.16" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.14.Final" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.2.Final" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.1.5.RELEASE" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: mysql:mysql-connector-java:8.0.15" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-starter-test:2.1.3.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test:2.1.3.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework.boot:spring-boot-test-autoconfigure:2.1.3.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.jayway.jsonpath:json-path:2.4.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.assertj:assertj-core:3.11.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-core:2.23.4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy:1.9.10" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.bytebuddy:byte-buddy-agent:1.9.10" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.objenesis:objenesis:2.6" level="project" />
<orderEntry type="library" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-library:1.3" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.skyscreamer:jsonassert:1.5.0" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.vaadin.external.google:android-json:0.0.20131108.vaadin1" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.1.5.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.springframework:spring-test:5.1.5.RELEASE" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.xmlunit:xmlunit-core:2.6.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: javax.xml.bind:jaxb-api:2.3.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: javax.activation:javax.activation-api:1.2.0" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid:1.1.14" level="project" />
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.6" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger2:2.6.1" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-annotations:1.5.10" level="project" />
<orderEntry type="library" name="Maven: io.swagger:swagger-models:1.5.10" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spi:2.6.1" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-core:2.6.1" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-schema:2.6.1" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-common:2.6.1" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-spring-web:2.6.1" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:18.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.4.0" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.plugin:spring-plugin-metadata:1.2.0.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.0.0.Final" level="project" />
<orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.6.1" level="project" />
<orderEntry type="library" name="Maven: com.youbenzi:MDTool:1.2.3" level="project" />
<orderEntry type="library" name="Maven: net.minidev:json-smart:2.3" level="project" />
<orderEntry type="library" name="Maven: net.minidev:accessors-smart:1.2" level="project" />
<orderEntry type="library" name="Maven: org.ow2.asm:asm:5.0.4" level="project" />
<orderEntry type="library" name="Maven: net.sf.json-lib:json-lib:jdk15:2.4" level="project" />
<orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.0" level="project" />
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.5" level="project" />
<orderEntry type="library" name="Maven: commons-logging:commons-logging:1.1.1" level="project" />
<orderEntry type="library" name="Maven: net.sf.ezmorph:ezmorph:1.0.6" level="project" />
<orderEntry type="library" name="Maven: com.qiniu:qiniu-java-sdk:7.2.27" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.squareup.okhttp3:okhttp:3.14.4" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.squareup.okio:okio:1.17.2" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: com.google.code.gson:gson:2.8.5" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-mail:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.sun.mail:javax.mail:1.6.2" level="project" />
<orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-data-redis:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-redis:2.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-keyvalue:2.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.data:spring-data-commons:2.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-oxm:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.lettuce:lettuce-core:5.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.33.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.33.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.33.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.33.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.33.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.33.Final" level="project" />
<orderEntry type="library" name="Maven: io.projectreactor:reactor-core:3.2.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.reactivestreams:reactive-streams:1.0.2" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:2.0.1" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.1.3.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.2.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.1.5.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:2.0.1" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.1" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.1" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.2.12" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.2.12" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.1.10" level="project" />
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:2.0" level="project" />
<orderEntry type="library" name="Maven: com.dyuproject.protostuff:protostuff-core:1.0.8" level="project" />
<orderEntry type="library" name="Maven: com.dyuproject.protostuff:protostuff-api:1.0.8" level="project" />
<orderEntry type="library" name="Maven: com.dyuproject.protostuff:protostuff-runtime:1.0.8" level="project" />
<orderEntry type="library" name="Maven: com.dyuproject.protostuff:protostuff-collectionschema:1.0.8" level="project" />
<orderEntry type="library" name="Maven: eu.bitwalker:UserAgentUtils:1.20" level="project" />
<orderEntry type="library" name="Maven: junit:junit:4.12" level="project" />
<orderEntry type="library" name="Maven: io.jsonwebtoken:jjwt:0.9.1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.8" level="project" />
</component>
</module>

92
blog.sql Normal file
View File

@@ -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 '用户表';

286
mvnw vendored Normal file
View File

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

161
mvnw.cmd vendored Normal file
View File

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

162
pom.xml Normal file
View File

@@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.celess</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>blog</name>
<description>personal blog system project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.14</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!--MarkDown 2 html -->
<dependency>
<groupId>com.youbenzi</groupId>
<artifactId>MDTool</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.3</version>
<scope>compile</scope>
</dependency>
<!--Json-->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<!-- 七牛云SDK -->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.2.0, 7.2.99]</version>
</dependency>
<!--Email-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!-- pageHelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<!-- protostuff序列化依赖 -->
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.0.8</version>
</dependency>
<dependency>
<groupId>com.dyuproject.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.0.8</version>
</dependency>
<!-- Ua解析-->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>1.20</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- JJwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,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("启动完成!");
}
}

View File

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

View File

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

View File

@@ -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<SessionListener> servletListenerRegistrationBean() {
// ServletListenerRegistrationBean<SessionListener> slrBean = new ServletListenerRegistrationBean<SessionListener>();
// slrBean.setListener(new SessionListener());
// return slrBean;
// }
}

View File

@@ -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<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

View File

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

View File

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

View File

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

View File

@@ -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<String, Integer> visitDetail = (HashMap<String, Integer>) 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;
}
}

View File

@@ -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<String, Integer>());
// se.getSession().setMaxInactiveInterval(10);// 10s for debug
logger.info("新增一个Session[{}]", se.getSession().getId());
}
@SuppressWarnings("unchecked")
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HashMap<String, Integer> visitDetail = (HashMap<String, Integer>) 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());
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<String, Long> 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<String, Object> map = new HashMap<>();
Enumeration<String> 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());
}
}

View File

@@ -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<JSONObject> nameAndCount = new ArrayList<>();
List<Tag> 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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<Article> findAllByAuthorId(long authorID);
List<Article> findAllByOpen(boolean isOpen);
String getTitleById(long id);
List<Article> findAllByCategoryId(long id);
List<Article> findAll();
Article getSimpleInfo(long id);
List<Article> getSimpleInfoByCategory(long categoryId);
List<Article> getSimpleInfoByTag(List<String> idList);
int setReadingNumber(long number, long id);
long count();
}

View File

@@ -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<Category> findAll();
List<String> getAllName();
String getNameById(long id);
Long getIDByName(String name);
Category getLastestCategory();
long count();
}

View File

@@ -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<Comment> findAllByAuthorIDAndType(long id, boolean isComment);
List<Comment> findAllByPId(long pid);
List<Comment> findAllByArticleID(long articleId);
List<Comment> findAllByArticleIDAndPId(long articleID, long pid);
List<Comment> findCommentsByTypeAndPId(boolean isComment, long pid);
List<Comment> findAllByPId(int pid);
List<Comment> findAllByType(boolean isComment);
long countByType(boolean isComment);
}

View File

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

View File

@@ -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<Tag> findAll();
long count();
}

View File

@@ -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<User> findAll();
int update(User user);
}

View File

@@ -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<Visitor> findAll();
long count();
}

View File

@@ -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<WebUpdate> findAll();
Date getLastestOne();
}

View File

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

View File

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

View File

@@ -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<CommentModel> retrievePage(Boolean isComment, int page, int count);
/**
* 通过pid获取数据
*
* @param pid 父id
* @param count 单页数据量
* @param page 数据页
* @return 分页数据
*/
PageInfo<CommentModel> retrievePageByPid(long pid, int page, int count);
/**
* 根据评论者获取数据
*
* @param isComment true评论 false留言
* @param count 单页数据量
* @param page 数据页
* @return 分页数据
*/
PageInfo<CommentModel> retrievePageByAuthor(Boolean isComment, int page, int count);
/**
* 根据文章获取数据
*
* @param articleID 文章id
* @param pid 父id
* @param count 单页数据量
* @param page 数据页
* @return 分页数据
*/
PageInfo<CommentModel> retrievePageByArticle(long articleID, long pid, int page, int count);
/**
* 根据数据的type和pid获取数据
*
* @param isComment true评论 false留言
* @param pid 父id
* @param count 单页数据量
* @param page 数据页
* @return 分页数据
*/
PageInfo<CommentModel> retrievePageByTypeAndPid(Boolean isComment, int pid, int page, int count);
/**
* 根据type获取数据
*
* @param isComment true评论 false留言
* @param count 单页数据量
* @param page 数据页
* @return 分页数据
*/
PageInfo<CommentModel> retrievePageByType(Boolean isComment, int page, int count);
}

View File

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

View File

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

View File

@@ -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<PartnerSite> PartnerSitePages(int page, int count);
/**
* 获取全部数据
*
* @return 全部友链数据
*/
List<PartnerSite> findAll();
}

View File

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

View File

@@ -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<Tag> retrievePage(int page, int count);
/**
* 获取全部标签数据
*
* @return 标签数据列表
*/
List<Tag> findAll();
}

View File

@@ -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<UserModel> getUserList(Integer page, Integer count);
/**
* 更改用户信息
*
* @param user 用户数据
* @return 用户信息
*/
UserModel adminUpdate(UserReq user);
/**
* 获取电子邮件的存在状态
*
* @param email email
* @return true:存在 false不存在
*/
boolean getStatusOfEmail(String email);
}

View File

@@ -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<VisitorModel> visitorPage(int page, int count, boolean showLocation);
/**
* 新增访客
*
* @param request HttpServletRequest
* @return 返回状态 null: 访客信息已记录、爬虫
*/
VisitorModel addVisitor(HttpServletRequest request);
/**
* 获取位置信息
*
* @param ip ip地址
* @return 位置信息
*/
String location(String ip);
}

View File

@@ -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<WebUpdateModel> pages(int count, int page);
/**
* 获取全部的更新记录
*
* @return 更新记录
*/
List<WebUpdateModel> findAll();
/**
* 获取最后更新时间
*
* @return
*/
String getLastestUpdateTime();
}

View File

@@ -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<Article> 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<Article> 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<String> list = Arrays.asList(split);
List<Article> articleList = articleMapper.getSimpleInfoByTag(list);
PageInfo pageInfo = new PageInfo(articleList);
return pageInfo;
}
/**
* page转换
*
* @param articleList 数据源
* @param level 转换级别
* @return list
*/
private List<ArticleModel> list2list(List<Article> articleList, LevelEnum level) {
List<ArticleModel> 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;
}
}

View File

@@ -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<Category> retrievePage() {
return categoryMapper.findAll();
}
}

View File

@@ -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<CommentModel> retrievePage(Boolean isComment, int page, int count) {
PageHelper.startPage(page, count);
List<Comment> commentList = commentMapper.findAllByType(isComment);
PageInfo pageInfo = new PageInfo(commentList);
pageInfo.setList(list2List(commentList));
return pageInfo;
}
@Override
public PageInfo<CommentModel> retrievePageByPid(long pid, int page, int count) {
PageHelper.startPage(page, count);
List<Comment> commentList = commentMapper.findAllByPId(pid);
PageInfo pageInfo = new PageInfo(commentList);
pageInfo.setList(list2List(commentList));
return pageInfo;
}
@Override
public PageInfo<CommentModel> retrievePageByArticle(long articleID, long pid, int page, int count) {
PageHelper.startPage(page, count);
List<Comment> commentList = commentMapper.findAllByArticleIDAndPId(articleID, pid);
PageInfo pageInfo = new PageInfo(commentList);
pageInfo.setList(list2List(commentList));
return pageInfo;
}
@Override
public PageInfo<CommentModel> retrievePageByTypeAndPid(Boolean isComment, int pid, int page, int count) {
PageHelper.startPage(page, count);
List<Comment> commentList = commentMapper.findCommentsByTypeAndPId(isComment, pid);
PageInfo pageInfo = new PageInfo(commentList);
pageInfo.setList(list2List(commentList));
return pageInfo;
}
@Override
public PageInfo<CommentModel> retrievePageByAuthor(Boolean isComment, int page, int count) {
PageHelper.startPage(page, count);
List<Comment> commentList = commentMapper.findAllByAuthorIDAndType(redisUserUtil.get(request).getId(), isComment);
PageInfo pageInfo = new PageInfo(commentList);
pageInfo.setList(list2List(commentList));
return pageInfo;
}
@Override
public PageInfo<CommentModel> retrievePageByType(Boolean isComment, int page, int count) {
PageHelper.startPage(page, count);
List<Comment> commentList = commentMapper.findAllByType(isComment);
PageInfo pageInfo = new PageInfo(commentList);
pageInfo.setList(list2List(commentList));
return pageInfo;
}
private List<CommentModel> list2List(List<Comment> commentList) {
List<CommentModel> 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;
}
}

View File

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

View File

@@ -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 = "<xiaohai2271@163.com>";
@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;
}
}

View File

@@ -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<PartnerSite> PartnerSitePages(int page, int count) {
PageHelper.startPage(page, count);
List<PartnerSite> sitePage = partnerMapper.findAll();
PageInfo pageInfo = new PageInfo(sitePage);
return pageInfo;
}
@Override
public List<PartnerSite> findAll() {
List<PartnerSite> all = partnerMapper.findAll();
return all;
}
}

View File

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

View File

@@ -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<Tag> retrievePage(int page, int count) {
PageHelper.startPage(page, count);
PageInfo pageInfo = new PageInfo(tagMapper.findAll());
return pageInfo;
}
@Override
public List<Tag> findAll() {
return tagMapper.findAll();
}
}

View File

@@ -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<UserModel> getUserList(Integer page, Integer count) {
PageHelper.startPage(page, count);
List<User> all = userMapper.findAll();
PageInfo pageInfo = PageInfo.of(all);
List<UserModel> 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;
}
}

View File

@@ -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<VisitorModel> visitorPage(int page, int count, boolean showLocation) {
PageHelper.startPage(page, count);
List<Visitor> 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<VisitorModel> list2List(List<Visitor> visitorList, boolean showLocation) {
List<VisitorModel> 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<String, Object> 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();
}
}

View File

@@ -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<WebUpdateModel> pages(int count, int page) {
PageHelper.startPage(page, count);
List<WebUpdate> updateList = webUpdateInfoMapper.findAll();
PageInfo pageInfo = new PageInfo(updateList);
pageInfo.setList(list2List(updateList));
return pageInfo;
}
@Override
public List<WebUpdateModel> findAll() {
List<WebUpdate> all = webUpdateInfoMapper.findAll();
List<WebUpdateModel> webUpdateModels = new ArrayList<>();
for (WebUpdate w : all) {
webUpdateModels.add(trans(w));
}
return webUpdateModels;
}
@Override
public String getLastestUpdateTime() {
return DateFormatUtil.get(webUpdateInfoMapper.getLastestOne());
}
private List<WebUpdateModel> list2List(List<WebUpdate> webUpdates) {
List<WebUpdateModel> 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()));
}
}

View File

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

View File

@@ -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<String, Object> 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;
}
}

View File

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

View File

@@ -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 <T> byte[] serialize(T obj) {
if (obj == null) {
throw new RuntimeException("序列化对象(" + obj + ")!");
}
@SuppressWarnings("unchecked")
Schema<T> schema = (Schema<T>) 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> T deserialize(byte[] paramArrayOfByte, Class<T> 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<T> schema = RuntimeSchema.getSchema(targetClass);
ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
return instance;
}
/**
* 序列化列表
*
* @param objList
* @return
*/
public static <T> byte[] serializeList(List<T> objList) {
if (objList == null || objList.isEmpty()) {
throw new RuntimeException("序列化对象列表(" + objList + ")参数异常!");
}
@SuppressWarnings("unchecked")
Schema<T> schema = (Schema<T>) 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 <T> List<T> deserializeList(byte[] paramArrayOfByte, Class<T> targetClass) {
if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
throw new RuntimeException("反序列化对象发生异常,byte序列为空!");
}
Schema<T> schema = RuntimeSchema.getSchema(targetClass);
List<T> result = null;
try {
result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema);
} catch (IOException e) {
throw new RuntimeException("反序列化对象列表发生异常!", e);
}
return result;
}
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -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<String, String> 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<Article> 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;
}
}

View File

@@ -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中提取纯文本
//剔出<html>的标签
String txtcontent = html.replaceAll("</?[^>]+>", "");
//去除字符串中的空格,回车,换行符,制表符
txtcontent = txtcontent.replaceAll("<a>\\s*|\t|\r|\n</a>", "");
return txtcontent;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.celess.blog.mapper.CategoryMapper">
<resultMap id="categoryResultMap" type="cn.celess.blog.entity.Category">
<id column="c_id" property="id"/>
<result column="c_name" property="name"/>
</resultMap>
<insert id="insert">
insert into category (c_name, articles)
values (#{name}, #{articles});
<selectKey resultType="java.lang.Long" keyProperty="id">
SELECT LAST_INSERT_ID() AS id
</selectKey>
</insert>
<update id="update">
update category
set c_name=#{name},
articles=#{articles}
where c_id = #{id}
</update>
<delete id="delete">
delete
from category
where c_id = #{id}
</delete>
<select id="findCategoryByName" resultMap="categoryResultMap">
select *
from category
where c_name = #{name}
</select>
<select id="findCategoryById" resultMap="categoryResultMap">
select *
from category
where c_id = #{id}
</select>
<select id="findAll" resultMap="categoryResultMap">
select *
from category
</select>
<select id="getAllName" resultType="java.lang.String">
select c_name
from category
</select>
<select id="getNameById" resultType="java.lang.String">
select c_name
from category
where c_id = #{id}
</select>
<select id="getIDByName" resultType="java.lang.Long">
select c_id
from category
where c_name = #{name}
</select>
<select id="existsByName" resultType="java.lang.Boolean">
SELECT EXISTS(SELECT * FROM category WHERE c_name = #{name})
</select>
<select id="existsById" resultType="java.lang.Boolean">
SELECT EXISTS(SELECT * FROM category WHERE c_id = #{id})
</select>
<select id="getLastestCategory" resultMap="categoryResultMap">
select *
from category
order by c_id desc
limit 1;
</select>
<select id="count" resultType="java.lang.Long">
select count(*)
from category;
</select>
</mapper>

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