├── .gitignore
├── .mvn
└── wrapper
│ ├── MavenWrapperDownloader.java
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── LICENSE
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── docker
│ └── Dockerfile
├── java
│ └── com
│ │ └── hiyj
│ │ └── blog
│ │ ├── LBlogApplication.java
│ │ ├── annotation
│ │ ├── PassToken.java
│ │ └── Permission.java
│ │ ├── caches
│ │ └── redis
│ │ │ ├── JDKSerializer.java
│ │ │ ├── RedisCache.java
│ │ │ ├── RedisCallback.java
│ │ │ ├── RedisConfig.java
│ │ │ ├── RedisConfigurationBuilder.java
│ │ │ └── Serializer.java
│ │ ├── config
│ │ └── WebConfig.java
│ │ ├── controller
│ │ ├── ArticleController.java
│ │ ├── ArticleLabelController.java
│ │ ├── CommentController.java
│ │ ├── FileController.java
│ │ ├── FriendLinkController.java
│ │ ├── OtherController.java
│ │ ├── SysConfigController.java
│ │ └── UserController.java
│ │ ├── doc
│ │ └── SwaggerConfig.java
│ │ ├── exception
│ │ └── GlobalExceptionHandler.java
│ │ ├── interceptor
│ │ ├── CodeInterceptor.java
│ │ ├── CrosInterceptor.java
│ │ ├── MappingInterceptor.java
│ │ └── PermissionsInterceptor.java
│ │ ├── mapper
│ │ ├── ArticleLabelMapper.java
│ │ ├── ArticleMapper.java
│ │ ├── CommentMapper.java
│ │ ├── FileMapper.java
│ │ ├── LinkMapper.java
│ │ ├── PermissionMapper.java
│ │ ├── RoleMapper.java
│ │ ├── SysConfigMapper.java
│ │ └── UserMapper.java
│ │ ├── model
│ │ ├── request
│ │ │ ├── ArticlePageModel.java
│ │ │ ├── CodeUrlModel.java
│ │ │ ├── ContentModel.java
│ │ │ ├── IdModel.java
│ │ │ ├── IdTokenModel.java
│ │ │ ├── IdTokenTypeModel.java
│ │ │ ├── IdTypeModel.java
│ │ │ ├── PageBaseModel.java
│ │ │ ├── PageModel.java
│ │ │ ├── ReqCommentModel.java
│ │ │ ├── ReqFriendLinkModel.java
│ │ │ ├── ReqFriendLinkStatusModel.java
│ │ │ ├── TokenModel.java
│ │ │ └── TokenTypeModel.java
│ │ ├── response
│ │ │ ├── ClientIdModel.java
│ │ │ ├── RspCommentsModel.java
│ │ │ ├── RspFriendLinkModel.java
│ │ │ └── RspListType.java
│ │ └── share
│ │ │ └── ClientModel.java
│ │ ├── object
│ │ ├── Article.java
│ │ ├── ArticleLabel.java
│ │ ├── ArticleType.java
│ │ ├── CakeChartData.java
│ │ ├── Comment.java
│ │ ├── FriendLink.java
│ │ ├── Msg.java
│ │ ├── OtherUser.java
│ │ ├── PanelData.java
│ │ ├── Permission.java
│ │ ├── Role.java
│ │ ├── SysUiConfig.java
│ │ ├── User.java
│ │ └── base
│ │ │ ├── CommentBase.java
│ │ │ ├── LabelBase.java
│ │ │ ├── Link.java
│ │ │ └── PermissionRole.java
│ │ ├── oss
│ │ └── OssUtils.java
│ │ ├── services
│ │ ├── ArticleJsonService.java
│ │ ├── ArticleLabelJsonService.java
│ │ ├── CommentJsonService.java
│ │ ├── FileJsonService.java
│ │ ├── FriendLinkJsonService.java
│ │ ├── OtherJsonService.java
│ │ ├── SysConfigJsonService.java
│ │ ├── UserJsonService.java
│ │ ├── base
│ │ │ ├── ArticleLabelService.java
│ │ │ ├── ArticleService.java
│ │ │ ├── CommentService.java
│ │ │ ├── FileService.java
│ │ │ ├── FriendLinkService.java
│ │ │ ├── OtherService.java
│ │ │ ├── PermissionService.java
│ │ │ ├── RoleService.java
│ │ │ ├── SysConfigService.java
│ │ │ └── UserService.java
│ │ └── otherlogin
│ │ │ └── GiteeService.java
│ │ └── utils
│ │ ├── CodeUtils.java
│ │ └── JwtUtils.java
└── resources
│ ├── application-dev.yml
│ ├── application-prod.yml
│ ├── application.yml
│ ├── db
│ └── migration
│ │ └── V1_0_1__init.sql
│ └── mybatis
│ └── mapper
│ ├── ArticleLabelMapper.xml
│ ├── ArticleMapper.xml
│ ├── CommentMapper.xml
│ ├── LinkMapper.xml
│ ├── PermissionMapper.xml
│ ├── RoleMapper.xml
│ ├── SysConfigMapper.xml
│ └── UserMapper.xml
└── test
└── java
└── com
└── hiyj
└── blog
├── LBlogApplicationTests.java
├── caches
└── redis
│ └── RedisConfigTest.java
├── mapper
├── ArticleLabelMapperTest.java
├── ArticleMapperTest.java
├── CommentMapperTest.java
├── LinkMapperTest.java
├── PermissionsServiceTest.java
├── RoleMapperTest.java
├── SysConfigMapperTest.java
└── UserMapperTest.java
├── oss
└── OssUtilsTest.java
├── services
├── ArticleLabelServiceTest.java
├── ArticleServiceTest.java
├── CommentServiceTest.java
├── FileServiceTest.java
├── GiteeServiceTest.java
├── OtherServiceTest.java
├── SysConfigServiceTest.java
└── UserServiceTest.java
├── test
├── HttpRequestTest.java
└── TestEnum.java
└── utils
└── JwtUtilsTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
35 | ### log ###
36 | log.*
37 | /log/
38 | *.log
--------------------------------------------------------------------------------
/.mvn/wrapper/MavenWrapperDownloader.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2007-present the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | import java.net.*;
18 | import java.io.*;
19 | import java.nio.channels.*;
20 | import java.util.Properties;
21 |
22 | public class MavenWrapperDownloader {
23 |
24 | private static final String WRAPPER_VERSION = "0.5.6";
25 | /**
26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
27 | */
28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
30 |
31 | /**
32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
33 | * use instead of the default one.
34 | */
35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
36 | ".mvn/wrapper/maven-wrapper.properties";
37 |
38 | /**
39 | * Path where the maven-wrapper.jar will be saved to.
40 | */
41 | private static final String MAVEN_WRAPPER_JAR_PATH =
42 | ".mvn/wrapper/maven-wrapper.jar";
43 |
44 | /**
45 | * Name of the property which should be used to override the default download url for the wrapper.
46 | */
47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
48 |
49 | public static void main(String args[]) {
50 | System.out.println("- Downloader started");
51 | File baseDirectory = new File(args[0]);
52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
53 |
54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom
55 | // wrapperUrl parameter.
56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
57 | String url = DEFAULT_DOWNLOAD_URL;
58 | if (mavenWrapperPropertyFile.exists()) {
59 | FileInputStream mavenWrapperPropertyFileInputStream = null;
60 | try {
61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
62 | Properties mavenWrapperProperties = new Properties();
63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
65 | } catch (IOException e) {
66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
67 | } finally {
68 | try {
69 | if (mavenWrapperPropertyFileInputStream != null) {
70 | mavenWrapperPropertyFileInputStream.close();
71 | }
72 | } catch (IOException e) {
73 | // Ignore ...
74 | }
75 | }
76 | }
77 | System.out.println("- Downloading from: " + url);
78 |
79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
80 | if (!outputFile.getParentFile().exists()) {
81 | if (!outputFile.getParentFile().mkdirs()) {
82 | System.out.println(
83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
84 | }
85 | }
86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
87 | try {
88 | downloadFileFromURL(url, outputFile);
89 | System.out.println("Done");
90 | System.exit(0);
91 | } catch (Throwable e) {
92 | System.out.println("- Error downloading");
93 | e.printStackTrace();
94 | System.exit(1);
95 | }
96 | }
97 |
98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception {
99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
100 | String username = System.getenv("MVNW_USERNAME");
101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
102 | Authenticator.setDefault(new Authenticator() {
103 | @Override
104 | protected PasswordAuthentication getPasswordAuthentication() {
105 | return new PasswordAuthentication(username, password);
106 | }
107 | });
108 | }
109 | URL website = new URL(urlString);
110 | ReadableByteChannel rbc;
111 | rbc = Channels.newChannel(website.openStream());
112 | FileOutputStream fos = new FileOutputStream(destination);
113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
114 | fos.close();
115 | rbc.close();
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WindSnowLi/w-blog-api/5636845ead19a03a37e29062b3a8a44eda6fa78b/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 WindSnowLi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # w-blog
2 |
3 | ## 描述
4 |
5 | 一个后端使用Spring Boot 2.x、前台使用nuxtJs、后台使用vue的个人博客
6 |
7 | ## 简介
8 |
9 | 1. 链接
10 | * Gitee链接:
11 | * [api](https://gitee.com/windsnowli/w-blog-api): `https://gitee.com/windsnowli/w-blog-api`
12 |
13 | * [前台](https://gitee.com/windsnowli/vue-ssr-blog): `https://gitee.com/windsnowli/vue-ssr-blog`
14 |
15 | * [后台](https://gitee.com/windsnowli/vue-admin-blog): `https://gitee.com/windsnowli/vue-admin-blog`
16 |
17 | * GitHub链接:
18 | * [api](https://github.com/WindSnowLi/w-blog-api): `https://github.com/WindSnowLi/w-blog-api`
19 |
20 | * [前台](https://github.com/WindSnowLi/vue-ssr-blog): `https://github.com/WindSnowLi/vue-ssr-blog`
21 |
22 | * [后台](https://github.com/WindSnowLi/vue-admin-blog): `https://github.com/WindSnowLi/vue-admin-blog`
23 |
24 | 2. 一个简单的的个人博客项目,共分为了 `前台`、 `后台`、 `api`三个部分。
25 |
26 | * api: 后端基于 `SpringBoot` 。主要依赖 `Mybatis` 、 `Mybatis-Redis` 、 `Redis` 、 `fastjson` 、 `DruidDataSource` 、 `Lombok` 、 `java-jwt` 、 `aliyun-sdk-oss` 、 `knife4j` 等,数据库使用的是 `MySQL8.0+`
27 |
28 | * 前台: 前台的主要样式是来源于网络上了一个 `BizBlog` 模板,最初来源于哪我不得而知,在原本的基础上改写成了 `nuxtJs` 项目。
29 | * 后台: 后台UI套用的[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin),基本是直接拿来用了,想自己定制着实实力不允许。
30 |
31 | 3. 示例:[绿色食品——菜狗](https://www.blog.hiyj.cn/)
32 |
33 | ## 本地启动
34 |
35 | ### api:前台后台请求的api使用的是同一个项目
36 |
37 | 1. `git clone https://gitee.com/WindSnowLi/w-blog-api.git`或`git clone https://github.com/WindSnowLi/w-blog-api.git` 克隆项目到本地
38 | 2. `mvn clean install dependency:tree` 安装依赖
39 | 3. 创建数据库,并设置为`UTF8`编码(`utf8mb4`)
40 | 4. 修改环境设置
41 | * 修改开发环境 `application-dev.yml` 和生产环境 `application-prod.yml` 中的数据库配置信息;
42 | * 修改 `redis.properties` 中的 `Redis` 相关信息;
43 | * 注: `knife4j` 只在开发环境中激活。
44 |
45 | 5. `mvn clean package -Dmaven.test.skip=true` 跳过测试并生成 `jar` 包
46 | 6. `java -jar 生成的包名.jar` 运行开发配置环境,初次运行会自动初始化数据库(生产环境可指定加载的配置文件`--spring.profiles.active="prod"`)
47 | 7. 访问 `http://127.0.0.1:9000/doc.html` 查看 `api` 文档
48 | 8. *推荐使用IDEA打开项目文件夹自动处理依赖、方便运行*
49 |
50 | ### 前台
51 |
52 | 1. `git clone https://gitee.com/WindSnowLi/vue-ssr-blog.git`或`git clone https://github.com/WindSnowLi/vue-ssr-blog.git` 克隆项目到本地
53 | 2. `npm install` 安装依赖
54 | 3. 可修改 `config/sitemap.xml` 文件中的 `host` 地址,用于生成访问地图
55 | 4. 可修改 `nuxt.config.js` 中的端口号
56 | 5. 可修改 `package.json` 文件中的 `script` 中的 `BASE_URL` 来指定后端 `api` 地址
57 | 6. `npm run build` 编译
58 | 7. `npm start` 本地运行
59 |
60 | ### 后台
61 |
62 | 1. `git clone https://gitee.com/WindSnowLi/vue-admin-blog.git`或`git clone https://github.com/WindSnowLi/vue-admin-blog.git` 克隆项目到本地
63 | 2. `npm install` 安装依赖
64 | 3. `npm run dev` 使用模拟数据预览界面
65 | 4. 修改 `.env.production` 文件中的 `VUE_APP_BASE_API` 地址为后端 `api` 的地址
66 | 5. `npm run build:prod` 编译
67 | 6. `dist` 文件夹下的为编译好的文件,可放到 `http` 服务器下(可以使用 `npm` 安装 `http-server` )进行访问
68 |
69 | ## 界面展示
70 |
71 | ### 前台
72 |
73 | 
74 |
75 |
76 |
77 | 
78 |
79 |
80 |
81 | 
82 |
83 | ### 后台
84 |
85 | 
86 |
87 |
88 |
89 | 
90 |
91 |
92 |
93 | 
94 |
95 |
96 |
97 | 
98 |
99 |
100 |
101 | 
102 |
103 | ## License
104 |
105 | [MIT](https://github.com/WindSnowLi/w-blog-api/blob/master/LICENSE)
106 |
107 | Copyright (c) 2021 WindSnowLi
108 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.5.0
9 |
10 |
11 | com.hiyj
12 | w-blog
13 | 1.0.1
14 | w-blog
15 | WindSnowLi blog
16 |
17 | 11
18 | w-blog
19 |
20 |
21 |
22 | org.mybatis.spring.boot
23 | mybatis-spring-boot-starter
24 | 2.1.4
25 |
26 |
27 | com.alibaba
28 | fastjson
29 | 1.2.62
30 |
31 |
32 | com.alibaba.druid
33 | druid-wrapper
34 | 0.2.9
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-web-services
39 |
40 |
41 |
42 | mysql
43 | mysql-connector-java
44 | runtime
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-test
49 | test
50 |
51 |
52 | org.projectlombok
53 | lombok
54 |
55 |
56 | com.auth0
57 | java-jwt
58 | 3.4.0
59 |
60 |
61 |
62 | com.aliyun.oss
63 | aliyun-sdk-oss
64 | 3.10.2
65 |
66 |
67 | javax.activation
68 | activation
69 | 1.1.1
70 |
71 |
72 |
73 | org.glassfish.jaxb
74 | jaxb-runtime
75 | 2.3.3
76 |
77 |
78 |
79 | com.fasterxml.uuid
80 | java-uuid-generator
81 | 3.3.0
82 |
83 |
84 |
85 | com.github.xiaoymin
86 | knife4j-spring-boot-starter
87 | 3.0.3
88 |
89 |
90 |
91 |
92 | org.flywaydb
93 | flyway-core
94 | 5.2.4
95 |
96 |
97 |
98 |
99 | redis.clients
100 | jedis
101 | 3.7.0
102 |
103 |
104 |
105 |
106 |
107 |
108 | org.springframework.boot
109 | spring-boot-maven-plugin
110 | 2.5.3
111 |
112 |
113 |
114 | repackage
115 |
116 |
117 |
118 |
119 |
120 |
121 | com.spotify
122 | docker-maven-plugin
123 | 1.0.0
124 |
125 |
126 | javax.activation
127 | activation
128 | 1.1.1
129 |
130 |
131 |
132 | ${docker.image.prefix}/${project.artifactId}
133 | src/main/docker
134 |
135 |
136 | /
137 | ${project.build.directory}
138 | ${project.build.finalName}.jar
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/src/main/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM adoptopenjdk/openjdk11:jre-11.0.6_10-alpine
2 |
3 | LABEL "author"="WindSnowLi"
4 | LABEL "version"="1.0.1"
5 | LABEL "email"="windsnowli@163.com"
6 |
7 | ADD w-blog-1.0.1.jar w-blog.jar
8 |
9 | # 配置环境变量支持中文
10 | ENV LANG="en_US.UTF-8"
11 |
12 | # 环境配置文件
13 | ENV active="dev"
14 |
15 | EXPOSE 9000
16 |
17 | CMD ["sh","-c","java -jar w-blog.jar --spring.profiles.active=$active"]
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/LBlogApplication.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog;
2 |
3 | import com.alibaba.druid.pool.DruidDataSource;
4 | import com.hiyj.blog.caches.redis.RedisConfigurationBuilder;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.SpringApplication;
7 | import org.springframework.boot.autoconfigure.SpringBootApplication;
8 | import org.springframework.boot.context.properties.ConfigurationProperties;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Import;
11 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
12 |
13 | @EnableSwagger2
14 | @SpringBootApplication
15 | @Import(RedisConfigurationBuilder.class)
16 | public class LBlogApplication {
17 |
18 | @Autowired
19 | public void setRedisConfigurationBuilder(RedisConfigurationBuilder redisConfigurationBuilder) {
20 | // 为了优先加载
21 | }
22 |
23 | public static void main(String[] args) {
24 | SpringApplication.run(LBlogApplication.class, args);
25 | }
26 |
27 | @Bean(name = "DruidDataSource", destroyMethod = "close", initMethod = "init")
28 | @ConfigurationProperties(prefix = "spring.datasource")
29 | public DruidDataSource druidDataSource() {
30 | return new DruidDataSource();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/annotation/PassToken.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.annotation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * @author windSnowLi
10 | */
11 | @Target({ElementType.METHOD, ElementType.TYPE})
12 | @Retention(RetentionPolicy.RUNTIME)
13 | public @interface PassToken {
14 | boolean required() default true;
15 | }
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/annotation/Permission.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Permission.java, 2021-08-26
3 | *
4 | * Copyright 2021 by WindSnowLi, Inc. All rights reserved.
5 | *
6 | */
7 |
8 | package com.hiyj.blog.annotation;
9 |
10 | import java.lang.annotation.ElementType;
11 | import java.lang.annotation.Retention;
12 | import java.lang.annotation.RetentionPolicy;
13 | import java.lang.annotation.Target;
14 |
15 | @Target({ElementType.METHOD, ElementType.TYPE})
16 | @Retention(RetentionPolicy.RUNTIME)
17 | public @interface Permission {
18 | // 需要的权限
19 | String[] value() default {};
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/caches/redis/JDKSerializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.hiyj.blog.caches.redis;
17 |
18 | import java.io.ByteArrayInputStream;
19 | import java.io.ByteArrayOutputStream;
20 | import java.io.ObjectInputStream;
21 | import java.io.ObjectOutputStream;
22 |
23 | import org.apache.ibatis.cache.CacheException;
24 |
25 | public enum JDKSerializer implements Serializer {
26 | // Enum singleton, which is preferred approach since Java 1.5
27 | INSTANCE;
28 |
29 | JDKSerializer() {
30 | // prevent instantiation
31 | }
32 |
33 | public byte[] serialize(Object object) {
34 | try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
35 | ObjectOutputStream oos = new ObjectOutputStream(baos)) {
36 | oos.writeObject(object);
37 | return baos.toByteArray();
38 | } catch (Exception e) {
39 | throw new CacheException(e);
40 | }
41 | }
42 |
43 | public Object unserialize(byte[] bytes) {
44 | if (bytes == null) {
45 | return null;
46 | }
47 | try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
48 | ObjectInputStream ois = new ObjectInputStream(bais)) {
49 | return ois.readObject();
50 | } catch (Exception e) {
51 | throw new CacheException(e);
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/caches/redis/RedisCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.hiyj.blog.caches.redis;
17 |
18 | import org.apache.ibatis.cache.Cache;
19 | import redis.clients.jedis.Jedis;
20 | import redis.clients.jedis.JedisPool;
21 |
22 | import java.util.Map;
23 |
24 | /**
25 | * Cache adapter for Redis.
26 | *
27 | * @author Eduardo Macarron
28 | */
29 | public class RedisCache implements Cache {
30 |
31 | private final String id;
32 |
33 | private static JedisPool pool;
34 |
35 | private final RedisConfig redisConfig;
36 |
37 | public RedisCache(final String id) {
38 | if (id == null) {
39 | throw new IllegalArgumentException("Cache instances require an ID");
40 | }
41 | this.id = id;
42 | redisConfig = RedisConfigurationBuilder.getRedisConfig();
43 | pool = new JedisPool(redisConfig, redisConfig.getHost(), redisConfig.getPort(), redisConfig.getConnectionTimeout(),
44 | redisConfig.getSoTimeout(), redisConfig.getPassword(), redisConfig.getDatabase(), redisConfig.getClientName(),
45 | redisConfig.isSsl(), redisConfig.getSslSocketFactory(), redisConfig.getSslParameters(),
46 | redisConfig.getHostnameVerifier());
47 | }
48 |
49 | // TODO Review this is UNUSED
50 | private Object execute(RedisCallback callback) {
51 | try (Jedis jedis = pool.getResource()) {
52 | return callback.doWithRedis(jedis);
53 | }
54 | }
55 |
56 | @Override
57 | public String getId() {
58 | return this.id;
59 | }
60 |
61 | @Override
62 | public int getSize() {
63 | return (Integer) execute(jedis -> {
64 | Map result = jedis.hgetAll(id.getBytes());
65 | return result.size();
66 | });
67 | }
68 |
69 | @Override
70 | public void putObject(final Object key, final Object value) {
71 | execute(jedis -> {
72 | final byte[] idBytes = id.getBytes();
73 | jedis.hset(idBytes, key.toString().getBytes(), redisConfig.getSerializer().serialize(value));
74 | if (redisConfig.getTimeout() != null && jedis.ttl(idBytes) == -1) {
75 | jedis.expire(idBytes, redisConfig.getTimeout());
76 | }
77 | return null;
78 | });
79 | }
80 |
81 | @Override
82 | public Object getObject(final Object key) {
83 | return execute(jedis -> redisConfig.getSerializer().unserialize(jedis.hget(id.getBytes(), key.toString().getBytes())));
84 | }
85 |
86 | @Override
87 | public Object removeObject(final Object key) {
88 | return execute(jedis -> jedis.hdel(id, key.toString()));
89 | }
90 |
91 | @Override
92 | public void clear() {
93 | execute(jedis -> {
94 | jedis.del(id);
95 | return null;
96 | });
97 |
98 | }
99 |
100 | @Override
101 | public String toString() {
102 | return "Redis {" + id + "}";
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/caches/redis/RedisCallback.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.hiyj.blog.caches.redis;
17 |
18 | import redis.clients.jedis.Jedis;
19 |
20 | public interface RedisCallback {
21 |
22 | Object doWithRedis(Jedis jedis);
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/caches/redis/RedisConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.hiyj.blog.caches.redis;
17 |
18 | import lombok.Getter;
19 | import lombok.Setter;
20 | import lombok.ToString;
21 | import org.springframework.boot.context.properties.ConfigurationProperties;
22 | import org.springframework.stereotype.Component;
23 | import redis.clients.jedis.JedisPoolConfig;
24 | import redis.clients.jedis.Protocol;
25 |
26 | import javax.net.ssl.HostnameVerifier;
27 | import javax.net.ssl.SSLParameters;
28 | import javax.net.ssl.SSLSocketFactory;
29 |
30 | @Component
31 | @ConfigurationProperties(prefix = "redis")
32 | @ToString
33 | @Getter
34 | @Setter
35 | public class RedisConfig extends JedisPoolConfig {
36 | private String host = Protocol.DEFAULT_HOST;
37 | private int port = Protocol.DEFAULT_PORT;
38 | private int connectionTimeout = Protocol.DEFAULT_TIMEOUT;
39 | private int soTimeout = Protocol.DEFAULT_TIMEOUT;
40 | private String password;
41 | private int database = Protocol.DEFAULT_DATABASE;
42 | private String clientName;
43 | private boolean ssl;
44 | private SSLSocketFactory sslSocketFactory;
45 | private SSLParameters sslParameters;
46 | private HostnameVerifier hostnameVerifier;
47 | private Serializer serializer = JDKSerializer.INSTANCE;
48 | private Long timeout = 60 * 60 * 24L;
49 |
50 | public boolean isSsl() {
51 | return ssl;
52 | }
53 |
54 | public void setHost(String host) {
55 | if (host == null || "".equals(host)) {
56 | host = Protocol.DEFAULT_HOST;
57 | }
58 | this.host = host;
59 | }
60 |
61 | public void setPassword(String password) {
62 | if ("".equals(password)) {
63 | password = null;
64 | }
65 | this.password = password;
66 | }
67 |
68 | public void setClientName(String clientName) {
69 | if ("".equals(clientName)) {
70 | clientName = null;
71 | }
72 | this.clientName = clientName;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/caches/redis/RedisConfigurationBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.hiyj.blog.caches.redis;
17 |
18 | import lombok.Getter;
19 | import lombok.NonNull;
20 | import lombok.Setter;
21 | import org.springframework.beans.BeansException;
22 | import org.springframework.context.ApplicationContext;
23 | import org.springframework.context.ApplicationContextAware;
24 | import org.springframework.stereotype.Component;
25 |
26 | /**
27 | * Converter from the Config to a proper {@link RedisConfig}.
28 | *
29 | * @author Eduardo Macarron
30 | */
31 | @Getter
32 | @Component
33 | public final class RedisConfigurationBuilder implements ApplicationContextAware {
34 |
35 | private static ApplicationContext applicationContext;
36 |
37 | /**
38 | * Hidden constructor, this class can't be instantiated.
39 | */
40 | private RedisConfigurationBuilder() {
41 | }
42 |
43 | public static RedisConfig getRedisConfig() {
44 | return applicationContext.getBean(RedisConfig.class);
45 | }
46 |
47 | @Override
48 | public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
49 | RedisConfigurationBuilder.applicationContext = applicationContext;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/caches/redis/Serializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2021 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.hiyj.blog.caches.redis;
17 |
18 | public interface Serializer {
19 |
20 | /**
21 | * Serialize method
22 | *
23 | * @param object
24 | * @return serialized bytes
25 | */
26 | byte[] serialize(Object object);
27 |
28 | /**
29 | * Unserialize method
30 | *
31 | * @param bytes
32 | * @return unserialized object
33 | */
34 | Object unserialize(byte[] bytes);
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/config/WebConfig.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.config;
2 |
3 | import com.hiyj.blog.interceptor.CodeInterceptor;
4 | import com.hiyj.blog.interceptor.CrosInterceptor;
5 | import com.hiyj.blog.interceptor.MappingInterceptor;
6 | import com.hiyj.blog.interceptor.PermissionsInterceptor;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
10 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
11 |
12 | /**
13 | * 配置拦截器
14 | *
15 | * @author windSnowLi
16 | */
17 | @Configuration
18 | public class WebConfig implements WebMvcConfigurer {
19 |
20 | private CrosInterceptor cros;
21 |
22 | @Autowired
23 | public void setCros(CrosInterceptor cros) {
24 | this.cros = cros;
25 | }
26 |
27 | private MappingInterceptor mappingInterceptor;
28 |
29 | @Autowired
30 | public void setMappingInterceptor(MappingInterceptor mappingInterceptor) {
31 | this.mappingInterceptor = mappingInterceptor;
32 | }
33 |
34 | private PermissionsInterceptor permissionsInterceptor;
35 |
36 | @Autowired
37 | public void setPassTokenInterceptor(PermissionsInterceptor permissionsInterceptor) {
38 | this.permissionsInterceptor = permissionsInterceptor;
39 | }
40 |
41 |
42 | private CodeInterceptor codeInterceptor;
43 |
44 | @Autowired
45 | public void setCodeInterceptor(CodeInterceptor codeInterceptor) {
46 | this.codeInterceptor = codeInterceptor;
47 | }
48 |
49 | @Override
50 | public void addInterceptors(InterceptorRegistry registry) {
51 | registry.addInterceptor(codeInterceptor)
52 | .addPathPatterns("/**")
53 | .excludePathPatterns("/swagger**/**", "/webjars/**", "/v3/**", "/doc.html");
54 | registry.addInterceptor(cros)
55 | .addPathPatterns("/**")
56 | .excludePathPatterns("/swagger**/**", "/webjars/**", "/v3/**", "/doc.html");
57 | registry.addInterceptor(mappingInterceptor)
58 | .addPathPatterns("/**")
59 | .excludePathPatterns("/swagger**/**", "/webjars/**", "/v3/**", "/doc.html");
60 | registry.addInterceptor(permissionsInterceptor)
61 | // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
62 | .addPathPatterns("/**")
63 | .excludePathPatterns("/swagger**/**", "/webjars/**", "/v3/**", "/doc.html");
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/controller/ArticleLabelController.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.controller;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 | import com.hiyj.blog.annotation.Permission;
5 | import com.hiyj.blog.model.request.PageBaseModel;
6 | import com.hiyj.blog.object.ArticleLabel;
7 | import io.swagger.annotations.Api;
8 | import io.swagger.annotations.ApiOperation;
9 | import io.swagger.annotations.ApiResponse;
10 | import io.swagger.annotations.ApiResponses;
11 | import lombok.extern.slf4j.Slf4j;
12 | import org.springframework.beans.factory.annotation.Autowired;
13 | import org.springframework.web.bind.annotation.PostMapping;
14 | import org.springframework.web.bind.annotation.RequestBody;
15 | import org.springframework.web.bind.annotation.RequestMapping;
16 | import org.springframework.web.bind.annotation.RestController;
17 | import com.hiyj.blog.annotation.PassToken;
18 | import com.hiyj.blog.model.request.IdModel;
19 | import com.hiyj.blog.object.Msg;
20 | import com.hiyj.blog.services.ArticleLabelJsonService;
21 |
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | @Slf4j
26 | @RestController
27 | @Api(tags = "文章标签相关", value = "文章标签相关")
28 | @RequestMapping(value = "/api/articleLabel", produces = "application/json;charset=UTF-8")
29 | public class ArticleLabelController {
30 | private ArticleLabelJsonService articleLabelJsonService;
31 |
32 | @Autowired
33 | public void setArticleLabelJsonService(ArticleLabelJsonService articleLabelJsonService) {
34 | this.articleLabelJsonService = articleLabelJsonService;
35 | }
36 |
37 | /**
38 | * 通过类型ID获取类型
39 | *
40 | * @param idModel 类型ID {id:int}
41 | * @return 类型信息串
42 | */
43 | @ApiOperation(value = "通过标签ID获取标签")
44 | @ApiResponses({
45 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS, response = ArrayList.class),
46 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
47 | })
48 | @PostMapping(value = "getTypeById")
49 | @PassToken
50 | public String getTypeById(@RequestBody IdModel idModel) {
51 | return articleLabelJsonService.getTypeByIdJson(idModel.getId());
52 | }
53 |
54 | /**
55 | * 获取所有标签
56 | *
57 | * @return Msg
58 | */
59 | @ApiOperation(value = "获取所有标签")
60 | @ApiResponses({
61 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
62 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
63 | })
64 | @PostMapping(value = "getAllLabel")
65 | @PassToken
66 | public String getAllLabel() {
67 | return articleLabelJsonService.getAllLabelJson();
68 | }
69 |
70 |
71 | /**
72 | * 通过标签ID获取标签
73 | *
74 | * @param idModel 标签ID {id:int}
75 | * @return Msg
76 | */
77 | @ApiOperation(value = "通过标签ID获取标签")
78 | @ApiResponses({
79 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS, response = ArticleLabel.class),
80 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
81 | })
82 | @PostMapping(value = "getLabelById")
83 | @PassToken
84 | public String getLabelById(@RequestBody IdModel idModel) {
85 | return articleLabelJsonService.getLabelByIdJson(idModel.getId());
86 | }
87 |
88 | /**
89 | * 文章可选标签
90 | *
91 | * @return {
92 | * code: 20000,
93 | * message: "请求成功",
94 | * data: [{value:"",label:""}]
95 | * }
96 | */
97 | @ApiOperation(value = "文章可选标签")
98 | @ApiResponses({
99 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
100 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
101 | })
102 | @PostMapping(value = "labels")
103 | @PassToken
104 | public String labels() {
105 | final List allLabels = articleLabelJsonService.getAllLabel();
106 | final ArrayList labelList = new ArrayList<>();
107 | for (ArticleLabel label : allLabels) {
108 | JSONObject temp = new JSONObject();
109 | temp.put("value", label.getName());
110 | temp.put("label", label.getName());
111 | labelList.add(temp);
112 | }
113 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, labelList);
114 | }
115 |
116 | /**
117 | * 获取所有分类
118 | *
119 | * @return 分类表
120 | */
121 | @ApiOperation(value = "获取所有分类")
122 | @ApiResponses({
123 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
124 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
125 | })
126 | @PostMapping(value = "getAllType")
127 | @PassToken
128 | public String getAllType() {
129 | return articleLabelJsonService.getTypes();
130 | }
131 |
132 | /**
133 | * 分页获取标签
134 | *
135 | * @param pageBaseModel 分页信息
136 | * @return 分类表
137 | */
138 | @ApiOperation(value = "分页获取标签")
139 | @ApiResponses({
140 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
141 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
142 | })
143 | @PostMapping(value = "getLabelByPage")
144 | @PassToken
145 | public String getLabelByPage(@RequestBody PageBaseModel pageBaseModel) {
146 | return articleLabelJsonService.getLabelByPageJson(pageBaseModel.getLimit(),
147 | pageBaseModel.getPage());
148 | }
149 |
150 | /**
151 | * 设置标签内容
152 | *
153 | * @return Msg
154 | */
155 | @ApiOperation(value = "设置标签内容")
156 | @ApiResponses({
157 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
158 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
159 | })
160 | @PostMapping(value = "setLabel")
161 | @Permission(value = {"UPDATE-ARTICLE-LABEL"})
162 | public String setLabel(@RequestBody ArticleLabel articleLabel) {
163 | articleLabelJsonService.setLabel(articleLabel);
164 | return Msg.getSuccessMsg();
165 | }
166 | }
167 |
168 |
169 |
170 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/controller/CommentController.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.controller;
2 |
3 | import com.hiyj.blog.annotation.PassToken;
4 | import com.hiyj.blog.annotation.Permission;
5 | import com.hiyj.blog.model.request.*;
6 | import com.hiyj.blog.model.response.RspCommentsModel;
7 | import com.hiyj.blog.object.Comment;
8 | import com.hiyj.blog.object.Msg;
9 | import com.hiyj.blog.object.base.CommentBase;
10 | import com.hiyj.blog.services.CommentJsonService;
11 | import com.hiyj.blog.utils.JwtUtils;
12 | import io.swagger.annotations.Api;
13 | import io.swagger.annotations.ApiOperation;
14 | import io.swagger.annotations.ApiResponse;
15 | import io.swagger.annotations.ApiResponses;
16 | import lombok.extern.slf4j.Slf4j;
17 | import org.springframework.beans.factory.annotation.Autowired;
18 | import org.springframework.web.bind.annotation.PostMapping;
19 | import org.springframework.web.bind.annotation.RequestBody;
20 | import org.springframework.web.bind.annotation.RequestMapping;
21 | import org.springframework.web.bind.annotation.RestController;
22 |
23 | @Slf4j
24 | @RestController
25 | @Api(tags = "评论相关", value = "评论相关")
26 | @RequestMapping(value = "/api/comment", produces = "application/json;charset=UTF-8")
27 | public class CommentController {
28 | private CommentJsonService commentJsonService;
29 |
30 | @Autowired
31 | public void setCommentService(CommentJsonService commentJsonService) {
32 | this.commentJsonService = commentJsonService;
33 | }
34 |
35 | /**
36 | * 添加评论
37 | *
38 | * @param tokenTypeModel 评论对象和token
39 | * @return Msg
40 | */
41 | @ApiOperation(value = "通过token添加评论")
42 | @ApiResponses({
43 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
44 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
45 | })
46 | @PostMapping(value = "addComment")
47 | @Permission(value = {"COMMENT"})
48 | public String addComment(@RequestBody TokenTypeModel tokenTypeModel) {
49 | int userId = JwtUtils.getTokenUserId(tokenTypeModel.getToken());
50 | tokenTypeModel.getContent().setFromUser(userId);
51 | if (tokenTypeModel.getContent().getContent() == null || tokenTypeModel.getContent().getContent().length() == 0) {
52 | Msg.makeJsonMsg(Msg.CODE_FAIL, "内容不可为空", null);
53 | }
54 | commentJsonService.addComment(tokenTypeModel.getContent());
55 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, "评论成功,审核通过后可见。", null);
56 | }
57 |
58 | /**
59 | * 根据评论目标ID、会话类型、评论状态获取评论
60 | *
61 | * @param reqCommentModel 目标ID、会话类型、评论状态
62 | * @return Msg
63 | */
64 | @ApiOperation(value = "获取评论")
65 | @ApiResponses({
66 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS, response = RspCommentsModel.class),
67 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
68 | })
69 | @PostMapping(value = "getTargetComments")
70 | @PassToken
71 | public String getTargetComments(@RequestBody ReqCommentModel reqCommentModel) {
72 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS,
73 | commentJsonService.getTargetCommentsJson(reqCommentModel.getTargetId(),
74 | reqCommentModel.getSessionType(),
75 | reqCommentModel.getStatus()));
76 | }
77 |
78 | /**
79 | * 修改评论状态
80 | *
81 | * @param idTypeModel { id: "评论ID", content:"Status" }
82 | * @return Msg
83 | */
84 | @ApiOperation(value = "管理员修改评论状态")
85 | @ApiResponses({
86 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
87 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
88 | })
89 | @PostMapping(value = "setCommentStatus")
90 | @Permission(value = {"VERIFY-COMMENT"})
91 | public String setCommentStatus(@RequestBody IdTypeModel idTypeModel) {
92 | commentJsonService.setCommentStatus(idTypeModel.getId(), idTypeModel.getContent());
93 | return Msg.getSuccessMsg();
94 | }
95 |
96 | /**
97 | * 分页获取评论列表
98 | *
99 | * @param pageModel 分页查询对象
100 | * @return Msg
101 | */
102 | @ApiOperation(value = "分页获取评论列表")
103 | @ApiResponses({
104 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
105 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
106 | })
107 | @PostMapping(value = "getCommentList")
108 | @Permission(value = {"VERIFY-COMMENT"})
109 | public String getCommentListJson(@RequestBody PageModel pageModel) {
110 | return Msg.getSuccessMsg(commentJsonService.getCommentListJson(
111 | pageModel.getLimit(),
112 | (pageModel.getPage() - 1) * pageModel.getLimit(),
113 | pageModel.getSort(),
114 | pageModel.getStatus()));
115 | }
116 |
117 | /**
118 | * 获取所有文章最新的评论
119 | *
120 | * @param limit 条数限制 {"limit": "int"}
121 | * @return Comment json list
122 | */
123 | @ApiOperation(value = "获取所有文章最新的评论")
124 | @ApiResponses({
125 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
126 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
127 | })
128 | @PostMapping(value = "getRecentComment")
129 | @PassToken
130 | public String getRecentComment(@RequestBody ContentModel limit) {
131 | return Msg.getSuccessMsg(commentJsonService.getRecentComment(limit.getContent()));
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/controller/FileController.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.controller;
2 |
3 | import io.swagger.annotations.Api;
4 | import io.swagger.annotations.ApiOperation;
5 | import io.swagger.annotations.ApiResponse;
6 | import io.swagger.annotations.ApiResponses;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.web.bind.annotation.*;
10 | import com.hiyj.blog.annotation.PassToken;
11 | import com.hiyj.blog.annotation.Permission;
12 | import com.hiyj.blog.model.request.TokenModel;
13 | import com.hiyj.blog.model.request.TokenTypeModel;
14 | import com.hiyj.blog.object.Msg;
15 | import com.hiyj.blog.services.FileJsonService;
16 | import com.hiyj.blog.services.UserJsonService;
17 | import com.hiyj.blog.utils.JwtUtils;
18 |
19 | import java.util.Map;
20 |
21 | @Slf4j
22 | @RestController
23 | @Api(tags = "文件相关", value = "文件相关")
24 | @RequestMapping(value = "/api/file", produces = "application/json;charset=UTF-8")
25 | public class FileController {
26 | private FileJsonService fileJsonService;
27 | protected UserJsonService userJsonService;
28 |
29 | @Autowired
30 | public void setFileJsonService(FileJsonService fileJsonService) {
31 | this.fileJsonService = fileJsonService;
32 | }
33 |
34 | @Autowired
35 | public void setUserJsonService(UserJsonService userJsonService) {
36 | this.userJsonService = userJsonService;
37 | }
38 |
39 | /**
40 | * 文件上传回调
41 | *
42 | * @return 请求信息
43 | */
44 | @ApiOperation(value = "文件上传回调")
45 | @ApiResponses({
46 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
47 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
48 | })
49 | @PostMapping(value = "callback")
50 | @PassToken
51 | public String uploadCallback(@RequestHeader Map header, @RequestParam Map bodyMap, @RequestBody String ossCallbackBody) {
52 | String fileName = bodyMap.get("fileName");
53 | header.put("uri", "/api/file/callback");
54 | int userId = JwtUtils.getTokenUserId(bodyMap.get("token"));
55 | if (fileJsonService.getOssUtils().verifyOssCallbackRequest(header, ossCallbackBody)) {
56 | return Msg.getFailMsg();
57 | }
58 | userJsonService.addUserFile(userId, fileName);
59 |
60 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, null);
61 | }
62 |
63 | /**
64 | * 用户上传头像
65 | *
66 | * @param tokenModel {"token":"token"}
67 | * @return Msg {urlParams: 上传签名Url对象, GetUrl: Get请求Url}
68 | */
69 | @ApiOperation(value = "用户上传头像")
70 | @ApiResponses({
71 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
72 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
73 | })
74 | @PostMapping(value = "getUploadAvatarUrl")
75 | @Permission(value = {"UPLOAD-FILE"})
76 | public String getUploadAvatarUrl(@RequestBody TokenModel tokenModel) {
77 | int userId = JwtUtils.getTokenUserId(tokenModel.getToken());
78 |
79 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, fileJsonService.getUploadAvatarMap(tokenModel.getToken()));
80 | }
81 |
82 | /**
83 | * 文章封面上传
84 | *
85 | * @param tokenModel {"token":"token"}
86 | * @return Msg {host: 上传服务的url, urlParams: 上传签名Url对象, GetUrl: Get请求Url}
87 | */
88 | @ApiOperation(value = "文章封面上传")
89 | @ApiResponses({
90 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
91 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
92 | })
93 | @PostMapping(value = "getUploadArticleCoverImageUrl")
94 | @Permission(value = {"UPLOAD-FILE"})
95 | public String getUploadArticleCoverImageUrl(@RequestBody TokenModel tokenModel) {
96 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, fileJsonService.getUploadArticleCoverImageUrl(tokenModel.getToken()));
97 | }
98 |
99 | /**
100 | * 获取文章图片上传url和Object路径
101 | *
102 | * @param tokenModel {"token":"token"}
103 | * @return Msg {host: 上传服务的url, urlParams: 上传签名Url对象, GetUrl: Get请求Url}
104 | */
105 | @ApiOperation(value = "获取文章图片上传url和Object路径")
106 | @ApiResponses({
107 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
108 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
109 | })
110 | @PostMapping(value = "getUploadArticleImageUrl")
111 | @Permission(value = {"UPLOAD-FILE"})
112 | public String getUploadArticleImageUrl(@RequestBody TokenModel tokenModel) {
113 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, fileJsonService.getUploadArticleImageUrl(tokenModel.getToken()));
114 | }
115 |
116 | /**
117 | * 删除文件
118 | *
119 | * @param tokenTypeModel {
120 | * "token":String,
121 | * "content": filePath
122 | * }
123 | */
124 | @ApiOperation(value = "删除文件")
125 | @ApiResponses({
126 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
127 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
128 | })
129 | @PostMapping(value = "deleteObject")
130 | @Permission(value = {"DELETE-FILE"})
131 | public String deleteObject(@RequestBody TokenTypeModel tokenTypeModel) {
132 | int userId = JwtUtils.getTokenUserId(tokenTypeModel.getToken());
133 | fileJsonService.deleteUserFile(userId, tokenTypeModel.getContent());
134 | return Msg.getSuccessMsg();
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/controller/FriendLinkController.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.controller;
2 |
3 | import com.hiyj.blog.annotation.PassToken;
4 | import com.hiyj.blog.annotation.Permission;
5 | import com.hiyj.blog.model.request.ReqFriendLinkModel;
6 | import com.hiyj.blog.model.request.ReqFriendLinkStatusModel;
7 | import com.hiyj.blog.model.response.RspFriendLinkModel;
8 | import com.hiyj.blog.object.FriendLink;
9 | import com.hiyj.blog.object.Msg;
10 | import com.hiyj.blog.services.FriendLinkJsonService;
11 | import io.swagger.annotations.Api;
12 | import io.swagger.annotations.ApiOperation;
13 | import io.swagger.annotations.ApiResponse;
14 | import io.swagger.annotations.ApiResponses;
15 | import lombok.extern.slf4j.Slf4j;
16 | import org.springframework.beans.factory.annotation.Autowired;
17 | import org.springframework.web.bind.annotation.PostMapping;
18 | import org.springframework.web.bind.annotation.RequestBody;
19 | import org.springframework.web.bind.annotation.RequestMapping;
20 | import org.springframework.web.bind.annotation.RestController;
21 |
22 | @Slf4j
23 | @RestController
24 | @Api(tags = "链接相关", value = "链接相关")
25 | @RequestMapping(value = "/api/links", produces = "application/json;charset=UTF-8")
26 | public class FriendLinkController {
27 | private FriendLinkJsonService friendLinkJsonService;
28 |
29 | @Autowired
30 | public void setFriendLinkJsonService(FriendLinkJsonService friendLinkJsonService) {
31 | this.friendLinkJsonService = friendLinkJsonService;
32 | }
33 |
34 | /**
35 | * 获取友链列表
36 | *
37 | * @param fiendLinkStatusModel 友链状态 {status: FiendLink.Status}
38 | * @return Msg
39 | */
40 | @ApiOperation(value = "获取友链列表")
41 | @ApiResponses({
42 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS, response = RspFriendLinkModel.class),
43 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
44 | })
45 | @PostMapping(value = "getFriendLinks")
46 | @PassToken
47 | public String getFriendLinks(@RequestBody ReqFriendLinkStatusModel fiendLinkStatusModel) {
48 | return friendLinkJsonService.getFriendLinksJson(fiendLinkStatusModel.getStatus());
49 | }
50 |
51 | /**
52 | * 申请友链
53 | *
54 | * @param fiendLinkModel 友链信息
55 | * @return Msg
56 | */
57 | @ApiOperation(value = "申请友链")
58 | @ApiResponses({
59 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
60 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
61 | })
62 | @PostMapping(value = "applyFriendLink")
63 | @PassToken
64 | public String applyFriendLink(@RequestBody ReqFriendLinkModel fiendLinkModel) {
65 | return friendLinkJsonService.applyFriendLinkJson(fiendLinkModel);
66 | }
67 |
68 | /**
69 | * 设置友链整体对象
70 | *
71 | * @param friendLink 友链对象
72 | * @return Msg
73 | */
74 | @ApiOperation(value = "设置友链状")
75 | @ApiResponses({
76 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
77 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
78 | })
79 | @PostMapping(value = "setFriendLink")
80 | @Permission(value = {"VERIFY-LINK"})
81 | public String setFriendLink(@RequestBody FriendLink friendLink) {
82 | return friendLinkJsonService.setFriendLinkJson(friendLink);
83 | }
84 | }
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/controller/OtherController.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.controller;
2 |
3 | import com.hiyj.blog.annotation.Permission;
4 | import com.hiyj.blog.object.Msg;
5 | import com.hiyj.blog.services.OtherJsonService;
6 | import io.swagger.annotations.Api;
7 | import io.swagger.annotations.ApiOperation;
8 | import io.swagger.annotations.ApiResponse;
9 | import io.swagger.annotations.ApiResponses;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.web.bind.annotation.PostMapping;
13 | import org.springframework.web.bind.annotation.RequestMapping;
14 | import org.springframework.web.bind.annotation.RestController;
15 |
16 | @Slf4j
17 | @RestController
18 | @Api(tags = "后台杂项", value = "后台杂项")
19 | @RequestMapping(value = "/api/other", produces = "application/json;charset=UTF-8")
20 | @Permission(value = {"BACKGROUND-LOGIN"})
21 | public class OtherController {
22 | private OtherJsonService otherJsonService;
23 |
24 | @Autowired
25 | public void setOtherJsonService(OtherJsonService otherJsonService) {
26 | this.otherJsonService = otherJsonService;
27 | }
28 |
29 | /**
30 | * 获取仪表盘折线图和panel-group部分
31 | *
32 | * @return Msg
33 | */
34 | @ApiOperation(value = "获取仪表盘折线图和panel-group部分")
35 | @ApiResponses({
36 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
37 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
38 | })
39 | @PostMapping(value = "getPanel")
40 | public String getPanel() {
41 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, otherJsonService.getPanel());
42 | }
43 |
44 | /**
45 | * 获取图表信息
46 | *
47 | * @return Msg
48 | */
49 | @ApiOperation(value = "获取图表信息")
50 | @ApiResponses({
51 | @ApiResponse(code = 20000, message = Msg.MSG_SUCCESS),
52 | @ApiResponse(code = -1, message = Msg.MSG_FAIL)
53 | })
54 | @PostMapping(value = "getChart")
55 | public String getChart() {
56 | return Msg.makeJsonMsg(Msg.CODE_SUCCESS, Msg.MSG_SUCCESS, otherJsonService.getChart());
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/doc/SwaggerConfig.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.doc;
2 |
3 | import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
4 | import com.hiyj.blog.object.Msg;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.context.annotation.Profile;
9 | import org.springframework.http.HttpMethod;
10 | import springfox.documentation.builders.ApiInfoBuilder;
11 | import springfox.documentation.builders.PathSelectors;
12 | import springfox.documentation.builders.RequestHandlerSelectors;
13 | import springfox.documentation.builders.ResponseBuilder;
14 | import springfox.documentation.service.Contact;
15 | import springfox.documentation.service.Response;
16 | import springfox.documentation.spi.DocumentationType;
17 | import springfox.documentation.spring.web.plugins.Docket;
18 | import springfox.documentation.swagger2.annotations.EnableSwagger2;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | @Configuration
24 | @EnableSwagger2
25 | @Profile("dev")
26 | public class SwaggerConfig {
27 |
28 | private OpenApiExtensionResolver openApiExtensionResolver;
29 |
30 | @Autowired
31 | public void setOpenApiExtensionResolver(OpenApiExtensionResolver openApiExtensionResolver) {
32 | this.openApiExtensionResolver = openApiExtensionResolver;
33 | }
34 |
35 | @Bean
36 | public Docket createRestApi() {
37 | List responseMessageList = new ArrayList<>();
38 | responseMessageList.add(
39 | new ResponseBuilder().code(String.valueOf(Msg.CODE_SUCCESS)).build()
40 | );
41 |
42 | responseMessageList.add(
43 | new ResponseBuilder().code(String.valueOf(Msg.CODE_FAIL)).build()
44 | );
45 |
46 | return new Docket(DocumentationType.SWAGGER_2)
47 | .useDefaultResponseMessages(false)
48 | .globalResponses(HttpMethod.POST, responseMessageList)
49 | .globalResponses(HttpMethod.GET, responseMessageList)
50 | .globalResponses(HttpMethod.PUT, responseMessageList)
51 | .globalResponses(HttpMethod.DELETE, responseMessageList)
52 | .pathMapping("/")
53 | .select()
54 | .apis(RequestHandlerSelectors.any())
55 | .paths(PathSelectors.any())
56 | .build().host("http://127.0.0.1:8888")
57 | .apiInfo(new ApiInfoBuilder()
58 | .title("w-blog-api接口")
59 | .description("w-blog-api接口")
60 | .contact(new Contact("WindSnowLi", "https://www.blog.firstmeet.xyz/", "windsnowli@163.com"))
61 | .license("The MIT License")
62 | .licenseUrl("https://github.com/WindSnowLi/w-blog-api/blob/master/LICENSE")
63 | .version("0.0.1")
64 | .build())
65 | .extensions(openApiExtensionResolver.buildExtensions("md"));
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/exception/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.exception;
2 |
3 | import com.auth0.jwt.exceptions.JWTVerificationException;
4 | import org.springframework.web.bind.annotation.ExceptionHandler;
5 | import com.hiyj.blog.object.Msg;
6 |
7 | public class GlobalExceptionHandler {
8 |
9 | /**
10 | * 处理JWTVerificationException异常
11 | */
12 | @ExceptionHandler(JWTVerificationException.class)
13 | public Msg jWTVerificationExceptionHandler() {
14 | return Msg.makeMsg(Msg.CODE_FAIL, Msg.MSG_FAIL, null);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/interceptor/CodeInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.interceptor;
2 |
3 | import org.springframework.stereotype.Component;
4 | import org.springframework.web.servlet.HandlerInterceptor;
5 | import org.springframework.web.servlet.ModelAndView;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 |
10 | /**
11 | * @author windSnowLi
12 | */
13 | @Component
14 | public class CodeInterceptor implements HandlerInterceptor {
15 | @Override
16 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
17 | request.setCharacterEncoding("utf-8");
18 | response.setCharacterEncoding("utf-8");
19 | return true;
20 | }
21 |
22 | @Override
23 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
24 | request.setCharacterEncoding("utf-8");
25 | response.setCharacterEncoding("utf-8");
26 | }
27 |
28 | @Override
29 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
30 | request.setCharacterEncoding("utf-8");
31 | response.setCharacterEncoding("utf-8");
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/interceptor/CrosInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.interceptor;
2 |
3 | import org.springframework.stereotype.Component;
4 | import org.springframework.web.servlet.HandlerInterceptor;
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 | import javax.servlet.http.HttpServletResponse;
8 |
9 | /**
10 | * 拦截器,允许跨域
11 | *
12 | * @author windSnowLi
13 | */
14 | @Component
15 | public class CrosInterceptor implements HandlerInterceptor {
16 | final public static String OPTIONS = "OPTIONS";
17 |
18 | @Override
19 | public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
20 |
21 |
22 | httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
23 |
24 | httpServletResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization,token,Accept,X-Requested-With");
25 |
26 | httpServletResponse.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
27 |
28 | httpServletResponse.setHeader("Access-Control-Max-Age", "3600");
29 | String method = httpServletRequest.getMethod();
30 |
31 | if (OPTIONS.equals(method)) {
32 | httpServletResponse.setStatus(200);
33 | return false;
34 | }
35 |
36 | return true;
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/interceptor/MappingInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.interceptor;
2 |
3 | import org.springframework.stereotype.Component;
4 | import org.springframework.web.method.HandlerMethod;
5 | import org.springframework.web.servlet.HandlerInterceptor;
6 |
7 | import javax.servlet.http.HttpServletRequest;
8 | import javax.servlet.http.HttpServletResponse;
9 |
10 | /**
11 | * @author windSnowLi
12 | */
13 | @Component
14 | public class MappingInterceptor implements HandlerInterceptor {
15 | @Override
16 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
17 | // 如果不是映射到方法直接拒绝
18 | return handler instanceof HandlerMethod;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/interceptor/PermissionsInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * PermissionsInterceptor.java, 2021-08-26
3 | *
4 | * Copyright 2021 by WindSnowLi, Inc. All rights reserved.
5 | *
6 | */
7 |
8 | package com.hiyj.blog.interceptor;
9 |
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.stereotype.Component;
12 | import org.springframework.web.method.HandlerMethod;
13 | import org.springframework.web.servlet.HandlerInterceptor;
14 | import com.hiyj.blog.annotation.PassToken;
15 | import com.hiyj.blog.annotation.Permission;
16 | import com.hiyj.blog.object.Msg;
17 | import com.hiyj.blog.object.Role;
18 | import com.hiyj.blog.object.User;
19 | import com.hiyj.blog.object.base.PermissionRole;
20 | import com.hiyj.blog.services.base.PermissionService;
21 | import com.hiyj.blog.services.base.RoleService;
22 | import com.hiyj.blog.services.base.UserService;
23 | import com.hiyj.blog.utils.JwtUtils;
24 |
25 | import javax.servlet.http.HttpServletRequest;
26 | import javax.servlet.http.HttpServletResponse;
27 | import java.lang.reflect.Method;
28 | import java.util.List;
29 |
30 | /**
31 | * @author windSnowLi
32 | */
33 | @Component
34 | public class PermissionsInterceptor implements HandlerInterceptor {
35 |
36 | private UserService userService;
37 |
38 | @Autowired
39 | public void setUserService(UserService userService) {
40 | this.userService = userService;
41 | }
42 |
43 | private PermissionService permissionService;
44 |
45 | @Autowired
46 | public void setPermissionService(PermissionService permissionService) {
47 | this.permissionService = permissionService;
48 | }
49 |
50 | private RoleService roleService;
51 |
52 | @Autowired
53 | public void setRoleService(RoleService roleService) {
54 | this.roleService = roleService;
55 | }
56 | @Override
57 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
58 | HandlerMethod handlerMethod = (HandlerMethod) object;
59 | Method method = handlerMethod.getMethod();
60 | //检查是否有passToken注释,有则跳过认证
61 | if (method.isAnnotationPresent(PassToken.class)) {
62 | PassToken passToken = method.getAnnotation(PassToken.class);
63 | if (passToken.required()) {
64 | return true;
65 | }
66 | }
67 | if (method.isAnnotationPresent(Permission.class) || method.getDeclaringClass().isAnnotationPresent(Permission.class)) {
68 | Permission permissionClass = method.getAnnotation(Permission.class) == null ?
69 | method.getDeclaringClass().getAnnotation(Permission.class) :
70 | method.getAnnotation(Permission.class);
71 | if (permissionClass.value().length == 0) {
72 | response.getWriter().println(Msg.getFailMsg("没有相应权限"));
73 | return false;
74 | } else {
75 | // 从 http 请求头中取出 token
76 | String token = request.getHeader("token");
77 | List rolePermissionsName;
78 | if (token == null || token.equals("")) {
79 | //获取默认的访问角色权限
80 | rolePermissionsName = permissionService.getRolePermissionsName(
81 | roleService.getRoleByName(Role.VISITOR).getId(), PermissionRole.Status.NORMAL);
82 | } else {
83 | // 获取 token 中的 user id
84 | int userId = JwtUtils.getTokenUserId(token);
85 | User user = userService.findUserById(userId);
86 | String userAccount = JwtUtils.getTokenUserAccount(token);
87 | String userPassword = JwtUtils.getTokenUserPassword(token);
88 | if (user == null || !user.getPassword().equals(userPassword) || !user.getAccount().equals(userAccount)) {
89 | response.getWriter().println(Msg.getFailMsg("身份验证错误"));
90 | return false;
91 | }
92 | rolePermissionsName = permissionService.getUserPermissionsName(userId);
93 | }
94 |
95 | for (String value : permissionClass.value()) {
96 | // 如果用户不包含所需权限则不允许访问
97 | if (!rolePermissionsName.contains(value)) {
98 | response.getWriter().println(Msg.getFailMsg("没有相应权限"));
99 | return false;
100 | }
101 | }
102 | }
103 | }
104 | return true;
105 | }
106 | }
--------------------------------------------------------------------------------
/src/main/java/com/hiyj/blog/mapper/ArticleLabelMapper.java:
--------------------------------------------------------------------------------
1 | package com.hiyj.blog.mapper;
2 |
3 | import com.hiyj.blog.object.ArticleLabel;
4 | import com.hiyj.blog.object.ArticleType;
5 | import com.hiyj.blog.object.base.LabelBase;
6 | import org.apache.ibatis.annotations.Delete;
7 | import org.apache.ibatis.annotations.Mapper;
8 | import org.apache.ibatis.annotations.Param;
9 | import org.apache.ibatis.annotations.Select;
10 | import org.springframework.stereotype.Repository;
11 |
12 | import java.util.List;
13 | import java.util.Map;
14 |
15 | @Mapper
16 | @Repository
17 | public interface ArticleLabelMapper {
18 | /**
19 | * 通过类型ID获取类型
20 | *
21 | * @param typeId 标签ID
22 | * @return 类型对象
23 | */
24 | LabelBase getTypeById(@Param("typeId") int typeId);
25 |
26 | /**
27 | * 通过类型名获取类型
28 | *
29 | * @param typeName 类型名
30 | * @return 类型对象
31 | */
32 | ArticleType getTypeByName(@Param("typeName") String typeName);
33 |
34 | /**
35 | * 通过标签ID获取标签
36 | *
37 | * @param labelId 标签ID
38 | * @return 标签对象
39 | */
40 | ArticleLabel getLabelById(@Param("labelId") int labelId);
41 |
42 | /**
43 | * 通过文章ID获取文章所属类型ID
44 | *
45 | * @param articleId 文章ID
46 | * @return 文章类型ID
47 | */
48 | int getArticleTypeById(@Param("articleId") int articleId);
49 |
50 | /**
51 | * 添加文章——分类映射
52 | *
53 | * @param articleId 文章ID
54 | * @param typeId 所属类型
55 | */
56 | void addArticleMapType(@Param("articleId") int articleId, @Param("typeId") int typeId);
57 |
58 | /**
59 | * 获取所有标签
60 | *
61 | * @return List ArticleLabel
62 | */
63 | List getAllLabel();
64 |
65 | /**
66 | * 清空文章标签
67 | *
68 | * @param articleId 文章标签
69 | */
70 | @Delete("DELETE FROM article_map_label WHERE article_id=#{articleId}")
71 | void deleteLabels(@Param("articleId") int articleId);
72 |
73 | /**
74 | * 清空文章分类
75 | *
76 | * @param articleId 文章标签
77 | */
78 | @Delete("DELETE FROM article_map_type WHERE article_id=#{articleId}")
79 | void deleteType(@Param("articleId") int articleId);
80 |
81 | /**
82 | * 按分类获取每个分类多少文章
83 | *
84 | * @param limit 取最多的前几条
85 | * @return [{name=String, value=Object}]
86 | */
87 | @Select("select t.num as value, al.name from " +
88 | "( " +
89 | "select count(*) as num, amt.type_id from article_map_type amt group by type_id order by num desc limit #{limit} " +
90 | ") " +
91 | "t " +
92 | "LEFT JOIN article_label al on t.type_id = al.id " +
93 | "order by num desc ")
94 | List